//
// 书写规范 //
//结构体定义:一律大写字母,中间可用"_"区分 //
//全局变量 :全部用小写字母,加前缀"g_" //
//局部变量 :全部用小写字母组合,无其他前后缀 //
//指针变量 :在变量前加"p",优先级比"g_"低 //
//数组 :在变量前加"t",优先级比"g_"低 //
//自制函数 :自制函数名字都以"key_"作为前缀 //
//
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/poll.h> #include <linux/irq.h> #include <asm/irq.h> #include <linux/interrupt.h> #include <asm/uaccess.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/platform_device.h> #include <linux/cdev.h> #include <linux/miscdevice.h> /
// #define IRQ_TYPE_EDGE_RISING 0x00000001
// #define IRQ_TYPE_EDGE_FALLING 0x00000002
// #define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
// #define IRQ_TYPE_LEVEL_HIGH 0x00000004 // #define IRQ_TYPE_LEVEL_LOW 0x00000008 // #define IRQ_TYPE_SENSE_MASK 0x0000000f // #define IRQ_TYPE_PROBE 0x00000010 // set_external_irq(key_info->irq_no, IRQ_TYPE_LEVEL_LOW, GPIO_PULLUP_DIS); //set INT low voltage level target
// int set_irq_type (unsigned int irq, unsigned int type);
set_irq_type(g_tkey_info[i].irq_no, IRQ_TYPE_LEVEL_LOW); if(request_irq(key_info->irq_no, key_eint_handler, IRQF_DISABLED,"Mini2440_Key", &i)) { return -1; } } return 0; } void free_irqs(void) { struct KEY_INFO *key_info; int i; for(i=0; i<(sizeof(g_tkey_info)/sizeof(g_tkey_info[1])); i++) { key_info = g_tkey_info + i; free_irq(key_info->irq_no, &i); } } static void keyEvent(int key_index) { g_pkey_dev->tbuf[g_pkey_dev->head] = key_index; g_pkey_dev->head = INC_BUF_POINTOR(g_pkey_dev->head,MAX_KEY_BUF); wake_up_interruptible(&g_pkey_dev->wq); } static void key_timer_handler(unsigned long data) { int key_index = data; //printk("B:get key %d\n",s3c2410_gpio_getpin(g_tkey_info[key_index].gpio_port)); if (ISKEY_DOWN(key_index)) { // printk(KERN_NOTICE "B\n");
if(g_pkey_dev->tkeystatus[key_index] == KEYSTATUS_X) { g_pkey_dev->tkeystatus[key_index] = KEYSTATUS_DOWN; //change key state
g_tkey_timer[key_index].expires = jiffies + KEY_DELAY_100MS; //re_initial timer
keyEvent(key_index); add_timer(&g_tkey_timer[key_index]); //restart timer
} else //wait for user release the key
{ g_tkey_timer[key_index].expires = jiffies + KEY_DELAY_100MS; add_timer(&g_tkey_timer[key_index]); } } else //user have released the key
{ g_pkey_dev->tkeystatus[key_index] = KEYSTATUS_UP; //del_timer(&g_tkey_timer[key_index]); enable_irq(g_tkey_info[key_index].irq_no); } } static int key_open(struct inode *inode, struct file *filp) { printk(KERN_NOTICE "key opened\n"); g_pkey_dev->head = g_pkey_dev->tail = 0; return 0; } static int key_release(struct inode *inode, struct file *filp) { return 0; } static ssize_t key_read(struct file *filp, char *buf, size_t count, loff_t *ppos) { unsigned int ret,temp; unsigned long flag; retry: if(g_pkey_dev->head != g_pkey_dev->tail) { local_irq_save(flag); //进入临界区,关闭中断 ret = g_pkey_dev->tbuf[g_pkey_dev->tail]; //读取尾部指针所指内容 g_pkey_dev->tail = INC_BUF_POINTOR(g_pkey_dev->tail, MAX_KEY_BUF); local_irq_restore(flag); //退出临界区 //printk(KERN_NOTICE "driver key_read,key no:%d\n",ret);
temp = copy_to_user(buf, &ret, sizeof(unsigned int)); //printk(KERN_NOTICE "copy to user return %d\n", temp);
return (sizeof(unsigned int)); } else { //printk(KERN_NOTICE "A\n");
if(filp->f_flags & O_NONBLOCK) { return -EAGAIN; } //printk("E:test %d\n",s3c2410_gpio_getpin(g_tkey_info[0].gpio_port));
interruptible_sleep_on(&(g_pkey_dev->wq)); goto retry; } // return 0;
} static int key_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) { unsigned long flag; switch(cmd) { case KEY_BUF_CLR: local_irq_save(flag); g_pkey_dev->head = g_pkey_dev->tail = 0; local_irq_restore(flag); printk(KERN_NOTICE "key buf is clear\n"); break; default: return - EINVAL; } return 0; } static struct file_operations g_tkey_fops = { .owner = THIS_MODULE, .open = key_open, //打开设备 .release = key_release, //关闭设备 .read = key_read, //读取按键的键值 .ioctl = key_ioctl, //清除缓冲区 }; static void key_setup_cdev(struct KEY_DEV *pdev, int index) { //1. cdev init
//2. cdev bind fops
//3. cdev add
int err, devno; devno = MKDEV(g_key_major, index); cdev_init(&(g_pkey_dev->cdev), &g_tkey_fops); pdev->cdev.owner = THIS_MODULE; pdev->cdev.ops = &g_tkey_fops; err = cdev_add(&pdev->cdev, devno, 1); if(err) { printk(KERN_NOTICE "Error %d adding dev %d", err, index); } } static int mini2440_key_init(void) { //********************************** //申请设备号,添加设备 //********************************** int ret,i; dev_t devno = MKDEV(g_key_major, 0); if(g_key_major) { ret = register_chrdev_region(devno, 1, "Mini2440_Key"); } else { ret = alloc_chrdev_region(&devno, 0, 1,"Mini2440_Key"); g_key_major = MAJOR(devno); } if(ret < 0) { return ret; } g_pkey_dev = kmalloc(sizeof(struct KEY_DEV), GFP_KERNEL); if(!g_pkey_dev) { ret = -ENOMEM; goto fail_malloc; } memset(g_pkey_dev, 0, sizeof(struct KEY_DEV)); key_setup_cdev(g_pkey_dev, 0); //********************************** //申请设备号,添加设备 完毕!
//下面初始化其他内容 //********************************** request_irqs(); //request all the key irq
g_pkey_dev->head = g_pkey_dev->tail = 0; //initial key_dev
for(i=0; i<KEY_NUM; i++) { g_pkey_dev->tkeystatus[i] = KEYSTATUS_UP; } init_waitqueue_head(&(g_pkey_dev->wq)); //initial wait queue
for(i=0; i<KEY_NUM; i++) { // setup_timer(&g_tkey_timer[i], key_timer_handler,i);
g_tkey_timer[i].function = key_timer_handler; g_tkey_timer[i].data = i; init_timer(&g_tkey_timer[i]); } return 0; fail_malloc:unregister_chrdev_region(devno, 1); return ret; } static void key_exit(void) { free_irqs(); //free irq
cdev_del(&g_pkey_dev->cdev); //del cdev
kfree(g_pkey_dev); //free memory
g_pkey_dev = NULL; unregister_chrdev_region(MKDEV(g_key_major,0), 1); } MODULE_AUTHOR("Benson"); MODULE_LICENSE("Dual BSD/GPL"); module_param(g_key_major, int, S_IRUGO); module_init(mini2440_key_init); module_exit(key_exit); |