usb总线驱动分析(针对使用)

USB总线设备驱动分析(使用)

USB驱动程序框架:

app:   
-------------------------------------------
          USB设备驱动程序      // 知道数据含义
内核 --------------------------------------
          USB总线驱动程序      // 1. 识别, 2. 找到匹配的设备驱动, 3. 提供USB读写函数 (它不知道数据含义)
-------------------------------------------
           USB主机控制器
           UHCI OHCI EHCI
硬件        -----------
              USB设备

UHCI: intel,     低速(1.5Mbps)/全速(12Mbps)
OHCI: microsoft  低速/全速
EHCI:            高速(480Mbps)

接上USB设备,内核打印信息

接上usbU盘后内核打印:

/*使用的是USB高速,148MB/s,设备号为3,使用的是echi*/
<6>[   51.848206] usb 1-1.1: new high speed USB device number 3 using s5p-ehci  
/*usb设备类型是:storage 存储设备  ,通过USB设备描述符得到的*/
<6>[   51.962050] scsi0 : usb-storage 1-1.1:1.0
<5>[   52.966223] scsi 0:0:0:0: Direct-Access     Generic  STORAGE DEVICE   0819 PQ: 0 ANSI: 6
<5>[   52.993741] sd 0:0:0:0: Attached scsi generic sg0 type 0
<5>[   53.237914] sd 0:0:0:0: [sda] 31116288 512-byte logical blocks: (15.9 GB/14.8 GiB)
<5>[   53.239028] sd 0:0:0:0: [sda] Write Protect is off
<7>[   53.239077] sd 0:0:0:0: [sda] Mode Sense: 23 00 00 00
<5>[   53.240191] sd 0:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
/* 映射到内核的分区的名字 */
<6>[   53.255055]  sda: sda1
<5>[   53.269893] sd 0:0:0:0: [sda] Attached SCSI removable disk

拔掉:

<6>[   98.756713] usb 1-1.1: USB disconnect, device number 3

再插:

<6>[  118.918368] usb 1-1.1: new high speed USB device number 4 using s5p-ehci
<6>[  119.013751] scsi1 : usb-storage 1-1.1:1.0
<5>[  120.016908] scsi 1:0:0:0: Direct-Access     Generic  STORAGE DEVICE   0819 PQ: 0 ANSI: 6
<5>[  120.022879] sd 1:0:0:0: Attached scsi generic sg0 type 0
<5>[  120.273979] sd 1:0:0:0: [sda] 31116288 512-byte logical blocks: (15.9 GB/14.8 GiB)
<5>[  120.274958] sd 1:0:0:0: [sda] Write Protect is off
<7>[  120.275006] sd 1:0:0:0: [sda] Mode Sense: 23 00 00 00
<5>[  120.275959] sd 1:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
<6>[  120.285008]  sda: sda1
<5>[  120.291078] sd 1:0:0:0: [sda] Attached SCSI removable disk

再拔:

<6>[  134.596681] usb 1-1.1: USB disconnect, device number 4

根据打印设想USB设备挂接逻辑

根据正常逻辑分析 USB总线驱动程序作用:
1、识别USB设备
1.1 分配地址 (0-127)
1.2 设置USB设备地址(set address)
1.3 发出命令获取USB描述符。
2、查找并安装对应的设备驱动程序
3、提供USB读写函数

其中1、是被USB的过程就是USB设备枚举的过程。

根据打印信息,追踪源码,逆推USB设备挂接过程

查找:USB device number 去源码中定位到发现usb设备的源码:

drivers/usb/core/hub.c:2878: “%s %s speed %sUSB device number %d using %s\n”,
hub_port_init

由此函数逆推函数调用过程:
从硬件中断开始:(drivers/usb/core/hub.c)

hub_irq
	kick_khubd
		hub_thread   //usb_hub_init中创建的线程,此函数在drivers/usb/core/usb.c中调用,usb总线驱动注册时建立的subsys_initcall(usb_init);
			hub_events
				hub_port_connect_change
                usb_alloc_dev(hdev, hdev->bus, port1);
                    dev->dev.bus = &usb_bus_type; //总线设备模型,usb总线。
                hub_port_init
                    hub_set_address //为usb分配一个设备地址
                    usb_get_device_descriptor(udev, 8); /*获取设备描述符,这里获取前8个。由USB设备描述符可知,前8个字节所有usb设备都是固定并且bMaxPacketSize0描述了总包的最大size。*/
                    usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); 
                usb_new_device(udev);
                    usb_enumerate_device(udev); // 读设备描述符
                    device_add(&udev->dev); //总线驱动设备模型,把设备挂到USB udev设备链表上。然后从总线driver链表里一一取出和device进行匹配,匹配成功后调用dirver的probe函数

USB主节点入口在/drivers/usb/core/usb.c中

subsys_initcall(usb_init);//系统总线
module_exit(usb_exit);

usb_init
    usb_hub_init
        usb_deregister(&hub_driver);
        kthread_run(hub_thread, NULL, "khubd");
    
    hub_probe
        hub_configure(hub, endpoint) 
            usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval);

USB设备描述符简要说明

在这里插入图片描述

这里还要说一下USB设备的描述符:
USB设备描述符包含多个配置描述符,配置描述符包含多个接口描述符,接口描述符包含多个端点描述符。
接口:逻辑上的设备,比如usb声卡 有两个接口分别是:播放、录音。每一个接口对应一个驱动程序。
端点:描述输入输出方向、数据类型、等。usb数据的交互都是端点和端点之间的交互。

附录:USB设备描述符。( include/linux/usb/ch9.h )

/* USB_DT_DEVICE: Device descriptor*/
struct usb_device_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;
	__le16 bcdUSB;
	__u8  bDeviceClass;
	__u8  bDeviceSubClass;
	__u8  bDeviceProtocol;
	__u8  bMaxPacketSize0;
	__le16 idVendor;
	__le16 idProduct;
	__le16 bcdDevice;
	__u8  iManufacturer;
	__u8  iProduct;
	__u8  iSerialNumber;
	__u8  bNumConfigurations;
} __attribute__ ((packed));

/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__u8  bInterfaceNumber;
	__u8  bAlternateSetting;
	__u8  bNumEndpoints;
	__u8  bInterfaceClass;
	__u8  bInterfaceSubClass;
	__u8  bInterfaceProtocol;
	__u8  iInterface;
} __attribute__ ((packed));

/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__u8  bEndpointAddress;
	__u8  bmAttributes;
	__le16 wMaxPacketSize;
	__u8  bInterval;

	/* NOTE:  these two are _only_ in audio endpoints. */
	/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
	__u8  bRefresh;
	__u8  bSynchAddress;
} __attribute__ ((packed));

由追踪源码总结usb设备驱动

usb总线驱动–>总线驱动模型

根据分析可以发现,usb是实体的总线设备驱动,platform模型。总线设备驱动模型把驱动分成两个部分:

1、设备部分(device)

通过usb_new_device建立usb_interface。每当有usb硬件中断来的时候,usb通过访问端点0设置usb地址和获取设备描述符,然后通过设备描述符描述的usb类型,实例化对应类型的usb_device挂到usb_bus的设备链表上。同时usb核心层会根据usb总线协议为usb_device数据读写功能。

注:“usb通过访问端点0设置usb地址和获取设备描述符”,此部分即为usb设备的枚举过程。细节复杂,有兴趣可以详细分析。

2、驱动部分(driver)

driver部分,此部分我会实例化一个代码来说明。

目标:
usb鼠标用作按键。

1.首先注册usb驱动模型
USB设备驱动程序步骤:
1、分配/设置usb_driver结构体
.id_table
.probe
.disconnect

//填写id_table,
static struct usb_device_id usbmouse_as_key_id_table[] = {
	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
		USB_INTERFACE_PROTOCOL_MOUSE) },
	{ }	/* Terminating entry */

};
static int usbmouse_as_key_probe (struct usb_interface *intf, const struct usb_device_id *id)
{
    //input模型
    
    //从usb主机控制器获取usb数据
}
static void usbmouse_as_key_disconnect (struct usb_interface *intf)
{
    //释放probe中申请的内存
    
    //卸载probe中注册的设备
}

注意usb_device_id,此结构体中描述的描述符会和usb设备枚举出来的interface通过usb总线驱动的mach函数进行匹配。
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
若匹配成功则调用,usb_driver结构体中的probe函数。
然后再去根据USB总线驱动读写函数的数据进行逻辑操作,这些逻辑操作都是在usb设备驱动中实现。比如我们的input_event来上报鼠标传来的按键值。

2、注册

//实现usb_driver
static struct usb_driver usbmouse_as_key_driver = {
	.name		= "usbmouse",
	.probe		= usbmouse_as_key_probe,
	.disconnect	= usbmouse_as_key_disconnect,
	.id_table	= usbmouse_as_key_id_table,
};

//module入口函数
static int usbmouse_as_key_init(void)
{
    //注册usb_driver
	int retval = usb_register(&usbmouse_as_key_driver);
	if (retval != 0)
		printk("register usbmouse_as_key driver failed! \n");

	return retval;
}
//出口函数
static void usbmouse_as_key_exit(void)
{
	usb_deregister(&usbmouse_as_key_driver);
}

注册部分,调用usb_register函数来注册实例化的usb_dirver。
当销毁此driver时,调用usb_deregister函数来销毁。

2.作为按键,即是input设备,所以搞个input模型
input设备主要步骤:
1、分配input_dev结构体
2、设置
3、注册
4、硬件操作

此部分内容在probe中实现

//全局变量uk_dev
static struct input_dev *uk_dev;
    /*1、分配一个input_dev*/
    uk_dev = input_allocate_device();
    /*2、设置*/
    /*2.1、能产生那类事件*/
    set_bit(EV_KEY, uk_dev->evbit);
    set_bit(EV_PWR, uk_dev->evbit);
    /*2.1、能产生哪些事件*/
    set_bit(KEY_L, uk_dev->keybit);
    set_bit(KEY_S, uk_dev->keybit);
    set_bit(KEY_ENTER, uk_dev->keybit);
    /*3、注册*/
    input_register_device(uk_dev);
    
    /*4、硬件相关操作*/
    //硬件操作部分用于从usb总线驱动获取

说明:此部分为注册一个input device,类型为ev_key,注册后会通过input子系统与evdev handler进行绑定。从而注册输入设备。

3.然后再input模型中的硬件操作中填入usb获取数据的方法

    //interface描述符
    interface = intf->cur_altsetting;
    //获取端点描述符
    endpoint = &interface->endpoint[0].desc;

    /*数据传输3要素*/
    /*源:USB设备的某个端点*/
    //usb设备每一个端点和端点之前都有一个通道,此通道用于两端点之间的通讯。
    pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

    /*长度*/
    //端点最大包长度
    len = endpoint->wMaxPacketSize;
    
    /*目的 */
    //我们后面会对usb_buf里面包含的数据,进行解析
    usb_buf = usb_alloc_coherent(dev, len, GFP_ATOMIC, &usb_buf_phys);

    /*使用3要素*/
    /*分配usb request block*/
    uk_urb = usb_alloc_urb(0, GFP_KERNEL);
    /*使用3要素设置urb usb请求块,设备,源,目的,                 长度    完成函数                       usb控制器查询频率  */  
    //usb设备没有中断能力,但是usb主机控制器有中断能力,当usb主机查询到usb设备有数据时会中断主机,从而调用usbmouse_as_key_irq
	usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_as_key_irq, NULL, endpoint->bInterval);
    //usb请求块的物理地址
	uk_urb->transfer_dma = usb_buf_phys;
	uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

    /*使用urb*/
    //告诉usb总线驱动,此urb可以使用
    usb_submit_urb(uk_urb, GFP_KERNEL);

此部分主要是通过usb总线驱动获取usb设备的数据。通过数据传输三要素,进行设置数据流向,然后通过申请并填充urb来获取数据。

到此就结束了,本文只是粗略的介绍了usb控制器驱动在插上usb之后的过程,没有具体介绍usb数据传输过程,此过程可以通过usb抓包工具,抓取usb总线数据包并结合驱动分析。

总的来看,usb设备驱动仍是总线驱动模型的一种实例化。device部分由usb核心层(usb主机控制器驱动)通过枚举usb设备的接口描述符来实现。driver部分就需要由开发者实现,此部分主要涉及逻辑功能

本文涉及的usb driver部分的源码:
https://github.com/cshang983255766/friendlyArm-linux3.0.8/tree/master/drivers/usb_driver

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Peak LIN USB驱动是一种用于连接汽车LIN总线设备驱动程序。它是在Peak公司的Lin USB分析仪(LIN-USB)中使用的,它允许用户轻松地与LIN总线进行通信并监视来自机车的数据。该驱动程序包含在Peak LIN USB分析仪的软件包中,用户可以在安装设备使用其自带的线缆将其与汽车的LIN总线连接。驱动程序和软件包是适用于Windows操作系统的。驱动程序可以轻松地安装,并且具有友好的用户界面,用户可以理解和操作。当驱动程序和软件包最终安装后,您将能够查看LIN总线上所有节点和信息的实时数据流。Peak LIN USB驱动具有高可靠性,高精度,高安全性和高速度,并且非常适用于汽车制造商和服务工程师之间的通信和故障排除。与其他LIN总线连接设备相比,Peak LIN USB分析仪和驱动程序的成本相对较低,效果非常出色。 ### 回答2: Peak LIN USB驱动是针对Peak LIN USB接口的一款驱动程序。Peak LIN USB接口是一个通用的工业标准接口,用于与控制器区域网络(LIN)通信。这个接口可以用于各种应用领域,例如汽车和车辆领域、嵌入式和工业应用等。 Peak LIN USB驱动是一个提供给用户的软件,安装在计算机上,使得计算机可以识别Peak LIN USB接口,通过该接口和控制器区域网络(LIN)进行通信。驱动程序的作用是提供对应的控制器API,使得用户可以编写自己的应用程序,以实现控制器区域网络(LIN)的功能。 此外,Peak LIN USB驱动还提供了一些工具,例如Peak Trace和Peak Analyzer,用于在控制器区域网络(LIN)中对数据进行分析和调试,以及在系统中进行故障诊断和测试。 总的来说,Peak LIN USB驱动是通信领域的重要工具,能够帮助用户轻松地控制和管理控制器区域网络(LIN),并为用户的应用程序提供良好的支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值