Linux Device Driver学习笔记(1)
字符设备(1)
修改历史
内容
版本
初始版本
V1.0
说明:
本文档记录了创建一个字符设备的学习小结。内容包括如何创建一个字符设备,如何对该设备进行互斥读写操作,如何通过mknode在/dev/下创建一个设备文件和如何编写一个简单的Makefile。
1 创建字符设备
在Linux 2.6下使用“struct cdev”记录字符设备的信息。结构定义如下:
struct cdev {
…
struct module *owner;
struct file_operations *ops;
dev_t dev;
…
};
void cdev_init(struct cdev *, struct file_operations *);
struct cdev *cdev_alloc(void);
int cdev_add(struct cdev *, dev_t, unsigned);
void cdev_del(struct cdev *);
…
如果cdev是嵌套在一个设备结构中的数据成员,需要使用cdev_init来初始化cdev结构。“cdev_add”函数将字符设备加入到内核的字符设备数组中(chrdev[])。在调用“cdev_add”前需要调用“alloc_chrdev_region”函数来获得设备的主设备号和将设备的名称记录到内核的字符设备链表中,该方法将会动态的分配设备号,主设备号就是字符设备数组的下标,如果已经确定设备号可以使用“register_chrdev_region”来记录设备的名称和检查是否可以获得改设备号。在释放设备时需要使用“cdev_del”和“unregister_chrdev_region”函数来释放资源。在创建了设备后可以在“
/proc/devices”文件中获取到设备的名称和主设备号,可以使用该设备号在“/dev”下创建设备文件。
关键代码如下:
struct my_dev_t {
struct cdev cdev;
...
} my_dev;
static int __init hello_init(void)
{
...
cdev_init(&my_dev.cdev, &my_op); //初始化
my_dev.cdev.owner = THIS_MODULE;
alloc_chrdev_region(&my_dev_no, 0, 1, DEV_NAME);//获取字符设备号
ret = cdev_add(&my_dev.cdev, my_dev_no, 1); //注册设备
...
}
static void __exit hello_exit(void)
{
unregister_chrdev_region(my_dev_no, 1);//释放占用的设备号
cdev_del(&my_dev.cdev);//注销设备
...
}
2 互斥读写操作
为了实现互斥的读写操作使用了“struct semaphore”创建一个读信号量来协调操作,代码如下:
ssize_t my_read(struct file *f, char __user *buf, size_t count, loff_t *offset)
{
...
等待有数据的时候读取数据。
if (down_interruptible(&my_dev.sem_r)) {
return -ERESTARTSYS;
}
...
}
ssize_t my_write(struct file *f, char __user *buf, size_t count, loff_t *offset)
{
...
将如数据写入缓存后释放信号量,通知读进程可以读取数据,
在这个练习程序中并没有考虑到写数据时另一个进程正在读
数据的情况。
up(&my_dev.sem_r);
...
}
struct my_dev_t {
struct semaphore sem_r;
...
} my_dev;
static int __init hello_init(void)
{
...
由于初始时是没有数据的,所以信号量初始化为locked状态。
init_MUTEX_LOCKED(&my_dev.sem_r);
...
}
读写操作使用,“copy_to_user”和“copy_from_user”来完成对用户控件缓存的读写操作,注意这两个函数的返回值表示还有多少数据没有写入用户空间或没有从用户空间读取,如果成功返回的是0。
3 编写简单的Makefile
ifneq ($(KERNELRELEASE),)
obj-m = helloworld.o
else
KERNELDIR = /lib/modules/2.6.15-1.2054_FC5/build
PWD = $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.ko *.mod.c
endif
4 通过脚本创建/dev/XXXX设备
#!/bin/sh
if [ "$#" -ne "3" ]; then
echo "setup <name> <major> <minor>"
exit 0
fi
mknod /dev/$1 c $2 $3
if [ "$?" -ne "0" ]; then
echo "setup successfully"
else
echo $?
echo "setup failed"
fi
使用mknod在/dev目录下创建一个设备文件,通过ll可以看到所创建设备的详细信息
crw-r--r-- 1 root root 253, 0 Jun 17 19:42 /dev/hello
“c”表示是字符设备
“253”是主设备号
“0”是次设备号
5 问题
描述
状态
备注
在linux 2.4下可以使用“devfs_register”在“/dev/”下创建设备文件,但在2.6的内核中没有发现该函数,是在2.6内核中不支持该函数了吗?
Open