在上回的代码上修改,将first_drv.c改成second_drv.c,firstdrvtest.c改成seconddrvtest.c。
注意:在vi里批量替换使用命令 :%s/first/second/gc 将first字样全部改成second。
#include <asm/mach/map.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpgcon = NULL;
volatile unsigned long *gpfdat = NULL;
volatile unsigned long *gpgdat = NULL;
static int second_drv_open(struct inode *inode,struct file *file)
{
*gpfcon &= ~(0x3<<(0*2)|(0x3<<(2*2)));
*gpgcon &= ~(0x3<<(3*2)|(0x3<<(11*2)));
return 0;
}
static ssize_t second_drv_read(struct file *file,const char __user *buf,size_t len,loff_t *ppos)
{
unsigned char key_value[4];
int temp;
if(len!=sizeof(key_value))
return -EINVAL;
temp = *gpfdat;
key_value[0] = (temp & (1<<0)) ? 1:0;
key_value[1] = (temp & (1<<2)) ? 1:0;
temp = *gpgdat;
key_value[2] = (temp & (1<<3)) ? 1:0;
key_value[3] = (temp & (1<<11)) ? 1:0;
copy_to_user(buf,key_value,sizeof(key_value));
return sizeof(key_value);
}
static struct file_operations second_drv_fops = {
.owner = THIS_MODULE,
.open = second_drv_open,
.read = second_drv_read,
};
int major;
static struct class *seconddrv_class;
static struct device *seconddrv_device;
static int second_drv_init(void)
{
int i;
major = register_chrdev(0,"second_drv",&second_drv_fops);
seconddrv_class = class_create(THIS_MODULE,"seconddrv");
seconddrv_device = device_create(seconddrv_class,NULL,MKDEV(major,0),NULL,"buttons");
gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);
gpfdat = gpfcon + 1;
gpgcon = (volatile unsigned long *)ioremap(0x56000060,16);
gpgdat = gpgcon + 1;
printk("second_drv_init\n");
return 0;
}
static void second_drv_exit(void)
{
iounmap(gpfcon);
iounmap(gpgcon);
unregister_chrdev(major,"second_drv");
device_destroy(seconddrv_class,MKDEV(major,0));
class_destroy(seconddrv_class);
printk("second_drv_exit\n");
}
module_init(second_drv_init);
module_exit(second_drv_exit);
MODULE_LICENSE("GPL");
make出现 warning: passing argument 1 of 'copy_to_user' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers],原来是static ssize_t second_drv_read(struct file *file,const char __user *buf,size_t len,loff_t *ppos)中的buf在read函数不能用const修饰,毕竟buf是要被写入的,不能不被修改。疏忽大意。
再次make出现second_drv.c:54:6: warning: unused variable 'i' [-Wunused-variable],在vi中使用命令 :set nu显示出行号,找到第54行,使用命令dd删除此行即可。编译通过。
测试文件seconddrvtest.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[4];
int cnt = 1;
fd = open("/dev/buttons",O_RDWR);
if(fd<0)
{
printf("can't open /dev/buttons!\n");
return 0;
}
while(1)
{
read(fd,key_value,sizeof(key_value));
if(!key_value[0]||!key_value[1]||!key_value[2]||!key_value[3])
printf("%04d key_pressed: %d %d %d %d\n",cnt++,key_value[0],key_value[1],key_value[2],key_value[3]);
}
return 0;
}
编译通过。
注意:%04d表示输出的数据为整形,4表示输出的数据宽度为4,不足位用0填充。
测试驱动:
# insmod second_drv.ko
second_drv_init
# cat /proc/devices
Character devices:
248 second_drv
# ls /dev/buttons -l
crw-rw---- 1 0 0 248, 0 Jan 4 02:58 /dev/buttons
# ./seconddrvtest
0001 key_pressed: 1 0 1 1
0002 key_pressed: 1 0 1 1
0003 key_pressed: 1 0 1 1
0004 key_pressed: 1 0 1 1
0005 key_pressed: 1 0 1 1
测试成功。
# ./seconddrvtest &
# top
Mem: 11792K used, 46204K free, 0K shrd, 0K buff, 4688K cached
CPU: 20.0% usr 80.0% sys 0.0% nic 0.0% idle 0.0% io 0.0% irq 0.0% sirq
Load average: 0.83 0.43 0.18 2/31 1090
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
1089 873 0 R 1632 2.8 0 73.1 ./seconddrvtest
1090 873 0 R 3624 6.2 0 6.6 top
可以看到./seconddrvtest cpu进程占比为73.1%。