/*********************************************************************************************
*注册设备,创建设备节点
**********************************************************************************************/
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_NUM;i++)
key_devp->key_status[i]=KEYSTATUS_UP; //初始化键盘状态
for(i=0;i<KEY_NUM;i++)
key_devp->key_values[i]=0; //初始化键值
key_devp->key_values_flag=0; //表示四个按键都没有被按下
init_waitqueue_head(&key_devp->key_waitq);
for(i=0;i<KEY_NUM;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)); //删掉类
class_destroy(key_class); //注销类结构体
unregister_chrdev_region(MKDEV(keyboard_major,0),1); // 释放设备号
}
/* 这两行指定驱动程序的初始化函数和卸载函数 */
module_init(key_init);
module_exit(key_exit);
/* 描述驱动程序的一些信息,不是必须的 */
MODULE_AUTHOR("Ma Dongpeng<madongpeng@hrbeu.edu.cn>"); // 驱动程序的作者
MODULE_DESCRIPTION("keyborad Driver"); // 一些描述信息
MODULE_LICENSE("GPL"); // 遵循的协议
makefile文件:
CC = arm-linux-gcc
HOSTCC = gcc
#######################################################################
KERNELDIR = /opt/S3C2440/linux-2.6.25.9
#######################################################################
obj-m := keybord.o
#module-objs := keybord.o
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o
应用程序: