Linux驱动开发(二)注册字符设备
对于字符设备驱动程序,最核心的就是file_operations结构,这个架构对应提供给虚拟文件系统(VFS)的文件结构,它的每一个成员函数一般都对应一个系统调用。用户进程利用系统调用对设备文件进行诸如读和写等操作时,系统调用通过设备文件的煮设备号找到响应的设备驱动程序。file_operations结构体定义如下:
注册字符设备使用register_chrdev:
register_chrdev函数原型为:
int register_chrdev(unsigned int major,const *name,struct file_operation *fops);
参数major为主设备号,可以在写驱动的时候指定,当一般设置为0。major为0时,则主设备号由系统动态分配。
注销字符设备使用unregister_chrdev:
unregister_chrdev函数原型为:
int unregister_chrdev(unsigned int major,const char *name);
具体例子:
字符驱动
simple_chrdev.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <asm/errno.h>
#define simple_MAJOR 0
static unsigned char simple_inc = 0;
static unsigned char demoBuffer[256];
int simple_open(struct inode *inode,struct file *filp)
{
if(simple_inc>0)return -ERESTARTSYS;
simple_inc++;
return 0;
}
int simple_release(struct inode *inode,struct file *filp)
{
simple_inc--;
return 0;
}
ssize_t simple_read(struct file *filp,char __user *buf,size_t count,loff_t *fpos)
{
if(copy_to_user(buf,demoBuffer,count)) //数据内核空间都用户空间的拷贝
{
count = -EFAULT;
}
return count;
}
ssize_t simple_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos)
{
if(copy_from_user(demoBuffer,buf,count)) //数据从用户空间到内核空间的拷贝
{
count = -EFAULT;
}
return count;
}
struct file_operations simple_fops = {
.owner = THIS_MODULE,
.read = simple_read,
.write = simple_write,
.open = simple_open,
.release = simple_release,
};
void simple_cleanup_module(void)
{
unregister_chrdev(simple_MAJOR, "simple");
printk("simple_cleanup_module!\n");
}
int simple_init_module(void)
{
int ret;
ret = register_chrdev(simple_MAJOR,"simple",&simple_fops);
if(ret < 0)
{
printk("Unable to register character device %d\n",simple_MAJOR);
return ret;
}
return 0;
}
module_init(simple_init_module);
module_exit(simple_cleanup_module);
MODULE_LICENSE("GPL");//没加这句可能会报错module license 'unspecified' taints kernel
Makefile:
obj-m := simple_chrdev.o
KDIR := /home/vinkim/OrangePiH6/kernel
PWD := $(shell pwd)
default:
make ARCH=arm64 CROSS_COMPILE=/opt/toolchain/gcc-linaro-aarch/bin/aarch64-linux-gnu- -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.* *.ko *.symvers *.order
KDIR:内核所在目录
ARCH为芯片架构,我这里为arm64架构
CROSS_COMPILE为交叉编译工具链
编译成功后生成simple_chrdev.ko文件
测试程序:
main.c
#include <linux/fs.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
void main(void)
{
int fd;
int i;
char data[256];
int retval;
fd = open("/dev/vinkim",O_RDWR);
if(fd == -1)
{
perror("error open\n");
exit(-1);
}
printf("open /dev/vinkim successfully.\n");
retval = write(fd,"vinkim",6);
if(retval == -1)
{
perror("write error!\n");
exit(-1);
}
retval = read(fd,data,6);
if(retval == -1)
{
perror("read error!\n");
exit(-1);
}
data[retval] = 0;
printf("read successfully:%s\n",data);
close(fd);
}
编译生成main.o文件
将simple_chrdev.ko和main.o拷贝到linux开发板上
1.加载simple_chrdev.ko模块:
insmod simple_chrdev.ko
2.创建字符设备文件
创建字符设备文件之前需要先查询字符设备文件的主设备号,系统是通过主设备号将字符设备文件和字符驱动进行关联的。
cat /proc/devices
我们注册字符设备的名称为"simple"
我们可以看到simple所对应的主设备号为240
这样我们就可以创建我们的字符设备文件了:
mknod /dev/vimk c 240 0
vimk为创建的文件名,这个可以随便名
c表示穿件的我字符设备文件
240就是我们上一步查询到的主设备号
0位从设备号
3.运行测试程序
./main.o
上一篇: LVS 负载均衡 ---- DR模式
下一篇: mysql实现随机查询