科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件Linux Device Driver学习笔记(1)—— 字符设备(1)

Linux Device Driver学习笔记(1)—— 字符设备(1)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文档记录了创建一个字符设备的学习小结。内容包括如何创建一个字符设备,如何对该设备进行互斥读写操作,如何通过mknode在/dev/下创建一个设备文件和如何编写一个简单的Makefile。

作者:车灯 来源:CSDN 2008年3月26日

关键字: 字符设备 Device Linux 开源

  • 评论
  • 分享微博
  • 分享邮件

说明:

本文档记录了创建一个字符设备的学习小结。内容包括如何创建一个字符设备,如何对该设备进行互斥读写操作,如何通过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内核中不支持该函数了吗?

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章