点击(此处)折叠或打开

/* my_bus.c   */

#include

#include

#include

#include

#include

#include "my_bus.h"

MODULE_LICENSE("Dual BSD/GPL");

#define MYBUS "mybus: "

#define PRINT(x...) printk(KERN_ALERT MYBUS x);

static char *Version = "$Revision: 1.9 $";

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

{

PRINT("%s\n", __func__);

return snprintf(buf, PAGE_SIZE, "my_bus: %s\n", Version);

}

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);

static void my_bus_release(struct device *dev)

{

PRINT("%s\n", __func__);

}

static int my_bus_match(struct device *dev, struct device_driver *drv)

{

struct my_device *device = to_my_device(dev);

PRINT("%s\n", __func__);

return !strncmp(device->name, drv->name, strlen(drv->name));

}

static int my_bus_hotplug(struct device *dev, struct kobj_uevent_env *env){

PRINT("%s\n", __func__);

return 0;

}

struct bus_type my_bus_type = {

.name = "my_bus",

.match = my_bus_match,

.uevent = my_bus_hotplug

};

static struct device my_bus = {

.init_name = "my_bus0",

.release = my_bus_release

};

/* interface to device. */

int register_my_device(struct my_device *device)

{

PRINT("%s\n", __func__);

device->device.bus = &my_bus_type;

device->device.parent = &my_bus;

device->device.release = my_bus_release;

//strncpy(device->device.bus_id, device->name, BUS_ID_SIZE);

return device_register(&device->device);

}

EXPORT_SYMBOL(register_my_device);

void unregister_my_device(struct my_device *device)

{

PRINT("%s\n", __func__);

device_unregister(&device->device);

}

EXPORT_SYMBOL(unregister_my_device);

static ssize_t show_version(struct device_driver *driver, char *buf)

{

struct my_driver *drv = to_my_driver(driver);

PRINT("%s\n", __func__);

sprintf(buf, "%s\n", drv->version);

return strlen(buf);

}

/* interface to driver. */

int register_my_driver(struct my_driver *driver)

{

int ret = 0;

PRINT("%s\n", __func__);

driver->driver.bus = &my_bus_type;

ret = driver_register(&driver->driver);

if (ret) {

PRINT("%s, driver_register %s failed!!!\n", __func__, driver->driver.name);

return ret;

}

driver->version_attr.attr.name = "version";

//driver->version_attr.attr.owner = driver->module;

driver->version_attr.attr.mode = S_IRUGO;

driver->version_attr.show = show_version;

return driver_create_file(&driver->driver, &driver->version_attr);

}

EXPORT_SYMBOL(register_my_driver);

void unregister_my_driver(struct my_driver *driver)

{

PRINT("%s\n", __func__);

driver_unregister(&driver->driver);

}

EXPORT_SYMBOL(unregister_my_driver);

static int __init my_bus_init(void)

{

int ret = 0;

ret = bus_register(&my_bus_type);

if (ret) {

PRINT("%s, bus_register failed!\n", __func__);

goto bus_register_failed;

}

ret = bus_create_file(&my_bus_type, &bus_attr_version);

if (ret) {

PRINT("%s, bus_create_file failure...!\n", __func__);

goto bus_create_file_failed;

}

ret = device_register(&my_bus);

if (ret) {

PRINT("%s, device_register failure...!\n", __func__);

goto device_register_failed;

}

PRINT("%s, bus & device register succeed!\n", __func__);

return 0;

device_register_failed:

bus_create_file_failed:

bus_unregister(&my_bus_type);

bus_register_failed:

return ret;

}

static void __exit my_bus_exit(void)

{

PRINT("%s!\n", __func__);

device_unregister(&my_bus);

bus_unregister(&my_bus_type);

}

module_init(my_bus_init);

module_exit(my_bus_exit);

my_bus.c 是实现 my_bus 的主要文件. 其实一条总线, 在 Linux 设备驱动模型中, 它也是一个设备. 所以, 需要声明 my_bus_type 的同时, 还要声明 my_bus 这个设备.(注:C语言中,非导出符号在文件中声明时用static标明.所以, 在my_bus.c中, 你将看到大多数的函数都是static.)

注册 my_bus 的步骤.

1. 声明my_bus_type, 类型为 bus_type. 作为总线.

点击(此处)折叠或打开

struct bus_type my_bus_type = {

.name    = "my_bus",      //总线名称.

.match   = my_bus_match,  //用来匹配设备和驱动的函数.

.uevent  = my_bus_hotplug //用来发送uevent到用户空间.

};2. 声明my_bus,类型为 struct device, 因为my_bus也是一种设备.

点击(此处)折叠或打开

static struct device my_bus = {

.init_name = "my_bus0", //my_bus设备的名称.在device_add函数里会将init_name复制到kobject中.

.release = my_bus_release //取消注册的设备的时候要调用的函数.

};

3. 调用 bus_register(&my_bus_type) 将 my_bus_type 这个总线类型注册到系统.

4. 调用 device_register(&my_bus) 将总线设备注册到系统.

(步骤3和4都在my_bus_init函数中.)

点击(此处)折叠或打开

static int __init my_bus_init(void)

{

int ret = 0;

ret = bus_register(&my_bus_type); //注册my_bus_type到Linux设备驱动模型中.

if (ret) {

PRINT("%s, bus_register failed!\n", __func__);

goto bus_register_failed;

}

ret = bus_create_file(&my_bus_type, &bus_attr_version);//创建my_bus的一个属性.在sysfs中体现.

if (ret) {

PRINT("%s, bus_create_file failure...!\n", __func__);

goto bus_create_file_failed;

}

ret = device_register(&my_bus); //注册my_bus到Linux设备驱动模型中.

if (ret) {

PRINT("%s, device_register failure...!\n", __func__);

goto device_register_failed;

}

PRINT("%s, bus & device register succeed!\n", __func__);

return 0;

device_register_failed:

bus_create_file_failed:

bus_unregister(&my_bus_type);

bus_register_failed:

return ret;

}上面四个步骤, 就将一条总线注册到 Linux设备驱动模型中.

编译并将 my_bus.ko 插入到到系统后,

可以通过命令 ls /sys/bus/  会看到 my_bus 文件夹.

通过命令 ls /sys/device/ 会看到 my_bus0 文件夹.

其实, 对于 Linux 设备驱动模型而言, 它管理的, 是 bus_type, device 和 device_driver 三大主体. 譬如我这里的my_bus, my_device, my_driver 都是 bus_type, device, device_driver 的拓展, 都离不开 bus_type, device, device_driver 这三个主体. 所以, 这也就是为什么对应的数据结构中间都要包含它们.(my_bus_type 本身就是 bus_type 类型.)

取消 my_bus 这条总线, 有两个步骤:

1. 取消 my_bus 设备的注册.

2. 取消 my_bus_type 的注册.

步骤1和2都是在 my_bus_exit 函数中.

点击(此处)折叠或打开

static void __exit my_bus_exit(void)

{

PRINT("%s!\n", __func__);

device_unregister(&my_bus);

bus_unregister(&my_bus_type);

}

驱动的加载和卸载都是 module_init 和 module_exit 来实现的.

module_init(my_bus_init);

module_exit(my_bus_exit);

总线上的驱动和设备的匹配函数如下. 就是通过简单的驱动的名称和设备的名称一致即可.(Linux内核很多都是这样实现的.)

点击(此处)折叠或打开

static int my_bus_match(struct device *dev, struct device_driver *drv)

{

struct my_device *device = to_my_device(dev);

PRINT("%s\n", __func__);

return !strncmp(device->name, drv->name, strlen(drv->name));

}

注册与卸载设备:

在 my_bus 上注册设备的过程, 就是将 my_device 结构体中 device 结构体进行赋值:

1. bus_type 成员设置为 my_bus_type

2. parent 设置为 my_bus.

3. release 函数设置为 my_bus_release.

然后调用 device_register 函数将 my_device 中的 device 结构加入到 Linux 设备驱动模型的管理中.

点击(此处)折叠或打开

int register_my_device(struct my_device *device)

{

PRINT("%s\n", __func__);

device->device.bus = &my_bus_type;

device->device.parent = &my_bus;

device->device.release = my_bus_release;

//strncpy(device->device.bus_id, device->name, BUS_ID_SIZE);

return device_register(&device->device);

}

EXPORT_SYMBOL(register_my_device);

卸载 my_bus 上的 my_device 过程:

1. 调用 device_unregister 函数将 my_device 中的 device 结构从 Linux 设备驱动模型中移除.

点击(此处)折叠或打开

void unregister_my_device(struct my_device *device)

{

PRINT("%s\n", __func__);

device_unregister(&device->device);

}

EXPORT_SYMBOL(unregister_my_device);

注册与卸载驱动:

在my_bus总线上注册驱动的过程, 也就是对 my_driver 中 device_driver 的处理过程.

1. 设置 device_driver 的成员 bus 为 my_bus_type.

2. 调用 driver_register 函数, 将 device_driver 添加到 Linux 设备驱动模型中管理.

点击(此处)折叠或打开

int register_my_driver(struct my_driver *driver)

{

int ret = 0;

PRINT("%s\n", __func__);

driver->driver.bus = &my_bus_type;

ret = driver_register(&driver->driver);

if (ret) {

PRINT("%s, driver_register %s failed!!!\n", __func__, driver->driver.name);

return ret;

}

driver->version_attr.attr.name = "version";

//driver->version_attr.attr.owner = driver->module;

driver->version_attr.attr.mode = S_IRUGO;

driver->version_attr.show = show_version;

return driver_create_file(&driver->driver, &driver->version_attr);

}

EXPORT_SYMBOL(register_my_driver);

在my_bus总线上卸载驱动的过程, 也是对 my_driver 中 device_driver 的处理过程.

1. 调用driver_unregister函数将 device_driver 从 Linux 设备驱动模型中移除.

点击(此处)折叠或打开

void unregister_my_driver(struct my_driver *driver)

{

PRINT("%s\n", __func__);

driver_unregister(&driver->driver);

}

EXPORT_SYMBOL(unregister_my_driver);

EXPORT_SYMBOL 是用来导出符号的. 用 EXPORT_SYMBOL 导出的符号, 其他模块也可以使用.

属性(Attribute)

在 Linux 设备驱动模型中, 总线, 设备, 驱动的特性, 都是通过属性这一工具来呈现在 sysfs 文件系统中. 导出到用户空间的.

1. 声明一个属性 bus_attr_version.

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);

在内核源码中, 会看到, BUS_ATTR 是一个宏, 基于 __ATTR 这个宏而来的, 只是在 __ATTR 宏的基础上, 赋予一些初值.BUS_ATTR 宏如下:

#define BUS_ATTR(_name, _mode, _show, _store)    \

struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)

其中:

_mode 是属性在 sysfs 中对应文件的访问权限.

_show 是读取 sysfs 中对应文件时调用的方法.

_store 是写 sysfs 中对应的文件触发的方法.

2. 将属性和bus_type挂接. 那么, Linux 设备驱动模型会在 sysfs 文件系统下生成对应的文件.

__________________________________________________________________________________________

下面是测试 my_bus 总线使用的 驱动和设备的代码.

我的设备 my_device.c

linux平台设备驱动模型是什么意思,Linux设备驱动模型之我理解相关推荐

  1. 爱可信携手Marvell展示爱可信Linux平台

    导读: 全球领先的无线数据解决方案提供商爱可信公司(ACCESS)(东京股票交易所4813)和Marvell公司 (纳斯达克股票代码: MRVL)近日宣布,双方携手共同向业界展示了运行于Marvell ...

  2. amd 显卡 linux驱动程序,狂追NV AMD发布新版Linux开源显卡驱动

    AMD终于正式发布了新版Linux系统开源显卡驱动程序,支持Tonga.Carrizo.Iceland.Fiji以及Stoney架构所有系列主流显卡,有望进一步追赶Nvidia在Linux平台上的脚步 ...

  3. amd显卡测试软件linux,狂追Nvidia:AMD发布新版Linux开源显卡驱动

    IT之家讯 11月23日消息,AMD今天终于正式发布了新版Linux系统开源显卡驱动程序,支持Tonga.Carrizo.Iceland.Fiji以及Stoney架构所有系列主流显卡,有望进一步追赶N ...

  4. linux平台学x86汇编语言学习集合帖

    linux平台学x86汇编语言学习集合帖 linux平台学x86汇编(一):https://blog.csdn.net/shallnet/article/details/45543237 linux平 ...

  5. linux java平台,如何下载和安装用于 Linux 平台的 Java

    本文适用于: 平台: Red Hat Linux, SUSE Linux, Oracle Linux, Oracle Enterprise Linux, SLES Linux 系统要求 请参阅受支持的 ...

  6. 花旗linux 内核 如何调试,揭秘首个运行在Linux平台的核心银行系统

    上个星期社区进行了一场直播,关于"新一代核心银行系统解决方案CBOD"--首个运行在Linux平台的核心银行系统. 国外上线Linux核心系统的银行已经不少,例如花旗银行在主机系统 ...

  7. Unity3D下Linux平台播放RTSP或RTMP流

    背景 尽管Windows平台有诸多优势,Linux平台的发展还是势不可挡,特别实在传统行业,然而Linux生态构建,总是差点意思,特别是有些常用的组件,本文基于已有的Linux平台RTSP.RTMP播 ...

  8. Linux平台网络配置-----C语言

    上一期我们已经介绍了VM虚拟机安装CentOS 7系统的步骤过程,这次就来看看使用Linux对初学者有什么障碍? 零基础学习C语言---Linux平台配置网络 用VM虚拟机启动Linux系统时出现的问 ...

  9. Linux平台总线驱动设备模型

    platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.Linux 2.6的设备驱动模型中,把I2C.RTC.LCD等都归纳为pl ...

  10. 支持驱动最好的linux软件,Linux平台设备和驱动

    一 platform总线 一个现实的linux设备驱动通常需要挂接在一种总线上,对于本身依附于PCI,USB,IIC,SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SOC系统中集成的独立的 ...

最新文章

  1. 黄仁勋回应放弃收购Arm:公司战略并没有太大改变
  2. 《WCF技术剖析(卷2)》目录
  3. boost::graph::distributed用法的测试程序
  4. FileReader/FileWriter复制文件
  5. ORACLE将查询字段指定为某种类型
  6. lucene分词器与搜索
  7. 几个性能测试工具/框架的比较
  8. rest-framework解析器,url控制,分页,响应器,渲染器,版本控制
  9. 2.CND技术详解---CDN技术概述
  10. ArcGIS修改矢量边界(土地利用图图斑)
  11. 认识 Arduino 开发板
  12. 视觉slam十四讲 学习笔记-3(李群和李代数)
  13. 程序设计与算法郭炜老师的课堂笔记2
  14. 谷歌PR风采依旧 推动网络推广产业链
  15. Python基础 实例
  16. 攻防世界PWN之house_of_grey题解
  17. 微信分享会根据分享的不同,为原始链接拼接如下参数
  18. 【服务通信自定义srv调用3----客户端的优化】
  19. Unity3D开发(编程)小技巧之二:文字如打字机效果逐字出现
  20. 如何尽快找到近期要召开的相关国际会议?

热门文章

  1. python导入excel模块_python如何导入excel
  2. uwsgi --http :8888 --wsgi-file test.py(无法部署)
  3. 超级硬盘数据恢复软件v2.7.2.6_电脑磁盘上的视频误删如何恢复?误删视频恢复教程...
  4. atlas mysql 安装_atlas中间件安装配置
  5. 依赖反转原理,IoC容器和依赖注入:第1部分
  6. 自清洁集合和自清洁事件
  7. 使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)——第2部分
  8. ASP.NET MVC 中解决Session,Cookie等依赖的方式
  9. Python 3 - 如何下载视图和保存证书
  10. 单位阶跃信号是周期信号吗_vivoS7e是5G手机吗-支持5G吗-5G信号怎么样