S3C44B0X键盘的uClinux驱动
2009-08-24 23:45
471 查看
最近几天在研究S3C44B0X键盘驱动,在网上搜了遍,只找到一篇(是千篇一律,不是只有一个搜索结果),都是讲把pc_keyb.c改造成合适的驱动,我业尝试过这个方法,开始是一头雾水(毕竟自己还是很菜),pc_keyb.c里面那么多函数,对linux上的中断驱动没有任何经验,最终放弃了这条路,我们正着走,光明一些。看了一些关于linux驱动的资料,再结合ARM手册上的说明,终于从正向实现了键盘的驱动,然后我再回过去看pc_keyb.c,下意识地就把它改好了,这个事实告诉我们要踏踏实实地,一步一个脚印向前走,要深厚内功。
下面是我自己写的驱动代码:
由于只有3个LED,所以第四个键没用到,不过原理是一样的
下面是我修改pc_keyb.c得到的键盘驱动,我把它重命名为44b0kbd.c
这里需要注意一个问题:
(*(volatile unsigned *)S3C44B0X_EXTINPND) |= 0xF;
(*(volatile unsigned *)S3C44B0X_INTPND) &= ~(1<<21); //clear interrupt request
(*(volatile unsigned *)S3C44B0X_I_ISPC) &= ~(1<<21);
---------------------------------------------
if((jiffies - jiffies_IRQ_21) < 100)
return IRQ_HANDLED;
上面用分隔线分开的两部分不能颠倒,当时我颠倒了,按了一次之后老是出错,系统输出:
IRQ LOCK: IRQ21 is locking the system, disabled
这个问题折腾了我好久,可能是我当时犯傻了,这样的逻辑都整理不好……
接着再把初始化函数写入driver/char文件夹下的mem.c里面,再做一些改动(前面我写的那篇《uClinux+S3C44B0X驱动编写总结》有详细的步骤),kbd驱动要使用用户程序来打开才能使用,44b0kbd就不用了(系统初始化时已经设置好中断),因此在make menuconfig的时候两个驱动不能同时选中,这样给调试带来了一些麻烦。
编译后放到板子上,两个驱动都正常工作。
下面是我自己写的驱动代码:
#include <linux/init.h> #include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/sched.h> #include <linux/types.h> #include <linux/interrupt.h> #include <asm/uaccess.h> #include <asm/arch/s3c44b0x.h> #define IO_IRQ_NUM 21 #define KBD_MAJOR 232 #define KBD_NAME "keyboard" ////////// global vars //////////// //static struct tasklet_struct keytask; long jiffies_IRQ_21; ////////////////// announce of key functions ///////////////////// static int kbd_open(struct inode *inode, struct file *filp); static int kbd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param); static int kbd_release(struct inode *inode, struct file *filp); void kbd_init(void); int kbd_cleanup(void); ///////////////// interrupt handler ///////////////// static irqreturn_t interrupt_handler_4567(int irq, void *dev_id, struct pt_regs *regs); struct file_operations fd_ops = { owner: THIS_MODULE, open: kbd_open, release: kbd_release, ioctl: kbd_ioctl, }; static int kbd_open(struct inode *inode, struct file *filp) { int ret; printk("Open kbd driver!/n"); //assign IRQ 21 ret = request_irq(IO_IRQ_NUM, interrupt_handler_4567, 0, "ih_4567", NULL); if(ret != 0) { printk("Can not assign IRQ!/n"); return -EAGAIN; } jiffies_IRQ_21 = jiffies; (*(volatile unsigned *)S3C44B0X_EXTINT) &= 0xFFFF; (*(volatile unsigned *)S3C44B0X_PCONG) |= 0xFF00; (*(volatile unsigned *)S3C44B0X_PUPG) |= 0x00; (*(volatile unsigned *)S3C44B0X_INTMOD) &= ~(1<<21); //irq mode (*(volatile unsigned *)S3C44B0X_INTCON) &= ~(2); //enable FIQ interrupt (*(volatile unsigned *)S3C44B0X_EXTINPND) |= 0xF; (*(volatile unsigned *)S3C44B0X_INTPND) &= ~(1<<21); //clear 21 interrupt request //config led registers (*(volatile unsigned *)S3C44B0X_PUPC) = 0x00; (*(volatile unsigned *)S3C44B0X_PCONC) &= 0xFFFFFF00; (*(volatile unsigned *)S3C44B0X_PCONC) |= 0x00000055; (*(volatile unsigned *)S3C44B0X_PDATC) &= 0xFFFFFF00; printk("EXTINTPND = %02X/n", (*(volatile unsigned *)S3C44B0X_EXTINPND)); MOD_INC_USE_COUNT; return 0; } static int kbd_release(struct inode *inode, struct file *filp) { printk("Release kbd driver!/n"); free_irq(IO_IRQ_NUM, NULL); MOD_DEC_USE_COUNT; return 0; } static int kbd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { printk("ioctl of kbd driver!/n"); } static irqreturn_t interrupt_handler_4567(int irq, void *dev_id, struct pt_regs *regs) { int wval, ibits; (*(volatile unsigned *)S3C44B0X_EXTINPND) |= 0xF; (*(volatile unsigned *)S3C44B0X_INTPND) &= ~(1<<21); //clear interrupt request (*(volatile unsigned *)S3C44B0X_I_ISPC) &= ~(1<<21); if((jiffies - jiffies_IRQ_21) < 100) return IRQ_HANDLED; wval = (*(volatile unsigned *)S3C44B0X_PDATC); ibits = ((*(volatile unsigned *)S3C44B0X_EXTINPND) << 1); ibits &= 0x0000000E; wval ^= ibits; (*(volatile unsigned *)S3C44B0X_PDATC) = wval; return IRQ_HANDLED; } /////////////////////// module initialization ///////////////////////////// void __init kbd_init(void) { int ret; ret = register_chrdev(KBD_MAJOR, KBD_NAME, &fd_ops); if(ret < 0) printk("Unable to use major: %d/n", KBD_MAJOR); else printk("Init keyboard driver OK!/n"); } int kbd_cleanup(void) { unregister_chrdev(KBD_MAJOR, KBD_NAME); return 0; } MODULE_AUTHOR("Cricket"); MODULE_LICENSE("GPL");
由于只有3个LED,所以第四个键没用到,不过原理是一样的
下面是我修改pc_keyb.c得到的键盘驱动,我把它重命名为44b0kbd.c
#include <linux/config.h> #include <linux/spinlock.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/mm.h> #include <linux/signal.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/random.h> #include <linux/poll.h> #include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/pm.h> #include <asm/arch/s3c44b0x.h> #include <asm/bitops.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/system.h> #include <asm/io.h> unsigned long prevjiffies; static unsigned char handle_kbd_event(void); static unsigned char handle_kbd_event(void) { (*(volatile unsigned *)S3C44B0X_EXTINPND) |= 0xF; (*(volatile unsigned *)S3C44B0X_INTPND) &= ~(1<<21); //先清除中断位 (*(volatile unsigned *)S3C44B0X_I_ISPC) &= ~(1<<21); //同上 if((jiffies - prejiffies) < 100) //100个周期内只响应一次按键 return 1; prevjiffies = jiffies; return 0; } static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) { printk("Cricket's keyboard, invoked ketboard_interrupt()/n"); handle_kbd_event(); } /******************** *** module init *** ********************/ void __init pckbd_init_hw(void) { int ret; ret = request_irq(21, keyboard_interrupt, 0, "keyboard", NULL); if(ret != 0) { printk("Can not assign IRQ 21!/n"); return; } (*(volatile unsigned *)S3C44B0X_INTPND) &= ~(1<<21); (*(volatile unsigned *)S3C44B0X_INTMOD) &= ~(1<<21); //IRQ模式,不能设为FIQ模式 (*(volatile unsigned *)S3C44B0X_INTCON) &= ~(2); //IRQ模式 (*(volatile unsigned *)S3C44B0X_EXTINT) |= 0xFFFF0000; //一个上升沿加一个下降沿出发 printk("Assign IRQ 21 successfully!/n"); }
这里需要注意一个问题:
(*(volatile unsigned *)S3C44B0X_EXTINPND) |= 0xF;
(*(volatile unsigned *)S3C44B0X_INTPND) &= ~(1<<21); //clear interrupt request
(*(volatile unsigned *)S3C44B0X_I_ISPC) &= ~(1<<21);
---------------------------------------------
if((jiffies - jiffies_IRQ_21) < 100)
return IRQ_HANDLED;
上面用分隔线分开的两部分不能颠倒,当时我颠倒了,按了一次之后老是出错,系统输出:
IRQ LOCK: IRQ21 is locking the system, disabled
这个问题折腾了我好久,可能是我当时犯傻了,这样的逻辑都整理不好……
接着再把初始化函数写入driver/char文件夹下的mem.c里面,再做一些改动(前面我写的那篇《uClinux+S3C44B0X驱动编写总结》有详细的步骤),kbd驱动要使用用户程序来打开才能使用,44b0kbd就不用了(系统初始化时已经设置好中断),因此在make menuconfig的时候两个驱动不能同时选中,这样给调试带来了一些麻烦。
编译后放到板子上,两个驱动都正常工作。
相关文章推荐
- S3C44B0X键盘的uClinux驱动程序设计
- S3C44B0X按键键盘的uClinux驱动程序设计
- S3C44B0X键盘的uClinux驱动程序设计
- S3C44B0X按键键盘的uClinux驱动程序设计
- 键盘过滤驱动
- 【原创】驱动中实现模拟键盘按键
- 键盘驱动系列---JIURL键盘驱动 2
- 基于stm32f429的uclinux-W5500网络设备内核驱动
- uClinux2.6(bf561)的NorFlash驱动实现分析(2): chips和maps
- 51单片机的4×4键盘识别与74LS164驱动数码显示
- 关于键盘过滤驱动中写入文件乱码的问题的解决!
- 初尝windows内核编程-键盘过滤驱动
- 模拟键盘 驱动
- 驱动usb鼠标产生键盘信息
- s5pv210-Linux驱动之USB键盘
- Qt键盘驱动处理类的实现:Qt键盘驱动处理类的实现,通过Qt的插件机制实现嵌入式开发中的自定义键盘处理。
- JIURL键盘驱动 2
- USB驱动——键盘,U盘
- 【驱动】USB驱动实例·串口驱动·键盘驱动
- 调试nios的uclinux驱动的两点经验总结