//keyboard1.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUTTON_IRQ1 IRQ_EINT5
#define BUTTON_IRQ2 IRQ_EINT6
#define DEVICE_NAME "button"
static int buttonMajor=0;
#define BUTTONMINOR 0
#define MAX_BUTTON_BUF 16
#define BUTTONSTATUS_1 5
#define BUTTONSTATUS_2 6
static unsigned char buttonRead(void);
static int flag=0;
typedef struct {
unsigned int buttonStatus; //按键状态
unsigned char buf[MAX_BUTTON_BUF]; //按键缓冲区
unsigned int head,tail; //按键缓冲区头和尾
wait_queue_head_t wq; //等待队列
} BUTTON_DEV;
static BUTTON_DEV buttondev;
#define BUF_HEAD (buttondev.buf[buttondev.head]) //缓冲区头
#define BUF_TAIL (buttondev.buf[buttondev.tail]) //缓冲区尾
#define INCBUF(x,mod) ((++(x)) & ((mod)-1)) //移动缓冲区指针
static void (*buttonEvent)(void);
static void buttonEvent_dummy(void) {}
static void buttonEvent_1(void)
{
if(buttondev.buttonStatus==BUTTONSTATUS_2) {
BUF_HEAD=BUTTONSTATUS_2;
}
else {
BUF_HEAD=BUTTONSTATUS_1;
}
buttondev.head=INCBUF(buttondev.head,MAX_BUTTON_BUF);
flag=1;
wake_up_interruptible(&(buttondev.wq));
printk("buttonEvent_1\n");
}
static irqreturn_t isr_button(int irq,void *dev_id,struct pt_regs *regs)
{
printk("Occured key board Inetrrupt,irq=%d\n",irq-44);
switch (irq) {
case BUTTON_IRQ1:buttondev.buttonStatus=BUTTONSTATUS_1;
break;
case BUTTON_IRQ2:buttondev.buttonStatus=BUTTONSTATUS_2;
break;
default:break;
}
buttonEvent();
return 0;
}
static int button_open(struct inode *inode,struct file *filp)
{
int ret;
buttondev.head=buttondev.tail=0;
buttonEvent=buttonEvent_1;
ret=request_irq(BUTTON_IRQ1,isr_button,SA_INTERRUPT,DEVICE_NAME,NULL);
if(ret) {
printk("BUTTON_IRQ1: could not register interrupt ret=%d\n",ret);
return ret;
}
ret=request_irq(BUTTON_IRQ2,isr_button,SA_INTERRUPT,DEVICE_NAME,NULL);
if(ret) {
printk("BUTTON_IRQ2: could not register interrupt\n");
return ret;
}
return 0;
}
static int button_release(struct inode *inode,struct file *filp)
{
buttonEvent=buttonEvent_dummy;
free_irq(BUTTON_IRQ1,NULL);
free_irq(BUTTON_IRQ2,NULL);
return 0;
}
static ssize_t button_read(struct file *filp,char *buffer,size_t count,loff_t *ppos)
{
static unsigned char button_ret;
retry:
printk("retry start\n");
if(buttondev.head!=buttondev.tail) {
button_ret=buttonRead();
copy_to_user(buffer,(char *)&button_ret,sizeof(unsigned char));
printk("the button_ret is 0x%x\n",button_ret);
return sizeof(unsigned char);
}
else {
if(filp->f_flags & O_NONBLOCK)
return -EAGAIN;
printk("sleep\n");
//interruptible_sleep_on(&(buttondev.wq));//为安全起见,最好不要调用该睡眠函数
wait_event_interruptible(buttondev.wq,flag);
flag=0;
printk("sleep_after\n");
if(signal_pending(current))
{
printk("rturn -ERESTARTSYS\n");
return -ERESTARTSYS;
}
goto retry;
}
return sizeof(unsigned char);
}
static struct file_operations button_fops= {
.owner = THIS_MODULE,
.open = button_open,
.read = button_read,
.release = button_release,
};
static int __init s3c2410_button_init(void)
{
int ret;
set_irq_type(BUTTON_IRQ1,IRQT_FALLING);
set_irq_type(BUTTON_IRQ2,IRQT_FALLING);
buttonEvent=buttonEvent_dummy;
ret=register_chrdev(0,DEVICE_NAME,&button_fops);
if(ret<0) {
printk("button: can't get major number\n");
return ret;
}
buttonMajor=ret;
#ifdef CONFIG_DEVFS_FS
devfs_mk_cdev(MKDEV(buttonMajor,BUTTONMINOR),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME);
#endif
//buttondev.head=buttondev.tail=0;
buttondev.buttonStatus=BUTTONSTATUS_1;
init_waitqueue_head(&(buttondev.wq));
printk(DEVICE_NAME" initialized\n");
return 0;
}
static unsigned char buttonRead(void)
{
unsigned char button_ret;
button_ret=BUF_TAIL;
buttondev.tail=INCBUF(buttondev.tail,MAX_BUTTON_BUF);
return button_ret;
}
static void __exit s3c2410_button_eixt(void)
{
#ifdef CONFIG_DEVFS_FS
devfs_remove(DEVICE_NAME);
#endif
unregister_chrdev(buttonMajor,DEVICE_NAME);
printk("\nbutton remove\n");
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kision");
MODULE_DESCRIPTION ("the first char device driver");
module_init(s3c2410_button_init);
module_exit(s3c2410_button_eixt);
//keyboard2.c
#include
#include
#include
#include
#include /* for in_interrupt */
#include
#include
#include /* for udelay */
#include
#include
#include
#include
#include
#include
//linux在初始化的时候已经把每个中断向量的地址准备好
#define IRQ_KEY_UP IRQ_EINT19
#define IRQ_KEY_DOWN IRQ_EINT11
#define IRQ_KEY_LEFT IRQ_EINT2
#define IRQ_KEY_RIGHT IRQ_EINT8
#define IRQ_KEY_SPACE IRQ_EINT21
#define IRQ_KEY_ALT IRQ_EINT22
#define IRQ_KEY_ENTER IRQ_EINT23
//
#define Keypad_MAJOR 97//定义键盘设备号
typedef struct devfs_entry *devfs_handle_t;
devfs_handle_t dev_handle; /* register handle to store device fs */
static int Keycode = 0;
static unsigned char haveData = 0;
static DECLARE_WAIT_QUEUE_HEAD(keypad);// 经过宏展开后就是定义了一个keypad等待队列头变量,核心运行过程中,经常会因为某些条件不满足而需要挂起当前线程,直至条件满足了才继续执行
//static unsigned char spiRead();
//static void keyboard_Init();
static void KEY_interrupt(int nr, void *devid, struct pt_regs *regs);
ssize_t keypad_read (struct file * file ,char * buf, size_t count, loff_t * f_ops)
{
interruptible_sleep_on(&keypad);//挂起程序
copy_to_user(buf, &Keycode, sizeof Keycode);
haveData = 0;
return 1;
}
ssize_t keypad_open (struct inode * inode ,struct file * file)
{
printk("s3c2410:device open operation!\n");
return 0;
}
struct file_operations Keypad_ops ={
open: keypad_open,
read: keypad_read,
// poll: keypad_select,
};
//中断处理函数
static void KEY_interrupt(int nr, void *devid, struct pt_regs *regs)
{
switch(nr)
{
case IRQ_KEY_UP:
Keycode=0x1013;
break;
case IRQ_KEY_DOWN:
Keycode=0x1015;
break;
case IRQ_KEY_LEFT:
Keycode=0x1012;
break;
case IRQ_KEY_RIGHT:
Keycode=0x1014;
break;
case IRQ_KEY_SPACE:
Keycode=0x1003;
break;
case IRQ_KEY_ALT:
Keycode=0x1023;
break;
case IRQ_KEY_ENTER:
Keycode=0x1005;
break;
default: break;
}
haveData = 1;
wake_up_interruptible(&keypad);//唤醒程序
}
static int __init keypad_init(void)//键盘初始化程序
{
int ret = -ENODEV;
set_irq_type(IRQ_KEY_UP,IRQT_RISING);
//请求中断
set_irq_type(IRQ_KEY_DOWN,IRQT_RISING);
//请求中断
set_irq_type(IRQ_KEY_LEFT,IRQT_RISING);
//请求中断
set_irq_type(IRQ_KEY_RIGHT,IRQT_RISING);
//请求中断
set_irq_type(IRQ_KEY_SPACE,IRQT_RISING);
//请求中断
set_irq_type(IRQ_KEY_ALT,IRQT_RISING);
//请求中断
set_irq_type(IRQ_KEY_ENTER,IRQT_RISING);
//请求中断
ret = devfs_register_chrdev(Keypad_MAJOR, "Keypad", &Keypad_ops);
//字符设备注册,主设备号,设备名,函数关联结构体
if( ret < 0 ){
printk (" Keypad: init_module failed with %d\n", ret);
return ret;
}
ret = request_irq(IRQ_KEY_UP, KEY_interrupt, SA_INTERRUPT,
"Keypad", NULL);// 注册中断服务程序,把中断向量和中断服务程序对应起来。
if (ret) {
devfs_unregister_chrdev(Keypad_MAJOR, "Keypad");//取消注册
printk(KERN_INFO "request Keypad IRQ failed (%d)\n", IRQ_KEY_UP);
return ret;
}
ret = request_irq(IRQ_KEY_DOWN, KEY_interrupt, SA_INTERRUPT,
"Keypad", NULL);// 注册中断服务程序,把中断向量和中断服务程序对应起来。
if (ret) {
devfs_unregister_chrdev(Keypad_MAJOR, "Keypad");//取消注册
printk(KERN_INFO "request Keypad IRQ failed (%d)\n", IRQ_KEY_DOWN);
return ret;
}
ret = request_irq( IRQ_KEY_LEFT, KEY_interrupt, SA_INTERRUPT,
"Keypad", NULL);// 注册中断服务程序,把中断向量和中断服务程序对应起来。
if (ret) {
devfs_unregister_chrdev(Keypad_MAJOR, "Keypad");//取消注册
printk(KERN_INFO "request Keypad IRQ failed (%d)\n", IRQ_KEY_LEFT);
return ret;
}
ret = request_irq(IRQ_KEY_RIGHT, KEY_interrupt, SA_INTERRUPT,
"Keypad", NULL);// 注册中断服务程序,把中断向量和中断服务程序对应起来。
if (ret) {
devfs_unregister_chrdev(Keypad_MAJOR, "Keypad");//取消注册
printk(KERN_INFO "request Keypad IRQ failed (%d)\n", IRQ_KEY_RIGHT);
return ret;
}
ret = request_irq(IRQ_KEY_SPACE, KEY_interrupt, SA_INTERRUPT,
"Keypad", NULL);// 注册中断服务程序,把中断向量和中断服务程序对应起来。
if (ret) {
devfs_unregister_chrdev(Keypad_MAJOR, "Keypad");//取消注册
printk(KERN_INFO "request Keypad IRQ failed (%d)\n", IRQ_KEY_SPACE);
return ret;
}
ret = request_irq(IRQ_KEY_ALT, KEY_interrupt, SA_INTERRUPT,
"Keypad", NULL);// 注册中断服务程序,把中断向量和中断服务程序对应起来。
if (ret) {
devfs_unregister_chrdev(Keypad_MAJOR, "Keypad");//取消注册
printk(KERN_INFO "request Keypad IRQ failed (%d)\n", IRQ_KEY_ALT);
return ret;
}
ret = request_irq(IRQ_KEY_ENTER, KEY_interrupt, SA_INTERRUPT,
"Keypad", NULL);// 注册中断服务程序,把中断向量和中断服务程序对应起来。
if (ret) {
devfs_unregister_chrdev(Keypad_MAJOR, "Keypad");//取消注册
printk(KERN_INFO "request Keypad IRQ failed (%d)\n", IRQ_KEY_ENTER);
return ret;
}
dev_handle = devfs_register( NULL, "Keypad", DEVFS_FL_DEFAULT,
Keypad_MAJOR, 0, S_IFCHR, &Keypad_ops, NULL);
//登记设备入口点,获得文件句柄
return ret;
}
int spiWrite(u8 Keycode)
{
ZLGCSEN();
ZLGMO();
udelay(60);
while((SPSTA1 & 0x01)== 0);
SPTDAT1 = Keycode;//数据寄存器
while((SPSTA1 & 0x01)== 0);
ZLGCSDIS();
return 0;
}
static unsigned char spiRead(void)
{
unsigned char code;
ZLGCSEN();
ZLGMO();
udelay(60);
while((SPSTA1 & 0x01)== 0);
SPTDAT1 = 0x15;
while((SPSTA1 & 0x01)== 0);
udelay(30);
ZLGMI();
SPTDAT1 = 0xff;//状态寄存器
while((SPSTA1 & 0x01)== 0);
ZLGCSDIS();
ZLGMO();
code = SPSTA1; //状态寄存器
return code;
}
static void spi_Init()//spi外围串口初始化程序
{
// Setup IO port for SPI interface & Keyboard
// Setup EINT1 (KBDINT)
GPFCON &= ~(0x3 << 2); // Clear GPF1
GPFCON |= (0x2 << 2); // Set GPF1 to EINT1 for Keyboard interrupt
EXTINT0 &= ~(0x7 << 4); // Clear EINT1
EXTINT0 |= (0x2 << 4); // fallig edge triggered for EINT1
// setup SPI interface
GPGCON &= ~((0x3 << 10) | (0x3 << 12) | (0x3 << 14)); // Clear GPG5,6,7
GPGCON |= ((0x3 << 10) | (0x3 << 12) | (0x3 << 14));
// setup _SS signal(nSS_KBD)
GPBCON &= ~(0x3 << 12); // Clear GPB6
GPBCON |= (0x01 << 12); // Set Port GPB6 to output for nSS signal
ZLGCSDIS(); // Set /SS high
// setup Dir signal (KEYBOARD) CPU->7289
GPBCON &= ~(0x3 << 0); // Clear GPB0
GPBCON |= (0x01 << 0); // Set Port GPB0 to output for _PWR_OK signal
ZLGMO();
// Setup SPI registers
SPCON1 = (0<<5)|(0X01 << 4)|(0X01 << 3)|(0x0<<2)|(0<<1);
// Developer MUST change the value of prescaler properly whenever value of PCLK is changed.
SPPRE1 = 255; // 99.121K = 203M/4/2/(255+1) PCLK=50.75Mhz FCLK=203Mhz SPICLK=99.121Khz
spiWrite(0xa4); //send init command
printk("Key Pad Init complete:\n");
}
/*static int keypad_select(struct file *file, struct poll_table_struct *wait)
{
if(haveData)
return 1;
return 0;
}*/
int __init sw4_init_module()
{
int ret = -ENODEV;
ret = keypad_init();//键盘初始化
if (ret)
return ret;
return 0;
}
void __exit sw4_cleanup_module()
{
free_irq(IRQ_KBD, NULL);// 释放中断
devfs_unregister_chrdev( Keypad_MAJOR, "Keypad" );//注销设备号
devfs_unregister( dev_handle );//注销设备文件句柄
return;
}
module_init(sw4_init_module);//内核特殊的宏,指明次函数为模块
module_exit(sw4_cleanup_module);
MODULE_LICENSE("GPL");//采用GPL软件许可证