zoukankan      html  css  js  c++  java
  • 【Linux开发】linux设备驱动归纳总结(八):1.总线、设备和驱动

    linux设备驱动归纳总结(八):1.总线、设备和驱动


    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    这几天一直在看设备模型,内核的代码看得我越来越沮丧,特别是kbojectksetktype之间的关系。但是,设备模型的归纳我打算先跳过这几个重要结构体,先介绍总线、设备和驱动——设备管理的相关内容。先介绍如何使用,有机会介绍大概的原理。

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


    一、sysfs文件系统


    设备模型是2.6内核新引入的特征。设备模型提供了一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构。

    2.4内核中,设备的信息放在/proc中。

    而在2.6内核,内核把设备相关的信息归类在新增加sysfs文件系统,并将它挂载到/sys目录中,把设备信息归类的同时,让用户可以通过用户空间访问。


    接下来简单介绍一些sys中的目录:

    block:用于管理块设备,系统中的每一个块设备会在该目录下对应一个子目录。

    bus:用于管理总线,没注册一条总线,在该目录下有一个对应的子目录。

    其中,每个总线子目录下会有两个子目录:devicesdrivers

    devices包含里系统中所有属于该总线的的设备。

    drivers包含里系统中所有属于该总线的的驱动。

    class:将系统中的设备按功能分类。

    devices:该目录提供了系统中设备拓扑结构图。

    dev:该目录已注册的设备节点的视图。

    kernel:内核中的相关参数。

    module:内核中的模块信息。

    fireware:内核中的固件信息。

    Fs:描述内核中的文件系统。

    上面的目录,接下来的章节会常常提起busdevice


    再说说这些目录,来个简单的命令:

    root@xiaobai-laptop:/sys# ll class/net/eth0

    lrwxrwxrwx 1 root root 0 2011-01-31 10:11 class/net/eth0 -> ../../devices/pci0000:00/0000:00:1c.5/0000:86:00.0/net/eth0/

    上面的命令也可以看到class/net/eth0的路径其实就是devices目录中一个网卡设备的软连接


    贴个书上的图:

    由上面两个例子看到,sys中的其他目录都是将devvice目录下的数据加以转换加工而得。上面的图中,将use设备归类到bus总线上,又把它归类到class。正是在sys中有很多这样的结构,内核就有一个完整而且复杂的拓扑结构图。

    而维护这些关系的结构体就包括kobjectksetktypesubsystem等数据结构,不过这里就先不介绍。

    通过设备模型,内核就能实现多种不同的任务,如:

    1、电源管理和系统关机。

    2、与用户空间通信。这个就比较容易理解,sys目录向用户展示了设备模型的结构图。

    3、热插拔设备。大概意思就是,当设备插入后,内核会根据插入的设备安装驱动,设备拔出后,内核又会自动卸载驱动。

    4、设备类型。将设备归类。


    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    在接下来的内容会简单介绍总线、设备和驱动程序的概念和函数调用,以下的函数我将模拟创建一条ubs总线,一个usb设备和一个usb驱动。

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


    二、总线


    总线是处理器和设备之间的通道,在设备模型中,所有的设备都通过总线相连,以总线来管理设备和驱动函数。总线有bus_type结构表示。

    /*linux/device.h*/

    51 struct bus_type {

    52 const char *name;

    53 struct bus_attribute *bus_attrs;

    54 struct device_attribute *dev_attrs;

    55 struct driver_attribute *drv_attrs;

    56

    57 int (*match)(struct device *dev, struct device_driver *drv);

    58 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);

    59 int (*probe)(struct device *dev);

    60 int (*remove)(struct device *dev);

    61 void (*shutdown)(struct device *dev);

    62

    63 int (*suspend)(struct device *dev, pm_message_t state);

    64 int (*suspend_late)(struct device *dev, pm_message_t state);

    65 int (*resume_early)(struct device *dev);

    66 int (*resume)(struct device *dev);

    67

    68 struct dev_pm_ops *pm;

    69

    70 struct bus_type_private *p;

    71 };

    红色部分是以后将会介绍的成员,其中name是总线的名字, bus_attrs是总线的属性,那些函数指针的操作总线的方法,在这一章节先不讲总线的方法。


    总线的注册和删除:

    总线的注册有两个步骤:

    1、定义一个bus_type结构体,并设置好需要设置的结构体成员。

    2、调用函数bus_register注册总线。函数原型如下:

    /*drivers/base/bus.c*/

    865 int bus_register(struct bus_type *bus)

    该调用有可能失败,所以必须检查它的返回值,如果注册成功,会在/sys/bus下看到指定名字的总线。


    总线删除时调用:

    /*drivers/base/bus.c*/

    946 void bus_unregister(struct bus_type *bus)


    接下来贴个函数:

    /*8th_devModule_1/1st/bus.c*/

    1 #include

    2 #include

    3

    4 #include

    5

    6 struct bus_type usb_bus = {

    7 .name = "usb", //定义总线的名字为usb,注册成功后将在/sys/bus目录下看到

    8 }; //目录usb,如果你的系统已经有usb总线,那你就要换个名字。

    9

    10 static int __init usb_bus_init(void)

    11 {

    12 int ret;

    13 /*总线注册,必须检测返回值*/

    14 ret = bus_register(&usb_bus);

    15 if(ret){

    16 printk("bus register failed! ");

    17 return ret;

    18 }

    19

    20 printk("usb bus init ");

    21 return 0;

    22 }

    23

    24 static void __exit usb_bus_exit(void)

    25 {

    26 bus_unregister(&usb_bus);

    27 printk("usb bus bye! ");

    28 }

    29

    30 module_init(usb_bus_init);

    31 module_exit(usb_bus_exit);

    32

    33 MODULE_LICENSE("GPL");

    上面的函数可以看到,我仅仅定义了总线的名字为usb,其他的都没有做。看看效果:

    [root: 1st]# insmod bus.ko

    usb bus init

    [root: 1st]# ls /sys/bus/usb/ //sys/bus目录下多了一个usb的目录,但是里面的东西都是空的,

    devices drivers_autoprobe uevent //因为我仅仅设置了总线的名字

    drivers drivers_probe


    总线属性添加和删除:

    个人理解,设置总线的属性后,会在对应的总线目录下增加了一个新的文件,通过对该文件的读写访问,触发相应的函数操作,从而实现/sys/的文件接口与内核设备模型的数据交互

    /*linux/sysfs.h*/

    28 struct attribute {

    29 const char *name; //设定该文件的名字

    30 struct module *owner; //设定该文件的属主

    31 mode_t mode; //设定该文件的文件操作权限

    32 };

    /*linux/device.h*/

    38 struct bus_attribute {

    39 struct attribute attr;

    40 ssize_t (*show)(struct bus_type *bus, char *buf);

    41 ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);

    42 };

    bus_attribute中有两个函数指针,showstore

    当访问总线目录中的name文件时,就会触发show函数,一般会将指定的信息存放到数组buf,并传到用户空间显示。

    当修改总线目录中的name文件是,就会触发stroe函数,一般会将从用户空间传来的buf指针存放的count个字节内容存放到内核中。

    由此可以看到,通过这样的文件,就能实现sys目录下的文件与内核设备模型之间的数据交互。


    设置总线属性有两个步骤:

    1、创建并初始化bus_attribute结构,使用宏BUS_ATTR

    BUS_ATTR(_name, _mode, _show, _store)

    该宏会定义一个名叫bus_attr__name(红色部分是固定的)的bus_attibute的结构,并且成员name设置为_name,文件权限mode设置为_mode,两个函数调用分别人showstore

    2、将bus_attibute添加到指定的总线上,使用以下调用:

    /*/drivers/base/bus.c*/

    123 int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)

    该函数失败时返回错误号。

    一旦调用该函数,会就在指定bus总线的目录下新建一个名叫_name的文件,权限为_mode,当访问和修改该文件是会分别调用showstore函数调用。


    如果不需要该属性时,使用以下函数删除:

    /*/drivers/base/bus.c*/

    135 void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)


    说了这么多,马上来个程序:


    /*8th_devModule_1/2nd/bus.c*/

    1 #include

    2 #include

    3

    4 #include

    5

    6 #define VER_SIZE 100

    7

    8 struct bus_type usb_bus = {

    9 .name = "usb",

    10 };

    11

    12 char Version[VER_SIZE] = "xiaobai V1.0";

    13

    14 static ssize_t show_bus_version(struct bus_type *bus, char *buf)

    15 {

    16 return snprintf(buf, VER_SIZE, "%s ", Version);

    17 }

    18 static ssize_t store_bus_version(struct bus_type *bus, const char *buf, size_t count)

    19 {

    20 return snprintf(Version, VER_SIZE, "%s", buf);

    21 }

    22 /*该宏会定义一个名叫bus_attr_versionbus_attribute的结构,并且成员name设置为

    23 * version,文件权限mode设置为S_IRUGO|S_IWUGO,并设置show函数为

    24 * show_bus_versionstror 函数为stroe_bus_version*/

    25 static BUS_ATTR(version, S_IRUGO|S_IWUGO, show_bus_version, store_bus_version);

    26

    27 static int __init usb_bus_init(void)

    28 {

    29 int ret;

    30

    31 /*总线注册*/

    32 ret = bus_register(&usb_bus);

    33 if(ret){

    34 printk("bus register failed! ");

    35 goto err1;

    36 }

    37 /*为总线添加属性,调用成功后在/sys/bus/usb目录下有一个version的文件,权限为

    38 * S_IRUGO|S_IWUGO,查看该文件时会调用函数show_bus_version,修改时调用store*/

    39 ret = bus_create_file(&usb_bus, &bus_attr_version);

    40 if(ret){

    41 printk("bus creat file failed! ");

    42 goto err2;

    43 }

    44 printk("usb bus init ");

    45 return 0;

    46

    47 err2:

    48 bus_unregister(&usb_bus);

    49 err1:

    50 return ret;

    51 }

    52

    53 static void __exit usb_bus_exit(void)

    54 {

    55 bus_remove_file(&usb_bus, &bus_attr_version); //不调用这个也可以的,删除总线时会删除

    56 bus_unregister(&usb_bus);

    57 printk("usb bus bye! ");

    58 }

    验证一下:

    [root: 2nd]# insmod bus.ko

    usb bus init

    [root: 2nd]# ls /sys/bus/usb/

    devices drivers_autoprobe uevent

    drivers drivers_probe version //多了一个version文件

    [root: 2nd]# ls -l /sys/bus/usb/version //文件的权限的可读可写(S_IRUGO|S_IWUGO

    -rw-rw-rw- 1 root root 4096 Oct 27 23:46 /sys/bus/usb/version

    [root: 2nd]# cat /sys/bus/usb/version //读文件时触发show函数

    xiaobai V1.0

    [root: 2nd]# echo "haha"> /sys/bus/usb/version //写文件是触发store函数

    [root: 2nd]# cat /sys/bus/usb/version

    haha


    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


    三、设备


    在最底层,linux系统中每个设备都用一个device结构的表示,如下,我省略掉部分成员:

    /*linux/device.h*/

    369 struct device {

    370 struct klist klist_children;

    371 struct klist_node knode_parent; /* node in sibling list */

    372 struct klist_node knode_driver;

    373 struct klist_node knode_bus;

    374 struct device *parent; //指定该设备的父设备,如果不指定(NULL),注册后的设备目录

    375 ///sys/device

    376 struct kobject kobj;

    377 char bus_id[BUS_ID_SIZE]; /* position on parent bus */ //在总线生识别设备的字符串,

    385 //同时也是设备注册后的目录名字。

    386 struct bus_type *bus; /* type of bus device is on */ //指定该设备连接的总线

    387 struct device_driver *driver; /* which driver has allocated this

    388 device */ //管理该设备的驱动函数

    389 void *driver_data; /* data private to the driver */ //驱动程序的私有数据

    392 struct dev_pm_info power;

    422 void (*release)(struct device *dev); //当给设备的最后一个引用被删除时,调用该函数

    423 };

    注册一个完整的device结构前,至少定义parrentbus_idbusrelease成员。但我接下来的程序仅仅定义了bus_id(指定目录的名字)、bus(对应的总线,不加也行)和release(这是必须的,不然卸载模块时会出错,不信自己试试)。


    设备注册和注销:


    与总线的注册一样:

    1、定义结构体device

    2、调用注册函数:

    int device_register(struct device *dev)

    函数失败返回非零,需要判断返回值来检查注册是否成功。


    设备注销函数:

    void device_unregister(struct device *dev)


    设备属性:


    这个也是和总线属性差不多,不细讲:

    设备相关的结构体和总线的类似,处理指定文件属性为,还定义了showstore两个函数。

    /*linux/device.h*/

    300 struct device_attribute {

    301 struct attribute attr;

    302 ssize_t (*show)(struct device *dev, struct device_attribute *attr,

    303 char *buf);

    304 ssize_t (*store)(struct device *dev, struct device_attribute *attr,

    305 const char *buf, size_t count);

    306 };


    设置设备属性有两个步骤:

    1、创建并初始化device_attribute结构,使用宏DEVICE_ATTR

    DEVICE_ATTR(_name, _mode, _show, _store)

    该宏会定义一个名叫dev_attr__name(红色部分是固定的)的device_attibute的结构,并且成员name设置为_name,文件权限mode设置为_mode,两个函数调用分别人showstore

    2、将device_attibute添加到指定的设备上,使用以下调用:

    /*drivers/base/core.c*/

    430 int device_create_file(struct device *dev, struct device_attribute *attr)

    该函数失败时返回错误号。

    一旦调用该函数,会就在指定dev设备的目录下新建一个名叫_name的文件,权限为_mode,当访问和修改该文件是会分别调用showstore函数调用。


    如果不需要该属性时,使用以下函数删除:

    /*drivers/base/core.c*/

    443 void device_remove_file(struct device *dev, struct device_attribute *attr)


    讲了这么多,来个函数,和总线那个函数差不多,具体功能就是新建了一个执行名字(usb_device)的的设备目录,并且里面有一个属性文件version

    /*8th_devModule_1/3rd/device.c*/

    1 #include

    2 #include

    3

    4 #include

    5

    6 #define VER_SIZE 100

    7

    8 extern struct bus_type usb_bus;

    9

    10 void usb_dev_release(struct device *dev)

    11 {

    12 printk(" release ");

    13 }

    14

    15 struct device usb_device = {

    16 .bus_id = "usb_device",

    17 .bus = &usb_bus, //指定该设备的总线,这样会在sys/bus/usb/device目录下有一个软连接

    18 .release = usb_dev_release, //必须要都有release函数,不然卸载时会出错

    19 };

    11

    12 char Version[VER_SIZE] = "xiaobai V1.0";

    13

    14 static ssize_t show_device_version(struct device *dev,

    15 struct device_attribute *attr, char *buf)

    16 {

    17 return snprintf(buf, VER_SIZE, "%s ", Version);

    18 }

    19 static ssize_t store_device_version(struct device *dev,

    20 struct device_attribute *attr, const char *buf, size_t count)

    21 {

    22 return snprintf(Version, VER_SIZE, "%s", buf);

    23 }

    24 /*该宏会定义一个名叫dev_attr_versiondevice_attribute的结构,并且成员name设置

    25 * version,文件权限mode设置为S_IRUGO|S_IWUGO,并设置show函数为

    26 *show_device_version, stror函数为stroe_device_version*/

    27 static DEVICE_ATTR(version, S_IRUGO|S_IWUGO,

    28 show_device_version, store_device_version);

    29

    30 static int __init usb_device_init(void)

    31 {

    32 int ret;

    33

    34 /*设备注册,注册成功后在/sys/device目录下创建目录usb_device*/

    35 ret = device_register(&usb_device);

    36 if(ret){

    37 printk("device register failed! ");

    38 goto err1;

    39 }

    40 /*为设备添加属性,调用成功后在/sys/device/usb_device/目录下有一个version

    41 * 文件,权限为S_IRUGO|S_IWUGO,查看该文件时会调用函数show_device_version,

    42 * 修改时调用store_device_version*/

    43 ret = device_create_file(&usb_device, &dev_attr_version);

    44 if(ret){

    45 printk("device creat file failed! ");

    46 goto err2;

    47 }

    48 printk("usb device init ");

    49 return 0;

    50

    51 err2:

    52 device_unregister(&usb_device);

    53 err1:

    54 return ret;

    55 }

    56

    57 static void __exit usb_device_exit(void)

    58 {

    59 device_remove_file(&usb_device, &dev_attr_version);

    60 device_unregister(&usb_device);

    61 printk("usb device bye! ");

    62 }

    63

    64 module_init(usb_device_init);

    65 module_exit(usb_device_exit);

    再看看效果,这是没有设置总线(bus = &usb_bus)时的效果,代码在8th_devModule_1/3rd/device_bak.c,我没有编译,如果需要的话自己编译运行看看

    [root: 3rd]# insmod device.ko

    usb device init

    [root: /]# find -name "usb_device" //注册后查找一下在哪里有以设备bus_id为名字的目录

    ./sys/devices/usb_device ///sys/device下有一个

    [root: /]#

    [root: /]# ls /sys/devices/usb_device/ //里面有一个空文件,一个属性文件version

    uevent version

    [root: /]# cat /sys/devices/usb_device/version //查看一下version,调用shoe函数

    xiaobai V1.0

    [root: /]# echo "haha" > /sys/devices/usb_device/version //修改version,调用store函数

    [root: /]# cat /sys/devices/usb_device/version

    haha

    下面的是程序8th_devModule_1/3rd/device.c的效果:

    [root: /]# cd review_driver/8th_devModule/8th_devModule_1/3rd/

    [root: 3rd]# insmod bus.ko //先加载总线的模块

    usb bus init

    [root: 3rd]# insmod device.ko //再加载设备的模块

    usb device init

    [root: 3rd]# cd /

    [root: /]# find -name "usb_device" //查找一下usb_device,发现比没有指定总线时多了一个路径

    ./sys/devices/usb_device //这个目录的出现是因为语句(.bus = &usb_bus,

    ./sys/bus/usb/devices/usb_device //这个目录的出现是因为语句(device_register(&usb_device);

    [root: /]# cat /sys/devices/usb_device/version

    xiaobai V1.0

    [root: /]# ls -l sys/bus/usb/devices //原来该路径只是一个软连接,是该设备归类到usb_bus总线下

    lrwxrwxrwx 1 root root 0 Oct 27 13:49 usb_device -> ../../../devices/usb_device

    [root: /]# rmmod device

    release //下载时调用release函数调用,如果没有设置release,卸载时会出错。

    usb device bye!

    [root: /]# rmmod bus

    usb bus bye!

    [root: /]#

    上面的验证需要先加载bus.kobus.c源程序和1st/bus.c的函数没什么区别,只是将usb_bus导出到符号表。不然的话,加载模块时不能找到对应的总线。


    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


    四、驱动程序


    设备模型跟踪所有系统所知道的设备。进行跟踪的主要原因是让驱动程序协调与设备之间的关系。

    先看驱动程序的结构体,我仅仅贴出一些重要的成员:

    /*linux/device.h*/

    122 struct device_driver {

    123 const char *name; //驱动函数的名字,在对应总线的driver目录下显示

    124 struct bus_type *bus; //指定该驱动程序所操作的总线类型,必须设置,不然会注册失败

    125

    126 struct module *owner;

    127 const char *mod_name; /* used for built-in modules */

    128

    129 int (*probe) (struct device *dev); //探测函数,以后会讲

    130 int (*remove) (struct device *dev); //卸载函数,当设备从系统中删除时调用,以后讲

    131 void (*shutdown) (struct device *dev); //当系统关机是调用

    132 int (*suspend) (struct device *dev, pm_message_t state);

    133 int (*resume) (struct device *dev);

    134 struct attribute_group **groups;

    135

    136 struct dev_pm_ops *pm;

    137

    138 struct driver_private *p;

    139 };

    和设备不一样的是,在注册驱动函数是必须指定该驱动函数对应的总线,因为驱动函数注册成功后,会存放在对应总线的driver目录下,如果没有总线,注册当然会失败。


    与总线的注册一样:

    1、定义结构体device_driver

    2、调用注册函数:

    214 int driver_register(struct device_driver *drv)

    函数失败返回非零,需要判断返回值来检查注册是否成功。


    设备注销函数:

    249 void driver_unregister(struct device_driver *drv)


    驱动函数属性:


    这个也是和总线属性差不多,不细讲:

    驱动函数相关的结构体和总线的类似,处理指定文件属性为,还定义了showstore两个函数。

    155 struct driver_attribute {

    156 struct attribute attr;

    157 ssize_t (*show)(struct device_driver *driver, char *buf);

    158 ssize_t (*store)(struct device_driver *driver, const char *buf,

    159 size_t count);

    160 };


    设置设备属性有两个步骤:

    1、创建并初始化device_attribute结构,使用宏DEVICE_ATTR

    DRIVER_ATTR(_name, _mode, _show, _store)

    该宏会定义一个名叫driver_attr__name(红色部分是固定的)的driver_attibute的结构,并且成员name设置为_name,文件权限mode设置为_mode,两个函数调用分别人showstore

    2、将device_attibute添加到指定的驱动函数上,使用以下调用:

    /*drivers/base/driver.c*/

    93 int driver_create_file(struct device_driver *drv, struct driver_attribute *attr)

    该函数失败时返回错误号。

    一旦调用该函数,会就在指定dev设备的目录下新建一个名叫_name的文件,权限为_mode,当访问和修改该文件是会分别调用showstore函数调用。


    如果不需要该属性时,使用以下函数删除:

    /*drivers/base/driver.c*/

    110 void driver_remove_file(struct device_driver *drv, struct driver_attribute *attr)


    贴上函数:

    /*8th_devModule_1/4th/driver.c*/

    1 #include

    2 #include

    3

    4 #include

    5

    6 #define VER_SIZE 100

    7

    8 extern struct bus_type usb_bus;

    9

    10 struct device_driver usb_driver = {

    11 .name = "usb_driver",

    12 .bus = &usb_bus,

    13 };

    14

    15 char Version[VER_SIZE] = "xiaobai V1.0";

    16

    17 static ssize_t show_driver_version(struct device_driver *drv, char *buf)

    18 {

    19 return snprintf(buf, VER_SIZE, "%s ", Version);

    20 }

    21 static ssize_t store_driver_version(struct device_driver *drv,

    22 const char *buf, size_t count)

    23 {

    24 return snprintf(Version, VER_SIZE, "%s", buf);

    25 }

    26 /*该宏会定义一个名叫driver_attr_versiondriver_attribute的结构,并且成员

    27 * name设置为version,文件权限mode设置为S_IRUGO|S_IWUGO,并设置show函数为

    28 * show_driver_version,stror函数为stroe_driver_version*/

    29 static DRIVER_ATTR(version, S_IRUGO|S_IWUGO,

    30 show_driver_version, store_driver_version);

    31

    32 static int __init usb_driver_init(void)

    33 {

    34 int ret;

    35

    36 /*驱动注册,注册成功后在/sys/bus/usb/driver目录下创建目录usb_driver*/

    37 ret = driver_register(&usb_driver);

    38 if(ret){

    39 printk("driver register failed! ");

    40 goto err1;

    41 }

    42 /*为驱动添加属性,调用成功后在/sys/bus/usb/dirver目录下有一个version

    43 * 文件,权限为S_IRUGO|S_IWUGO,查看该文件时会调用函数show_driver_version,修改时

    44 * 调用store_driver_version*/

    45 ret = driver_create_file(&usb_driver, &driver_attr_version);

    46 if(ret){

    47 printk("driver creat file failed! ");

    48 goto err2;

    49 }

    50 printk("usb driver init ");

    51 return 0;

    52

    53 err2:

    54 driver_unregister(&usb_driver);

    55 err1:

    56 return ret;

    57 }

    58

    59 static void __exit usb_driver_exit(void)

    60 {

    61 driver_remove_file(&usb_driver, &driver_attr_version);

    62 driver_unregister(&usb_driver);

    63 printk("usb driver bye! ");

    64 }

    看看效果,同样必须先加载bus.ko

    [root: /]# cd review_driver/8th_devModule/8th_devModule_1/4th/

    [root: 4th]# insmod bus.ko //必须先加载总线

    usb bus init

    [root: 4th]# insmod driver.ko

    usb driver init

    [root: 4th]# cd /

    [root: /]# find -name "usb_driver" //只有一处创建了usb_driver目录

    ./sys/bus/usb/drivers/usb_driver

    [root: /]# ls /sys/bus/usb/drivers/usb_driver/

    bind uevent unbind version

    [root: /]# cat /sys/bus/usb/drivers/usb_driver/version //访问version文件是触发show函数

    xiaobai V1.0


    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


    五、总结


    这节讲得内容其实不多,归纳起来就是四个函数一个属性结构体

    属性结构体:xx_attribute

    注册函数:xx_register

    注销函数:xx+unregister

    创建属性文件函数:xx_create_file

    删除属性文件函数:xx_remove_file

    其中xx可以是总线(bus)、设备(device)或者驱动函数(deriver)

    一但注册成功,就会在/sys目录下相应的地方创建一个自己命名的目录。其中,设备和驱动函数还可以添加到指定的bus目录下。

    总线的成功注册后会在/sys/bus目录下创建相应的目录。

    设备的成功注册后会在/sys/device目录下创建相应的目录,如果指定总线,会在指定总线目录/sys/bus/xx/device下创建一个指向/sys/device目录的软连接。

    驱动函数的公共注册会在/sys/bus/xx/driver目录下创建相应的目录。


    属性文件提供了shoestore两个函数调用,当读写文件时会触发相应的函数调用,实现内核sysfs与用户空间的数据交互。


    三者具体的关系就在后面章节介绍。

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    源代码: 8th_devModule_1.rar   

  • 相关阅读:
    浙江省CIO协会钱塘江论坛近日在网易云创沙龙宣布成立
    用Python解析XMind
    Flask写web时cookie的处理
    一篇文章看懂Facebook和新浪微博的智能FEED
    改进网易云音乐的“音乐社交”构想
    移动端爬虫工具与方法介绍
    用供应链管理思路降低教培产品成本
    【网易严选】iOS持续集成打包(Jenkins+fastlane+nginx)
    网易严选的wkwebview测试之路
    linux多进程之间的文件锁
  • 原文地址:https://www.cnblogs.com/huty/p/8518563.html
Copyright © 2011-2022 走看看