天嵌科技的个人空间 https://bbs.21ic.com/?948798 [收藏] [复制] [RSS]

日志

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

已有 303 次阅读2016-1-18 15:14 |个人分类:技术文章|系统分类:嵌入式系统| 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);


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)