初涉 linux 驱动开发,路漫漫其修远兮

1. 实例:usbmouse.c

1.1 下载 linux 源码包

从 linux 内核源码中学习个人认为会是比较快入门的一种方法。
第一步就是获取源码包,有两个途径:

  • 官网下载:https://www.kernel.org/
  • 阿里云镜像:https://mirrors.aliyun.com/linux-kernel/

官网上面提供了最新的 linux 源码,可以网页下载,或使用 git 工具获取。鉴于国内网络的特殊性,连接外网速度比较慢的,所以我推荐使用阿里云镜像的方法来获取 linux 源码。Linux 内核版本命名规则偶数表示稳定版,为了研究方便我下载的是 2.6.14 版本。下载回来之后进行解压:

$ tar -xvf linux-2.6.14.tar.xz

如果出现 bash: xz: command not found 提示,安装 xz 工具即可解决:

$ sudo apt-get install -y xz-utils

解压之后打开 linux-2.6.14/drivers/usb/input/usbmouse.c 文件,接下来我们就一起来 hack 一下 linux 驱动开发。

延伸阅读:xz 是一种压缩文件格式,采用 LZMA SDK 压缩,目标文件较 gzip 压缩文件 .gz 或 ·tgz 小 30%,较 ·bz2 小 15%。xz 官网

1.2 基本框架

一个 Linux USB 设备驱动的基本框架包括了:初始化模块、卸载模块、probe 函数、disconnect 函数、设备 ID 表。

初始化/卸载模块

linux 驱动使用 module_init 函数来初始化一个设备模块,使用 module_exit 来卸载模块,这两个函数分别给 insmodrmmod 指令所使用。

static int __init usb_mouse_init(void)
{int retval = usb_register(&usb_mouse_driver);if (retval == 0)info(DRIVER_VERSION ":" DRIVER_DESC)return retval;
}static void __exit usb_mouse_exit(void)
{usb_deregister(&usb_mouse_driver);
}module_init(usb_mouse_init);
module_exit(usb_mouse_exit);

源码中的 DRIVER_VERSIONDRIVER_DESC 为局部宏定义:

#define DRIVER_VERSION "v1.6"
#define DRIVER_DESC "USB HID Boot Protocol mouse driver"

usb_mouse_init 函数负责驱动装载,usb_mouse_exit 函数负责驱动卸载时的指令动作,核心函数:

  • usb_register
  • usb_deregister

以上两个函数定义在 drivers/usb/core/usb.c 文件中

/* drivers/usb/core/usb.c */
int usb_register(struct usb_driver *new_driver);
void usb_deregister(struct usb_driver *driver);

源码中的 usb_mouse_driver 定义为:

static struct usb_driver usb_mouse_driver = {.owner      = THIS_MODULE,.name       = "usbmouse",.probe      = usb_mouse_probe,.disconnect = usb_mouse_disconnect,.id_table   = usb_mouse_id_table,
};

从代码看来,usb_mouse_driver 需要初始化五个字段:

name member value
模块的所有者 .owner THIS_MODULE
模块名称 .name “usbmouse”
probe 函数 .probe usb_mouse_probe
disconnect 函数 .disconnect usb_mouse_disconnect
id 表 .id_table usb_mouse_id_table

结构体 struct usb_driver 定义参见 include/linux/usb.h 文件:

/* include/linux/usb.h */
struct usb_driver {struct module *owner;const char *name;int (*probe) (struct usb_interface *intf, const struct usb_device_id *id);void (*disconnect) (struct usb_interface *intf);int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);int (*suspend) (struct usb_interface *intf, pm_message_t message);int (*resume) (struct usb_interface *intf);const struct usb_device_id *id_table;struct device_driver driver;
};

此处可见 struct usb_driver 结构体中还包括了 .ioctl, .suspend, .resume.driver 的成员。现在暂时放下 struct usb_driver 结构体不说,我们来看看 usb_mouse_driver 中的 .id_table 值。

id_table

在这里面,代码定义了 usb_mouse_id_table ID 表,首先看下其定义:

static struct usb_device_id usb_mouse_id_table [] = {{ USB_INTERFACE_INFO(3, 1, 2) },{ }                     /* Terminating entry */
};MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);

struct usb_device_id 结构体提供了一列不同类型的该驱动程序能够支持的 USB 设备。USB 核心使用该列表来判断对于一个设备该使用哪一个驱动程序,热插拔脚本使用它来确定当一个特定的设备插入到系统时该自动装载哪一个驱动程序。——《Linux 设备驱动程序》

struct usb_device_id 结构体定义于 include/linux/mod_devicetable.h 文件中,包括下列字段:

  • __u16 match_flags
    确定设备和结体体中下列字段中的哪一个相匹配。
  • __u16 idVendor
    设备的 USB 制造商 ID,该编号是由 USB 论坛指派给其成员的,不会由其他人指定。
  • __u16 idProduct
    设备的 USB 产品 ID,所有指派了制造商 ID 的制造商都可以随意地赋予其产品 ID
  • __u16 bcdDevice_lo
  • __u16 bcdDevice_hi
    定义了制造商指派的产品的版本号范围的最低和最高值。
  • __u8 bDeviceClass
  • __u8 bDeviceSubClass
  • __u8 bDeviceProtocol
    分别定义设备的类型、子类型和协议。这些编号由 USB 论坛指派,定义在 USB 规范中。
  • __u8 bInterfaceClass
  • __u8 bInterfaceSubClass
  • __u8 bInterfaceProtocol
    和上述设备特定的值很类似,这些值分别定义类型、子类型和单个接口的协议。这些编号由 USB 论坛指派,定义在 USB 规范中。
  • kernel_ulong_t driver_info
    该值不是用来比较是否匹配的,不过它包含了驱动程序在 USB 驱动程序的探测回调函数中可以用来区分不同设备的信息。

USB_INTERFACE_INFO 宏定义用于创建一个匹配特定接口类的 struct usb_device_id, 鼠标设备遵循 USB 人机接口设备 (HID),在 HID 规范中规定鼠标接口类码为:

  • 接口类 (InterfaceClass): 0x03
  • 接口子类 (InterfaceSubClass): 0x01
  • 接口协议 (InterfaceProtocol): 0x02

这样分类的好处是设备厂商可以直接利用规范中所定义的标准的驱动程序,而无需为每个设备编写特定的驱动程序。

对于 PC 驱动程序,MODULE_DEVICE_TABLE 宏是必需的,以允许用户空间的工具判断出该驱动程序可以控制什么设备。但是对于 USB 驱动程序来说,字符串 usb 必须是该宏中的第一个值。

对于 PCI 设备来说,include/linux/usb.h 头文件中定义了四个用来初始化 struct usb_device_id 结构体的宏:

  • USB_DEVICE (vid, pid)
  • USB_DEVICE_VER (vid, pid, lo, hi)
  • USB_DEVICE_INFO (class, subclass, protocol)
  • USB_INTERFACE_INFO (class, subclass, protocol)

如果针对特定芯片的驱动程序编程,使用 USB_DEVICE 应该更频繁一些,比如 ThinkPad E430 蓝牙驱动 BCM43142A0 一文便使用了 USB_DEVICE 宏与 .driver_info 来区分不同的设备信息。源代码可参考 linux 3.13 内核源码 linux-3.13.0/drivers/bluetooth/btusb.c 文件,也可直接从上面的链接处获取具体细节信息。

/* Broadcom BCM43142A0 */
{ USB_DEVICE(0x04ca, 0x2007), .driver_info = BTUSB_BCM_PATCHRAM },
{ USB_DEVICE(0x105b, 0xe065), .driver_info = BTUSB_BCM_PATCHRAM },

探测函数 _probe

参考资料:

[1] ThinkPad E430 蓝牙驱动 BCM43142A0
[2] Linux USB 驱动开发实例(二)—— USB 鼠标驱动注解及测试

Linux 驱动开发研究相关推荐

  1. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  2. Linux驱动开发环境配置(内核源码树构造)

    来源:季义钦BLOG 作者:季义钦 初次接触Linux驱动程序开发,买了一本<Linux设备驱动程序>,第一件事当然就是构建开发环境了!!! 它上面有一个Hello World的列子: / ...

  3. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之设备树模型

    文章目录 前言 1.设备树的作用 2.设备树的语法 2.1.设备树的逻辑图和dts文件.dtb文件 2.1.1.1Devicetree格式 1DTS文件的格式 node的格式 properties的格 ...

  4. 嵌入式 Linux 驱动开发你想知道的都在这

    最近看到公众号上写的一篇文章,关于嵌入式 Linux 驱动开发的方方面面,感觉提供不错,此处特意贴出来供大家参考借鉴. 1.嵌入式驱动开发到底学什么 嵌入式大体分为以下四个方向: 嵌入式硬件开发:熟悉 ...

  5. Linux驱动开发概述

    第 1 章 Linux驱动开发概述 设备驱动程序是计算机硬件与应用程序的接口,是软件系统与硬件系统沟通的桥梁.如果没有设备驱动程序,那么硬件设备就只是一堆废铁,没有什么功能.本章将对Linux驱动开发 ...

  6. 如何学习Linux驱动开发?

    原文链接:https://blog.csdn.net/hwunion/article/details/41621655 Linux驱动开发,看起来是一份很高大上的职业,毕竟从事上层应用开发人员太多,而 ...

  7. 华清远见嵌入式Linux驱动开发培训班

    课程背景 开放的 Linux 受到广泛的欢迎,得到越来越多公司的支持,但是阻碍 Linux 在各个领域广泛应用的主要因素就是内核/驱动高端人才极度缺乏,Linux源代码中85%是设备驱动,嵌入式系统中 ...

  8. linux内核培训广州,嵌入式Linux驱动开发高级培训班-华清远见嵌入式培训中心

    课程目标 本课程以案例教学为主,系统地介绍Linux下有关FrameBuffer.MMC卡.USB设备的驱动程序开发.参加本课程学习的学员,因为具备了Linux设备驱动开发基础,所以本课程针对性较强, ...

  9. 【正点原子Linux连载】第三十八章 根文件系统构建 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

最新文章

  1. 分布式存储系统的关键技术-存储层级内的优化技术
  2. 信息学奥赛一本通_长乐一中老师演绎“奥赛传奇”
  3. dependencies与devDependencies的区别
  4. java计算字符串中字符出现的次数_java – 计算字符串中字符出现次数
  5. java代码编写的文本特征提取_Test1 java语言写的特征提取源代码,有搞文字识别的可以下载一看,简单易学 Develop 274万源代码下载- www.pudn.com...
  6. IDEA工具开发必备设置-极大提高开发效率
  7. Netty之Bootstrap详解
  8. 外媒:苹果公司将在美国为其“苹果汽车”生产电池
  9. ECS中的Entity实体
  10. Nginx学习总结(4)——负载均衡session会话保持方法
  11. 软件项目开发文档模板
  12. 纪念feedsky彻底成为广告公司
  13. 分切机设备的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  14. UninstallPKG for Mac(PKG文件卸载)
  15. HDU 6608 Fansblog——————大素数检测
  16. mysql中数据发生变化时判断_MySql插入记录时判断
  17. 信息收集详情(高能集锦)
  18. Elasticsearch进阶笔记
  19. VintaSoft Twain.NET SDK,实现扫描文档
  20. 《Android开发艺术探索》读书笔记

热门文章

  1. 一张贴纸欺骗AI,对抗性补丁让人类隐身
  2. AI技术升级,景联文科技助力扫地机器人行业加快技术迭代,提供数据采集服务
  3. 移动端浮层scroll时,禁止后面的网页也scroll的解决方法
  4. 文献中常见的表格(三线表)制作
  5. 光流测速和视觉里程计
  6. Linux和windows之间实现文件的粘贴复制
  7. Linux安装防火墙学习
  8. 基于JAVA高校共享机房管理系统的设计与实现计算机毕业设计源码+系统+数据库+lw文档+部署
  9. react页面渲染之前_react 渲染顺序
  10. 基于android的通讯录,基于Android的通讯录管理系统.doc