platform之按键驱动多种写法(笔记)

来源:互联网 发布:销售管理论文数据 编辑:程序博客网 时间:2024/04/28 06:32

platform之按键驱动多种写法(笔记)

  • 1.读引脚电平高低(ioctl方式)(应用层采用查询ioctl的方式)
缺点:无阻塞、不能按键防抖
  • 2.外部中断方式(key_read方式)(应用层调用read)
缺点:无阻塞、不能按键防抖
  • 3.再加定时器方式(key_read方式)(应用层调用read)
优点:按键能防抖缺点:无阻塞
  • 4.再加中断顶半步方式(key_read方式)(应用层调用read)
优点:按键能防抖,中断响应更合理缺点:无阻塞
  • 5.再加消息队列(key_read方式)(应用层调用read)
优点:按键能防抖,中断响应更合理,有阻塞

通用部分

1.模块三要素

1.1 初始化模块  1.2 退出模块  1.3 模块签证

2.platform总线的三个步骤

2.1 实例化platform_driver结构体i)实例化回掉函数probe,并为成员.probe赋值ii)实例化回掉函数remove,并为成员.remove赋值iii)选择一种匹配方式进行匹配(设备树,ACPI,名字,ID四选一)2.2 注册2.3 注销

3.字符设备框架流程(天龙八部)

3.1 申请设备号3.2 注册设备号3.3 实例化cdev结构体3.4 实例化file_operations结构体,并初始化3.5 初始化cdev结构体3.6 注册cdev结构体3.7 注销cdev结构体3.8 注销设备号

4.自动创建设备节点

4.1 创建class4.2 创建设备节点4.3 注销设备节点4.4 注销class

方式一:读引脚电平高低

(ioctl方式,无中断,无阻塞)(应用层采用查询方式)

//***********************head.h中***************************//#define     MAGIC 'k'#define     KEY_STATUS  _IO(MAGIC,1)//***********************key_probe函数中*********************//gpx1dat = ioremap(pdev->resource[2].start,pdev->resource[2].end - pdev->resource[2].start);//***********************key_ioctl函数中*********************//long key_ioctl (struct file * file, unsigned int cmd, unsigned long arg){    int ret;    printk("key_ioctl cmd=%x \n",cmd);    switch(cmd)    {    case KEY_STATUS:        ret = *gpx1dat & (0x1 << 1);        printk("key1 = %d",ret);        break;    default:        printk("no such the cmd!\n");        return -EFAULT;        break;    }    return 0;}//***********************key_remove函数中***************************//iounmap(gpx1dat);

方式二:加外部中断

//*******************************全局变量*****************************//#define     IRQ1_NAME   "key2"#define     IRQ2_NAME   "key3"int key;//*******************************key_read函数*****************************//ssize_t key_read (struct file *file, char __user *buf, size_t size, loff_t * loft){     int ret;     printk(" key_read!!!\n");     if (size < 0) return -EFAULT;     if (size > sizeof(key)) size = sizeof(key);     ret = copy_to_user(buf,&key,size);     return sizeof(key) - ret;}//*******************************key_handler中断函数*****************************//irqreturn_t key_handler(int num,void *dev){     if (mydev->resource[0].start == num)     {         key = 2;     }     if (mydev->resource[1].start == num)     {         key = 3;     }     return IRQ_HANDLED;}//*******************************probe_key函数*****************************//ret = request_irq(pdev->resource[0].start,key_handler,IRQF_TRIGGER_FALLING | IRQF_DISABLED,IRQ1_NAME,NULL);if (ret < 0){    printk("request irq fail!!!\n");    return -EFAULT;}ret = request_irq(pdev->resource[1].start,key_handler,IRQF_TRIGGER_FALLING | IRQF_DISABLED,IRQ2_NAME,NULL);if (ret < 0){    printk(" request_irq fail!!!\n");    return -EFAULT;}//***********key_remove函数中*********//free_irq(pdev->resource[0].start,NULL);free_irq(pdev->resource[1].start,NULL);

方式三:再加消息队列和内核定时器

//************************head.h****************************//#define     IRQ1_NAME   "key2"#define     IRQ2_NAME   "key3"//struct tasklet_struct my_tasklet;struct work_struct my_wq;wait_queue_head_t wqt;static int flag;static int irq;struct timer_list my_timer;struct resource * res1;struct resource * res2;struct resource * res3;volatile unsigned int * gpx1dat;static int key;//************************key_probe函数****************************//init_waitqueue_head(&wqt);init_timer(&my_timer);my_timer.function = do_my_timer;my_timer.expires = jiffies + 40;add_timer(&my_timer);//  tasklet_init(&my_tasklet,do_tasklet_fun,0);INIT_WORK(&my_wq,work_func_t wq_do_work);res1 = platform_get_resource(pdev,IORESOURCE_IRQ,0);res2 = platform_get_resource(pdev,IORESOURCE_IRQ,1);res3 = platform_get_resource(pdev,IORESOURCE_MEM,0);ret = request_irq(res1->start,key_irq_handler,IRQF_TRIGGER_FALLING | IRQF_DISABLED,IRQ1_NAME,NULL);if(ret < 0){  printk("request_irq fail!\n");  return ret;}ret = request_irq(res2->start,key_irq_handler,IRQF_TRIGGER_FALLING | IRQF_DISABLED,IRQ2_NAME,NULL);if(ret < 0){  printk("request_irq fail!\n");  return ret;}gpx1dat = ioremap(res3->start,res3->end - res3->start);if(gpx1dat == NULL){  printk("ioremap fail!\n");  return ret;}//************************key_remove函数****************************//del_timer(&my_timer);iounmap(gpx1dat);free_irq(res1->start,NULL);free_irq(res2->start,NULL);//************************key_read函数****************************//ssize_t key_read (struct file * file, char __user * buf, size_t size, loff_t * loft){    int ret;    if(size < 0)    {        return-EFAULT;    }    if(size > sizeof(key))    {        size = sizeof(key);    }    wait_event_interruptible(wqt,flag == 1);    flag = 0;    ret = copy_to_user(buf,&key,size);    return size -ret;}//************************key_irq_handler函数****************************//irqreturn_t key_irq_handler(int num,void * dev){    irq = num;//  tasklet_schedule(&my_tasklet);    schedule_work(&my_wq);    return IRQ_HANDLED;}//************************wq_do_work函数****************************//void wq_do_work(struct work_struct *work){    mod_timer(&my_timer,jiffies + 40);}//************************do_my_timer函数****************************//void do_my_timer(unsigned long num){    if(res1->start == irq)    {        if(*gpx1dat & (0x1 << 1))        {            key = 2;            wake_up_interruptible(&wqt);            flag = 1;        }    }    if(res2->start == irq)    {        if(*gpx1dat & (0x1 << 2))        {            key = 3;            wake_up_interruptible(&wqt);            flag = 1;        }    }}

加中断顶半步

未完待续
0 0