在上回代码上修改为third_drv.c和 thirddrvtest.c。
(1)third_drv.c中增加中断注册注销(设置,让门卫老大爷帮忙提醒快递已到)
static irqreturn_t buttons_irq(int irq,void *dev_id)
{
printk("irq = %d\n",irq);
return IRQ_HANDLED;
}
static int third_drv_open(struct inode *inode,struct file *file)
{
request_irq(IRQ_EINT0, buttons_irq,IRQT_BOTHEDGE,"S2",1);
request_irq(IRQ_EINT2, buttons_irq,IRQT_BOTHEDGE,"S3",1);
request_irq(IRQ_EINT11,buttons_irq,IRQT_BOTHEDGE,"S4",1);
request_irq(IRQ_EINT19,buttons_irq,IRQT_BOTHEDGE,"S5",1);
return 0;
}
static int third_drv_close(struct inode *inode,struct file *file)
{
free_irq(IRQ_EINT0, 1);
free_irq(IRQ_EINT2, 1);
free_irq(IRQ_EINT11,1);
free_irq(IRQ_EINT19,1);
return 0;
}
static struct file_operations third_drv_fops = {
.owner = THIS_MODULE,
.open = third_drv_open,
.read = third_drv_read,
.release = third_drv_close,
};
make出现error: unknown type name 'irqreturn_t',增加头文件#include <linux/irq.h>
再次make出现error: implicit declaration of function 'request_irq' [-Werror=implicit-function-declaration],增加头文件#include <linux/interrupt.h>
再次make出现error: 'IRQT_BOTHEDGE' undeclared (first use in this function),将IRQT_BOTHEDGE换成IRQ_TYPE_EDGE_BOTH
再次make出现warning: passing argument 5 of 'request_irq' makes pointer from integer without a cast [-Wint-conversion],根本就不管,通过。
# exec 5</dev/buttons
# ps
PID USER TIME COMMAND
872 0 0:00 -/bin/sh
# ls -l /proc/872/fd
lr-x------ 1 0 0 64 Jan 1 19:37 5 -> /dev/buttons
# cat /proc/interrupts
16: 0 s3c-ext0 0 Edge S2
18: 0 s3c-ext0 2 Edge S3
59: 0 s3c-ext 11 Edge S4
67: 0 s3c-ext 19 Edge S5
# exec 5<&-
# exec 5</dev/buttons
# irq = 16
irq = 16
irq = 16
irq = 16
(2)third_drv.c中增加读pin值(阻塞读,等快递等得睡着了,没门卫老大爷给的通知就继续睡,通知到了才去拿)
#include <asm/mach/map.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press = 0;
static unsigned char key_val;
struct pin_desc{
unsigned int pin;
unsigned int key_val;
};
struct pin_desc pin_desc[4]={
{S3C2410_GPF(0), 0X01},
{S3C2410_GPF(2), 0X02},
{S3C2410_GPG(3), 0X03},
{S3C2410_GPG(11),0X04},
};
static irqreturn_t buttons_irq(int irq,void *dev_id)
{
unsigned int pinval;
struct pin_desc *pindesc = (struct pin_desc *)dev_id;
pinval = s3c2410_gpio_getpin(pindesc->pin);
if(pinval)
{
key_val = 0x80|pindesc->key_val;
}
else
{
key_val = pindesc->key_val;
}
ev_press = 1;
wake_up_interruptible(&button_waitq);
return IRQ_HANDLED;
}
static int third_drv_open(struct inode *inode,struct file *file)
{
request_irq(IRQ_EINT0, buttons_irq,IRQ_TYPE_EDGE_BOTH,"S2",&pin_desc[0]);
request_irq(IRQ_EINT2, buttons_irq,IRQ_TYPE_EDGE_BOTH,"S3",&pin_desc[1]);
request_irq(IRQ_EINT11,buttons_irq,IRQ_TYPE_EDGE_BOTH,"S4",&pin_desc[2]);
request_irq(IRQ_EINT19,buttons_irq,IRQ_TYPE_EDGE_BOTH,"S5",&pin_desc[3]);
return 0;
}
static ssize_t third_drv_read(struct file *file,char __user *buf,size_t len,loff_t *ppos)
{
if(len!=1)
return -EINVAL;
wait_event_interruptible(button_waitq,ev_press);
copy_to_user(buf,key_val,1);
ev_press = 0;
return 1;
}
static int third_drv_close(struct inode *inode,struct file *file)
{
free_irq(IRQ_EINT0, &pin_desc[0]);
free_irq(IRQ_EINT2, &pin_desc[1]);
free_irq(IRQ_EINT11,&pin_desc[2]);
free_irq(IRQ_EINT19,&pin_desc[3]);
return 0;
}
static struct file_operations third_drv_fops = {
.owner = THIS_MODULE,
.open = third_drv_open,
.read = third_drv_read,
.release = third_drv_close,
};
int major;
static struct class *thirddrv_class;
static struct device *thirddrv_device;
static int third_drv_init(void)
{
major = register_chrdev(0,"third_drv",&third_drv_fops);
thirddrv_class = class_create(THIS_MODULE,"thirddrv");
thirddrv_device = device_create(thirddrv_class,NULL,MKDEV(major,0),NULL,"buttons");
printk("third_drv_init\n");
return 0;
}
static void third_drv_exit(void)
{
unregister_chrdev(major,"third_drv");
device_destroy(thirddrv_class,MKDEV(major,0));
class_destroy(thirddrv_class);
printk("third_drv_exit\n");
}
module_init(third_drv_init);
module_exit(third_drv_exit);
MODULE_LICENSE("GPL");
make出现error: implicit declaration of function 'S3C2410_GPF' ,则添加头文件#include <mach/gpio-samsung.h>
再次make出现error: implicit declaration of function 's3c2410_gpio_getpin',则将s3c2410_gpio_getpin() 换成 gpio_get_value()
再次make出现warning: passing argument 2 of 'copy_to_user' makes pointer from integer without a cast,则copy_to_user(buf,key_val,1);应该为copy_to_user(buf,&key_val,1);编译通过。
vi thirddrvtest.c
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
int fd;
unsigned char key_value;
fd = open("/dev/buttons",O_RDWR);
if(fd<0)
{
printf("can't open /dev/buttons!\n");
return 0;
}
while(1)
{
read(fd,&key_value,1);
printf("key_value = 0x%x\n",key_value);
}
return 0;
}
编译通过。
测试驱动:# rmmod third_drv.
rmmod: remove 'third_drv': Resource temporarily unavailable
# exec 5<&-
/mnt/5 # rmmod third_drv.ko
third_drv_exit
# cat /proc/interrupts
CPU0
16: 18 s3c-ext0 0 Edge S2
18: 1 s3c-ext0 2 Edge S3
59: 1 s3c-ext 11 Edge S4
67: 0 s3c-ext 19 Edge S5
# 按键按下断开
key_value = 0x1
key_value = 0x81
key_value = 0x1
key_value = 0x81
(3)third_drv.c中增加poll(不能一直睡着了啊,定个10分钟闹钟醒来看看撒)
static int third_drv_poll(struct file *file, poll_table *wait)
{
int mask = 0;
poll_wait(file, &button_waitq, wait);
if (ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static struct file_operations third_drv_fops = {
.owner = THIS_MODULE,
.open = third_drv_open,
.read = third_drv_read,
.release = third_drv_close,
.poll = third_drv_poll,
make出现error: unknown type name 'poll_table',则添加头文件#include <linux/poll.h>
再次make出现error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.poll = third_drv_poll,
^
/home/embedfire/linux/nfs/6/third_drv.c:97:10: note: (near initialization for 'third_drv_fops.poll'),将static int third_drv_poll(struct file *file, poll_table *wait)替换为__poll_t third_drv_poll (struct file *, struct poll_table_struct *)编译通过。
vi thirddrvtest.c
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
int main(int argc,char *argv[])
{
int fd;
unsigned char key_value;
int ret;
struct pollfd fds[1];
fd = open("/dev/buttons",O_RDWR);
if(fd<0)
{
printf("can't open /dev/buttons!\n");
return 0;
}
fds[0].fd = fd;
fds[0].events = POLLIN;
while(1)
{
ret = poll(fds, 1, 5000);
if(ret==0)
{
printf("time out!\n");
}
else
{
read(fd,&key_value,1);
printf("key_value = 0x%x\n",key_value);
}
}
return 0;
}
测试驱动:# insmod third_drv.ko
third_drv: loading out-of-tree module taints kernel.
third_drv_init
# ./thirddrvtest &
# time out!
time out!
time out!
time out!
time out!
time out!
time out!
key_value = 0x1
key_value = 0x81
#top
Mem: 10456K used, 47540K free, 0K shrd, 0K buff, 3492K cached
CPU: 0.1% usr 0.1% sys 0.0% nic 99.0% idle 0.0% io 0.0% irq 0.5% sirq
Load average: 0.05 0.04 0.00 1/30 887
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
887 873 0 R 3624 6.2 0 0.5 top
886 873 0 S 1764 3.0 0 0.0 ./thirddrvtest