tq), 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,
};
/*********************************************************************************************
*注册设备,创建设备节点
**********************************************************************************************/
static int key_setup_cdev(struct key_dev *dev,int index)
{
int err;
int devno = MKDEV(KEYBOARD_MAJOR,index);
cdev_init(&dev->cdev,&key_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &key_fops;
err = cdev_add(&dev->cdev,devno,1); //向系统注册设备
if(err) printk(KERN_ALERT "Error %d adding key %d",err,index);
//注册一个类,使mdev可以在"/dev/"目录下面建立设备节点
key_class = class_create(THIS_MODULE, DEVICE_NAME);
if(IS_ERR(key_class))
{
printk("Err: failed in led class. \n");
return -1;
}
//创建一个设备节点,节点名为DEVICE_NAME
class_device_create(key_class, NULL, MKDEV(keyboard_major, 0), NULL, DEVICE_NAME);
return 0;
}
/*********************************************************************************************
* 执行“insmod key.ko”命令时就会调用这个函数
*********************************************************************************************/
static int __init key_init(void)
{
int ret,i;
printk(info);
/* 注册字符设备驱动程序
* 参数为主设备号、设备名字、file_operations结构;
* 这样,主设备号就和具体的file_operations结构联系起来了,
* 操作主设备为BUTTON_MAJOR的设备文件时,就会调用key_fops中的相关成员函数
* keyboard_major可以设为0,表示由内核自动分配主设备号
*/
dev_t devno = MKDEV(keyboard_major,0);
if(keyboard_major) ret=register_chrdev_region(devno,1,DEVICE_NAME); //注册主设备号
else //申请主设备号
{
ret = alloc_chrdev_region(devno,0,1,DEVICE_NAME);
keyboard_major = MAJOR(devno);
}
if(ret<0) return ret;
key_devp = kmalloc(sizeof(struct key_dev),GFP_KERNEL); // 动态申请设备结构体的内存
if(!key_devp)
{
ret = -ENOMEM;
goto fail_malloc;
}
memset(key_devp,0,sizeof(struct key_dev));
key_setup_cdev(key_devp,0);
for(i=0;i key_devp->key_status[i]=KEYSTATUS_UP; //初始化键盘状态
for(i=0;i key_devp->key_values[i]=0; //初始化键值
key_devp->key_values_flag=0; //表示四个按键都没有被按下
init_waitqueue_head(&key_devp->key_waitq);
for(i=0;i setup_timer(&key_timer[i],key_timer_handler,(void *)&key_irqs[i]); //将&key_irqs[i]作为参数传入定时器中断处理程序
return 0;
fail_malloc: unregister_chrdev_region(devno,1);
return ret;
}
/***********************************************************************************************
* 执行”rmmod key.ko”命令时就会调用这个函数
************************************************************************************************/
static void __exit key_exit(void)
{
/* 卸载驱动程序 */
printk(KERN_ALERT "******************unregister keyboard driver*************************\n");
cdev_del(&key_devp->cdev); //注消cdev
kfree(key_devp);
class_device_destroy(key_class, MKDEV(keyboard_major, 0)); /