驱动案例三:platform按键驱动(二、驱动)

本文详细介绍了S3C24XX平台的按键驱动实现,包括注册中断、处理中断、读取键值等关键步骤,展示了如何为6个按键设置中断并进行响应处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

plat_buttondriver.c

#include <linux/module.h>

#include <linux/types.h>

#include <linux/miscdevice.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/platform_device.h>

#include <linux/interrupt.h>

#include <linux/clk.h>

#include <linux/uaccess.h>

#include <linux/io.h>

#include <mach/map.h>

#include <mach/regs-gpio.h>

#include <linux/poll.h>

#include <linux/irq.h>

#include <asm/unistd.h>

#include <linux/device.h>

 

#include <linux/sched.h>

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);   //定义和初始化等待队列

 

static volatile int ev_press = 0;

 

 

static int key_value;

static struct device     *buttons_dev; 

static struct resource *buttons_mem;

static struct resource   *buttons_irq;

static void __iomem     *buttons_base;

 

 

static int button_irqs[6];

 

static irqreturn_t buttons_interrupt(int irq, void *dev_id)

{

 int i;

 for(i=0; i<6; i++){

  if(irq == button_irqs[i]){

   //printk("==>interrput number:%d\n",irq); 

   key_value = i;

   ev_press =1;  //键值标志位置位,表示有键值可读

   wake_up_interruptible(&button_waitq);  //唤醒阻塞的进程  

  }

 }

 

    return IRQ_RETVAL(IRQ_HANDLED);

 

}

 

static int s3c24xx_buttons_open(struct inode *inode, struct file *file)

{

 int i;

 int err = 0;

 

 for(i=0; i<6; i++)

 {

  if (button_irqs[i] < 0)

   continue;       

    

         err = request_irq(button_irqs[i],buttons_interrupt,IRQ_TYPE_EDGE_RISING,NULL,NULL);   //注册6个中断

  if(err)

    break;

 }

 

 if (err) {  //注册失败,关闭中断,释放中断

  i--;

  for (; i >= 0; i--) {

   if (button_irqs[i] < 0) {

    continue;

   }

   disable_irq(button_irqs[i]);

   free_irq(button_irqs[i], NULL);

  }

  return -EBUSY;

 }

 

    ev_press = 0;   //键值标志位清零,表示无键值可读 

    return 0;

}

 

static int s3c24xx_buttons_close(struct inode *inode, struct file *file)

{

    int i;   

    for (i=0; i<6; i++) {  //释放6个中断

   if (button_irqs[i] < 0) {

    continue;

   }

   free_irq(button_irqs[i],NULL);

    }

    return 0;

}

 

static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

{

    unsigned long err;

    if (!ev_press) {   //判断如果没有键值可读

  if (filp->f_flags & O_NONBLOCK)   //如果文件属性为 O_NONBLOCK

   return -EAGAIN;//立即返回

  else

   wait_event_interruptible(button_waitq, ev_press);   //否则阻塞进程

    }   

    ev_press = 0;   //键值标志位清零,表示无键值可读

    err = copy_to_user(buff, &key_value, sizeof(key_value));   //将 key_value 的值复制到 buff

    return sizeof(key_value);   //返回 返回值长度

}

 

static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)

{

    unsigned int mask = 0;

    poll_wait(file, &button_waitq, wait);   //将等待队列加入到poll_table中

    if (ev_press){   //如果有键值可读,置位掩码可读位,结束sellect函数阻塞状态

        mask |= POLLIN | POLLRDNORM;

 }

    return mask;

}

 

 

 

static struct file_operations mini2440buttons_fops = {   //混杂设备操作定义

    .owner   =   THIS_MODULE,

    .open    =   s3c24xx_buttons_open,  //定义混杂设备打开操作函数名 s3c24xx_buttons_open

 .release =   s3c24xx_buttons_close,  //定义混杂设备关闭操作函数名 s3c24xx_buttons_close

    .read    =   s3c24xx_buttons_read,  //定义混杂设备读取操作函数名 s3c24xx_buttons_read

 .poll    =   s3c24xx_buttons_poll,  //定义混杂设备监控操作函数名 s3c24xx_buttons_poll

};

 

static struct miscdevice mini2440_miscdev = {  //定义 mini2440_miscdev 混杂设备

 

    .minor = MISC_DYNAMIC_MINOR,  //混杂设备次设备号系统分配

    .name ="buttonstest",  //混杂设备名为 buttonstest

    .fops = &mini2440buttons_fops,  //混杂设备操作命名为 mini2440buttons_fops

};

 

/* device interface */

static int mini2440_buttons_probe(struct platform_device *pdev)

{

 struct resource *res;

 struct device *dev;

 int ret;

 int size;

 int i;

 

 printk("probe:%s\n", __func__);

 dev = &pdev->dev;

 buttons_dev = &pdev->dev;

 

 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);   //获取 mini2440buttons 设备的内存单元资源

 if (res == NULL) {

  dev_err(dev, "no memory resource specified\n");

  return -ENOENT;

 }

 

 size = (res->end - res->start) + 1;   //计算内存单元大小

 buttons_mem = request_mem_region(res->start, size, pdev->name);   //申请I/O内存

 

 if (buttons_mem == NULL) {

  dev_err(dev, "failed to get memory region\n");

  ret = -ENOENT;

  goto err_req;

 }

 

 buttons_base = ioremap(res->start, size);   //映射I/O内存

 if (buttons_base == NULL) {

  dev_err(dev, "failed to ioremap() region\n");

  ret = -EINVAL;

  goto err_req;

 }

 printk(KERN_DEBUG"probe: mapped buttons_base=%p\n", buttons_base);   //打印I/O内存映射的虚拟地址

 

   for(i=0; i<6; i++)   //获取 mini2440buttons 设备的中断资源

 {

 

  buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i);

 

  if(buttons_irq == NULL)

  {

      dev_err(dev,"no irq resource specified\n");

    ret = -ENOENT;

   goto err_map;

  }

 button_irqs[i] = buttons_irq->start;   //将button_irqs[]赋值

 

 //printk("button_irqs[%d]=%d\n",i,button_irqs[i]); 

 }

 

 ret = misc_register(&mini2440_miscdev);    //注册 mini2440_miscdev 混杂设备

  

 return 0;

 

 err_map:

 iounmap(buttons_base);

 

 err_req:

 release_resource(buttons_mem);

 kfree(buttons_mem);

 

 return ret;

}

 

static int mini2440_buttons_remove(struct platform_device *dev)   //在卸载平台设备时调用

{

 release_resource(buttons_mem);   //释放 struct resource buttons_mem

 kfree(buttons_mem);   //释放 struct resource *buttons_mem 占用到内存单元

 buttons_mem = NULL;   //清空指针

 

 iounmap(buttons_base);   //释放I/O内存

 misc_deregister(&mini2440_miscdev);   //注销混杂设备驱动

 return 0;

}

 

static struct platform_driver mini2440buttons_driver = {   //定义平台驱动 mini2440buttons_driver

 .probe  = mini2440_buttons_probe,   //定义probe函数名,在平台驱动和平台设备匹配时调用

 .remove  = mini2440_buttons_remove,   //定义remove函数名,在卸载平台设备时调用

 .driver  = {

  .owner = THIS_MODULE,

  .name = "mini2440buttons",   //定义平台驱动名,和 plat_device 中的设备名对应

 },

};

 

static char banner[] __initdata =

  "Mini2440 Buttons Driver\n";

 

static int __init buttons_init(void)

{

 printk(banner);

 platform_driver_register(&mini2440buttons_driver);   //注册平台驱动 mini2440buttons_driver

 return 0;

}

 

static void __exit buttons_exit(void)

{

 platform_driver_unregister(&mini2440buttons_driver);   //注销平台驱动 mini2440buttons_driver

}

 

module_init(buttons_init);

module_exit(buttons_exit);

 

MODULE_LICENSE("GPL");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值