红联Linux门户
Linux帮助

我编的字符按键驱动不知道哪里出错了,测试没有反应,大家帮帮忙啊

发布时间:2012-09-04 15:23:55来源:红联作者:hangyixiao
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include


#define DEVICE_NAME "buttondev"
#define BUTTONDEV_NR_DEVS 1
#define BUTTON_MAJOR 0

const char *button_dev;
struct cdev cdev;
static button_major = BUTTON_MAJOR;
static volatile int ev_press = 0; /* 中断事件标志, 中断服务程序将它置1,buttons_read将它清0 */
static struct class *button_class;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);//初始化等待队列



/* 定义含中断,管脚,管脚设置等信息的结构体 */
struct button_irq_desc
{
int irq;
int pin;
int pin_setting;
int number;
char *name;
};

static int key_values=0;


/* 用来指定按键所用的外部中断引脚及中断触发方式, 名字 */
static struct button_irq_desc button_irqs [] =
{
{IRQ_EINT1, S3C2410_GPF1, S3C2410_GPF1_EINT1, 0, "KEY1"}, /* K1 */
{IRQ_EINT4, S3C2410_GPF4, S3C2410_GPF4_EINT4, 1, "KEY2"}, /* K2 */
{IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_EINT2, 2, "KEY3"}, /* K3 */
{IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, 3, "KEY4"}, /* K4 */
};



/* 中断处理函数*/
static irqreturn_t button_interrupt(int irq, void *dev_id)
{

struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
int down;
// udelay(0);

/*上升沿触发,GPIO DAT 应该为非0 的数*/
down = !s3c2410_gpio_getpin(button_irqs->pin);
if (!down) {
//printk("rising\n");
key_values = button_irqs->number;
ev_press = 1;
wake_up_interruptible(&button_waitq);
}
else {
//printk("falling\n");
ev_press = 0;
return 0;
}
return IRQ_RETVAL(IRQ_HANDLED);
}


/*文件打开函数*/
static int button_open(struct inode *inode, struct file *filp)
{
int i;
int err=0;
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, button_interrupt,IRQ_TYPE_EDGE_RISING, button_irqs[i].name, (void *)&button_irqs[i]);
if (err)
// printf("request irq error");
break;
}

if (err) {
i--;
for (; i >= 0; i--) {
if (button_irqs[i].irq < 0)
continue;

disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
}
return -EBUSY;
}
ev_press = 0;
return 0;

}

/*读文件在驱动中的实现*/
static int button_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
unsigned long err;

if (!ev_press)
{
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
else
/* 如果ev_press等于0,休眠 */
wait_event_interruptible(button_waitq, ev_press);
}

ev_press = 0;

/* 把按键值的信息从内核空间复制到用户空间*/
err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));
memset((void *)key_values, 0, sizeof(key_values));//清零键值,以便下一次中断

return err ? -EFAULT : min(sizeof(key_values), count);
}


/* 被上层应用程序调用的select函数在驱动程序里的实现*/
static unsigned int button_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;
}


/* 被上层应用程序调用的ioctl函数在驱动程序里的实现*/
/*static int button_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
if (arg > 4)
{
return -EINVAL;
}
switch(cmd) {
case IOCTL_LED_ON: //如果是点亮
s3c2410_gpio_setpin(led_table[arg], 0);//点亮相应的管脚
return 0;
case IOCTL_LED_OFF://如果是熄灭
s3c2410_gpio_setpin(led_table[arg], 1);//熄灭相应的管脚
return 0;
default:
return -EINVAL;
}
}*/


int button_release(struct inode *inode, struct file *filp)
{
int i;
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
if (button_irqs[i].irq < 0) {
continue;
}
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
}
return 0;
}

/*文件操作结构体*/
static const struct file_operations button_fops =
{
.owner = THIS_MODULE,
.read = button_read,
.open = button_open,
.poll = button_poll,
// .ioctl = button_ioctl,
.release = button_release,
};

static int button_init(void)
{
int result;

dev_t devno = MKDEV(button_major, 0);

/* 静态申请设备号*/
if (button_major)
result = register_chrdev_region(devno, 1, DEVICE_NAME);
else /* 动态分配设备号 */
{
result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
button_major = MAJOR(devno);
}

if (result < 0)
return result;

/*初始化cdev结构*/
cdev_init(&cdev, &button_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &button_fops;

/* 注册字符设备 */
cdev_add(&cdev, MKDEV(button_major, 0), BUTTONDEV_NR_DEVS);

button_class = class_create(THIS_MODULE, DEVICE_NAME);
if(IS_ERR(button_class))
{
printk("Err: failed in button class. \n");
return -1;
}
//创建一个设备节点,节点名为DEVICE_NAME
device_create(button_class, NULL, MKDEV(button_major, 0), NULL, DEVICE_NAME);
return 0;

}

static void button_exit(void)
{
cdev_del(&cdev); /*注销设备*/
unregister_chrdev_region(MKDEV(button_major, 0), 1); /*释放设备号*/
device_destroy(button_class,MKDEV(button_major,0));
}


MODULE_AUTHOR("OuYang");
MODULE_LICENSE("GPL");

module_init(button_init);
module_exit(button_exit);



测试程序如下

/*调用系统的头文件*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

int main(void)
{
int i;
int buttons_fd;
int key_values;


/*打开按键设备文件*/
buttons_fd = open("/dev/buttondev", 0);
if (buttons_fd < 0) {
perror("open device buttondev");
exit(1);
}
printf("buttondev open success/n");
for (;;) //一直循环来监听是否有按键按下
{
fd_set rds;
int ret;

FD_ZERO(&rds);
FD_SET(buttons_fd, &rds);

/*使用系统调用select检查是否能够从/dev/buttondev设备读取数据*/
ret = select(buttons_fd + 1, &rds, NULL, NULL, NULL);

/*读取出错则退出程序*/
if (ret < 0) {
perror("select");
exit(1);
}

if (ret == 0) {
printf("Timeout.\n");
}
/*能够读取到数据*/
else if (FD_ISSET(buttons_fd, &rds)) {
/*开始读取键盘驱动发出的数据,注意key_value和键盘驱动中定义为一致的类型*/
printf("keydown/n");
int ret = read(buttons_fd, &key_values, sizeof key_values);
if (ret != sizeof key_values) {
if (errno != EAGAIN)
perror("read buttons\n");
continue;
} else {
printf("buttons_value: %d\n", key_values+1);
}

}
}
/*关闭设备文件句柄*/
close(buttons_fd);
return 0;
}
文章评论

共有 0 条评论