注:本文转载自http://club.topsage.com/thread-1231567-1-1.html

笔者曾得到一个类似于加密“狗”的USB设备,要使之在Linux下正常工作。然而,通过一个名为USBView的小程序判断,Linux内核无 法驱动这个USB设备,并且在“Linux USB Working Devices”的列表中也没有找到该设备,这意味着只有很少的人在使用这种类型的 USB设备。
在Linux的/proc/bus/usb/devices文件中,有这个USB设备的一些信息:

T: Bus=01 Lev=02 Prnt=03 Port=02 Cnt=01 Dev#=4 Spd=1.5 MxCh=0
D: Ver=1.00 Cls=ff(vend.) Sub=00 Prot=ff MxPS=8 #Cfgs=1
P: Vendor=0d7a ProdID=0001 Rev=1.07
S: Manufacturer=Marx
S: Product=USB crypToken
C: * #Ifs=1 Cfg#=1 Atr=80 MxPwr=16mA
I: If#=0 Alt=0 #EPs=0 Cls=ff(vend.) Sub=00 Prot=ff Driver=(none)

通过查阅该USB设备产品光盘上提供的文档,可以简单了解这个USB设备的用途。产品光盘上还提供了一个共享库,应用程序可以通过共享库使用这个USB设备。此外,产品光盘还提供了一个小的测试程序来展示不同的库方法是如何工作的。通过这个共享库,使用者可以采用libusb方式直接访问该设备。也就是说,使用这个USB设备并不需要一个内核级的驱动。但是,这个共享库的授权协议不允许一个遵循GPL协议的程序来使用它。只有以上这些信息是无法把这个USB设备驱动起来的,下面就从追溯Linux上的USB数据流开始,给大家提供一种解决此类问题的思路。
解决方案
可以从最新的2.6版本的内核入手,解决此问题。2.6版本的内核可以通过很多种渠道得到,这里不做详述。
在内核源代码的结构树中的drivers/usb/core/目录下,有inode.c、devices.c和devio.c三个文件,这三个文件共同实现了usbfs 文件系统。也就是说,Linux是通过这三个文件访问USB设备的。实现文件系统的主要工作由inode.c完成,它提供多种VFS代码,用 这些代码可以创建虚拟文件系统或虚拟文件。devices.c文件用于创建和读取/proc/bus/usb/devices下表示USB设备状态信息的文 件。devio.c文件用于控制通过usbfs文件系统对USB设备的访问。要想使Linux能够访问USB设备,需要对devices.c和devio.c做些修改。
具体实现
1.记录访问信息
探索USB数据流从记录所有的USB设备访问信息开始。在用户程序中,通过usbfs访问USB设备需要在相应的设备文件上调用ioctl()命令。通过进一步分析devices.c文件,发现每次执行ioctl()时都会调用usbdev_ioctl()函数,因此,在这里记录发送给USB设备的访问信息应该是一个很好的解决方法。通过在每一个case语句中加入一个自定义的printk()函数,可以实现此功能,基本内容如下:

case USBDEVFS_CLAIMINTERFACE:
             printk("CLAIMINTERFACE");
             ret = proc_claiminterface(ps, (void __user *)arg);
             break;
case USBDEVFS_RELEASEINTERFACE:
             printk("RELEASEINTERFACE");
             ret = proc_releaseinterface(ps, (void __user *)arg);
             break;

经过编译、安装等过程后,每个usbfs访问都被记录在内核日志当中,通过dmesg命令可以访问这些日志记录。
2.记录控制信息
通过分析/proc/bus/usb/devices文件中对USB设备的描述,可以得知要最终解决问题必须关心这些访问的控制终点(Control Endp oint)。devio.c文件中的proc_control()函数是用来处理控制消息的。该函数通过如下语句区分请求访问的类型是读控制消息,还是写控制消息:

if (ctrl.bRequestType & 0x80)

bRequestType是一个二进制变量,其最高位决定请求的类型。
在处理读消息的代码段中加入如下代码,用以记录控制请求的信息:

printk("control read: "
"bRequest=%02x bRrequestType=%02x "
"wValue=%04x wIndex=%04x",
ctrl.bRequest, ctrl.bRequestType,
ctrl.wValue, ctrl.wIndex);

然后,再加入如下代码,用来记录从设备中读出的实际数据:

printk("control read: data ");
for (j = 0; j < ctrl.wLength; ++j)
printk("%02x ", ctrl.data[j]);
printk("");

同样,可以在处理写消息的代码段中加入类似的代码。这样以来,生成并重新装载新的usbcore模块后,就可以记录对设备的所有 双向控制消息了。这些消息可能会返回如下信息:

CONTROL
control read: bRequest=06 bRrequestType=80 wValue=0300 wIndex=0000
control read: data 00 00 61 63

3.优化
接下来要对修改代码做些优化,以使内核源代码很好地接受这些修改。首先,应该修正在printk()调用中的一些不正确的地方。其次,所有的printk()调用都应该有一个相应的日志级别(LoggingLevel),这些日志级别可以通过预处理的方式生成。将include /linux/kernel.h文件修改如下:

#define KERN_EMERG  "" /* system is unusable */
#define KERN_ALERT  "" /* action must be taken immediately */
#define KERN_CRIT   "" /* critical conditions */
#define KERN_ERR    "" /* error conditions */
#define KERN_WARNING "" /* warning conditions */
#define KERN_NOTICE "" /* normal but significant condition */
#define KERN_INFO   "" /* informational */
#define KERN_DEBUG  "" /* debug-level messages */

以上修改完成后,将usbfs_ioctl()函数中的printk()调用从“printk("CLAIMINTERFACE");”修改为“printk(KERN_INFO "CLAIMINTE RFACE);”。
实际上,并不是所有的消息都需要记录到日志中。可以采用头文件include/linux/device.h中所提供的宏(包括dev_printk()、de v_dbg()、dev_warn()、dev_info()和dev_err())来决定何种类型的USB设备访问消息需要被记录。这些宏都需要一个附加指针指向一个结构类型,以此标识惟一的设备ID。将dev_info()调用修改如下:

dev_info(&dev->dev, "CLAIMINTERFACE");

然后将确定读、写消息请求的printk()调用修改如下:

dev_info(&dev->dev, "control read: "
"bRequest=%02x bRrequestType=%02x "
"wValue=%04x wIndex=%04x",
ctrl.bRequest, ctrl.bRequestType,
ctrl.wValue, ctrl.wIndex);
dev_info(&dev->dev, "control read: data ");
for (j = 0; j < ctrl.wLength; ++j)
printk("%02x ", ctrl.data[j]);
printk("");

经过上述修改,得到如下返回信息:

usb 1-1: CONTROL
usb 1-1: control read: bRequest=06 bRrequestType=80 wValue=0300 wIndex=0000
usb 1-1: control read: data 00 00 61 63

不难看出,经过上述修改,清除掉了无关的USB设备的消息记录信息。
上述过程会产生一个易用性上的问题,即消息记录信息并不是在用户请求时刻产生的,这样会导致用户的消息记录过于庞大。在de vio.c文件中加入下面的代码行可以解决这一问题:

static int usbfs_snoop = 0;
module_param (usbfs_snoop, bool, S_IRUGO | S_IWUSR);
MODULE_Parm_DESC (usbfs_snoop, "true to log all usbfs traffic");

上述代码定义了一个新的module_param()函数,用来代替原来的MODULE_Parm()函数。两者之间的主要区别在于module_param()中含有一个新的参数“usbfs_snoop”。可以运行modinfo命令查看修改后的效果:

$ modinfo usbcore
license: GPL
parm: blinkenlights:true to cycle leds on hubs
parm: usbfs_snoop:true to log all usbfs traffic

正常的模块装载命令如下:

#modprobe usbcore

修改后,可以通过下面的命令装载模块:

#modprobe usbcore usbfs_snoop=1

当usbfs_snoop不为0时,它将会在sysfs中显示,并允许用户在模块被装载时查询和修改选项,其形式如下:

$ ls -l /sys/module/usbcore/
-r--r--r-- 1 root root 4096 May 13 15:33 blinkenlights
-r--r--r-- 1 root root 4096 May 13 15:33 refcnt
-rw-r--r-- 1 root root 4096 May 13 15:33 usbfs_snoop

如果想打开消息记录功能,可以进行如下操作:

#echo 1 > /sys/module/usbcore/usbfs_snoop

如果要确定用户是否想打开消息记录功能,还需对dev_info()进行更深一步修改,创建下述宏:

#define snoop(dev, format, arg...)
do {
      if (usbfs_snoop)
      dev_info( dev , format , ## arg);
} while (0)

这个宏用于测试参数usbfs_snoop的值,如果为“true”,则调用dev_info(dev , format , ##arg)。
接下来将先前调用dev_info()宏的地方改为调用snoop()宏:

snoop(&dev->dev, "control read: ","bRequest=%02x bRrequestType=%02x ","wValue=
%04x wIndex=%04x", ctrl.bRequest, ct rl.bRequestType,ctrl.wValue, ctrl.wIndex);

为了能正确打印数据,需对snoop()宏做简单修改(只需判断usbfs_snoop的值即可):

if (usbfs_snoop) {
dev_info(&dev->dev, "control read: data ");
for (j = 0; j < ctrl.wLength; ++j)
printk("%02x ", ctrl.data[j]);
printk("");

}

至此,修改工作完毕。这样,当通过libusb访问一个USB设备时,应该可以很好地得到usbfs的访问信息。

把脉Linux上USB数据流相关推荐

  1. debian linux上usb摄像头,debian linux 下面安装摄像头

    摄像头是天敏的minicom,硬件像素30万,插值像素48万.最大分辨率640x480. 安装驱动的过程如下: 软件包是spca5xx-source.这是source for the spca5xx ...

  2. linux grep命令详解_Linux 上USB 调试神器lsusb命令详解

    大家好, 我是吉阿, 今天给大家介绍Linux上USB调试工具lsusb命令. ​ USB,是英文Universal Serial Bus(通用串行总线)的缩写,是一个外部总线标准,早期用于规范电脑与 ...

  3. 制作linux usb安裝,如何在Linux上安装和使用Etcher来制作Linux临场USB

    Etcher 是一款流行的 USB 烧录应用,可用于创建可启动的 Linux USB.让我来告诉你如何安装它,以及如何使用它来制作一个 Linux 临场盘. Etcher:一个用于在 SD 卡和 US ...

  4. TL-WDN5200H无线usb网卡在Linux上的使用

    买了个TL-WDN5200H无线usb网卡,但是发现它居然不支持Linux,但是我有时需要在Linux上使用,这就尴尬了.于是到网上搜索资料,终于解决了这个问题. 首先编译安装:https://git ...

  5. linux4 sd卡驱动,在Linux上,如何格式化USB驱动器和SD卡

    在Linux中,你可以使用图形工具,如GParted或命令行工具,例如fdisk或parted,来格式化驱动器和分区. 在本教程中,向你展示如何使用Linux的parted工具格式化USB驱动器或SD ...

  6. linux图像化界面读取u盘,Linux上用的4种USB image程序:Etcher,Unetbootin,DD,MultiWriter

    本文介绍Linux上使用的4种最佳USB image应用程序,它们是:Etcher.Unetbootin.DD.GNOME MultiWriter. 1.Etcher Etcher是一款适用于Mac. ...

  7. EdgeX(7)使用usb ttl 链接 RX TX 调试,输出乱码问题解决,没有想到最后居然是没有焊好。可以使用cuteCom或者putty 在linux上进行界面查询日志

    目录 前言 1,usb ttl 转串口 2,linux 上使用 cuteCom查看日志 3,也可以使用 linux 版本的putty 4,总结 前言 相关EdgeX Foundry 全部分类: htt ...

  8. linux使用usb打印机驱动精灵,Qomo Linux上的“驱动精灵”

    明星编辑国人最爱Qomo新版发布 开创Linux驱动先河CBSi中国·ZOL 作者:中关村在线 涂兰敬 责任编辑:涂兰敬 [原创] 2012年04月02日 05:48 评论 不过,据了解,Qomo的& ...

  9. 基于Linux的USB 主/从设备之间通讯的三种方式

    转载:http://archive.eet-china.com/www.eet-china.com/ART_8800323770_617693_TA_eda530e7.HTM 随着简单易用的USB接口 ...

最新文章

  1. vue 02-上计算属性、样式的操作,指令(含自定义,全局和局部)
  2. Redis运行流程源码解析--转载
  3. 互联网公司败局汇总,这些公司都是怎么死的?(下篇)
  4. 嵌入式android pdf,Embedded Android 英文原版PDF
  5. 性能测试常用的软件有哪些,常用的正经CPU测试软件有哪些
  6. 手机能打开的表白代码_数据分析移动化:打开手机就能做分析
  7. 塔塔建网站服务器,塔塔帝国忘记哪个区怎么办
  8. 理查森外推法 matlab,数值代数–理查森外推法.doc
  9. UWP 流畅设计中的光照效果(容易的 RevealBorderBrush 和不那么容易的 RevealBackgroundBrush)...
  10. 10分钟搭建服务器集群——Windows7系统中nginx与IIS服务器搭建集群实现负载均衡...
  11. 【Qt串口调试助手】1.5 - 发送/接收字节数量统计
  12. 【辨异】relation, relationship
  13. BOOST库介绍(七)——时间处理相关的库
  14. NLP在医学领域的应用(更新中)
  15. iphone个系列尺寸_iphone各机型尺寸
  16. java写俄罗斯方块难吗_用JAVA写的俄罗斯方块
  17. 尚硅谷-SpringBoot1.5.9(已过时,直接学2)
  18. 2012网易校园招聘笔试题
  19. 上传大文件超时upstream timed out ,nginx配置修改
  20. proxmox ve 7.2 AMD显卡直通 网卡驱动 调度器

热门文章

  1. 第十五届全国大学生智能汽车竞赛室外光电组全国总决赛方案
  2. 腾讯视频会议使用测试
  3. 山东省2021年普通高考成绩录取去向查询,2018年山东高考录取去向查询时间及入口...
  4. 环境图配置不存在pbr_小米11再曝光,硬件参数不存在短板,完全最高旗舰配置...
  5. 柱坐标系下的ns方程_笛卡尔坐标系到底是什么?
  6. java 是否含有日文_《JAVA编程思想》5分钟速成:第9章(接口)
  7. java hashmap存取效率_HashMap为什么存取效率那么高?
  8. SCAPY pcap文件数据分析 python3
  9. c语言eof_C语言 技能提升 系列文章(十)错误处理
  10. 中小型网络系统总体规划与设计(Small and medium-sized network system overall planning and design)