星期日, 十二月 30, 2007

我写的spi按键的驱动程序

由于工作需要,学着写了工作以来第一个真正能用的基于spi通信的按键程序,至于为什么,优缺点之类的就不是我要考虑的了,因为硬件工程师已经给设计成这样了,所以我只管写就好了

下面是arm主程序:
主要是参考了网上大家的一些方法,至于很多东西自己也不是很清楚,毕竟做linux驱动才几个月,还有就是在选择按键码的部分,后来对应得键码换了好多次,所以注释和代码不一致,这部分是为了对应单片机所以一改再改,反正最后能用最重要,键码的修改也比较简单,放在这就当个备份吧,呵呵

/********************************************************************/
/********************************************************************/
/*********Description: SPI keyboard driver ***************/
/*********Author: Kenshinxf <xuefengwang101@gmail.com> ***************/
/*********Date: 2007/11/12 **************/
/********************************************************************/
/********************************************************************/

#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/irq.h>
#include <linux/input.h>

#include <asm/irq.h>
#include <asm/io.h>

#include <asm/hardware.h>

#include <linux/module.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/iobuf.h>
#include <linux/highmem.h>
#include <linux/in.h>
#include <linux/vmalloc.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <linux/tqueue.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/keyboard.h>

#ifdef CONFIG_DEVFS_FS
#include <linux/devfs_fs_kernel.h>
#endif
#include <linux/kbd_kern.h>

devfs_handle_t MegaKbd_devfs_dir;
//#define spi_debug

void input_register_device (struct input_dev *);

void input_unregister_device (struct input_dev *);

void input_register_handler (struct input_handler *);
void input_unregister_handler (struct input_handler *);

int input_open_device (struct input_handle *);
void input_close_device (struct input_handle *);

devfs_handle_t input_register_minor (char *name, int minor, int minor_base);
void input_unregister_minor (devfs_handle_t handle);

void input_event (struct input_dev *dev, unsigned int type, unsigned int code,
int value);

#define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c))

#define DEVICE_NAME "MegaKbd"
#define MegaKbd_MAJOR 232

#define U8 unsigned char
#define U32 unsigned int

#define rSPCON0 (*(volatile unsigned long *)r_SPCON0) /*SPI control Register */
#define rSPSTA0 (*(volatile unsigned long *)r_SPSTA0) /*SPI status Register */
#define rSPPIN0 (*(volatile unsigned long *)r_SPPIN0) /* SPI pin control Register */
#define rSPPRE0 (*(volatile unsigned long *)r_SPPRE0) /*SPI Baud Rate Prescaler Register */
#define rSPTDAT0 (*(volatile unsigned long *)r_SPTDAT0) /*SPI Tx Data Register */
#define rSPRDAT0 (*(volatile unsigned long *)r_SPRDAT0) /*SPI Rx Data Register */

#define rGPECON (*(volatile unsigned long *)r_GPECON) /*Configure the pins of port E */
#define rGPEUP (*(volatile unsigned long *)r_GPEUP) /*Pull-up disable register for port E */
#define rGPGCON (*(volatile unsigned long *)r_GPGCON) /*Configure the pins of port G */
#define rGPGUP (*(volatile unsigned long *)r_GPGUP) /*Pull-up disable register for port G */
#define rGPGDAT (*(volatile unsigned long *)r_GPGDAT) /*The data register for port G */
unsigned long r_SPCON0, r_SPSTA0, r_SPPIN0, r_SPPRE0, r_SPTDAT0, r_SPRDAT0;
unsigned long r_GPECON, r_GPEUP;
unsigned long r_GPGCON, r_GPGUP, r_GPGDAT;

static struct input_dev *button_dev;

static void spi_poll_done (void);
void spi_tx_data (U8 data);

static int keycode = 0;
static DECLARE_WAIT_QUEUE_HEAD (key_wait);

/*address_map*/
int
address_map (void)
{
//SPI registers
r_SPCON0 = ioremap (0x59000000, 4);
r_SPSTA0 = ioremap (0x59000004, 4);
r_SPPIN0 = ioremap (0x59000008, 4);
r_SPPRE0 = ioremap (0x5900000C, 4);
r_SPTDAT0 = ioremap (0x59000010, 4);
r_SPRDAT0 = ioremap (0x59000014, 4);
//I/O registers
r_GPECON = ioremap (0x56000040, 4);
r_GPEUP = ioremap (0x56000048, 4);
r_GPGCON = ioremap (0x56000060, 4);
r_GPGUP = ioremap (0x56000068, 4);
r_GPGDAT = ioremap (0x56000064, 4);


return 0;
}

/**********************************************************/
static void spi_poll_done (void)
{
int j = 0;

while (!(rSPSTA0 & 0x01))
{
j++;
if (j >= 5000)
{
printk ("SPI state poll failed\n");
break;
}
} //endwhile
}

/**********************************************************/
void spi_tx_data (U8 data)
{
spi_poll_done ();
rSPTDAT0 = data; //transmit data
spi_poll_done ();
}

/**********************************************************/
void Init_SPI (void)
{
int i, config, value;
#ifdef spi_debug
printk ("************************\n*");
printk ("spi open program begin..\n");
printk ("now,GPE AND GPG port init...\n");
#endif

rSPPRE0 = 0xff;

#ifdef spi_debug
value = rSPPRE0;
printk ("rSPPRE0=0x%x\n", value);
#endif

for (i = 0; i < 10; i++)
{
rSPTDAT0 = 0xff;
}
rGPECON = (rGPECON & 0xf03fffff) | 0x0a800000; //GPECON-11,12,13=10
#ifdef spi_debug
value = rGPECON;
printk ("GPECON=0x%x\n", value);
#endif
rGPEUP |= 0x3800; //GPE11,12,13 pull-up disable

#ifdef spi_debug
value = rGPEUP;
printk ("GPEUP=0x%x\n", value);
#endif

rGPGCON = (rGPGCON & 0xffffffde) | 0x00000032;
#ifdef spi_debug
value = rGPGCON;
printk ("rGPGCON=0x%x\n", value);
#endif

rGPGUP |= 0x4; //GPG2 pull-up disable;
#ifdef spi_debug
value = rGPGUP;
printk ("rGPGUP=0x%x\n", value);
#endif

//select the chip
set_gpio_ctrl (GPIO_G2 | GPIO_PULLUP_EN | GPIO_MODE_OUT);
write_gpio_bit (GPIO_G2, 0);

#ifdef spi_debug
printk ("GPE AND GPG port init end!\n");
printk ("**************************\n");
#endif

}

/*********************Drive********************************/

static void megakbd_irq (int irq, void *dev_id, struct pt_regs *reg)
{
int i = 0;
int down = 0, keycode = 0;
int config;
char string;
#ifdef spi_debug
printk ("**************************\n");
printk ("\nThis is MegaKbd irq service\n");
printk ("SPI polling TX/RX Test...\n");
#endif
rSPCON0 = (1 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (0 << 1) | (0 << 0);
#ifdef spi_debug
config = (int) rSPCON0;
printk ("rSPCON0=0x%x\n", config);
#endif
//polling,en-sck,master,low,format A,nomal
rSPPIN0 = (0 << 2) | (1 << 1) | (0 << 0);
//Multi Master error detect disable,reserved,release
#ifdef spi_debug
config = (int) rSPPIN0;
printk ("rSPPIN0=0x%x\n", config);
#endif
spi_tx_data (0xff);
#ifdef spi_debug
string = rSPTDAT0;
printk ("transmit char=0x%x\n", string);
printk ("transmit char=%c\n", string);

string = rSPRDAT0;
printk ("receive char=%c\n", string);
printk ("receive char=0x%x\n", string);
#endif

keycode = rSPRDAT0;
#ifdef spi_debug
printk ("\nkeycode is %d\n", keycode);
#endif
switch (keycode)
{
case 255:
break;
/*
case 12: //1 down
keycode = KEY_1; //2;
down = 1;
break;
case 11: //1 up
keycode = KEY_1; //2;
break;
*/
case 42: //2 down
keycode = KEY_2; //3;
down = 1;
break;
case 41: //2 up
keycode = KEY_2; //3;
break;
/*
case 72: //3 down
keycode = KEY_3; //4;
down = 1;
break;
case 71: //3 up
keycode = KEY_3; //4;
break;
*/
//key #


case 9: //4 down
keycode = KEY_ENTER; //5;
down = 1;
break;
case 8: //4 up
keycode = KEY_ENTER; //5;
break;

case 39: //5 down
keycode = KEY_9; //6;
down = 1;
break;
case 38: //5 up
keycode = KEY_9; //6;
break;

case 69: //6 down
keycode = KEY_3; //7;
down = 1;
break;
case 68: //6 up
keycode = KEY_3; //7;
break;
case 6: //7 down
keycode = KEY_0; //8;
down = 1;
break;
case 5: //7 up
keycode = KEY_0; //8;
break;
case 36: //8 down
keycode = KEY_8; //9;
down = 1;
break;
case 35: //8 up
keycode = KEY_8; //9;
break;
case 66: //9 down
keycode = KEY_2; //10;
down = 1;
break;
case 65: //9 up
keycode = KEY_2; //10;
break;
case 33: //0 down
keycode = KEY_7; //11;
down = 1;
break;
case 32: //0 up
keycode = KEY_7; //11;
break;

//key *
case 3: //asterisk down shift+8
keycode = KEY_KPASTERISK; //55;
// keycode = KEY_LEFTSHIFT;
down = 1;
// input_report_key(&button_dev, keycode, down);
// input_sync(&button_dev);
// keycode = KEY_8;
// keycode = KEY_KPASTERISK; //55;
// down = 1;
break;
case 2: //asterisk up 8+shift
keycode = KEY_KPASTERISK; //55;
// keycode = KEY_8;
// input_report_key(&button_dev, keycode, down);
// input_sync(&button_dev);
// keycode = KEY_LEFTSHIFT;
// keycode = KEY_KPASTERISK; //55;
break;

case 63: //numbersign down shift+3
keycode = KEY_1;
// keycode = KEY_LEFTSHIFT;
down = 1;
// input_report_key(&button_dev, keycode, down);
// input_sync(&button_dev);
// keycode = KEY_3;
// keycode = KEY_KPPLUS;
// down = 1;
break;
case 62: //numbersign up 3+shift
keycode = KEY_1;
// input_report_key(&button_dev, keycode, down);
// input_sync(&button_dev);
// keycode = KEY_LEFTSHIFT;
// keycode = KEY_KPPLUS;
break;

case 27: //enter down
keycode = KEY_ENTER; //28;
down = 1;
break;
case 26: //enter up
keycode = KEY_ENTER; //28;
break;
case 57: //esc down
keycode = KEY_BACKSPACE; //1;
down = 1;
break;
case 56: //esc up
keycode = KEY_BACKSPACE; //1;
break;
case 15: //backspace down
keycode = KEY_S;
down = 1;
break;
case 14: //backspace up
keycode = KEY_S;
break;
case 75: //left down
keycode = KEY_LEFT;
down = 1;
break;
case 74: //left up
keycode = KEY_LEFT;
break;
case 60: //right down
keycode = KEY_L;
down = 1;
break;
case 59: //right up
keycode = KEY_L;
break;
case 30: //up down
keycode = KEY_UP;
down = 1;
break;
case 29: //up up
keycode = KEY_UP;
break;
/*
case 45: //down down
keycode = KEY_4;
down = 1;
break;
case 44: //down up
keycode = KEY_4;
break;
*/
case 24: //f1 down
keycode = KEY_F1;
down = 1;
break;
case 23: //f1 up
keycode = KEY_F1;
break;
case 54: //f2 down
keycode = KEY_6;
down = 1;
break;
case 53: //f2 up
keycode = KEY_6;
break;
case 21: //f3 down
keycode = KEY_F3;
down = 1;
break;
case 20: //f3 up
keycode = KEY_F3;
break;
case 51: //f4 down
keycode = KEY_5;
down = 1;
break;
case 50: //f4 up
keycode = KEY_5;
break;
case 18: //f5 down
keycode = KEY_F5;
down = 1;
break;
case 17: //f5 up
keycode = KEY_F5;
break;
case 48: //f6 down
keycode = KEY_4;
down = 1;
break;
case 47: //f6 up
keycode = KEY_4;
break;

default:;
}
#ifdef spi_debug
printk("keycode=0x%x\n",keycode);
#endif
if (keycode)
{
input_report_key (&button_dev, keycode, down);
// input_sync(&button_dev);
// printk("*********************[%d]", keycode);
}

// printk ("\nkeycode=[0x%x]\n", keycode);
// printk ("\nkeycode=[%d]\n", keycode);

handle_scancode (keycode, down);
tasklet_schedule (&keyboard_tasklet);
wake_up_interruptible (&key_wait);
}

//Read for megaKbd
static ssize_t megaKbd_read (struct file *file, char *buf, size_t count, loff_t * offset)
{
static int key;
key = keycode;
copy_to_user (buf, &key, sizeof key);
return sizeof keycode;

}


//Write to megaKbd
ssize_t megaKbd_write (struct file *file, char *buf, size_t count, loff_t * offset)
{

int i = 0;
int config;
int string;
#ifdef spi_debug
printk ("SPI polling TX/RX Test...\n");
printk ("Connet SPIMOSI0 into SPIMISO\n");
#endif
rSPCON0 = (1 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (0 << 1) | (0 << 0);
// config = (int) rSPCON0;
// printk ("rSPCON0=0x%x\n", config);

//polling,en-sck,master,low,format A,nomal
rSPPIN0 = (0 << 2) | (1 << 1) | (0 << 0);

//Multi Master error detect disable,reserved,release
// config = (int) rSPPIN0;
// printk ("rSPPIN0=0x%x\n", config);
spi_tx_data (*buf);
string = rSPTDAT0;
#ifdef spi_debug
printk ("\ntransmit char=%c\n", string);
printk ("transmit char=0x%x\n", string);
#endif
string = rSPRDAT0;
#ifdef spi_debug
printk (" receive char=%c\n\n\n", string);
printk (" receive char=0x%x\n\n\n", string);
printk ("****************\n");
printk ("****************\n");
printk ("****************\n");
printk ("****************\n");
printk ("****************\n");
printk ("****************\n");
#endif
return 0;

}

/**********************************************************/
//Open the megaKbd device
static int megaKbd_open (struct inode *inode, struct file *file)
{
return 0;
}

/**********************************************************/
//Close the megaKbd device
static int megaKbd_close (struct inode *inode, struct file *file)
{
return 0;
}

/**********************************************************/
static struct file_operations megaKbd_fops = {
owner:THIS_MODULE,
llseek:no_llseek,
read:megaKbd_read,
write:megaKbd_write,
open:megaKbd_open,
release:megaKbd_close,
};

static int __init HW_kbd_init (void)
{
unsigned int result;

// set_external_irq (IRQ_EINT8, EXT_FALLING_EDGE, GPIO_PULLUP_DIS);
set_external_irq (IRQ_EINT8, EXT_RISING_EDGE, GPIO_PULLUP_DIS);
disable_irq (IRQ_EINT8);
enable_irq (IRQ_EINT8);
result = request_irq (IRQ_EINT8, &megakbd_irq, SA_INTERRUPT, DEVICE_NAME, &megakbd_irq);
if (result)
{
printk ("Can't get assigned irq %d,result=%d\n", IRQ_EINT8, result);
return result;
}
}

static int mega_kbd_translate (U8 scancode, U8 * keycode, char raw_mode)
{
int Result = 1;
printk ("my transleate\n");
*keycode = (scancode & 0x7f);
return 1;
}


static int __init megaKbd_code (void)
{

/*
button_dev = input_allocate_device();
if (!button_dev) {
printk(KERN_ERR "input: not enough memory for input device\n");
return -ENOMEM;
}
*/
// input_register_device(&button_dev);
button_dev->name = "Spi Keyboard";
// button_dev->phys = "input/input0";
button_dev->evbit[0] = BIT (EV_KEY);
// button_dev->keybit[LONG(KEY_NUMLOCK)] = BIT(KEY_NUMLOCK);
set_bit (KEY_0, button_dev->keybit);
set_bit (KEY_1, button_dev->keybit);
set_bit (KEY_2, button_dev->keybit);
set_bit (KEY_3, button_dev->keybit);
set_bit (KEY_4, button_dev->keybit);
set_bit (KEY_5, button_dev->keybit);
set_bit (KEY_6, button_dev->keybit);
set_bit (KEY_7, button_dev->keybit);
set_bit (KEY_8, button_dev->keybit);
set_bit (KEY_9, button_dev->keybit);

set_bit (KEY_F1, button_dev->keybit);
set_bit (KEY_F2, button_dev->keybit);
set_bit (KEY_F3, button_dev->keybit);
set_bit (KEY_F4, button_dev->keybit);
set_bit (KEY_F5, button_dev->keybit);
set_bit (KEY_F6, button_dev->keybit);

set_bit (KEY_ENTER, button_dev->keybit);
set_bit (KEY_ESC, button_dev->keybit);
set_bit (KEY_UP, button_dev->keybit);
set_bit (KEY_DOWN, button_dev->keybit);
set_bit (KEY_LEFT, button_dev->keybit);
set_bit (KEY_RIGHT, button_dev->keybit);

set_bit (KEY_BACKSPACE, button_dev->keybit);
set_bit (KEY_LEFTSHIFT, button_dev->keybit);
set_bit (KEY_KPASTERISK, button_dev->keybit);
set_bit (KEY_KPPLUS, button_dev->keybit);

input_register_device (&button_dev);
return 0;
}


/**********************************************************/
// Install the megaKbd driver
static int __init megaKbd_init (void)
{
unsigned int result;

//Init Spi Device
address_map ();
Init_SPI ();

result = HW_kbd_init ();
if (result)
return result;

//k_translate = mega_kbd_translate;

megaKbd_code ();
result = register_chrdev (MegaKbd_MAJOR, DEVICE_NAME, &megaKbd_fops);
if (result < 0)
{
printk (DEVICE_NAME "cannot register maor number\n");
return result;
}

//Register device
MegaKbd_devfs_dir = devfs_mk_dir (NULL, "MegaKbd", NULL);

devfs_register (MegaKbd_devfs_dir, DEVICE_NAME, DEVFS_FL_AUTO_DEVNUM, 0, 0, S_IFCHR | S_IRUGO | S_IWUGO, &megaKbd_fops, NULL);
printk ("megaKbd driver installed OK\n");

return 0;
}

/**********************************************************/
// Remove the megaKbd driver
static void megaKbd_exit (void)
{
//Disable Interrupt
// disable_irq (IRQ_EINT8);
free_irq (IRQ_EINT8, NULL);

devfs_unregister (MegaKbd_devfs_dir);
input_unregister_device (&button_dev);
printk ("megaKbd driver uninstalled OK\n");
}

module_init (megaKbd_init);
module_exit (megaKbd_exit);

MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("Kenshinxf <xuefengwang101@gmail.com>");
MODULE_DESCRIPTION ("keyboard driver with spi S3C2410 board");

本来说只写arm就好了,谁知道最后单片机也得我写,真是。。。。

那就写吧,说写,其实就是改改一个师哥以前的单片机程序,不知道其他人为什么就不会呢?自己也没搞过单片机,工作后就直接arm了,其实还是比较简单的

下面是单片机程序:

/**key.c***/

#include <mega88.h>
#include "key.h"

#define INT PORTC.2
unsigned char ScanState = 0;
unsigned char KeyDelay[25];
unsigned char temp0;
bit flag0 = 0;

void SendKeyChar(unsigned char KeyValue)
{
PINC.5 = 1;
//SpiPutChar(KeyValue);
//I2cSendChar(KeyValue);
temp0 = SPSR;
SPDR = KeyValue;
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
INT = 1;
flag0 = 1;
}

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0=0x80;
switch(ScanState)
{
case 0:
if(Col1Row1 == ROW1)
{
if(Col1Row1 == 0)
{
if(++KeyDelay[0] == 7)
{
KeyDelay[0] = 0;
if(ColRow11)
{
ColRow11 = 0;
SendKeyChar(1);
}
}
}
}
else
{
if(Col1Row1 == 0) SendKeyChar(2);
else
{
KeyDelay[0] = 0;
ColRow11 = 1;
SendKeyChar(3);
}
}
Col1Row1 = ROW1;
if(Col1Row2 == ROW2)
{
if(Col1Row2 == 0)
{
if(++KeyDelay[1] == 7)
{
KeyDelay[1] = 0;
if(ColRow12)
{
ColRow12 = 0;
SendKeyChar(4);
}
}
}
}
else
{
if(Col1Row2 == 0) SendKeyChar(5);
else
{
KeyDelay[1] = 0;
ColRow12 = 1;
SendKeyChar(6);
}
}
Col1Row2 = ROW2;
if(Col1Row3 == ROW3)
{
if(Col1Row3 == 0)
{
if(++KeyDelay[2] == 7)
{
KeyDelay[2] = 0;
if(ColRow13)
{
ColRow13 = 0;
SendKeyChar(7);
}
}
}
}
else
{
if(Col1Row3 == 0) SendKeyChar(8);
else
{
KeyDelay[2] = 0;
ColRow13 = 1;
SendKeyChar(9);
}
}
Col1Row3 = ROW3;
if(Col1Row4 == ROW4)
{
if(Col1Row4 == 0)
{
if(++KeyDelay[3] == 7)
{
KeyDelay[3] = 0;
if(ColRow14)
{
ColRow14 = 0;
SendKeyChar(10);
}
}
}
}
else
{
if(Col1Row4 == 0) SendKeyChar(11);
else
{
KeyDelay[3] = 0;
ColRow14 = 1;
SendKeyChar(12);
}
}
Col1Row4 = ROW4;
if(Col1Row5 == ROW5)
{
if(Col1Row5 == 0)
{
if(++KeyDelay[4] == 7)
{
KeyDelay[4] = 0;
if(ColRow15)
{
ColRow15 = 0;
SendKeyChar(13);
}
}
}
}
else
{
if(Col1Row5 == 0) SendKeyChar(14);
else
{
KeyDelay[4] = 0;
ColRow15 = 1;
SendKeyChar(15);
}
}
Col1Row5 = ROW5;
COL1 = 0;
COL2 = 1;
break;
case 1:
if(Col2Row1 == ROW1)
{
if(Col2Row1 == 0)
{
if(++KeyDelay[5] == 7)
{
KeyDelay[5] = 0;
if(ColRow21)
{
ColRow21 = 0;
SendKeyChar(16);
}
}
}
}
else
{
if(Col2Row1 == 0) SendKeyChar(17);
else
{
KeyDelay[5] = 0;
ColRow21 = 1;
SendKeyChar(18);
}
}
Col2Row1 = ROW1;
if(Col2Row2 == ROW2)
{
if(Col2Row2 == 0)
{
if(++KeyDelay[6] == 7)
{
KeyDelay[6] = 0;
if(ColRow22)
{
ColRow22 = 0;
SendKeyChar(19);
}
}
}
}
else
{
if(Col2Row2 == 0) SendKeyChar(20);
else
{
KeyDelay[6] = 0;
ColRow22 = 1;
SendKeyChar(21);
}
}
Col2Row2 = ROW2;
if(Col2Row3 == ROW3)
{
if(Col2Row3 == 0)
{
if(++KeyDelay[7] == 7)
{
KeyDelay[7] = 0;
if(ColRow23)
{
ColRow23 = 0;
SendKeyChar(22);
}
}
}
}
else
{
if(Col2Row3 == 0) SendKeyChar(23);
else
{
KeyDelay[7] = 0;
ColRow23 = 1;
SendKeyChar(24);
}
}
Col2Row3 = ROW3;
if(Col2Row4 == ROW4)
{
if(Col2Row4 == 0)
{
if(++KeyDelay[8] == 7)
{
KeyDelay[8] = 0;
if(ColRow24)
{
ColRow24 = 0;
SendKeyChar(25);
}
}
}
}
else
{
if(Col2Row4 == 0) SendKeyChar(26);
else
{
KeyDelay[8] = 0;
ColRow24 = 1;
SendKeyChar(27);
}
}
Col2Row4 = ROW4;
if(Col2Row5 == ROW5)
{
if(Col2Row5 == 0)
{
if(++KeyDelay[9] == 7)
{
KeyDelay[9] = 0;
if(ColRow25)
{
ColRow25 = 0;
SendKeyChar(28);
}
}
}
}
else
{
if(Col2Row5 == 0) SendKeyChar(29);
else
{
KeyDelay[9] = 0;
ColRow25 = 1;
SendKeyChar(30);
}
}
Col2Row5 = ROW5;
COL2 = 0;
COL3 = 1;
break;
case 2:
if(Col3Row1 == ROW1)
{
if(Col3Row1 == 0)
{
if(++KeyDelay[10] == 7)
{
KeyDelay[10] = 0;
if(ColRow31)
{
ColRow31 = 0;
SendKeyChar(31);
}
}
}
}
else
{
if(Col3Row1 == 0) SendKeyChar(32);
else
{
KeyDelay[10] = 0;
ColRow31 = 1;
SendKeyChar(33);
}
}
Col3Row1 = ROW1;
if(Col3Row2 == ROW2)
{
if(Col3Row2 == 0)
{
if(++KeyDelay[11] == 7)
{
KeyDelay[11] = 0;
if(ColRow32)
{
ColRow32 = 0;
SendKeyChar(34);
}
}
}
}
else
{
if(Col3Row2 == 0) SendKeyChar(35);
else
{
KeyDelay[11] = 0;
ColRow32 = 1;
SendKeyChar(36);
}
}
Col3Row2 = ROW2;
if(Col3Row3 == ROW3)
{
if(Col3Row3 == 0)
{
if(++KeyDelay[12] == 7)
{
KeyDelay[12] = 0;
if(ColRow33)
{
ColRow33 = 0;
SendKeyChar(37);
}
}
}
}
else
{
if(Col3Row3 == 0) SendKeyChar(38);
else
{
KeyDelay[12] = 0;
ColRow33 = 1;
SendKeyChar(39);
}
}
Col3Row3 = ROW3;
if(Col3Row4 == ROW4)
{
if(Col3Row4 == 0)
{
if(++KeyDelay[13] == 7)
{
KeyDelay[13] = 0;
if(ColRow34)
{
ColRow34 = 0;
SendKeyChar(40);
}
}
}
}
else
{
if(Col3Row4 == 0) SendKeyChar(41);
else
{
KeyDelay[13] = 0;
ColRow34 = 1;
SendKeyChar(42);
}
}
Col3Row4 = ROW4;
if(Col3Row5 == ROW5)
{
if(Col3Row5 == 0)
{
if(++KeyDelay[14] == 7)
{
KeyDelay[14] = 0;
if(ColRow35)
{
ColRow35 = 0;
SendKeyChar(43);
}
}
}
}
else
{
if(Col3Row5 == 0) SendKeyChar(44);
else
{
KeyDelay[14] = 0;
ColRow35 = 1;
SendKeyChar(45);
}
}
Col3Row5 = ROW5;
COL3 = 0;
COL4 = 1;
break;
case 3:
if(Col4Row1 == ROW1)
{
if(Col4Row1 == 0)
{
if(++KeyDelay[15] == 7)
{
KeyDelay[15] = 0;
if(ColRow41)
{
ColRow41 = 0;
SendKeyChar(46);
}
}
}
}
else
{
if(Col4Row1 == 0) SendKeyChar(47);
else
{
KeyDelay[15] = 0;
ColRow41 = 1;
SendKeyChar(48);
}
}
Col4Row1 = ROW1;
if(Col4Row2 == ROW2)
{
if(Col4Row2 == 0)
{
if(++KeyDelay[16] == 7)
{
KeyDelay[16] = 0;
if(ColRow42)
{
ColRow42 = 0;
SendKeyChar(49);
}
}
}
}
else
{
if(Col4Row2 == 0) SendKeyChar(50);
else
{
KeyDelay[16] = 0;
ColRow42 = 1;
SendKeyChar(51);
}
}
Col4Row2 = ROW2;
if(Col4Row3 == ROW3)
{
if(Col4Row3 == 0)
{
if(++KeyDelay[17] == 7)
{
KeyDelay[17] = 0;
if(ColRow43)
{
ColRow43 = 0;
SendKeyChar(52);
}
}
}
}
else
{
if(Col4Row3 == 0) SendKeyChar(53);
else
{
KeyDelay[17] = 0;
ColRow43 = 1;
SendKeyChar(54);
}
}
Col4Row3 = ROW3;
if(Col4Row4 == ROW4)
{
if(Col4Row4 == 0)
{
if(++KeyDelay[18] == 7)
{
KeyDelay[18] = 0;
if(ColRow44)
{
ColRow44 = 0;
SendKeyChar(55);
}
}
}
}
else
{
if(Col4Row4 == 0) SendKeyChar(56);
else
{
KeyDelay[18] = 0;
ColRow44 = 1;
SendKeyChar(57);
}
}
Col4Row4 = ROW4;
if(Col4Row5 == ROW5)
{
if(Col4Row5 == 0)
{
if(++KeyDelay[19] == 7)
{
KeyDelay[19] = 0;
if(ColRow45)
{
ColRow45 = 0;
SendKeyChar(58);
}
}
}
}
else
{
if(Col4Row5 == 0) SendKeyChar(59);
else
{
KeyDelay[19] = 0;
ColRow45 = 1;
SendKeyChar(60);
}
}
Col4Row5 = ROW5;
COL4 = 0;
COL5 = 1;
break;
case 4:
if(Col5Row1 == ROW1)
{
if(Col5Row1 == 0)
{
if(++KeyDelay[20] == 7)
{
KeyDelay[20] = 0;
if(ColRow51)
{
ColRow51 = 0;
SendKeyChar(61);
}
}
}
}
else
{
if(Col5Row1 == 0) SendKeyChar(62);
else
{
KeyDelay[20] = 0;
ColRow51 = 1;
SendKeyChar(63);
}
}
Col5Row1 = ROW1;
if(Col5Row2 == ROW2)
{
if(Col5Row2 == 0)
{
if(++KeyDelay[21] == 7)
{
KeyDelay[21] = 0;
if(ColRow52)
{
ColRow52 = 0;
SendKeyChar(64);
}
}
}
}
else
{
if(Col5Row2 == 0) SendKeyChar(65);
else
{
KeyDelay[21] = 0;
ColRow52 = 1;
SendKeyChar(66);
}
}
Col5Row2 = ROW2;
if(Col5Row3 == ROW3)
{
if(Col5Row3 == 0)
{
if(++KeyDelay[22] == 7)
{
KeyDelay[22] = 0;
if(ColRow53)
{
ColRow53 = 0;
SendKeyChar(67);
}
}
}
}
else
{
if(Col5Row3 == 0) SendKeyChar(68);
else
{
KeyDelay[22] = 0;
ColRow53 = 1;
SendKeyChar(69);
}
}
Col5Row3 = ROW3;
if(Col5Row4 == ROW4)
{
if(Col5Row4 == 0)
{
if(++KeyDelay[23] == 7)
{
KeyDelay[23] = 0;
if(ColRow54)
{
ColRow54 = 0;
SendKeyChar(70);
}
}
}
}
else
{
if(Col5Row4 == 0) SendKeyChar(71);
else
{
KeyDelay[23] = 0;
ColRow54 = 1;
SendKeyChar(72);
}
}
Col5Row4 = ROW4;
if(Col5Row5 == ROW5)
{
if(Col5Row5 == 0)
{
if(++KeyDelay[24] == 7)
{
KeyDelay[24] = 0;
if(ColRow55)
{
ColRow55 = 0;
SendKeyChar(73);
}
}
}
}
else
{
if(Col5Row5 == 0) SendKeyChar(74);
else
{
KeyDelay[24] = 0;
ColRow55 = 1;
SendKeyChar(75);
}
}
Col5Row5 = ROW5;
COL5 = 0;
COL1 = 1;
break;
default:
break;
}
ScanState++;
if(ScanState == 5) ScanState = 0;

}


// Declare your global variables here


void main(void)
{
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif


PORTB=0x00;
DDRB=0x11;


PORTC=0x00;
DDRC=0x24;


PORTD=0x1F;
DDRD=0x60;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 7.813 kHz
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected TCCR0A=0x00;
TCCR0B=0x05;
TCNT0=0x80;
OCR0A=0x00;
OCR0B=0x00;


// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;


// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;


// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;


// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x01;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;


// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;


// SPI initialization
// SPI Type: Slave
// SPI Clock Rate: 125.000 kHz
// SPI Clock Phase: Cycle Half
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
SPCR=0x42;
SPSR=0x00;


// Global enable interrupts
#asm("sei")


while (1)
{
if(flag0)
{
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
flag0 = 0;
INT = 0;
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
INT = 1;
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
#asm("nop")
INT = 0;
}
};
}


/***key.h****/

#define COL1 DDRB.0
#define COL2 DDRB.1
#define COL3 DDRD.7
#define COL4 DDRD.6
#define COL5 DDRD.5

#define ROW1 PIND.0
#define ROW2 PIND.1
//#define KEY1 PIND.2
//#define KEY2 PIND.3
#define ROW3 PIND.2
#define ROW4 PIND.3
#define ROW5 PINB.6

bit Col1Row1 = 1;
bit Col1Row2 = 1;
bit Col1Row3 = 1;
bit Col1Row4 = 1;
bit Col1Row5 = 1;

bit Col2Row1 = 1;
bit Col2Row2 = 1;
bit Col2Row3 = 1;
bit Col2Row4 = 1;
bit Col2Row5 = 1;

bit Col3Row1 = 1;
bit Col3Row2 = 1;
bit Col3Row3 = 1;
bit Col3Row4 = 1;
bit Col3Row5 = 1;

bit Col4Row1 = 1;
bit Col4Row2 = 1;
bit Col4Row3 = 1;
bit Col4Row4 = 1;
bit Col4Row5 = 1;

bit Col5Row1 = 1;
bit Col5Row2 = 1;
bit Col5Row3 = 1;
bit Col5Row4 = 1;
bit Col5Row5 = 1;

bit ColRow11 = 1;
bit ColRow12 = 1;
bit ColRow13 = 1;
bit ColRow14 = 1;
bit ColRow15 = 1;

bit ColRow21 = 1;
bit ColRow22 = 1;
bit ColRow23 = 1;
bit ColRow24 = 1;
bit ColRow25 = 1;

bit ColRow31 = 1;
bit ColRow32 = 1;
bit ColRow33 = 1;
bit ColRow34 = 1;
bit ColRow35 = 1;

bit ColRow41 = 1;
bit ColRow42 = 1;
bit ColRow43 = 1;
bit ColRow44 = 1;
bit ColRow45 = 1;

bit ColRow51 = 1;
bit ColRow52 = 1;
bit ColRow53 = 1;
bit ColRow54 = 1;
bit ColRow55 = 1;

Read More...

RJ-45接线方法

1.Ethernet简介

IEEE 802标准给出了局域网(LAN)的标准化参考模型,它只对应于OSI参考模型中的数据链路层与物理层,并将数据链路层划分为逻辑链路控制(LLC)子层与介质访问控制(MAC)子层。

其中,IEEE 802.3标准定义了CSMA/CD总线介质访问控制子层与物理层规范,这也就是Ethernet(以太网)局域网的标准。

构成Ethernet网络连接的两个要素是以太网卡(带收发器)和传输介质(连接电缆)。

2.传输介质

最常用的传输介质为双绞线,又分为屏蔽双绞线(shielded twisted pair, STP)和非屏蔽双绞线(unshielded twisted pair, UTP)两种。

根据传输特性,又可分为三类、五类、超五类和六类、七类等,如下表。













































Cable Category



Rated Frequency Bandwidth (MHz)



Common Uses



1



None




2



1



Telephone Wiring



3



16



Telephone Wiring, 10Base-T



4



20



Token-Ring, 10Base-T



5



100



100Base-TX, 10Base-T



5e



100



1000Base-T, 100Base-TX, 10Base-T



6



250



1000Base-T, 100Base-TX, 10Base-T



*更详细资料可以参考[3][6]或其他资源。

目前我们最常用的是五类非屏蔽双绞线,由于信号在传输介质中的衰减,因此,五类非屏蔽双绞线的长度不可超过。

3.RJ-45

EIA/TIA(Electronic Industries Association/Telecommunications Industry Association)指定非屏蔽双绞线使用RJ-45接口(ISO8877)。

RJ(registered jack)是电话或计算机网络设备等电信设备的标准物理接口。


上图是RJ-45的插头与插孔示意图。双绞线中有4对导线,因此接口也相应的有1~8号引脚。注意在讨论接线顺序以及与信号的对应关系时,总是以引脚标号为准,母口与公口相连接时,也总是使标号一一对应。

4.接线方法

(1)双绞线的示意图如下:



(2)双绞线与水晶头(RJ-45公口)的连接方法有两种标准,一是T-568B(常用),二是T,如下图:


(3)平行线(Straight through cable)与交叉线(Crossover cable)

由于存在以上两种标准,一根双绞线的两头都可以采取任一标准与RJ-45水晶头进行连接,于是出现了平行线与交叉线的差别。

平行线是指双绞线的两头采取同一标准(通常是T-568B)与水晶头进行连接,内部不交叉的接线方法。

交叉线则是指双绞线的两头采取不同标准(一端采用T-568B,另一端采用T)与水晶头进行连接,4对线在内部都要交叉(包括不使用的蓝对和棕对),如下表:


平行线与交叉线用于不同场合和不同通信设备的互连,关键是要通过双绞线将互连的两个设备的Transmit+与Receive+连通,Transmit-与Receive-连通,这样两个设备才能正常地进行网络通信。

一般而言,平行线用于连接到Hub或Switch,交叉线则用于对等的两个通信设备的直连,这是因为对等的通信设备的接口定义通常采用同一标准,一个简单的例子是,假设计算机以太网卡的Transmit和Receive信号与RJ-45引脚的对应关系如下:


那么两台计算机如果使用一根双绞线进行直连通信,则需要采用交叉线,如下图所示:


有的网卡接口电路设计为可以根据需要自动对双绞线进行交叉或非交叉处理,这时采用平行线或交叉线都可以。


参考资料:

[1]How to wrie Ethernet cables

[2]T-568A/T568B

[3]RJ-45 wiki

[4]http://pinouts.ru/connector/8_pin_RJ45_male_connector.shtml

[5]双绞线接头(RJ45)连接方法详解

[6]RJ-45制作与原理教程

Read More...

一个mplayer配置文件



# Write your default config options here!
# Some video output drivers (svga, x11, vesa) do not support hardware scaling.
ao=alsa #音频驱动选择
vo=x11 #视频驱动选择
joystick=0 #是否支持手柄控制
stop-xscreensaver=yes #是否允许播放视频时出现屏保
monitoraspect=1280:800 #识别桌面分辨率为1280×800
zoom=yes #是否允许视频缩放
subcp=cp936 #字幕字符集编码
subfont-autoscale=1 #设置按什么方法来进行自动缩放字幕,0-不自动缩放,1-按电影高度缩放,2-按电影宽度缩放,3-按电影对角线缩放(默认值)
subfont-text-scale=5 #设置字幕文本的自动缩放系数(屏幕尺寸的百分比),值范围为0~100,默认值为5。
subfont-osd-scale=8 #OSD字幕的自动缩放系统(屏幕尺寸的百分比),值范围为0~100,默认值为6。
font="Microsoft YaHei" #选择字幕用的字体
overlapsub=1 #支持多语言字幕。
sub-fuzziness=1 #设定字幕自动加载的识别,播放时可以通过j键切换。
osdlevel=1 #在屏幕的左上角显示相应时间等
cache = 8192 #此选项指定用多少内存(以 kBytes 为单位)作为播放文件或 URL 的预缓冲。
autosync=0
mc=0


#subalign=2 #字幕对齐方式。顶部对齐 (原始行为)。中央对齐。底部对齐 (默认)。
#vf=expand=0:-30:0:0 #如果是16:9的影片,字幕可以放在下面的黑框中osdlevel
#vf=eq2=1.0:-0.8
#vf=delogo=380:0:120:45:0
#subfont-blur=0
#subfont-outline=5
#subpos=100
#flip=1
#mirror=0
#ffactor=0.75 #对字体的 alphamap 重新采样。

Read More...

.bash_profile和.bashrc说明

/etc/profile: 
此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行。并从/etc/profile.d目录的配置文件中搜集shell的设置.
/etc/bashrc: 
为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取.
~/.bash_profile:
每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件.
~/.bashrc:
该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取.
~/.bash_logout:
当每次退出系统(退出bash shell)时,执行该文件.另外,/etc/profile中设定的变量(全局)的可以作用于任何用户,而~/.bashrc等中设定的变量(局部)只能继承/etc/profile中的变量,他们是"父子"关系.
~/.bash_profile 是交互式、login 方式进入 bash 运行的
~/.bashrc 是交互式 non-login 方式进入 bash 运行的
通常二者设置大致相同,所以通常前者会调用后者。



* 每次bash作为login shell启动时会执行.bash_profile。

主要有(我所知道的)有以下几种情形:

a) 每次登录到服务器时默认启动的shell

b) "su -l [USER]"时进入的shell

c) "bash --login"进入的shell

* 每次bash作为普通的交互shell(interactive shell)启动时会执行.bashrc

常见的有:

i) "su [USER]"进入的shell
ii) 直接运行"bash"命令进入的shell。

** 注意

1, 在shell脚本中"#!/usr/bin/bash"启动的bash并不执行.bashrc。因为这里的bash不是
interactive shell。

2, bash作为login shell(login bash)启动时并不执行.bashrc。虽然该shell也是interactive shell,
但它不是普通的shell。

* 一般.bash_profile里都会调用.bashrc

尽管login bash启动时不会自动执行.bashrc,惯例上会在.bash_profile中显式调用.bashrc。

,-------------------------------------
| if [ -f ~/.bashrc ]; then
| . ~/.bashrc
| fi
`-------------------------------------

.bash_profile显示内容如下:
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

# User specific environment and startup programs

PATH=.:$PATH:$HOME/bin
BASH_ENV=$HOME/.bashrc
USERNAME="root"

export USERNAME BASH_ENV PATH

Read More...

全智贤

Read More...

星期五, 十二月 28, 2007

gcc核心扩展

===========================
Linux 内核使用的 GNU C 扩展
===========================

GNC CC 是一个功能非常强大的跨平台 C 编译器,它对 C 语言提供了很多扩展,
这些扩展对优化、目标代码布局、更安全的检查等方面提供了很强的支持。本文把
支持 GNU 扩展的 C 语言称为 GNU C。

Linux 内核代码使用了大量的 GNU C 扩展,以至于能够编译 Linux 内核的唯一编
译器是 GNU CC,以前甚至出现过编译 Linux 内核要使用特殊的 GNU CC 版本的情
况。本文是对 Linux 内核使用的 GNU C 扩展的一个汇总,希望当你读内核源码遇
到不理解的语法和语义时,能从本文找到一个初步的解答,更详细的信息可以查看
gcc.info。文中的例子取自 Linux 2.4.18。

语句表达式
==========

GNU C 把包含在括号中的复合语句看做是一个表达式,称为语句表达式,它可以出
现在任何允许表达式的地方,你可以在语句表达式中使用循环、局部变量等,原本
只能在复合语句中使用。例如:

++++ include/linux/kernel.h
159: #define min_t(type,x,y) \
160:         ({ type __x = (x); type __y = (y); __x window_clamp, tcp_full_space(sk));

复合语句的最后一个语句应该是一个表达式,它的值将成为这个语句表达式的值。
这里定义了一个安全的求最小值的宏,在标准 C 中,通常定义为:

#define min(x,y) ((x) " "%s:%d", filename, line)

使用 ## 的原因是处理 arg 不匹配任何参数的情况,这时 arg 的值为空,GNU
C 预处理器在这种特殊情况下,丢弃 ## 之前的逗号,这样

    pr_debug("success!\n")

扩展为

    printk("" "success!\n")

注意最后没有逗号。

标号元素
========

标准 C 要求数组或结构变量的初使化值必须以固定的顺序出现,在 GNU C 中,通
过指定索引或结构域名,允许初始化值以任意顺序出现。指定数组索引的方法是在
初始化值前写 '[INDEX] =',要指定一个范围使用 '[FIRST ... LAST] =' 的形式,
例如:

+++++ arch/i386/kernel/irq.c
1079: static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };

将数组的所有元素初使化为 ~0UL,这可以看做是一种简写形式。

要指定结构元素,在元素值前写 'FIELDNAME:',例如:

++++ fs/ext2/file.c
41: struct file_operations ext2_file_operations = {
42:         llseek:         generic_file_llseek,
43:         read:           generic_file_read,
44:         write:          generic_file_write,
45:         ioctl:          ext2_ioctl,
46:         mmap:           generic_file_mmap,
47:         open:           generic_file_open,
48:         release:        ext2_release_file,
49:         fsync:          ext2_sync_file,
50 };

将结构 ext2_file_operations 的元素 llseek 初始化为 generic_file_llseek,
元素 read 初始化为 genenric_file_read,依次类推。我觉得这是 GNU C 扩展中
最好的特性之一,当结构的定义变化以至元素的偏移改变时,这种初始化方法仍然
保证已知元素的正确性。对于未出现在初始化中的元素,其初值为 0。

Case 范围
=========

GNU C 允许在一个 case 标号中指定一个连续范围的值,例如:

++++ arch/i386/kernel/irq.c
1062:                         case '0' ... '9': c -= '0'; break;
1063:                         case 'a' ... 'f': c -= 'a'-10; break;
1064:                         case 'A' ... 'F': c -= 'A'-10; break;

    case '0' ... '9':

相当于

    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':

声明的特殊属性
==============

GNU C 允许声明函数、变量和类型的特殊属性,以便手工的代码优化和更仔细的代
码检查。要指定一个声明的属性,在声明后写

    __attribute__ (( ATTRIBUTE ))

其中 ATTRIBUTE 是属性说明,多个属性以逗号分隔。GNU C 支持十几个属性,这
里介绍最常用的:

* noreturn

属性 noreturn 用于函数,表示该函数从不返回。这可以让编译器生成稍微优化的
代码,最重要的是可以消除不必要的警告信息比如未初使化的变量。例如:

++++ include/linux/kernel.h
47: # define ATTRIB_NORET  __attribute__((noreturn)) ....
61: asmlinkage NORET_TYPE void do_exit(long error_code)
        ATTRIB_NORET;

* format (ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK)

属性 format 用于函数,表示该函数使用 printf, scanf 或 strftime 风格的参
数,使用这类函数最容易犯的错误是格式串与参数不匹配,指定 format 属性可以
让编译器根据格式串检查参数类型。例如:

++++ include/linux/kernel.h?
89: asmlinkage int printk(const char * fmt, ...)
90:         __attribute__ ((format (printf, 1, 2)));

表示第一个参数是格式串,从第二个参数起根据格式串检查参数。

* unused

属性 unused 用于函数和变量,表示该函数或变量可能不使用,这个属性可以避免
编译器产生警告信息。

* section ("section-name")

属性 section 用于函数和变量,通常编译器将函数放在 .text 节,变量放在
.data 或 .bss 节,使用 section 属性,可以让编译器将函数或变量放在指定的
节中。例如:

++++ include/linux/init.h
78: #define __init          __attribute__ ((__section__ (".text.init")))
79: #define __exit          __attribute__ ((unused, __section__(".text.exit")))
80: #define __initdata      __attribute__ ((__section__ (".data.init")))
81: #define __exitdata      __attribute__ ((unused, __section__ (".data.exit")))
82: #define __initsetup     __attribute__ ((unused,__section__ (".setup.init")))
83: #define __init_call     __attribute__ ((unused,__section__ (".initcall.init")))
84: #define __exit_call     __attribute__ ((unused,__section__ (".exitcall.exit")))

连接器可以把相同节的代码或数据安排在一起,Linux 内核很喜欢使用这种技术,
例如系统的初始化代码被安排在单独的一个节,在初始化结束后就可以释放这部分
内存。

* aligned (ALIGNMENT)

属性 aligned 用于变量、结构或联合类型,指定变量、结构域、结构或联合的对
齐量,以字节为单位,例如:

++++ include/asm-i386/processor.h
294: struct i387_fxsave_struct {
295:         unsigned short  cwd;
296:         unsigned short  swd;
297:         unsigned short  twd;
298:         unsigned short  fop;
299:         long    fip;
300:         long    fcs;
301:         long    foo;
......
308: } __attribute__ ((aligned (16)));

表示该结构类型的变量以 16 字节对齐。通常编译器会选择合适的对齐量,显示指
定对齐通常是由于体系限制、优化等原因。

* packed

属性 packed 用于变量和类型,用于变量或结构域时表示使用最小可能的对齐,用
于枚举、结构或联合类型时表示该类型使用最小的内存。例如:

++++ include/asm-i386/desc.h
51: struct Xgt_desc_struct {
52:         unsigned short size;
53:         unsigned long address __attribute__((packed));
54: };

域 address 将紧接着 size 分配。属性 packed 的用途大多是定义硬件相关的结
构,使元素之间没有因对齐而造成的空洞。

当前函数名
==========

GNU CC 预定义了两个标志符保存当前函数的名字,__FUNCTION__ 保存函数在源码
中的名字,__PRETTY_FUNCTION__ 保存带语言特色的名字。在 C 函数中,这两个
名字是相同的,在 C++ 函数中,__PRETTY_FUNCTION__ 包括函数返回类型等额外
信息,Linux 内核只使用了 __FUNCTION__。

++++ fs/ext2/super.c
98: void ext2_update_dynamic_rev(struct super_block *sb)
99: {
100:         struct ext2_super_block *es = EXT2_SB(sb)->s_es;
101:
102:         if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)
103:                 return;
104:
105:         ext2_warning(sb, __FUNCTION__,
106:                      "updating to rev %d because of new feature flag, "
107:                      "running e2fsck is recommended",
108:                      EXT2_DYNAMIC_REV);

这里 __FUNCTION__ 将被替换为字符串 "ext2_update_dynamic_rev"。虽然
__FUNCTION__ 看起来类似于标准 C 中的 __FILE__,但实际上 __FUNCTION__
是被编译器替换的,不象 __FILE__ 被预处理器替换。

内建函数
========

GNU C 提供了大量的内建函数,其中很多是标准 C 库函数的内建版本,例如
memcpy,它们与对应的 C 库函数功能相同,本文不讨论这类函数,其他内建函数
的名字通常以 __builtin 开始。

* __builtin_return_address (LEVEL)

内建函数 __builtin_return_address 返回当前函数或其调用者的返回地址,参数
LEVEL 指定在栈上搜索框架的个数,0 表示当前函数的返回地址,1 表示当前函数
的调用者的返回地址,依此类推。例如:

++++ kernel/sched.c
437:                 printk(KERN_ERR "schedule_timeout: wrong timeout "
438:                        "value %lx from %p\n", timeout,
439:                        __builtin_return_address(0));

* __builtin_constant_p(EXP)

内建函数 __builtin_constant_p 用于判断一个值是否为编译时常数,如果参数
EXP 的值是常数,函数返回 1,否则返回 0。例如:

++++ include/asm-i386/bitops.h
249: #define test_bit(nr,addr) \
250: (__builtin_constant_p(nr) ? \
251:  constant_test_bit((nr),(addr)) : \
252:  variable_test_bit((nr),(addr)))

很多计算或操作在参数为常数时有更优化的实现,在 GNU C 中用上面的方法可以
根据参数是否为常数,只编译常数版本或非常数版本,这样既不失通用性,又能在
参数是常数时编译出最优化的代码。

* __builtin_expect(EXP, C)

内建函数 __builtin_expect 用于为编译器提供分支预测信息,其返回值是整数表
达式 EXP 的值,C 的值必须是编译时常数。例如:

++++ include/linux/compiler.h
13: #define likely(x)       __builtin_expect((x),1)
14: #define unlikely(x)     __builtin_expect((x),0)
++++ kernel/sched.c
564:         if (unlikely(in_interrupt())) {
565:                 printk("Scheduling in interrupt\n");
566:                 BUG();
567:         }

这个内建函数的语义是 EXP 的预期值是 C,编译器可以根据这个信息适当地重排
语句块的顺序,使程序在预期的情况下有更高的执行效率。上面的例子表示处于中
断上下文是很少发生的,第 565-566 行的目标码可能会放在较远的位置,以保证
经常执行的目标码更紧凑。

Read More...

以用户空间权限访问GPIO

在将Linux系统移植到相关板子上后,我们面临的就是一个编程问题了。开发板上有很多资源是可以和内核中的驱动对应的,比如我们今天要介绍的,最简单的,gpio。

首先你需要用在/dev下mknod xgpio:

crw-rw-rw- 1 root root 10, 185 Jun 1 13:59 /dev/xgpio

下面就是具体访问gpio的示例:


To write to the channel change the call:
ioctl(fgpio,XGPIO_IN,&sGpioData); to ioctl(fgpio,XGPIO_OUT,&sGpioData);

#include
#include
#include
#include

#include

main(){

int fgpio =0;
struct xgpio_ioctl_data sGpioData;
/* {
__u32 device;
__u32 mask;
__u32 data;
}*/

sGpioData.device=0; /* N=0,1,2,3-> GPIO DEV NR 2*N (Lower 32 bit part)
2*N+1 (Upper 32 bit part)*/
sGpioData.mask=0xffffffff;
sGpioData.data=0×55555555;

fgpio = open (”/dev/xgpio”,O_RDWR);

if( fgpio != -1){
ioctl(fgpio,XGPIO_IN,&sGpioData);//pointer here to xgpio_ioctl_data
printf(”Dip Swich readout 0x%X\n”,sGpioData.data);
}
else
printf(”Can not open GPIO\n”);

close(fgpio);
}// end main

Read More...

星期一, 十二月 24, 2007

gentoo下的kde4

Read More...

键盘的改革

Read More...

星期一, 十二月 17, 2007

关于u8 u16 u32 以及arm中的长度问题。『转』

首先先来看看2个程序,第一次看会死人的。
#include <stdio.h>
struct test{
unsigned int a1;
unsigned char a2;
unsigned short a3;
unsigned char a5;
unsigned int a4;
};

int main(void)
{
printf("a:%d\n",sizeof(struct test));
return 0;
}
显示16
----------
#include <stdio.h>
struct test{
unsigned int a1;
unsigned char a2;
unsigned char a5;
unsigned short a3;
unsigned int a4;
};

int main(void)
{
printf("a:%d\n",sizeof(struct test));
return 0;
}
显示12
----------
为什么呢??
因为:
unsigned char a2;
unsigned short a3;
unsigned char a5;
主要是因为u16和u8的排列问题
--------------
如果char后面跟的是u16,那char就是2字节存储了。
后面的char是单字节,但是a5后面是int,所以a5就当4字节存储了。
u8就是unsigned char
那么u16=unsigned short
u32=unsigned int了呵呵。
short 16
char 8
int 32
在arm和32bit的intel中是这么定义的。
我晕,还要管哪家公司定义的。
结构体中的排列问题 是编译器的原因还是什么?
是 cpu架构和编译器共同作用
---------------------------------------
好了,我们回头看那个程序。
第一个:
4+2+2+4+4=16
4(unsigned char)+2(unsigned char因为后面的16、2个字节,所以变了)+2(unsigned short)+4(unsinged char因为后面的32、4个字节所以变了)+4(unsigned int)=16
第二个:
4+1+1+2+4=12
就没怎么变。(ps: 还不知道为什么这个就没有8--〉16变成2字节,或许不用吧, 下午再问)
在这里谢谢id=思想者的老兄了。呵呵。这么本质的问题都有。厉害。

Read More...

星期三, 十二月 12, 2007

gcc的组件和软件工具

gcc安装的各个部分
 部分            描述
c++        gcc的一个版本,默认语言设置为c++,而且在连续的时候自动包含标准c++库。这和g++一样
ccl        实际的c编译程序
cclplus        实际的c
++编译程序
collect2               在不使用GNU链接程序的系统上,有必要运行collect2来产生特定的全局初始化代码
(例如c++的构造函数和析构函数)
configure               GCC源代码树根目录中的一个脚本,用于设置值和创建GCC编译程序必须的make程序的描述文件
crt0
.o        这个初始化和结束代码是为每个系统定制的,而且也被编译进该文件,该文件然后会被连接到每个可执行文件中来执行必要的启动和终止程序。
cygwinl
.dll    windows的共享库提供的API,模拟UNIX系统调用。
f77        该驱动程序可用于编译Fortran
f77l        实际的Fortran编译程序。
g
++        gcc的一个版本,默认语言设置为c++,而且在链接的时候自动包含标准c++库,这和c++一样
gcc        该驱动程序等同于执行编译程序和链接程序以产生必要的输出
gcj        该驱动程序用于编译java
gnatl        实际的Ada编译程序
gnatbind               一种工具,用于执行Ada语言的绑定
gnatlink               一种工具,用于执行Ada语言的绑定
jcl        实际的java编译程序
libgcc        该库包含的例程被作为编译程序的一部分,是因为它们可被链接到实际的可执行程序中。它们是特殊的例程,链接到可执行程序,来执行基本的任务,例如浮点运算。这些库中的例程通常都是平台相关的。
libgcj        运行时库包含所有的核心Java类
libobjc        对所有Objective
-c程序都必须的运行时的库。
libstdc
++               运行时库,包括定义为标准语言一部分的所有的c++类和函数                
                    
[b]gcc使用的工具[/b
[
b工具    [/b]     [b说明[/b
addr2line               给出一个可执行文件的内部地址,addr2line使用文件中的调试信息将地址翻译成源代码文件名和行号。该程序是binutils包的一部分
ar        这是一个程序,可通过从文档中增加、删除和析取文件来维护库文件。通常使用该工具是为了创建和管理链接程序使用的目标库文档。该程序是binutils包的一部分。
as        GNU汇编器。实际上他是一组汇编器,因为它可以被编译或能够在各个不同平台上工作。
autoconf              产生的shell脚本自动配置源代码包去编译某个特定版本的UNIX
c
++filt        程序接受被c++编译程序转换过的名字(不是被重载的),而且将该名字翻译成初始形式。该程序是binutils包的一部分
f2c        是Fortran到c的翻译程序。不是GCC的一部分。
gcov        gprof使用的配置工具,用来确定程序运行的时候哪一部分耗时最大
gdb        GNU调试器,可用于检查程序运行时的值和行为
GNATS        GNU的调试跟踪系统
(GNU Bug Tracking System)。一个跟踪GCC和其他GNU软件问题的在线系统。
gprof        该程序会监督编译程序的执行过程,并报告程序中各个函数的运行时间,可以根据所提供的配置文件来优化程序。该程序是binutils包的一部分。
ld        GNU链接程序。该程序将目标文件的集合组合成可执行程序。该程序是binutils包的一部分。
libtool        一个基本库,支持make程序的描述文件使用的简化共享库用法的脚本。
make        一个工具程序,它会读makefile脚本来确定程序中的那个部分需要编译和链接,然后发布必要的命令。它读出的脚本
(叫做makefile或Makefile)定义了文件关系和依赖关系。
nlmconv        将可重定向的目标文件转换成NetWare可加载模块
(NetWare Loadable Module NLM)。该程序是binutils包的一部分。
nm        列出目标文件中定义的符号,该程序是binutils包的一部分。
objcopy        将目标文件从一种二进制格式复制或翻译到另外一种。该程序是binutils包的一部分
objdump        显示一个或多个目标文件中保存的多种不同信息
.该程序是binutils包的一部分。
ranlib        创建的添加到ar文档的索引。该索引被ld使用来定位库中的模块。        该程序是binutils包的一部分。
ratfor        Ratfor预处理程序可由GCC激活,但不是标准GCC发布版的一部分。
size        列出目标文件中每个部分的名字和尺寸。该程序是binutils的一部分。
strings        浏览所有类型的文件,析取出用于显示调试所需的信息。        该程序binutils包的一部分。
veg        Ratfor浏览器从文本中读取信息,并以图标形式显示它们。而vcg工具并不是GCC发布的一部分,但
-dv选项可被用来产生vcg可以理解的优化数据的格式
windres        window资源文件编译程序,该程序是binutils包的一部

Read More...

星期一, 十二月 10, 2007

用注册表加载,卸载GDI++

打开regedit,浏览到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows,修改AppInit_DLLs的值,将其中的gdi++.dll相关的去掉即可。

或者:


代码:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows]
"AppInit_DLLs"=""
保存为一个reg文件,例如remove.reg,双击它也可以,但要注意,如果你安装了WB之类的,一并解决掉了。

Read More...

s3c2410 _spi概述

概况:

S3C2410X的连续外围设备接口(SPI)能连接电路实现连续数据传递。S3C2410X包含2SPI,,每个都分别有两个8位转移寄存器用于数据的传输和接收。在一个SPI进行数据传递时,同步传送数据并连续输出数据。在某一频率的8位连续数据由它相应的通讯控制寄存器设置所决定。假如你只发送数据,接收数据就能设为哑元。反之,如果你只想接收数据,你应该发送设为哑元'1'数据。

S3C24104个与SPI传输有关的I/O信号引脚:SCK(SPICLK01)MISO(SPIMISOO1)数据线,MOSISPIMOSIO1)和低电平有效的/SS(nSS01)引脚(输入)

特点

SPI协议(Ver.2.11)兼容

8位移位寄存器输出

8位移位寄存器接收

8位预分频逻辑

查询,中断,DMA传输模式

 

 

SPI操作

采用SPI接口, S3C2410X可发送/接收与外部设备同步的8位数据。一个串行时钟线与两条用来移位和采样信息的数据线同步。 SPI为主机时,发送频率可以通过为SPPREn寄存器设置合适的值来控制。你可以通过调整波特率数据寄存器的值来修改它的频率。当SPI为从机时,其它的主机提供时钟。当编程者向SPTDATn寄存器写字节数据时,SPI的收/发将会同时开始。在其它情况下,在向SPTDATn寄存器写入字节数据时要把nSS激活。

 

编辑程序

 

当向SPTDATn寄存器写入字节时,如果ENSCKSPCONn被设置的话,SPI就开始传输

你可以使用一上典型的程序来操作一个SPI卡。

编程SPI模式,基本遵循这些基本步骤:

1.       设置波特率寄存器(SPPREn

2.       设置SPCONn以选择合适的SPI模式。

3.        写数据0xFFSPTDATn10次以初始化MMCSD卡。.

4.       设置GPIO引脚使其具有nSS功能,低电平时使MMCSD卡有效。

5.       发送数据:检查发送准备樗是否为1,如果为1 的话就开始向SPTDATn写数据。

6.       接收数据(1):SPCONn TAGD 位禁用 = 正常模式

    :向SPTDATn 0xFF,然后测试REDY,再从读缓存中读取数据。

7.       接收数据:SPCONnTAGD 能用 = 自动接收垃圾数据模式。

    :测试REDY,然后从读缓存中读取数据。

8.       设置GPIO引脚使其具有nSS功能,高电平时使MMCSD卡有效。

 

 

通过DMA发送的步骤

1.       SPI的配置为DMA模式

2.       DMA合适设置

3.       SPI请求DMA服务

4.       DMASPI发送一个字节数据.

5.        SPI向卡里发送数据

6.       返回到步骤3直到DAM计数变为0

7.       SMOD位把SPI设置为中断或查询模式

 

通过DMA接收的步骤

1.       SPI设置为DMASMOD位开始,并且设置TAGD.

2.       全适配置 DMA

3.       SPI从卡里接收一字节数据

4.       SPI请求DMA服务

5.       DMASPI接收数据

6.        自动的向SPIDATn写数据0xFF

7.        回到步骤4DAM计数变为0

8.       SMOD位把SPI配置为查询模式,并且清TAGD

9.       如果SPSTAnREDY 标志被设置,就读取最后的字节数据

 

:

总接收的数据 = DAM TC +在查询模式下的最后值.

DAM接收的第一个数据是哑元,所以使用者可以忽略它

SPI 从机接收模式和B模块

 

如果SPI从机接收模式有效和SPI模块被设成B模块,SPI操作将会失败。

READY信号这一内部信号将在SPI_CNT达到0之前变成高电平。因此,在DMA模式中,DATA_READ信号应该在最后一个数据结束之前产生。

注意

1)      DMA模式:这种模式不能在SPI从机接收模式和B模块下使用。

2)      查询模式:在SPI从机接收模式和B模块下DATA_READ信号应该推迟SPICLK的一个相位。

3)      中断模式:在SPI从机接收模式和B模块下DATA_READ信号应该推迟SPICLK的一个相位。

SPI特殊寄存器

SPI控制寄存器

SPI状态寄存器

SPI引脚控制寄存器

如果SPI系统使能时,除nSS引脚外的其它引脚的方向通过SPCONnMSTR位来控制。nSS引脚的方向总是输入。

SPI为主机时,nSS引脚用来检查由SPPINENMUL位提供的多主机错误信号,另一个GPIO应该选择从机。

如果SPI被设置为从机,nSS引脚奖被一个主机选择为从机。

SPIMISOSPIMOSI数据引脚用来发送和接收串行数据。当SPI为主机时,SPIMISO是数据输入引脚,SPIMOSI是数据输出引脚,SPICLKSCK)是时钟输出线。当SPI为从机时,这些引脚执行相反的功能。在多主机系统中,SPICLKSCK)、SPIMOSISPIMISO将被分别的配置在一个体系中。

当其它的SPI设备作为从机选择S3C2410 SPI为从机时,一个主机SPI可以发出一个多主机错误信号。当这个信号被探测到,将会立刻发生下面所说的事情。但是如果你想探测到这种信号的话必须事先设置SPPINnENMUL位。

 

1.       SPCONnMSTR位被强制为0来启动从机模式。

2.       SPSTAnMULF标志位被置位,一个SPI中断会产生。

概况:

S3C2410X的连续外围设备接口(SPI)能连接电路实现连续数据传递。S3C2410X包含2SPI,,每个都分别有两个8位转移寄存器用于数据的传输和接收。在一个SPI进行数据传递时,同步传送数据并连续输出数据。在某一频率的8位连续数据由它相应的通讯控制寄存器设置所决定。假如你只发送数据,接收数据就能设为哑元。反之,如果你只想接收数据,你应该发送设为哑元'1'数据。

S3C24104个与SPI传输有关的I/O信号引脚:SCK(SPICLK01)MISO(SPIMISOO1)数据线,MOSISPIMOSIO1)和低电平有效的/SS(nSS01)引脚(输入)

特点

SPI协议(Ver.2.11)兼容

8位移位寄存器输出

8位移位寄存器接收

8位预分频逻辑

查询,中断,DMA传输模式

 

 

SPI操作

采用SPI接口, S3C2410X可发送/接收与外部设备同步的8位数据。一个串行时钟线与两条用来移位和采样信息的数据线同步。 SPI为主机时,发送频率可以通过为SPPREn寄存器设置合适的值来控制。你可以通过调整波特率数据寄存器的值来修改它的频率。当SPI为从机时,其它的主机提供时钟。当编程者向SPTDATn寄存器写字节数据时,SPI的收/发将会同时开始。在其它情况下,在向SPTDATn寄存器写入字节数据时要把nSS激活。

Read More...