ioctl学习

一、内核和用户态数据的传输

1. copy_from_user 从用户态获取数据,传送到内核态

static __always_inline unsigned long __must_check

copy_from_user(void *to, const void __user *from, unsigned long n)

{

         if (likely(check_copy_size(to, n, false)))

                   n = _copy_from_user(to, from, n);

         return n;

}

static inline __must_check unsigned long

_copy_from_user(void *to, const void __user *from, unsigned long n)

{

         unsigned long res = n;

         might_fault();

         if (!should_fail_usercopy() && likely(access_ok(from, n))) {

                   instrument_copy_from_user(to, from, n);

                   res = raw_copy_from_user(to, from, n);

         }

         if (unlikely(res))

                   memset(to + (n - res), 0, res);

         return res;

}

函数的三个参数:*to是内核空间的指针,*from是用户空间指针,n表示从用户空间想内核空间拷贝数据的字节数。如果成功执行拷贝操作,则返回0,否则返回还没有完成拷贝的字节数。

access_ok用来对用户空间的地址指针from作某种有效性检验

2. copy_to_user 从内核态获取数据,传送到用户态

static __always_inline unsigned long __must_check

copy_to_user(void __user *to, const void *from, unsigned long n)

{

         if (likely(check_copy_size(from, n, true)))

                   n = _copy_to_user(to, from, n);

         return n;

}

static inline __must_check unsigned long

_copy_to_user(void __user *to, const void *from, unsigned long n)

{

         might_fault();

         if (should_fail_usercopy())

                   return n;

         if (access_ok(to, n)) {

                   instrument_copy_to_user(to, from, n);

                   n = raw_copy_to_user(to, from, n);

         }

         return n;

}

函数的三个参数:*to是用户空间的指针,*from是内核空间指针,n表示从内核空间想用户空间拷贝数据的字节数。如果成功执行拷贝操作,则返回0,否则返回还没有完成拷贝的字节数。

3. put_user 数据传送到用户态

put_user ( x, ptr);

x

Value to copy to user space.

ptr

Destination address, in user space.

4. get_user 从用户态获取数据

get_user ( x, ptr);

x

Variable to store result.

ptr

Source address, in user space.

二、创建字符型设备

1.MKDEV将主设备号和次设备号转换成dev_t类型的一个内核函数。

#define MKDEV(major,minor) (((major) << MINORBITS) | (minor))

宏:MKDEV(MAJOR, MINOR); 

说明:获取设备在设备表中的位置。

MAJOR   主设备号

MINOR   次设备号

成功执行返回dev_t类型的设备编号

2. register_chrdev_region

/*指定设备编号来静态注册一个字符设备*/

int register_chrdev_region(dev_t from, unsigned count, const char *name);

from: 注册的指定起始设备编号,比如:MKDEV(100, 0),表示起始主设备号100, 起始次设备号为0

count:需要连续注册的次设备编号个数,比如: 起始次设备号为0,count=100,表示0~99的次设备号都要绑定在同一个file_operations操作方法结构体上

*name:字符设备名称

当返回值小于0,表示注册失败

3. alloc_chrdev_region

/*动态分配一个字符设备,注册成功并将分配到的主次设备号放入*dev里*/

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name);

*dev: 存放起始设备编号的指针,当注册成功, *dev就会等于分配到的起始设备编号,可以通过MAJOR()和MINNOR()函数来提取主次设备号

baseminor:次设备号基地址,也就是起始次设备号

count:需要连续注册的次设备编号个数,比如: 起始次设备号(baseminor)为0,baseminor=2,表示0~1的此设备号都要绑定在同一个file_operations操作方法结构体上

*name:字符设备名称

当返回值小于0,表示注册失败

4. unregister_chrdev_region

/*注销字符设备*/

void unregister_chrdev_region(dev_t from, unsigned count);

from: 注销的指定起始设备编号,比如:MKDEV(100, 0),表示起始主设备号100, 起始次设备号为0

count:需要连续注销的次设备编号个数,比如: 起始次设备号为0,baseminor=100,表示注销掉0~99的次设备号

5. cdev_init

/*初始化cdev结构体,并将file_operations结构体放入cdev-> ops 里*/

void cdev_init(struct cdev *cdev, const struct file_operations *fops);

其中cdev结构体的成员,如下所示:

struct cdev {

       struct kobject    kobj;                   // 内嵌的kobject对象

       struct module   *owner;                   //所属模块

       const struct file_operations  *ops;     //操作方法结构体

       struct list_head  list;      //与 cdev 对应的字符设备文件inode->i_devices 的链表头

       dev_t dev;      //起始设备编号,可以通过MAJOR(),MINOR()来提取主次设备号

       unsigned int count;              //连续注册的次设备号个数

};

6. cdev_add

/*将cdev结构体添加到系统中,并将dev(注册好的设备编号)放入cdev-> dev里,  count(次设备编号个数)放入cdev->count里*/

int cdev_add(struct cdev *p, dev_t dev, unsigned count);

7. cdev_del

/*将系统中的cdev结构体删除掉*/

void cdev_del(struct cdev *p);

8.class_createdevice_create

内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

参考博客:

Linux驱动开发16之再论register_chrdev_region_wangdapao12138的博客-CSDN博客

注册字符设备时的 class_create() 与 device_create()_sir_zeng的专栏-CSDN博客


版权声明:本文为homezhuyihong原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。