Linux内核开发示例
[TOC]
内核驱动
结构体
inode结构体
inode结构体是用来在内核中表示一个设备的,用户层看不到这个结构体,我们需要初始化它内部的一个结构体cdev:
struct cdev *pcdev_reversion; pcdev_reversion = cdev_alloc(); //inode 结构的一个结构体,在内核内部表示设备 pcdev_reversion->owner = THIS_MODULE; pcdev_reversion->ops = &file_ops; cdev_add(pcdev_reversion, dev, number_reversion);
如果我们没有用动态创建的方式来创建这个结构体,那么就需要使用cdev_init来初始化它,这里cdev_alloc在分配后就立即初始化了设备,所以我们就不用再次初始化了。
注销此设备:
cdev_del(pcdev_reversion);
file结构体
文件结构体是内核暴露给用户层的,用户层通过这个文件结构体来访问内核里的cdev设备:
static struct file_operations file_ops = { .owner = THIS_MODULE, .open = open_reversion, .write = write_reversion, .read = read_reversion, .unlocked_ioctl = ioctl_reversion };
设备号结构体dev_t
这个结构体是一个32位的整数,里面存放了设备的设备号,设备号是所有设备在内核中的标识,是唯一键,为了避免冲突,我们使用动态分配的方式来注册设备号:
if(major_reversion){ dev = MKDEV(major_reversion, minor_reversion); ret = register_chrdev_region(dev, number_reversion, REVERSION_NAME); } else { ret = alloc_chrdev_region(&dev, minor_reversion, number_reversion, REVERSION_NAME); major_reversion = MAJOR(dev); } if(ret < 0){ printk(KERN_WARNING "reversion:can't get major %d\n", major_reversion); return ret; }
释放设备号:
unregister_chrdev_region(MKDEV(major_reversion, minor_reversion), number_reversion);//unregion device
文件操作
读操作
ssize_t read_reversion(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
if(copy_to_user(buf, "kernel", sizeof("kernel"))){
printk(KERN_ERR "reversion:can't set date to user space\n");
return EFAULT;
}
return 0;
}
写操作
ssize_t write_reversion(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
char auBuf[128] = {0};
if(copy_from_user(auBuf, buf, count)){
printk(KERN_ERR "reversion:can't get date form user space\n");
return EFAULT;
}
printk(KERN_DEBUG "reversion:get data form user space:%s\n", auBuf);
return 0;
}
控制操作
long ioctl_reversion(struct file *filp, unsigned int cmd, unsigned long arg)
{
return 0;
}
用户层代码
创建设备
我们在将驱动加载后,就可以在/proc/devices中看到设备的设备号了:
pct@ubuntu:~$ cat /proc/devices | grep reversion
246 reversion
然后我们根据这个设备号创建设备:
mknod [OPTION]... NAME TYPE [MAJOR MINOR]
首先获取设备号,用awk命令可获取到
pct@ubuntu:~$ cat /proc/devices | awk '{if($2=="reversion")print $1}'
246
我们动态分配得到的是设备的主设备号,次设备号是我们代码里写的0,然后创建设备:
pct@ubuntu:~$ sudo mknod /dev/reversion c 246 0
[sudo] password for pct:
pct@ubuntu:~$ ls /dev/reversion -l
crw-r--r-- 1 root root 246, 0 Jan 3 17:24 /dev/reversion
创建成功。 代码如下:
#define DEV "/dev/reversion"
int dev_file = 0;
int dev_open()
{
if(access(DEV,F_OK)){
FILE *fp = popen("cat /proc/devices | awk '{if($2==\"reversion\")print $1}'", "r");
char auMajor[5] = {0};
if(0 == fread(auMajor, 1, sizeof(auMajor), fp))
{
printf("fread error:%s\n", strerror(errno));
return -1;
}
int iMajor = atoi(auMajor);
printf("the device major is:%d\n", iMajor);
char auCommand[256] = {0};
snprintf(auCommand, sizeof(auCommand), "mknod /dev/reversion c %d 0", iMajor);
printf("command:%s\n", auCommand);
system(auCommand);
}
dev_file = open(DEV,O_RDWR);
if(dev_file == -1){
printf("open error:%s\n", strerror(errno));
return -1;
}
return 0;
}
读取设备
读取设备的操作就和读取文件一样:
char auRead[256] = {0};
if(read(dev_file, auRead, sizeof(auRead)) == -1){
printf("read error:%s\n", strerror(errno));
return -1;
}
printf("read:%s\n", auRead);
返回值是我们在内核中写入的东西。
最后更新于
这有帮助吗?