总结:int与char的混用导致错误(copy_to_user())。。。。。。。。。。。。。。。
#include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/gpio.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/irq.h> #include <linux/interrupt.h> #include <asm/uaccess.h> //#include <asm/arch/regs-gpio.h> //#include <asm/hardware.h> #include <linux/device.h> #include <linux/poll.h> #define DEVICE_NAME "EmbedSky-buttons" #define BUTTON_MAJOR 232 struct button_irq_desc { int irq; int pin; int pin_setting; int number; char *name; }; static struct button_irq_desc button_irqs [] = { {IRQ_EINT1, S3C2410_GPF1,S3C2410_GPF1_EINT1,0, "KEY1"}, {IRQ_EINT4, S3C2410_GPF4,S3C2410_GPF4_EINT4,1, "KEY2"}, {IRQ_EINT2, S3C2410_GPF2,S3C2410_GPF2_EINT2,2, "KEY3"}, {IRQ_EINT0, S3C2410_GPF0,S3C2410_GPF0_EINT0,3, "KEY4"}, }; static volatile int key_values[] = {'0', '0', '0', '0'};
/* 等待队列: * 当没有按键被按下时,如果有进程调用 EmbedSky_buttons_read 函数, * 它将休眠 */ static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
/* 中断事件标志, 中断服务程序将它置 1,EmbedSky_buttons_read 将它清 0 */ static volatile int ev_press = 0; static irqreturn_t buttons_interrupt(int irq, void *dev_id) { struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id; printk("come in %d",button_irqs->number); key_values[button_irqs->number] ='1'; ev_press = 1; /* 表示中断发生了 */ wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ return IRQ_RETVAL(IRQ_HANDLED); } static int EmbedSky_buttons_open(struct inode *inode, struct file *file) { int i; int err; 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]); if (err) break; } if (err) { // 释放已经注册的中断 i--; 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 int EmbedSky_buttons_close(struct inode *inode, struct file *file) { int i; 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; } static int EmbedSky_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) { int ii; unsigned long err; /* 如果 ev_press 等于 0,休眠 */ wait_event_interruptible(button_waitq, ev_press); /* 执行到这里时,ev_press 等于 1,将它清 0 */ ev_press = 0; /* 将按键状态复制给用户,并清 0 */ for(ii=0;ii<4;ii++) { printk("%c",key_values[ii]); printk("\n");} err = copy_to_user(buff, key_values, min(sizeof(key_values), count)); memset((void *)key_values, '0', sizeof(key_values)); return err ? -EFAULT : min(sizeof(key_values), count); } /************************************************** * 当用户程序调用 select 函数时,本函数被调用 * 如果有按键数据,则 select 函数会立刻返回 * 如果没有按键数据,本函数使用 poll_wait 等待 **************************************************/ static unsigned int EmbedSky_buttons_poll( struct file *file, struct poll_table_struct *wait) { unsigned int mask = 0; poll_wait(file, &button_waitq, wait); if (ev_press) mask |= POLLIN | POLLRDNORM; return mask; }
static struct file_operations EmbedSky_buttons_fops = { .owner=THIS_MODULE, .open = EmbedSky_buttons_open, .release = EmbedSky_buttons_close, .read = EmbedSky_buttons_read, .poll = EmbedSky_buttons_poll, }; static char __initdata banner[] = "TQ2440/SKY2440 LEDS, (c) 2008,2009 www.embedsky.net\n"; static struct class *button_class; static int __init EmbedSky_buttons_init(void) { int ret; printk(banner); ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &EmbedSky_buttons_fops); if (ret < 0) { printk(DEVICE_NAME " can't register major number\n"); return ret; }
button_class = class_create(THIS_MODULE, DEVICE_NAME); if(IS_ERR(button_class)) { printk("Err: failed in EmbedSky-leds class. \n"); return -1; } device_create(button_class, NULL, MKDEV(BUTTON_MAJOR, 0), NULL, DEVICE_NAME); printk(DEVICE_NAME " initialized\n"); return 0; } static void __exit EmbedSky_buttons_exit(void) { unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME); device_destroy(button_class, MKDEV(BUTTON_MAJOR, 0)); class_destroy(button_class); } module_init(EmbedSky_buttons_init); module_exit(EmbedSky_buttons_exit); MODULE_AUTHOR("http://www.embedsky.net"); MODULE_DESCRIPTION("TQ2440/SKY2440 LED Driver"); MODULE_LICENSE("GPL");
对应应用程序。。。。。。。。。。。。。。。。
#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 i; int buttons_fd; int key_value_temp[4];
/*打开键盘设备文件*/ buttons_fd = open("/dev/EmbedSky-buttons", 0); if (buttons_fd < 0) { perror("open device buttons"); exit(1); }
for (;;) {
int ret;
/*开始读取键盘驱动发出的数据,注意key_value和键盘驱动中定义为一致的类型*/ ret = read(buttons_fd, key_value_temp, sizeof(key_value_temp)); printf("hello\n"); for(i=0;i<4;i++) {printf("%c",key_value_temp[i]);} printf("\n"); for(i=0;i<4;i++) {key_value_temp[i]='0';} }
/*关闭设备文件句柄*/ close(buttons_fd); return 0; }