#include <linux/delay.h> #include <linux/platform_device.h> #include <linux/init.h> #include <linux/input.h> #include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/module.h> #include <linux/slab.h> //#include #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> #define SCAN_INTERVAL (50) /* ms */ //#define HINGE_SCAN_INTERVAL (150) /* ms */ static unsigned char mgc270btn_keycode[1] = {KEY_ENTER}; struct mgc270btn { unsigned char keycode[ARRAY_SIZE(mgc270btn_keycode)]; struct input_dev *input; char phys[32];
spinlock_t lock; struct timer_list timer; }; //#define KB_DISCHARGE_DELAY 10 //#define KB_ACTIVATE_DELAY 10 static inline int mgc270btn_get_status(void) { return ((GPLR0 & 0x01));//取得当前按键的状态 }
/* * The MagicARM270 Button only generates interrupts when it is pressed. * When it is pressed, we enable a timer which then scans the * button to detect when the it is released. */ /* * MagicARM270 button interrupt handler. */ /* Scan the hardware button and push any changes up through the input layer */ static void mgc270btn_scankeypad(struct mgc270btn *mgc270btn_data, struct pt_regs *regs) { /* struct pt_regs: * This struct defines the way the registers are stored on the * stack during a system call. Note that sizeof(struct pt_regs) * has to be a multiple of 8. */ unsigned long flags; unsigned int num_pressed = 0; unsigned int pressed;
spin_lock_irqsave(&mgc270btn_data->lock, flags);//获得自旋锁之前禁止中断 input_regs(mgc270btn_data->input, regs); //把input_dev在系统队列上注册,不知道这样理解有没有错 pressed = (~mgc270btn_get_status()) & 0x01; input_report_key(mgc270btn_data->input, mgc270btn_data->keycode[0], pressed); //告诉上层有哦按键动作发生 if (pressed) num_pressed++; input_sync(mgc270btn_data->input); //告诉上层,本时间已经完成 /* if button is pressed, enable the timer */ if (num_pressed) mod_timer(&mgc270btn_data->timer, jiffies + msecs_to_jiffies(SCAN_INTERVAL)); //重新给定时器新的终点,即在jiffies + msecs_to_jiffies(SCAN_INTERVAL)发生中断,也就是未来的msecs_to_jiffies(SCAN_INTERVAL) //msecs_to_jiffies()将ms值转化为相应的jiffy值 //功能是识别按键长按 spin_unlock_irqrestore(&mgc270btn_data->lock, flags);//解锁 #ifdef DEBUG printk(KERN_ALERT"evbit[0]: %d\n",mgc270btn_data->input->evbit[0]); printk(KERN_ALERT"keycode: %o\n",mgc270btn_data->keycode); #endif } static irqreturn_t mgc270btn_interrupt(int irq, void *dev_id, struct pt_regs *regs) { //该函数在按键按下去有效,判断定时器是否在计时是为了消抖,如果还在计时 struct mgc270btn *mgc270btn_data = dev_id; #ifdef DEBUG printk(KERN_ALERT"Interrupt!\n"); #endif if (!timer_pending(&mgc270btn_data->timer)) { //判断定时器有没有在计时,ldd3对于timer_pending()的原文是:通过读取timer_list //结构的一个不可见字段来返回定时器是否在被调度进行 /*我的理解就是查看定时器有没有在mod_timer(&mgc270btn_data->timer, jiffies)这种状态*/ /** wait chattering delay **/ #ifdef DEBUG printk(KERN_ALERT"Timer_pending!\n"); #endif udelay(20); mgc270btn_scankeypad(mgc270btn_data, regs); //读取按键值 } return IRQ_HANDLED; } /* * MagicARM270 timer checking for released button */ static void mgc270btn_timer_callback(unsigned long data) { struct mgc270btn *mgc270btn_data = (struct mgc270btn *) data; #ifdef DEBUG printk(KERN_ALERT"Timer_callback!\n"); #endif mgc270btn_scankeypad(mgc270btn_data, NULL);//解决按键长按的问题 }
static int __init mgc270btn_probe(struct platform_device *dev) { struct mgc270btn *mgc270btn; struct input_dev *input_dev; //int i; #ifdef DEBUG printk(KERN_ALERT"Init!\n"); #endif mgc270btn = kzalloc(sizeof(struct mgc270btn), GFP_KERNEL); if (!mgc270btn) return -ENOMEM; input_dev = input_allocate_device(); if (!input_dev) { kfree(mgc270btn); return -ENOMEM; } platform_set_drvdata(dev, mgc270btn); //把自定义的mgc270btn赋值给刚刚申请到了platform_device *dev设备的私有数据区 strcpy(mgc270btn->phys, "mgc270btn/input0"); spin_lock_init(&mgc270btn->lock);//初始化自旋锁 /* Init Keyboard rescan timer */ init_timer(&mgc270btn->timer); mgc270btn->timer.function = mgc270btn_timer_callback; mgc270btn->timer.data = (unsigned long) mgc270btn; //timer.data作为timer.function回调函数的传入参数 mgc270btn->input = input_dev; input_dev->private = mgc270btn;/* data private to the driver */ input_dev->name = "MagicARM270 button"; input_dev->phys = mgc270btn->phys; input_dev->cdev.dev = &dev->dev;
input_dev->id.bustype = BUS_HOST; input_dev->id.vendor = 0x0001; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); /*BIT(x) - returns the index in a long for bit x也就是找到x在long型里面的哪一位*/ /*在input驱动中的功能是然内核支持该功能*/ // input_dev->evbit[0] = BIT(EV_MSC);// | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); #define DEBUG printk(KERN_ALERT"evbit: %d\n",input_dev->evbit[0]); #endif input_dev->keycode = mgc270btn->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(mgc270btn_keycode);
memcpy(mgc270btn->keycode, mgc270btn_keycode, sizeof(mgc270btn->keycode)); // for (i = 0; i < ARRAY_SIZE(mgc270btn_keycode); i++)
set_bit(mgc270btn->keycode[0], input_dev->keybit); clear_bit(0, input_dev->keybit); set_bit(SW_LID, input_dev->swbit); set_bit(SW_TABLET_MODE, input_dev->swbit); set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
input_register_device(input_dev);
/* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ pxa_gpio_mode(0 | GPIO_IN); if (request_irq(IRQ_GPIO(0), mgc270btn_interrupt, IRQF_DISABLED|IRQF_TRIGGER_FALLING, "Mgc270btn Sense", mgc270btn)) printk(KERN_WARNING "mgc270btn: Can't get Sense IRQ: %d!\n", IRQ_GPIO(0)); /* Set Strobe lines as outputs - set high */ printk(KERN_INFO "input: MagicARM270 button Registered\n"); return 0; }
static int mgc270btn_remove(struct platform_device *dev) { struct mgc270btn *mgc270btn = platform_get_drvdata(dev);
free_irq(IRQ_GPIO(0), mgc270btn); del_timer_sync(&mgc270btn->timer);
input_unregister_device(mgc270btn->input); kfree(mgc270btn);
return 0; }
static struct platform_driver mgc270btn_driver = { .probe = mgc270btn_probe, .remove = mgc270btn_remove, .driver = { .name = "mgc270-button", }, };
static int __devinit mgc270btn_init(void) { printk(KERN_ALERT"DevInit!\n"); return platform_driver_register(&mgc270btn_driver); }
static void __exit mgc270btn_exit(void) { platform_driver_unregister(&mgc270btn_driver); }
module_init(mgc270btn_init); module_exit(mgc270btn_exit);
MODULE_AUTHOR("Chenxibing "); MODULE_DESCRIPTION("MagicARM270 button Driver"); MODULE_LICENSE("GPL");
|