S3C2440独立键盘Linux设备驱动(2)

/*******************************************************************************************
*应用程序对设备文件/dev/keyboard执行open(...)时,
* 就会调用key_open函数
 ********************************************************************************************/
static int key_open(struct inode *inode, struct file *file)
{
 int i;
 int err;

for (i = 0; i < KEY_NUM; i++)
 {
  set_irq_type(key_irqs[i].irq,IRQF_TRIGGER_LOW);
  //set_external_irq(key_irqs[i].irq,EXT_LOWLEVEL,GPIO_PULLUP_DIS);
  //将对应的引脚设置成中断功能
  s3c2410_gpio_cfgpin(key_irqs[i].pin,key_irqs[i].pin_setting);
  // 申请中断,注册中断处理函数
  err = request_irq(key_irqs[i].irq, key_interrupt, NULL,
   key_irqs[i].name, (void *)&key_irqs[i]);   //将&key_irqs[i]作为参数传入中断处理程序
  if (err)
   break;
 }

if (err)
 {
  // 释放已经注册的中断
  i--;
  for (; i >= 0; i--)
  {
   disable_irq(key_irqs[i].irq);
   free_irq(key_irqs[i].irq, (void *)&key_irqs[i]);
  }
  return -EBUSY;
 }

return 0;
}

/********************************************************************************************
* 应用程序对设备文件/dev/keyboard执行close(...)时,
* 就会调用key_close函数
*********************************************************************************************/
static int key_close(struct inode *inode, struct file *file)
{
 int i;

for (i = 0; i < KEY_NUM; i++)
 {
  // 释放已经注册的中断
  disable_irq(key_irqs[i].irq);
  free_irq(key_irqs[i].irq, (void *)&key_irqs[i]);
 }

return 0;
}


/********************************************************************************************
*应用程序对设备文件/dev/keyboard执行read(...)时,
* 就会调用key_read函数
*********************************************************************************************/
static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
 unsigned long err;
 retry:if(key_devp->key_values_flag==1)
 {
  /* 将按键状态复制给用户,并清0 */
  //printk(KERN_ALERT "key value:%d %d %d %d\n",key_devp->key_values[0],key_devp->key_values[1],key_devp->key_values[2],key_devp->key_values[3]);
  err = copy_to_user(buff, (const void *)key_devp->key_values, min(KEY_NUM, count));
  memset((void *)key_devp->key_values, 0, min(KEY_NUM, count));
  key_devp->key_values_flag=0;
 }
 else
 {
  if (filp->f_flags & O_NONBLOCK)
   return -EAGAIN;
  else
  {
   /* 如果key_values_flag等于0,休眠 */
   wait_event_interruptible(key_devp->key_waitq, key_devp->key_values_flag);
   goto retry;
  }
 }
 return err ? -EFAULT : min(KEY_NUM, count);
}

/********************************************************************************************
* 轮询函数判断是否能非阻塞的读取或写入
* 当用户程序调用select函数时,本函数被调用
* 如果有按键数据,则select函数会立刻返回
* 如果没有按键数据,本函数使用poll_wait等待
********************************************************************************************/
static unsigned int key_poll( struct file *file, struct poll_table_struct *wait)
{
 unsigned int mask = 0;
 poll_wait(file, &(key_devp->key_waitq), wait);   // 此处将当前进程加入到等待队列中,但并不阻塞
 if (key_devp->key_values_flag)
  mask |= POLLIN | POLLRDNORM;
 return mask;
}

/*********************************************************************************************
*这个结构是字符设备驱动程序的核心
* 当应用程序操作设备文件时所调用的open、read、write等函数,
* 最终会调用这个结构中的对应函数
*********************************************************************************************/
static struct file_operations key_fops =
{
 .owner  = THIS_MODULE,  /* 这是一个宏,指向编译模块时自动创建的__this_module变量 */
 .open  = key_open,
 .release  = key_close,
 .read  = key_read,
 .poll   = key_poll,
};

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwsyxy.html