/*mini2440_buttons_my.c*/ /*按键驱动程序*/ /*mini2440所用到的按键资源*/ /*要搞清楚谁是输入*/ /*如何得知一个设备究竟用到哪些资源呢?*/ /*引用的头文件*/ #include <linux/module.h> /*模块有关的*/ #include <linux/kernel.h> /*内核有关的*/ #include <linux/fs.h> /*文件系统有关的*/ #include <linux/init.h> /*init*/ #include <linux/delay.h> /*delay*/ #include <linux/poll.h> /*poll*/ #include <asm/irq.h> /*中断*/ #include <linux/interrupt.h> /*linux中断*/ #include <asm/uaccess.h> /*uaccess*/ #include <asm/arch/regs-gpio.h> /*寄存器设置*/ #include <asm/hardware.h> /*hardware*/ /*定义宏*/ #define BUTTON_MAJOR 221 /*主设备号,本来是232,我改为221*/ #define DEVICE_NAME "buttons_my" /*设备名,本来是buttons,我加上了_my*/ /*定义按钮中断的描述结构体*/ struct button_irq_desc int pin; /*中断控制的寄存器*/ int pin_setting; /*中断的引脚*/ int number; /*编号*/ /*指定6个按键的信息*/ static struct button_irq_desc button_irqs [] = /*这样,资源就组织起来了*/
static volatile int key_values [] = {0,0,0,0,0,0};
static volatile int ev_press = 0; /*初始为0*/ /*中断服务程序buttons_interrupt()的申明*/ /*参数irq---中断号*/ static irqreturn_t buttons_interrupt(int irq,void *dev_id); /*mini2440_buttons_open()函数申明*/ static int mini2440_buttons_open(struct inode *inode,struct file *file); /*mini2440_buttons_close()函数的申明*/ static int mini2440_buttons_close(struct inode *inode,struct file *file); /*mini2440_buttons_read()函数的申明*/ static int mini2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp); /*mini2440_buttons_poll()函数的申明*/ static unsigned int mini2440_buttons_poll(struct file *file,struct poll_table_struct *wait);
static struct file_operations mini2440_buttons_fops = .open = mini2440_buttons_open, /*open()*/ .release = mini2440_buttons_close, /*release()*/ .read = mini2440_buttons_read, /*read()*/ .poll = mini2440_buttons_poll /*poll()*/ /*mini2440_buttons_init()函数的申明*/ static int __init mini2440_buttons_init(void); /*mini2440_buttons_exit()函数的申明*/ static void __exit mini2440_buttons_exit(void); /*模块创建时的入口点*/ module_init(mini2440_buttons_init);
module_exit(mini2440_buttons_exit); /*驱动程序的一些信息*/ MODULE_AUTHOR("http://www.arm9.net"); /*驱动程序的作者*/ MODULE_DESCRIPTION("S3C2410/S3C2440 BUTTON Driver"); /*描述信息*/ MODULE_LICENSE("GPL"); /*遵循的协议*/ /********************************************************************/
static int __init mini2440_buttons_init(void) /*注册设备驱动程序*/ ret = register_chrdev(BUTTON_MAJOR,DEVICE_NAME,&mini2440_buttons_fops); /*对注册失败的处理*/ if(ret < 0) /*创建设备*/ devfs_mk_cdev(MKDEV(BUTTON_MAJOR,0),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME); printk(DEVICE_NAME " initialized\n"); return 0;
static void __exit mini2440_buttons_exit(void) devfs_remove(DEVICE_NAME); /*注消设备驱动*/ unregister_chrdev(BUTTON_MAJOR,DEVICE_NAME);
static int mini2440_buttons_open(struct inode *inode,struct file *file) int err; /*中断注册函数的返回值*/ /*对每个按钮分别处理,用for循环来做*/ for(i = 0;i < sizeof(button_irqs)/sizeof(button_irqs[0]);i++) s3c2410_gpio_cfgpin(button_irqs[i].pin,button_irqs[i].pin_setting); /*中断的注册*/ err = request_irq(button_irqs[i].irq,buttons_interrupt,NULL,button_irqs[i].name,(void *)&button_irqs[i]); /*中断类型的设置*/ /*有几个非常重要的问题*/ set_irq_type(button_irqs[i].irq,IRQT_BOTHEDGE); /*注册失败的处理*/ if(err) /*若有一个按钮中断注册失败*/ if(err) for(;i >=0; i--) /*依此拆除*/ disable_irq(button_irqs[i].irq); /*释放中断资源*/ free_irq(button_irqs[i].irq,(void *)&button_irqs[i]); return -EBUSY; /*中断注册没成功的最终的返回值*/ return 0; /*正常返回*/
static irqreturn_t buttons_interrupt(int irq,void *dev_id) struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id; /*获取寄存器的值*/ /*要注意,按一下按钮,会发生两次中断*/ /*即按下是一次中断,放开又是一次中断*/ int up = s3c2410_gpio_getpin(button_irqs->pin); /*通过电路原理图,可以知道没按下的时候,中断引脚应该是高电平*/ /*下面对up的值进行处理*/ if(up) /*如果是弹起的状态*/ key_values[button_irqs->number] = (button_irqs->number + 1) + 0x80; else /*如果按键是闭合的状态*/ key_values[button_irqs->number] = (button_irqs->number + 1); /*对数组可读标志位进行设置*/ ev_press = 1; /*表示数组已经可读了*/ /*唤醒休眠的进程?*/ wake_up_interruptible(&button_waitq); /*返回*/ return IRQ_RETVAL(IRQ_HANDLED); /*?*/ /**********************mini2440_buttons_close()*****************************/ static int mini2440_buttons_close(struct inode *inode,struct file *file) /*for循环,对各个按键依此释放中断*/ for(i = 0;i < sizeof(button_irqs)/sizeof(button_irqs[0]);i++) disable_irq(button_irqs[i].irq); /*释放资源*/ free_irq(button_irqs[i].irq,(void *)&button_irqs[i]); /*返回*/ return 0;
/*要注意,该read函数,只读取一次中断的值,而不是连续地读入*/ static int mini2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp) /*如果key_values 数组里没有值,则会此进程会休眠*/ /*进程等待队列的机制,是进程调度的一种方法*/ if(!ev_press) /*标志位为0,即无数据时*/ /*下面就是标志位为1,即有数据可读的的处理情况*/ /*那就开始往用户空间读数据呗*/ err = copy_to_user(buff,(const void *)key_values,min(sizeof(key_values),count)); /*对key_values数组清零*/ memset((void *)key_values,0,sizeof(key_values)); /*对标志位置0*/ ev_press = 0; /*对err的处理*/ if(err) /*读取错误*/ /************************mini2440_buttons_poll()***********************/ static unsigned int mini2440_buttons_poll(struct file *file,struct poll_table_struct *wait) /*poll_wait()函数*/ poll_wait(file,&button_waitq,wait); if(ev_press) return mask;
==================================================================================
下面是测试代码:
/*按键测试程序*/ #include <stdio.h> /*标准输入输出头文件*/ #include <stdlib.h> /*标准库*/ #include <unistd.h> /*一些宏的定义在这里*/ #include <sys/ioctl.h> /*设备的控制*/ #include <sys/types.h> /*定义了一些类型*/ #include <sys/stat.h> /*状态*/ #include <fcntl.h> /*文件控制*/ #include <sys/select.h> /*选择?*/ #include <sys/time.h> /*时间方面的函数*/ #include <errno.h> /*有关错误方面的宏*/ /*主函数入口*/ int main(void) int buttons_fd; /*buttons设备号*/ int key_value[4]; /*四个按键的取值*/ /*打开键盘设备文件*/ buttons_fd = open("/dev/buttons",0); /*以0方式打开*/ /*打开出错处理*/ if(buttons_fd < 0) /*打开出错就会返回一个负值*/ exit(1); /*返回1*/ /*for无限循环,等待用户输入*/ for(;;) int ret; /*for循环内定义的局部变量ret*/ FD_ZERO(&rds); /*rds初始化*/ FD_SET(buttons_fd,&rds); /*将buttons设备号赋给rds*/ /*使用系统调用select检查是否能够从/dev/buttons设备读取数据*/ ret = select(buttons_fd + 1,&rds,NULL,NULL,NULL); /*对ret的处理*/ if(ret < 0) /*当ret小于0*/ if(ret == 0) /*当ret等于0*/ int ret = read(buttons_fd,key_value,sizeof(key_value)); /*注意此处的ret和前面的ret有何不同*/ /*对ret的处理*/ /*关闭设备*/ close(buttons_fd); return 0; /*主函数返回*/ END!! |
转:一个相当详细的MINI2440按键驱动详解
最新推荐文章于 2019-10-11 12:58:03 发布
|