显示标签为“驱动”的博文。显示所有博文
显示标签为“驱动”的博文。显示所有博文

星期日, 十二月 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...

星期一, 十二月 03, 2007

一个Linux下的char型设备的驱动

        这个驱动程序是典型char型设备驱动,它涉及到了如何使用共享中断、相同功能的设备共用驱动程序等一些技巧。个人的愚见,欢迎来讨论。
/****************************************************************************
    直放站 UART3 driver
    shanghai xinmin telecom std.
    diming.feng 2007-05
*****************************************************************************/
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/errno.h>
#include <asm/delay.h>
//#include <asm/fcntl.h>
#include <asm/arch/irqs.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/serial_reg.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include "expuart.h"

#define GPIO_CFG0  VPint(0xFFF83000)
#define GPIO_DIR0  VPint(0xFFF83004)
#define GPIO_DATAOUT0 VPint(0xFFF83008)

#define GPIO_CFG5  VPint(0xFFF83050) 
#define GPIO_DIR5  VPint(0xFFF83054)
#define GPIO_DATAOUT5 VPint(0xFFF83058)

#define GPIO_XICFG  VPint(0xFFF83074)
#define GPIO_XISTATUS VPint(0xFFF83078)

#define UART_TX   VPchar(COM_TX_3)
#define UART_RX   VPchar(COM_RX_3)
#define UART_DLL  VPchar(COM_DLL_3)
#define UART_DLM  VPchar(COM_DLM_3) 
#define UART_IER  VPchar(COM_IER_3)
#define UART_IIR  VPchar(COM_IIR_3)
#define UART_FCR  VPchar(COM_FCR_3)
#define UART_LCR  VPchar(COM_LCR_3) 
#define UART_MCR  VPchar(COM_MCR_3) 
#define UART_LSR  VPchar(COM_LSR_3) 
#define UART_MSR  VPchar(COM_MSR_3) 
#define UART_TOR  VPchar(COM_TOR_3)

#define LSR_TE   0x40
#define LSR_THRE  0x20 
#define LSR_RFDR  0x01

#define nIRQ2   31
#define uart3_IRQ  12

#define NOIRQ   0x01
#define RSTIRQ   0x06 
#define RFVIRQ   0x04
#define RFTIRQ   0x0C
#define THRIRQ   0x02
#define MSTIRQ   0x00

#define RX_FIFO_LEVEL 14
#define UART_FCR_LEVEL  0xc0


#define CMD_BANDRATE 0   // set bandrate
#define CMD_UARTLCR  1   // set data bit
#define CMD_RXTIMEOUT 2
#define CMD_MODE  3   // set RS-485/RS-232 mode
#define CMD_MODEM_SET 4   // set internal modem

#define MAJOR_NUM  248
#define YES    1
#define NO    0
#define TIME_OUT  20000

#define uart3_int(band)   do{     \
         UART_LCR = 0; \
         UART_IER = 0; \
         UART_LCR = DLAB;\
         UART_DLL = band;\
         UART_DLM = 0; \
         UART_LCR = 0x03;\
         UART_FCR = 0x07;\ 
         UART_TOR = 0x00;\
        }while(0)

#define write_reg(reg,dat)  do{      \
         UART_TX = 0x80+reg; \
         while((UART_LSR&LSR_TE)!=LSR_TE); \
         UART_TX = dat; \
         while((UART_LSR&LSR_TE)!=LSR_TE); \
        }while(0)
        
#define read_reg(reg,dat)  do{      \
         UART_TX = reg; \
         while((UART_LSR & LSR_RFDR)!=LSR_RFDR); \
         dat = UART_RX; \
        }while(0)

static int uart3tx_busy;
static uart3_dev exp_uart[EXPUART_NUM]={
 {248, "uart3", 0},
 {247, "uart4", 1},
 {246, "uart5", 2},   // internal mode
 {245, "uart6", 3},
};

DECLARE_WAIT_QUEUE_HEAD(expuart1_queue_Rd);
DECLARE_WAIT_QUEUE_HEAD(expuart1_queue_Wr);

DECLARE_WAIT_QUEUE_HEAD(expuart2_queue_Rd);
DECLARE_WAIT_QUEUE_HEAD(expuart2_queue_Wr);

DECLARE_WAIT_QUEUE_HEAD(expuart3_queue_Rd);
DECLARE_WAIT_QUEUE_HEAD(expuart3_queue_Wr);

DECLARE_WAIT_QUEUE_HEAD(expuart4_queue_Rd);
DECLARE_WAIT_QUEUE_HEAD(expuart4_queue_Wr);

static void ms_delay(int ms)
{
 while(ms--){
  udelay(1000);
 }
}

/*
static void write_reg(char reg_addr, char reg_dat)
{
 char temp;
 
 UART_TX = 0x80+reg_addr;
 do{
  temp = UART_LSR;
 }while((temp&LSR_TE)!=LSR_TE);
 UART_TX = reg_dat;
 do{
  temp = UART_LSR;
 }while((temp&LSR_TE)!=LSR_TE);
}
*/

static int uart3_chkbuf(int write, int read, int reqnum)
{
 int temp = write-read;
 if(temp >= 0){
  if(temp >= reqnum){
   return 1;
  }
 }
 else{
  if((temp + RX_BUFF_SIZE)>= reqnum){
   return 1;
  }
 }
 return 0;
}

static void expuart_handler(int irq, void *dev_id, struct pt_regs * regs)
{
 char sub_sifr, int_no, sub_ssr;
 int  expnum;
 int  ctn;
 
 GPIO_XISTATUS = 0;
 uart3_dev *dev = (uart3_dev *)dev_id;
 expnum = dev->no;
 
 /* disable VK3214 all interrupt */
 write_reg(gIR,0x00);
 
 read_reg(gIR,int_no);   // read current interrupt uart
 int_no = int_no & 0x0f;
 if(1<<expnum != int_no){
  goto out;
 }

/* read sub uart of VK3214 interrupt flags */
 read_reg(SSR(expnum),sub_ssr);
 
 // send data to uart
 if((dev->usr_wr_num>0)&&((sub_ssr&4)==4)){
  ctn = dev->usr_wr_num - dev->tx_ctn;
  if(ctn >15){
   ctn = 15;
  }
  UART_TX = 0xc0+(expnum<<4)+(ctn-1);
  while(ctn--){
   UART_TX = dev->txbuf[dev->tx_ctn++];
  }
  while((UART_LSR & LSR_TE)!=LSR_TE);
  do{
   UART_TX = SSR(expnum);
   while((UART_LSR & LSR_RFDR)!=LSR_RFDR);
  }while((UART_RX&4)!=4);
  if(dev->tx_ctn == dev->usr_wr_num){
   write_reg(SIER(expnum),0x01);   // tx interrupt disable, rx interrupt enable
   dev->usr_wr_num = 0;
   dev->tran_flag = 1;
   uart3tx_busy = NO;
   if(exp_uart[0].wait_flag == 1){
   // printk("wake 0\n");
    exp_uart[0].wait_flag = 0;
    wake_up_interruptible(&expuart1_queue_Wr); //
   }
   if(exp_uart[1].wait_flag == 1){
   // printk("wake 1\n");
    exp_uart[1].wait_flag = 0;
    wake_up_interruptible(&expuart2_queue_Wr); //
   }
   if(exp_uart[2].wait_flag == 1){
   // printk("wake 2\n");
    exp_uart[2].wait_flag = 0;
    wake_up_interruptible(&expuart3_queue_Wr); //
   }
   if(exp_uart[3].wait_flag == 1){
   // printk("wake 3\n");
    exp_uart[3].wait_flag = 0;
    wake_up_interruptible(&expuart4_queue_Wr); //
   }
  }
  goto out;  
 }
 
 // receive data from uart
 if((sub_ssr&1) == 1){
  goto out;
 } 
 read_reg(SFSR(expnum), ctn);
 ctn = UART_RX & 0x0f;
 while(ctn--){
  read_reg(SFDR(expnum), dev->rxbuf[dev->Recv_wr_index++]);
  if(dev->Recv_wr_index == RX_BUFF_SIZE){
   dev->Recv_wr_index = 0;
  }
 }
 dev->recv_flag = uart3_chkbuf(dev->Recv_wr_index,dev->Recv_rd_index,dev->usr_rd_num);
 if(dev->recv_flag){
  switch(expnum){
   case 0:
    wake_up_interruptible(&expuart1_queue_Rd); //
    break;
   case 1:
    wake_up_interruptible(&expuart2_queue_Rd); //
    break;
   case 2:
    wake_up_interruptible(&expuart3_queue_Rd); //
    break;
   case 3:
    wake_up_interruptible(&expuart4_queue_Rd); //
    break;
   default:
    break;
  }
 }
out:
 write_reg(gIR,0xf0);
}
                         
ssize_t uart3_read(struct file *flip, char *buf, size_t count, loff_t *offset)
{     
 int i;        
 int expnum;
 wait_queue_t wait;
 uart3_dev *dev = (uart3_dev *)flip->private_data;
         
 expnum = dev->no;
 dev->usr_rd_num = count;
 dev->recv_flag = uart3_chkbuf(dev->Recv_wr_index,dev->Recv_rd_index,dev->usr_rd_num);
 if(dev->recv_flag==0){
  init_waitqueue_entry(&wait, current); //
  switch(expnum){
   case 0:
    add_wait_queue(&expuart1_queue_Rd, &wait); //
    break;
   case 1:
    add_wait_queue(&expuart2_queue_Rd, &wait); //
    break;
   case 2:
    add_wait_queue(&expuart3_queue_Rd, &wait); //
    break;
   case 3:
    add_wait_queue(&expuart4_queue_Rd, &wait); //
    break;
   default:
    break;
  }  
  set_current_state(TASK_INTERRUPTIBLE);
  schedule_timeout(dev->time_out*HZ); 
  set_current_state(TASK_RUNNING);
  switch(expnum){
   case 0:
    remove_wait_queue(&expuart1_queue_Rd, &wait); //
    break;
   case 1:
    remove_wait_queue(&expuart2_queue_Rd, &wait); //
    break;
   case 2:
    remove_wait_queue(&expuart3_queue_Rd, &wait); //
    break;
   case 3:
    remove_wait_queue(&expuart4_queue_Rd, &wait); //
    break;
   default:
    break;
  }  
 }
 count = dev->Recv_wr_index - dev->Recv_rd_index;
 if(count<0){
  count += RX_BUFF_SIZE;
 }
 if(count > dev->usr_rd_num){
  count = dev->usr_rd_num; 
 }
 dev->usr_rd_num = 0;
 for(i=0; i<count; i++){
  buf[i] = dev->rxbuf[dev->Recv_rd_index];
  dev->Recv_rd_index += 1;
  if(dev->Recv_rd_index == RX_BUFF_SIZE){
   dev->Recv_rd_index = 0;
  }
 }
 return count;
}

static int uart3_write(struct file *flip, int *buf, size_t count, loff_t *offset)
{
 int expnum;
 wait_queue_t wait;
 uart3_dev *dev = (uart3_dev *)flip->private_data;
 
 if(count==0){
  return 0;
 }
 dev->tx_ctn = 0;
 expnum = dev->no;
 if((dev->tran_flag==1)&&(uart3tx_busy==NO)){
  goto copy_data;
 }
// printk("wait %d\n",expnum);
 dev->wait_flag = 1;
 init_waitqueue_entry(&wait, current); //
 switch(expnum){
  case 0:
   add_wait_queue(&expuart1_queue_Wr, &wait); //
   break;
  case 1:
   add_wait_queue(&expuart2_queue_Wr, &wait); //
   break;
  case 2:
   add_wait_queue(&expuart3_queue_Wr, &wait); //
   break;
  case 3:
   add_wait_queue(&expuart4_queue_Wr, &wait); //
   break;
  default:
   break;
 } 
 set_current_state(TASK_INTERRUPTIBLE);   
 schedule();
 set_current_state(TASK_RUNNING);
 switch(expnum){
  case 0:
   remove_wait_queue(&expuart1_queue_Wr, &wait); //
   break;
  case 1:
   remove_wait_queue(&expuart2_queue_Wr, &wait); //
   break;
  case 2:
   remove_wait_queue(&expuart3_queue_Wr, &wait); //
   break;
  case 3:
   remove_wait_queue(&expuart4_queue_Wr, &wait); //
   break;
  default:
   break;
 }
copy_data:
 if(count > TX_BUFF_SIZE){
  count = TX_BUFF_SIZE;
 }
 copy_to_user(dev->txbuf, buf, count);
 dev->tran_flag = 0;
 dev->usr_wr_num = count;
 uart3tx_busy = YES;
 write_reg(SIER(expnum),0x03);   // rx and tx interrupt enable
 return count;
}

static int uart3_open(struct inode *inode,struct file* flip)
{
 int result;
 int expnum;
 uart3_dev *dev;
 
 expnum = 248 - MAJOR(inode->i_rdev);
 dev =(uart3_dev *)(&exp_uart[expnum]);
 result = request_irq(nIRQ2, expuart_handler, SA_SHIRQ, dev->dev_name, dev);
 if(result == -1){
  printk("register the expand uart irq failed!\n");
  return -EIO;
 }
 
 dev->no = expnum;
 dev->Recv_wr_index = 0;
 dev->Recv_rd_index = 0;
 dev->usr_rd_num = 0;
 dev->recv_flag = 0;
 dev->time_out = 10;
 
 dev->tx_ctn = 0;
 dev->usr_wr_num = 0;
 dev->tran_flag = 1;
 
 MOD_INC_USE_COUNT;
 flip->private_data = dev;
 
 // default
 write_reg(SCTLR(expnum),B1200+0x08); // enable uart
 write_reg(SFOCR(expnum),0xff);  
 write_reg(SFOCR(expnum),0x0c);
 write_reg(SIER(expnum),0x01);   // rx interrupt enable, tx interrupt disable
 return 0;
}

static int uart3_close(struct inode* i,struct file* flip)
{
 uart3_dev *dev = (uart3_dev *)flip->private_data;
 
 free_irq(nIRQ2, dev);
 MOD_DEC_USE_COUNT;
 return 0;
}

static int uart3_ioctl(struct inode *inode, struct file *flip, unsigned int cmd, unsigned long arg)
{
 char temp;
 int  expnum;
 uart3_dev *dev = (uart3_dev *)flip->private_data;
 
 expnum = dev->no;
 
 switch(cmd)
 {
  case CMD_BANDRATE:  // set bandrate
   if(arg==115200)
    temp = B115200;
   else if(arg==57600)
    temp = B57600;
   else if(arg==38400)
    temp = B38400;
   else if(arg==19200)
    temp = B19200;
   else if(arg==9600)
    temp = B9600;
   else if(arg==4800)
    temp = B4800;
   else if(arg==2400)
    temp = B2400;
   else if(arg==1200)
    temp = B1200;
   else
    temp = B9600;
  // printk("set expuart %d bandrate:%d\n",expnum,arg);
   write_reg(SCTLR(expnum),temp+0x08); // enable uart
   break;
  case CMD_UARTLCR:  // set uart
   write_reg(SCONR(expnum),(char)arg);
   break;
  case CMD_RXTIMEOUT:
   dev->time_out = arg;
   break;
  case CMD_MODEM_SET:
   if((arg == 1)&&(expnum==2)){
    GPIO_DATAOUT5 |= 0x200;
    printk("high\n");
   }
   if((arg == 0)&&(expnum==2)){
    GPIO_DATAOUT5 &= 0xFFFFFDFF;
    printk("low\n");
   }
   break;
  default:
   break;
 }
 return 0;
}

struct file_operations uart3_fops =
{
 owner:  THIS_MODULE,
 open:  uart3_open,
 write:  uart3_write,
 read:  uart3_read,
 ioctl: uart3_ioctl,
 release: uart3_close,
};

static int __init uart3_init(void)
{
 int i;
 char temp;
 int result;
 int cfg;
 int time,time1;

 time1 = 1;
 cfg = GPIO_CFG0;
 cfg &= 0xFFFFFC00;
 cfg |= 0x3C2;   // GPIO.0=nIRQ2, GPIO.1=output, GPIO.3=TXD3,GPIO.4=RXD3
 GPIO_CFG0 = cfg;
 GPIO_DIR0 |= 0x60006;
 GPIO_DATAOUT0 |= 0x4;
 cfg = GPIO_XICFG;
 cfg &= 0xf0;
// cfg |= 0x8;    // low level sensitive
 cfg |= 0xa;    // negative edge triggered
 GPIO_XICFG = cfg;
 
 cfg = GPIO_CFG5;  // GPIO.14=output
 cfg &= 0x3F3FFFF;
 GPIO_CFG5 = cfg;
 GPIO_DIR5 = 0x2000200; 
 GPIO_DATAOUT5 |= 0x200;
  
 uart3_int(96);     // default 9600
 
 GPIO_DATAOUT0 |= 0x02;    // gpio.1=1
 ms_delay(10);
 GPIO_DATAOUT0 &= ~(0x02);   // gpio.1=0
 ms_delay(20);
 GPIO_DATAOUT0 |= 0x02;    // gpio.1=1
 write_reg(gIR,0xf0);   // enable all uart port interrupt

loop:
 uart3_int(96);     // default 9600
 write_reg(gMUCR,B115200);  // main uart bandrate 115200
 uart3_int(6);     // 230400bps@15MHz
 for(i=0;i<time1;i++){
  ms_delay(10);
 }
 time = TIME_OUT;
 UART_TX = gMUCR;
 do{
  temp = UART_LSR;
  time--;
  if(time == 0){
   time1++;
   goto loop;
  }
 }while((temp & LSR_RFDR)!=LSR_RFDR);
 temp = UART_RX;
 if(temp != B115200){
  time1++;
//  printk("temp = %02x\n",temp);
  goto loop;
 }
 
 for(i=0;i<EXPUART_NUM;i++){ 
  result = register_chrdev(exp_uart[i].major_num,exp_uart[i].dev_name,&uart3_fops);
  if(result == 0)
   printk("expand uart %d at 0xfff80300 (irq = 31) is a W90N745!\n",i+1);
 }
 uart3tx_busy = NO;
 return 0;
}

static void uart3_release(void)
{
 int i;
 
 for(i=0;i<EXPUART_NUM;i++){ 
  unregister_chrdev(exp_uart[i].major_num,exp_uart[i].dev_name);
 }
 printk("cancel the device expand uart1,2,3,4!\n");
 return;
}

module_init(uart3_init);
module_exit(uart3_release);
      

Read More...