前面一篇文章Linux kernel: USB driver编写入门(一)介绍了一个最简单的USB驱动的最基本框架,本文将加入probe和disconnect函数,用于响应该设备插入和拔出。

继续在那个目录下$vim usb_test_drv.c,加入如下代码:

static int usb_drv_probe(struct usb_interface *interface, const struct usb_device_id *id)
{struct usb_host_interface *interface_desc;int ret;interface_desc = interface->cur_altsetting;printk(KERN_INFO "USB info %d now probed: (%04x:%04x)\n", interface_desc->desc.bInterfaceNumber, id->idVendor, id->idProduct);printk(KERN_INFO "ID->bNumEndpoints:%02x\n", interface_desc->desc.bNumEndpoints);printk(KERN_INFO "ID->bInterfaceClass:%02x\n", interface_desc->desc.bInterfaceClass);ret = usb_register_dev(interface,&usb_cd);if(ret){printk(KERN_INFO "usb_register_dev erro: %d\n", ret);}else{printk(KERN_INFO "Minor number = %d\n", interface->minor);}return ret;}static void usb_drv_disconnect(struct usb_interface *interface)
{printk(KERN_INFO "Disconneced and Release the MINOR number %d\n", interface->minor);usb_deregister_dev(interface, &usb_cd);
}static struct usb_driver usb_drv_struct={.name = "Actions USB Driver",.probe = usb_drv_probe,.disconnect = usb_drv_disconnect,.id_table = usb_drv_table
};

注意,这里引用了usb_cd,需要在文件前面加上该变量的声明。

static struct usb_class_driver usb_cd;

保存后,在当前目录下make. 如果没有出错,则加载该模块(命令同(一)),加载成功后,运行$lsmod | grep usb 和 $dmesg | tail来验证已经加载。

这时候,插入文(一)中的USB设备。注意,如果在Linux主机运行期间,已经插入过该设备。则需要重新启动Linux主机,因为Linux已有Kernel的驱动已经对该设备进行了一系列处理,会和我们新写的driver相冲突。

dmesg | tail -n 20
[  241.357953] Register the usb driver with the usb subsystem
[  241.358000] usbcore: registered new interface driver Actions USB Driver
[  282.289547] usb 2-4: new high-speed USB device number 4 using xhci_hcd
[  282.438387] usb 2-4: New USB device found, idVendor=10d6, idProduct=1101, bcdDevice= 1.00
[  282.438400] usb 2-4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  282.438406] usb 2-4: Product: USB CARDREADER
[  282.438411] usb 2-4: Manufacturer: ACTIONS
[  282.438415] usb 2-4: SerialNumber: ㉕捤稰眷㕳愳㤷湲
[  282.441394] USB info 0 now probed: (10d6:1101)
[  282.441406] ID->bNumEndpoints:02
[  282.441411] ID->bInterfaceClass:08
[  282.441416] usb_register_dev erro: -22
[  282.441423] Actions USB Driver: probe of 2-4:1.0 failed with error -22
[  282.519352] usb-storage 2-4:1.0: USB Mass Storage device detected
[  282.519600] scsi host4: usb-storage 2-4:1.0
[  282.519755] usbcore: registered new interface driver usb-storage
[  283.533961] scsi 4:0:0:0: Direct-Access     ACTIONS  USB DISK FOB 2.0 0    PQ: 0 ANSI: 0 CCS
[  283.534475] sd 4:0:0:0: Attached scsi generic sg1 type 0
[  283.534848] sd 4:0:0:0: [sdb] Media removed, stopped polling
[  283.535920] sd 4:0:0:0: [sdb] Attached SCSI removable disk

之所以这次用了tail -n 20是因为消息比较多,很多是Linux kernel自带驱动识别该设备后触发的消息。橙色背景的是probe函数被调用打印的消息。大家自己结合程序去查看。

usb_register_dev erro: -22返回错误信息,usb_register_dev这个函数没有在我们自己写的程序中调用,但是make通过没有报错,说明这个函数必然是在Linux kernel中定义了。从#include的头文件里,我们看到#include <linux/usb.h>。那么几乎可以肯定,usb_register_dev这个函数在这个头文件里声明了。

于是找到这个文件,

$ find ~/stable_rc/linux-5.19.0/ -wholename */linux/usb.h
/home/minipc/stable_rc/linux-5.19.0/include/linux/usb.h

这里选项用-wholename是因为有路径名称,因为linux目录不是直接在~/stable_rc/linux-5.19.0/(kernel源文件根目录)下,所以前面有*。在该文件中查找该函数声明:

$ grep usb_register_dev /home/minipc/stable_rc/linux-5.19.0/include/linux/usb.h
 *      number from the USB core by calling usb_register_dev().
 * This structure is used for the usb_register_dev() and
extern int usb_register_device_driver(struct usb_device_driver *,
extern int usb_register_dev(struct usb_interface *intf,

最后一行即是:int usb_register_dev(struct usb_interface *intf,

之所以要找到函数原型,是为了后面查找定义更加方便,因为usb_register_dev的函数调用有很多。光有函数名称不够,还要有后面的参数定义就会更精准。

查找定义这个函数的文件。为减少搜索量,我们先在Linux kernel 源文件的根目录查找。

$find ~/stable_rc/linux-5.19.0/ -name usb
/home/minipc/stable_rc/linux-5.19.0/usr/include/linux/usb
/home/minipc/stable_rc/linux-5.19.0/tools/usb
/home/minipc/stable_rc/linux-5.19.0/tools/testing/selftests/drivers/usb
/home/minipc/stable_rc/linux-5.19.0/sound/usb
/home/minipc/stable_rc/linux-5.19.0/drivers/usb
/home/minipc/stable_rc/linux-5.19.0/drivers/media/usb
/home/minipc/stable_rc/linux-5.19.0/drivers/media/cec/usb
/home/minipc/stable_rc/linux-5.19.0/drivers/net/usb
/home/minipc/stable_rc/linux-5.19.0/drivers/net/can/usb
/home/minipc/stable_rc/linux-5.19.0/include/dt-bindings/usb
/home/minipc/stable_rc/linux-5.19.0/include/uapi/linux/usb
/home/minipc/stable_rc/linux-5.19.0/include/linux/usb
/home/minipc/stable_rc/linux-5.19.0/Documentation/usb
/home/minipc/stable_rc/linux-5.19.0/Documentation/devicetree/bindings/usb
/home/minipc/stable_rc/linux-5.19.0/Documentation/output/usb
/home/minipc/stable_rc/linux-5.19.0/Documentation/output/_sources/usb
/home/minipc/stable_rc/linux-5.19.0/Documentation/output/_sources/driver-api/usb
/home/minipc/stable_rc/linux-5.19.0/Documentation/output/.doctrees/usb
/home/minipc/stable_rc/linux-5.19.0/Documentation/output/.doctrees/driver-api/usb
/home/minipc/stable_rc/linux-5.19.0/Documentation/output/driver-api/usb
/home/minipc/stable_rc/linux-5.19.0/Documentation/driver-api/usb

从名称来看,我们先从 /home/minipc/stable_rc/linux-5.19.0/drivers/usb 文件夹里查找。

$ grep "usb_register_dev(struct" /home/minipc/stable_rc/linux-5.19.0/drivers/usb -r --include=*.c
/home/minipc/stable_rc/linux-5.19.0/drivers/usb/core/file.c:int usb_register_dev(struct usb_interface *intf,

这里为了更精确查找,字段选择"usb_register_dev(struct",其中struct是关键字,那么就排除了函数调用。其中--include=*.c,表示只从.c文件中选取。我们找到了函数定义文件usb/core/file.c.

打开该文件,可以找到该函数的定义:

int usb_register_dev(struct usb_interface *intf,struct usb_class_driver *class_driver)
{int retval;int minor_base = class_driver->minor_base;int minor;char name[20];#ifdef CONFIG_USB_DYNAMIC_MINORS/** We don't care what the device tries to start at, we want to start* at zero to pack the devices into the smallest available space with* no holes in the minor range.*/minor_base = 0;
#endifif (class_driver->fops == NULL)return -EINVAL;if (intf->minor >= 0)return -EADDRINUSE;mutex_lock(&init_usb_class_mutex);retval = init_usb_class();mutex_unlock(&init_usb_class_mutex);if (retval)return retval;dev_dbg(&intf->dev, "looking for a minor, starting at %d\n", minor_base);down_write(&minor_rwsem);for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {if (usb_minors[minor])continue;usb_minors[minor] = class_driver->fops;intf->minor = minor;break;}if (intf->minor < 0) {up_write(&minor_rwsem);return -EXFULL;}/* create a usb class device for this usb interface */snprintf(name, sizeof(name), class_driver->name, minor - minor_base);intf->usb_dev = device_create(usb_class->class, &intf->dev,MKDEV(USB_MAJOR, minor), class_driver,"%s", kbasename(name));if (IS_ERR(intf->usb_dev)) {usb_minors[minor] = NULL;intf->minor = -1;retval = PTR_ERR(intf->usb_dev);}up_write(&minor_rwsem);return retval;
}
EXPORT_SYMBOL_GPL(usb_register_dev);

从这个函数的定义里可以看到,

if (class_driver->fops == NULL)return -EINVAL;
if (intf->minor >= 0)return -EADDRINUSE;

这个EINVAL在include的头文件里<linux/errno.h>和<linux/usb.h>里都没有,所以要在原文件里查找它的定义

$ grep "^#define\s\+EINVAL" /home/minipc/stable_rc/linux-5.19.0/drivers/usb -r --include=*.h

这里使用了正则表达式,简单解释一下,^表示以这个开头,\s表示你空格,\+表示前面的字符有1个或多个。

结果输出为空,表明不在这个目录下,更换搜索目录为/home/minipc/stable_rc/linux-5.19.0/include/, 因为.h文件大部分都在这个目录下。

$ grep "^#define\s\+EINVAL" /home/minipc/stable_rc/linux-5.19.0/include/ -r --include=*.h
/home/minipc/stable_rc/linux-5.19.0/include/uapi/asm-generic/errno-base.h:#define       EINVAL          22      /* Invalid argument */

发现-EINVAL正好是erro: -22。说明程序在下面一步就出错退出了:

if (class_driver->fops == NULL)return -EINVAL;

这里的class_driver->fops就是在usb_drv_probe函数定义中的调用usb_register_dev

ret = usb_register_dev(interface,&usb_cd);

时的输入参数&usb_cd->fops,而在usb_test_drv.c文件中,usb_cd仅仅声明了

static struct usb_class_driver usb_cd;

没有定义。那么它内部的指针fops就缺省为空了。struct usb_class_driver的定义可以在<linux/usb.h>文件中找到。

struct usb_class_driver {char *name;char *(*devnode)(struct device *dev, umode_t *mode);const struct file_operations *fops;int minor_base;
};

下面一篇文章​​​​​​​Linux kernel: USB driver编写入门(三),我们将讲到如何对usb_cd变量进行赋值。

Linux kernel: USB driver编写入门(二)相关推荐

  1. linux下usb驱动编写

    linux下usb驱动编写(内核2.4)--2.6与此接口有区别2006-09-15 14:57我们知道了在Linux下如何去使用一些最常见的USB设备.但对于做系统设计的程序员来说,这是远远不够的, ...

  2. Linux 驱动USB键盘驱动入门demo

    1 需要内核配置文件禁用CONFIG_USB_HID,不然下面的驱动不会被探测到. 2 以下模块打印了8个控制按键是否被按下, 另外如果A按键按下,也会有打印. #include <linux/ ...

  3. Linux I2C设备驱动编写(二)

    I2C对外API I2C client的注册 i2c_register_board_info具体实现 i2c_new_device I2C driver 关于I2C设备驱动的小总结 I2C adapt ...

  4. I2C driver编写指导二:编写i2c client driver指南

    原文地址::http://blog.csdn.net/guoshaobei/archive/2010/06/08/5656001.aspx 译者:郭少悲 日期:2010/06/08 源文:linux- ...

  5. linux pci扫描链表,Linux Kernel ---- PCI Driver 分析

    自己笔记使用. Kernel 版本 4.15.0 (ubuntu 18.04,intel skylake) 最近想学习VGA驱动去了解 DDCCP / EDID 等协议,然后顺便了解下驱动是如何工作的 ...

  6. Linux Kernel - Debug Guide (Linux内核调试指南 )

    linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 ...

  7. 嵌入式Linux设备驱动程序:编写内核设备驱动程序

    嵌入式Linux设备驱动程序:编写内核设备驱动程序 Embedded Linux device drivers: Writing a kernel device driver 编写内核设备驱动程序 最 ...

  8. RISC-V Linux kernel debug 环境搭建

    目录 一.目的 二.准备工作 ①Build Ninja ②Build riscv-gnu-compiler toolchain and debug gdb ③命令行安装gcc-riscv64-linu ...

  9. linux驱动编写(usb host驱动入门)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] usb协议是一个复杂的协议,目前涉及到的版本就有usb1.0, usb2.0, usb3.0.大 ...

最新文章

  1. 安装esp8266库_基于ESP8266,DIY低成本智能远程开关灯小装置
  2. 自动化监控--zabbix中的show value详解
  3. mysql计算多少天后的日期_数据库 - mysql 计算某个时间,多少天后,多少个月后时间戳...
  4. AX2012 referencegroup
  5. JS Date格式化为yyyy-MM-dd类字符串
  6. 4015-基于递归的折半查找(C++)
  7. 目标检测之hough forest---霍夫森林(Hough Forest)目标检测算法
  8. python公式计算器_Python小白篇(二):Python计算器
  9. 关于@JsonView的使用心得及一些隐蔽的注意事项
  10. HTML5 怎么自定义字体
  11. 电脑时间校准方法,怎么校准电脑时间
  12. MSP430 G2553 Launchpad实现电容测量
  13. 相亲交友v6.7.7
  14. 可能是最全的:虚拟机使用失败解决方案汇总
  15. 【100%通过率】华为OD机试真题 Python 实现【核酸最快检测效率】【2022.11 Q4 新题】
  16. d3.js操作svg
  17. python新冠病毒COVID-19数据分析和数据可视化
  18. win10:mingw-w64安装教程
  19. Latex中编译时出现File `xxx.sty‘ not found.错误的解决方法
  20. 类Loopy是公共的, 应在名为 Loopy.java 的文件中声明

热门文章

  1. 最好用的数学神器Mathpix Snip-公式神器,只要截图就能识别公式,手写的公式都能识别
  2. c++工具库大全(值得收藏)
  3. 解决XAMPP中无法勾选/无服务/modules无反应/Service灰框/无✓X/提供虚拟服务器
  4. word2007 正文自动变为大纲一级 问题
  5. 有秒计时的数字时钟(10分)
  6. 【笔记整理 - 操作系统】(时间较早)
  7. 获取微信公众号图文封面图的方法
  8. PowerDesigner一键导入数据库所有表并画数据模型图
  9. 当今世界最牛的25位顶尖大数据科学家
  10. 堡垒机是什么,堡垒机的作用在哪里