字符设备驱动的框架
主次设备号
构造file operations结构体(open read write release函数)
注册字符设备(cdev_add 或者 register_char_device)
入口函数
出口函数
应用程序调用open函数时,调用对应驱动程序的open函数;
应用程序调用read函数时,调用对应驱动程序的read函数;
应用程序调用write函数时,调用对应驱动程序的write函数;
应用程序调用close函数时,调用对应驱动程序的release函数;
主设备号一般标识设备对应的驱动程序
次设备号一般确定设备文件所指向的设备
参考代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/major.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/types.h>
#include <linux/fs.h>
#define TAG "hello"
static int hello_major;
static struct cdev hello_cdev;
static ssize_t hello_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
printk(TAG" func:%s line:%d\n", __func__, __LINE__);
return count;
}
ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
printk(TAG" func:%s line:%d\n", __func__, __LINE__);
return count;
}
static int hello_open(struct inode *inode, struct file *file)
{
printk(TAG" func:%s line:%d\n", __func__, __LINE__);
return 0;
}
static int hello_release(struct inode *inode, struct file *file)
{
printk(TAG" func:%s line:%d\n", __func__, __LINE__);
return 0;
}
static const struct file_operations hello_ops = {
.owner = THIS_MODULE,
.read = hello_read,
.write = hello_write,
.open = hello_open,
.release = hello_release,
};
static int hello_init(void)
{
int retval;
dev_t dev_id;
printk(TAG" func:%s line:%d\n", __func__, __LINE__);
retval = alloc_chrdev_region(&dev_id, 0, 1, "hello");
hello_major = MAJOR(dev_id);
printk(TAG"major is %d\n", hello_major);
if (retval < 0) {
printk(TAG"can't get major number\n");
goto error;
}
cdev_init(&hello_cdev, &hello_ops);
retval = cdev_add(&hello_cdev, dev_id, 1);
if (retval < 0) {
printk(TAG"cannot add cdev\n");
goto cleanup_alloc_chrdev_region;
}
return 0;
cleanup_alloc_chrdev_region:
unregister_chrdev_region(dev_id, 1);
error:
return retval;
}
static void hello_exit(void)
{
dev_t dev_id = MKDEV(hello_major, 0);
cdev_del(&hello_cdev);
unregister_chrdev_region(dev_id, 1);
printk(TAG" func:%s line:%d\n", __func__, __LINE__);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
cat /proc/devices |grep hello 查看主设备号
通过mknod创建设备节点 如果主设备为226的话,用如下命令创建
mknod /dev/hello c 226 0
创建的节点/dev/hello,主设备号为226,次设备号为0
上层应用程序的编写
调用open函数打开设备节点获得文件描述符
对文件描述符调用read write函数
close函数关闭文件描述符
测试程序
int main(int argc, char **argv)
{
int fd;
char buf = '1';
if(argc != 2) {
printf("Usage: %s [node]\n", argv[0]);
exit(1);
}
fd = open(argv[1], O_RDWR);
if (fd < 0) {
printf("open %s failed\n", argv[1]);
}
write(fd, &buf, 1);
read(fd, &buf, 1);
close(fd);
return 0;
}
编译好测试程序,假如编译好的程序名为testhello,push到机器里,运行
./testhello /dev/hello
观察log,可以看出,应用层通过系统调用可以调用到驱动file_operations结构体里对应的函数
问题
设备节点是通过mknod手动创建的,可以自动创建吗?