1. 驱动层:--相当于下边的 char_read.c 文件 ①先实现 file_operations 结构体中列的我们想要实现的函数,比如 static int hello_open (struct inode *inode, struct file *file)
static int hello_release (struct inode *inode, struct file *file)
ssize_t hello_read (struct file *filp, char *buff, size_t count, loff_t *offp)
ssize_t hello_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos)
②关联上 file_operations 中的入口: struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.read = hello_read,
.write = hello_write
};
③注册主设备号和填充 cdev 结构体: dev_t devno = MKDEV (hello_major, hello_minor);
result = register_chrdev_region (devno, number_of_devices, "hello");
cdev_init (&cdev, &hello_fops); //两个THIS_MODULE填充上设备号,hello_fops填充上file_operations(字符设备操作集合)
cdev.owner = THIS_MODULE;
④注册 cdev 结构体: error = cdev_add (&cdev, devno , 1);
这一步之后,我们关联的函数的符号就放到了应用程序可以调用的地方了。
⑤卸载的时候,先注销 cdev 结构体,再注销主设备号 cdev_del (&cdev);
unregister_chrdev_region (devno, number_of_devices);
如果是上边的这种思路,还需要手动的创建设备节点,如果需要自动的在程序中创建设备节点,用如下的函数:
device_create函数(linux2.6之后版本):-- 创建设备节点(设备节点所在的位置是 /dev 下)
所需库:
linux/device.h
原型:
struct device *device_create(struct class *cls, struct device *parent,
dev_t devt, void *drvdata,
const char *fmt, ...);
参数:
①cls,指向将要注册设备节点的类
②parent,指向这个新的设备节点的类的父类,如果有的话,没有则是NULL
③devt,将要添加的字符设备的设备号
④drvdata,和类设备有关的设备的数据的指针(a pointer to a struct device that is assiociated with this class device.)
⑤fmt,要注册的设备要显示的节点名字
例子:
device_create(my_class,NULL,devno,NULL,"hello");
class_create函数:-- 创建类(在 /sys/class/ 下)
头文件:
linux/device.h
原型:
struct class *class_create(struct module *owner, const char *name)
owner,pointer to the module that is to "own" this struct class
name,pointer to a string for the name of this class.
例子:
struct class *my_class = class_create(THIS_MODULE,"char_hello");
他们相应的删除函数:
device_destroy(my_class, devno);
class_destroy(my_class);
这两个的顺序不能调换
2. 用户层函数:-- 相当于下边的 test.c 文件2.1 采用访问文件 IO 的方式打开文件 int fd;
fd = open ("/dev/hello",O_RDWR);
第一个参数是创建的节点
第二个参数:
O_RDONLY:表示对文件只读
O_WRONLY:表示对文件只写
O_RDWR:表示对文件可读可写
上边这3个标志位是互斥的
O_CREAT:当文件不存在时,创建文件
O_EXCL:配合O_CREAT使用,当文件已经存在时创建,那么就会出错。
O_TRUNC:如果文件已经存在,先删除源文件内容。
O_APPEND:以添加方式打开,对文件的写操作都是在文件的末尾进行
2.2 写:write:--向文件描述符中写入数据
原型:
ssize_t write(int fd,void *buf,size_t count);
参数:
fd,要写的文件描述符
buf,存放要写的数据
count,期望执行一次write要写的字节个数
返回值:
实际写入的字节个数。
例子:
if (write (fd, buff, strlen(buff)) < 0)
{
perror(&quot;fail to write&quot;);
}
2.3 读:read:--读文件,ssize其实就是int型,从文件描述符中读取数据
原型:
ssize_t read(int fd,void *buf,size_t count);
参数:
fd,要读的文件描述符
buf,存放读取到的数据
count,期望执行一次read要读取的字节个数
返回值:
实际读到的字节个数。
0,网络上断开连接返回
-1,没有独到
特点:
read读取数据和\n,\0没任何关系。
例子
printf (&quot;Read returns %d\n&quot;, read (fd, buf, sizeof(buf)));
2.4 文件描述符关闭: close (fd);
3. 程序:char_read.c |