static int key_event = 0; //唤醒中断的条件标记,1时满足唤醒条件,静态全局变量
static int key_value = 1; //按键键值
static DECLARE_WAIT_QUEUE_HEAD ( wq ); //调用宏定义,静态创建一个名为wq的等待队列
static void key_interrupt ( void ) //中断处理函数,注册中断时已注册了中断程序的入口地址
{
key_value = s3c2410_gpio_getpin ( key );
key_event = 1; //唤醒标记置位,表示条件达到,可以唤醒进程继续执行
wake_up_interruptible ( &wq ); //调用宏定义,唤醒标记置位后调用此函数,&wq是队列入口地址
}
static int key_read ( struct file *filp, char __user *buff, size_t count, loff_t *offp )
{
// wait_event_interruptible(wq,key_event); //若key_event为0,从此处将进程放入wq等待队列休眠,等待中断;key_event==1时,此宏不执行操作
//调用poll的时候来等待,这里可以不用wait_event_interrupt()
key_value = s3c2410_gpio_getpin ( key );
copy_to_user ( buff, &key_value, sizeof ( key_event ) ); //将&key_value地址的值从内核空间复制到用户空间
key_event = 0; //完成中断操作,将唤醒标记清零,继续休眠
return 0;
}
static unsigned int key_poll ( struct file *filp, poll_table *wait )
{
unsigned int mask = 0; //用来记录发生的事件,以unsigned int类型返回
poll_wait ( filp, &wq, wait ); //将当前进程添加到wq等待队列中
if ( key_event == 1 )
mask |= POLLIN | POLLRDNORM; //中断事件发生,这时有数据可读,在mask中标记是可读事件发生
return mask; //返回事件记录,返回0则表示等待事件超时
}
//设置寄存器,申请中断号等在open函数中完成
static int key_open ( struct inode *inode, struct file *filp )
{
int ret;
s3c2410_gpio_cfgpin ( key, key_cfg ); //设置引脚功能
s3c2410_gpio_pullup ( key, 1 ); //第二个参数1为禁止内部上拉
ret = request_irq ( key_irq, ( void * ) key_interrupt, SA_INTERRUPT, DEVICE_NAME, NULL ); //注册中断,中断不共享时最后一个参数为NULL
if ( ret )
{
printk ( "Could not register interrupt\n" );
return ret;
}
set_irq_type ( key_irq, IRQT_BOTHEDGE ); //设置中断方式为双边触发
return 0;
}
static int key_close ( struct inode *inode, struct file *filp )
{
free_irq ( key_irq, NULL ); //中断无共享时第二个参数为NULL
return 0;
}
static struct file_operations key_fops =
{
.owner = THIS_MODULE,
.open = key_open,
.release = key_close,
.read = key_read,
.poll = key_poll,
};
int key_init ( void )
{
int ret;
ret = alloc_chrdev_region ( &dev, DEVICE_MINOR, 1, DEVICE_NAME ); //采用主设备号动态分配
if ( ret < 0 )
{
printk ( "Register /dev/key failed!\n" );
return ret;
}
else
printk ( "Register /dev/key successfully!\n" );
major = MAJOR ( dev ); //取得分配到的主设备号
p_cdev = cdev_alloc(); //申请一个字符设备结构并返回指向它的指针
cdev_init ( p_cdev, &key_fops ); //相当于p_cdev->ops=&key_fops
p_cdev->owner = THIS_MODULE;
ret = cdev_add ( p_cdev, dev, 1 ); //向系统添加这个字符设备
if ( ret < 0 )
{
printk ( "Add cdev failed!\n" );
return ret;
}
devfs_mk_cdev ( dev, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEVICE_NAME );
return 0;
}
void key_exit ( void )
{
unregister_chrdev_region ( dev, 1 );
cdev_del ( p_cdev ); //删除字符设备
devfs_remove ( DEVICE_NAME );
printk ( "Device unregister!\n" );
}
MODULE_LICENSE ( "GPL" );
MODULE_AUTHOR ( "HJW" );
module_init ( key_init );
module_exit ( key_exit );