Linuxwilliam hill官网
直播中

tqsales05

10年用户 104经验值
擅长:嵌入式技术
私信 关注
[经验]

tq2440 按键驱动 中断方式(转)

  硬件平台:TQ2440
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #define DEVICE_NAME "key-device"
  MODULE_DESCRIPtiON("759981398@qq.com");
  MODULE_AUTHOR("traveler");
  MODULE_LICENSE("Dual BSD/GPL");
  //声明一个等待队列
  static DECLARE_WAIT_QUEUE_HEAD(keys_wait_irq) ;
  //事件 用于同步用户与驱动程序之间的数据
  static volatile int key_event = 0;
  //存储按键的值
  static volatile int key_value = 0;
  static void * key_devid = (void *)0;
  //ISR中断服务程序
  static irqreturn_t keys_irq(int irq,void *devid)
  {
  int down ;
  //GPIO的 基址 虚拟地址
  //对 GPIO的所有操作 都以此地址 作为 参考 地址
  const unsigned int gpio_base = (unsigned int )S3C24XX_VA_GPIO;
  //获取 GPFDAT寄存器 的 虚拟地址
  const unsigned int gpfdat = gpio_base + 16 * 5 + 4;
  if(devid!=key_devid)
  {
  printk("<1>DRIVER ERROR !devid=%dn",(int)devid);
  return IRQ_RETVAL(IRQ_NONE);
  }
  //获取按键引脚状态
  down = (*(unsigned int *)gpfdat) ;
  //如果当前值和存储的值不相等 则唤醒等待队列
  // if((down &0x01) != (key_value&0x01))
  {
  key_value = down & 0x01;
  key_event = 1;
  wake_up_interruptible(&keys_wait_irq);
  }
  //返回标志 中断已服务
  return IRQ_RETVAL(IRQ_HANDLED);
  }
  //读取 按键 状态 用户 调用 参数 列表
  static ssize_t key_read(struct file *filp,char __user *buf,
  size_t count,loff_t *loff)
  {
  int err;
  if(!key_event)
  {
  //如果事件未发生并且文件不允许阻塞,那么返回一个错误标识
  if(filp->f_flags & O_NONBLOCK)
  return -EAGAIN ;
  //等待事件
  wait_event_interruptible(keys_wait_irq,key_event);
  }
  //拷贝数据到用户空间
  err = copy_to_user(buf,(void *)(&key_value),min(sizeof(key_value),count));
  //已经读取了数据,重设事件标志
  key_event = 0;
  //返回拷贝到的数据长度
  return err ? -EFAULT : min(sizeof(key_value),count) ;
  };
  static int key_open(struct inode *inode,struct file *filp)
  {
  int err;
  //GPIO的 基址 虚拟地址
  //对 GPIO的所有操作 都以此地址 作为 参考 地址
  const unsigned int gpio_base = (unsigned int )S3C24XX_VA_GPIO;
  //获取 GPFCON的 地址
  const unsigned int gpfcon = gpio_base + 16 * 5;
  //获取 GPFDAT的 地址
  unsigned int gpfup = gpfcon + 2*4;
  //注册irq函数
  err = request_irq(IRQ_EINT0,keys_irq,IRQ_TYPE_EDGE_BOTH,
  "key0",key_devid);
  if(err)
  return -EBUSY;
  //设置事件标志
  key_event = 1;
  //配置 GPF0 端口 为EINT0
  (*(unsigned int *)gpfcon) &= ~(0x03);
  (*(unsigned int *)gpfcon) |= 0x02;
  //禁止 内部 上拉 电阻
  (*(unsigned int *)gpfup) |= 0x01;
  return 0;
  }
  static int key_release(struct inode *inode,struct file *filp)
  {
  //禁止中断
  disable_irq(IRQ_EINT0);
  //释放中断
  free_irq(IRQ_EINT0,key_devid);
  return 0;
  }
  static struct file_operations key_fops =
  {
  .owner= THIS_MODULE,
  .open = key_open,
  .read = key_read,
  .release = key_release,
  };
  static struct miscdevice key_misc=
  {
  .minor = MISC_DYNAMIC_MINOR,
  .name = DEVICE_NAME,
  .fops = &key_fops,
  };
  static int key_init_module(void)
  {
  int ret ;
  //注册 杂项 设备
  ret = misc_register(&key_misc);
  printk("<1>Module key init,major:10,minor:%dn",key_misc.minor );
  return 0;
  }
  static void key_exit_module(void)
  {
  //注销 杂项设备
  misc_deregister(&key_misc);
  printk("<1>Module key exitn" );
  }
  module_init(key_init_module);
  module_exit(key_exit_module);

更多回帖

发帖
×
20
完善资料,
赚取积分