Chinaunix首页 | 论坛 | 博客
  • 博客访问: 385903
  • 博文数量: 57
  • 博客积分: 2299
  • 博客等级: 大尉
  • 技术积分: 1109
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-27 23:12
文章分类
文章存档

2011年(4)

2010年(53)

分类: 嵌入式

2010-08-07 16:23:01

#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");

驱动结构:
platform_driver:先注册平台设备mgc270btn_probe,再让struct Button指向dev->driver_data,通过   |device.h中的dev_set_drvdata()实现,方便以后好操作struct Button自己定义的数据结构
    |
struct button:自己定义的关于按键的结构体,里面有input_dev和keycode等按键信息
    |
input_dev:指向struct button里面的input。
一级一级初始化。
阅读(3117) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~