Chinaunix首页 | 论坛 | 博客
  • 博客访问: 663510
  • 博文数量: 121
  • 博客积分: 4034
  • 博客等级: 上校
  • 技术积分: 1439
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-28 12:42
文章分类

全部博文(121)

文章存档

2017年(8)

2016年(10)

2013年(2)

2012年(3)

2011年(18)

2010年(80)

分类: LINUX

2010-07-22 17:24:08

linux usb device driver

USB主要的相关的硬件软件成分:

  • USB Hardware
    • USB Host Controller/Root Hub
    • USB Hubs
    • USB Devices
  • USB Software
    • USB Device Drivers
    • USB Driver
    • Host Controller Driver

usb的框架如右图所示: Image:Usb_subsystem_overview.JPG

  • usb interface(device) driver 指操作usb function的驱动,负责实现function层的协议(mass-storage, usb video class,HID…),比如usb-storage/uvc/hid等模块,一般每个(类)Interface使用一种驱动. 用户可自己开发一些标准class的驱动或者一些非标准的function驱动,系统中支持function的数目由usb 2.0 spec确定,一般来说不同(类)的function均有一个对应的Usb Interface driver, usb subsystem可以同时支持多个usb Interface driver(usb function)的运行. 一般来说,该层比较薄, class的协议都不是很复杂.主要分布在driver下的usb, sound/usb, input/touchscreen, media/*usb*, hid/usbhid/目录中。

  • Linux usb host controller driver指操作usb host controller(hardware)的驱动,主要负责将上层发来的URB传输请求转化成HC可识别的格式并启动HC传输,直至完成传输. 另外HC一般都集成了Root Hub的功能,hcd也要实现root hub port访问的功能 ,整个subsystem只有该驱动直接操作硬件寄存器. 该层也支持多种不同的host controller driver, 比如EHCI ,UHCI,OHCI以及一些非标准的HC实现(多用于嵌入式环境). 从软件角度该层在整个subsystem中较薄,但由于软硬件接口的复杂导致hcd driver都比较复杂. Linux Ehci device driver就属于该层.

  • linux usbcore模块是对整个linux usb subsytem的抽象, 在整个subsystem中起着承上启下的作用, 实现usb 2.0部分协议. 提供了大量的API供外部模块调用, 这些API 对应linux usbcore module中通过EXPORT_SYMBOL()导出的函数和变量; 同时,linux usbcore 也定义了接口类型, 这些接口需要usb interface driver以及usb host controller driver来实现. usbcore模块一般不需要用户改动.

  • 整个subsystem中, 用户只需要开发或者定制usb interface driver和usb host controller driver,Usbcore一般不需要修改.

usb详细的框架:
Image:Software Layers.jpg



linux usb hub topology structure

Image:Usb hub topology structure.JPG
Image:Usb hab.jpg
Transactions generated by the host controller are forwarded to the root hub to be transmitted to the USB. Consequently, every USB transaction originates at the root hub. The root hub provides the connection points for USB devices and performs the following key operations:
• 控制每个端口的电压。
• 使能和停止USb每个端口。
• 确定设备连接到每个端口。
• 设置和报告每个连接的端口的状态。(when polled by host software)
The root hub consists of a hub controller and repeater as illustrated above.
Hub Controller
The hub controller contains a USB interface, or serial interface engine (SIE). It also contains the descriptors that software reads to identify the device as a hub. The hub controller gathers hub and port status information also read by the USB host software to detect the connection and removal of devices and to determine other status information. The controller also receives commands from host software to control various aspects of the hub’s operation (e.g., powering and enabling the ports).

Hub Repeater
Image:Hub repeater.jpg
Refer to Figure above. Bus traffic arriving at the hub must be forwarded on in either the upstream (toward the host) or downstream (away from the host) direction. Transmissions originating at the host will arrive on the hub’s root port and must be forwarded to all enabled ports. When a target device responds to a host-initiated transaction, it must transmit a response upstream, which the hub must forward from the downstream port to the root port.

从我们driver的角度来讲,它也属于一种设备,也要分配相应的地址。它也包含了用于识别设备的描述符,如设备描述符,配置描述符,接口描述符等等。


USB Bandwidth Consideration Summary

USB共有四种传输方式,控制传输,等时传输,中断传输,批量传输(他们具体的区别下面会提到)。关于USB带宽的问题只有在等时传输和中断传输中含有。
USB控制器会把一秒钟分成1000份,每份只占1ms,1ms就是一个大包,一个大包有多个小包,所以呢,就在这一毫秒的时间就有可能是多个设备在接 受。这样就会产生一个问题,就是带宽,如音频设备需要的数据流比较稳定,所以在组织一帧的包的时候,首先考虑的是给这样的设备足够的空间,然后会在考虑其 他的设备,当这样的设备多的时候就会产生带宽不足的问题。
Image:Usb zheng.jpg The theoretical bandwidth available during each 1ms interval is 12,000 bits/ms, or 1.5KB/ms (1.5MB/s). However, overhead associated with performing transactions significantly reduces the efficiency of the bus. Consider the typical overhead associated with different types of transfers (including worst-case propagation delay):
• Isochronous transactions = 9 bytes
• Interrupt transactions = 13 bytes (FS) and 19 bytes (LS)
• Bulk transactions = 13 bytes
• Control (3 stage transfer) = 45 bytes (FS) and 63 bytes (LS)
To promote fairness during bandwidth sharing, the specification defines maximum packet sizes for various types of transfers. In general, isochronous transfers can have a maximum data payload of 1023 bytes and all others have a maximum payload of 64 bytes. Bus efficiency when performing transfers with various packet sizes is listed in follow picture.
Image:Usb 1ms frame.png
Image:Usb bandwidth dfficiency.jpg
Another important aspect of USB performance is the available bandwidth relative to the maximum data packet size. For example, while the bus efficiency is high for an isochronous transaction with a maximum payload of 1023 bytes, this transfer takes roughly 87% of the overall bus bandwidth. In contrast, a single bulk transaction with a maximum data payload of 64 bytes takes just over 5% of the available bandwidth. Thus, when a maximum bandwidth isochronous transaction is running, the remaining bandwidth permits just two more maximum-sized bulk transfers. Now imagine a scenario such as the one illustrated in Figure above. In this example, the bandwidth available may not be sufficient to support even the isochronous devices, without regard to the other devices requiring bus bandwidth.
The USB specification permits up to 90% of the overall bandwidth to be allocated to periodic transactions (isochronous and interrupt), while control transfers have a guaranteed reservation for up to 10% of the overall bandwidth. Bulk transfers simply get the bandwidth that is left over after all of the currently scheduled transactions complete. Considering the bandwidth limitations, the number of devices that can be supported adequately by USB 1.x is much lower than might be expected.



Packets

Transactions typically consist of three packets as illustrated follow. However, a transaction may consist of one, two, or three packets depending on the type:
Image:Packets compose.jpg
Image:USB Transactions Consist of Three Phases.jpg
below illustrates the basic format of a USB packet. Immediately preceding each packet is a synchronization sequence that permits USB devices to synchronize to the data rate of the incoming bits within the packet. The type of packet is defined by a bit pattern called a packet ID (PID). Following the PID is packetspecific information (e.g., an address or data) that varies depending on the packet type. Finally, each packet ends with a sequence of Cyclic Redundancy Check (CRC) bits, used to verify correct delivery of the packet-specific information.The end of each packet is identified by an end of packet (EOP). Each type of packet is detailed in the following sections.
Image:Packet Format 2.jpg
• Token Packet — 每一个交换的过程都是以令牌包开始的,令牌包中的信息包含目标设备,终端数量,和方向的数据传输,开始的帧是包含了当前帧的编号,广播给所有的设备。
• Data Packet — The data consists of a data packet that carries the payload associated with the transfer. A data packet can carry a maximum payload of 1023 bytes of data (isochronous transactions) during a single transaction; while the other transfer types have maximum data payloads of 64 bytes at full speed.
• Handshake Packet — 所有的usb传输(除了同步)都是保证数据的正确性的,使用握手数据包来验证是不是成功传输了一个数据,如果数据包传输错误,没与数据包传输给发送者,并标记错误。主机将要求发送者从新发送,直至错误三次。
The format and length of a packet depends on its type. Token packets are all 4 bytes in length, but contain different information that describes some aspect of the transaction that it defines. Data packets are variable length depending on the transfer type associated with the transaction. For example, at the data payload for bulk transfers is limited to 64 bytes during each transaction, while the data payload limit for isochronous transfers is 1023 bytes.

  • Token Packets:

Token packets define the type of transaction that is to be broadcast over the USB. All transactions begin with a token packet. Four types of token packets are defined by the USB specification:
• SOF (Start of Frame) — indicates start of the next 1ms frame.
• IN — specifies a USB transaction used to transfer data from a target USB device to the system.
• OUT — specifies a USB transaction used to transfer data from the system to a target USB device.
• SETUP — indicates the start of a control transfer. SETUP is the first stage of a control transfer and is used to send a request from the system to the target USB device.

  • Data Packets — DATA0 and Data1

Data packets carry the data payload associated with a given transaction. Direction of a data packet transfer is specified by the transaction type and may be used to transfer data either to or from a target USB device as listed in Table below.
Image:Direction of Data Packets.jpg
Two types of data packets (DATA0 and DATA1) are defined to support synchronization of long transfers between the sender and receiver. For example, if a long transfer is being sent from the host to a printer, the transfer will be performed in small blocks, usually over large number of frames. To verify that a data transaction is not missed during a long transfer, a technique called data toggle can be employed.
DATA0 Packet Format:
Image:DATA0 Packet Format.jpg
DATA1 Packet Format:
Image:DATA1 Packet Format.jpg

  • Handshake Packets

USB devices use handshake packets to report the completion status of a given transaction. The receiver of the data payload (either the target device or the root hub) is responsible for sending a handshake packet back to the sender. Three possible results can be reported via different handshake packets:
• Acknowledge packet (ACK) — 数据包已经正确传输.
• No Acknowledge packet (NAK) — 向主机报告没有数据接收到或没有数据返回。在中断传输中,没有可用的数据返还给主机。 (i.e., no interrupt request is currently pending).
• Stall packet (STALL) — used by the target to report that it is unable to complete the transfer and that software intervention will be required for the device to recover from the stall condition.

Image:Handshake Packet Formats.jpg

Control transfers are used to issue commands (also called requests) to USB devices. For example, control transfers are performed during USB device configuration to read the standard descriptors and assign a unique address to a device. Control transfers always begin with a setup transaction, called the setup stage. The setup stage defines the nature of the control transfer. Some control transfers include a data stage consisting of one or more IN or OUT transactions that are used to deliver the payload of the control transfer. Whether data is sent to or received from the device is defined by the setup stage. The final stage of a control transfer is the status stage. This stage confirms that the requested operation has been completed successfully. Control transfers exist in two basic forms:
• Transfers consisting of a setup stage and status stage.
• Transfers consisting of a setup stage, data stage, and status stage.
packet setup

Image:Usb packet in out.jpg
当鼠标放在Time Stamp的框上时,会跳出一个对话框,如下图所示。 Image:Usb packet time.jpg
在Time Stamp上显示的数字(如00000.0152 0058)是由三个部分组成的,小数点前面的是秒数,小数点后面的四个数字是uFrameCount,以125uSec的间隔计数,两个frame的 count为0160-0152=8,125uSec×8=1mSec。即USB frame的时间间隔。
由最后的四位数字uFrameOffset可以计算出该包相对于该FRAME的相对时间,计算过程,该包的uFrameCount减去该FRAME 的uFrameCount 然后乘以125uSec 乘以1000 最后加上 16.66(uFrameOffset的计数取样为60MHz,即(1000/60)= 16.66nSec) 乘以 该包的uFrameOffset减去该FRAME的uFrameOffset的差的积,如果uFrameOffset不够减,可以向 uFrameCount借位,7500进制。最后得到的值的单位为nSec。
例如:如下图所示,3526-4025为负值,所以需要借位,((2026-1)-2024)*125*1000 + ((3526+7500)-4025)*(1000/60) = 241683(nSec) = 241.683(uSec).该包相对于sof的时间差为241.683(uSec)
Image:Usb packet time1.jpg


USB Device Configuration

  • Configuration Process

Host software is responsible for detecting and configuring all devices attached to the root hub. The process of identifying and configuring a USB device is commonly referred to as USB device enumeration. Device enumeration begins at the root hub. Each hub port must be reset and enabled in turn. When powered, the hub determines if a low-, full-, or high-speed device is attached or no device at all. If a device is present, status bits within the root hub are set to reflect device attachment. Software recognizes that a device is attached, enables the port, resets the USB device, assigns a unique address, and completes the configuration. This operation is performed for each port until all devices attached to the root hub have been identified and configured. The following list specifies actions taken by host software and the root hub when configuring a device that is connected to a root hub port:

• 如果还没有供电,主机向设备供电。
• Hub探测设备的连接和设备的速度,和设置状态标志位。
• Host polls hub and identifies that a device is attached.
• Host控制设备复位。
• Host checks hub status again if the device originally reported full-speed operation.
This is done to see if the device is now operating at high speed.
• USB device now answers to default address (zero).
• Host performs GetDescriptor requests to fetch the standard descriptors that contain
configuration information. These descriptors are parsed by software to determine the
characteristics of the device. The configuration information includes bus power and bus
bandwidth requirements, and device class information.
• Host assigns unique address to USB device.
• Host verifies that the USB resources needed by the device are available.
• Host发送控制信息,要求得到设备如何使用的详细设备信息。

Default Control Pipe
The default control pipe accesses endpoint zero within each device.
Root Hub Configuration
Host software begins USB device enumeration by configuring the root hub. The root hub must implement a status change endpoint that can be used by the hub client to detect status changes pertaining to each port. Once the hub is configured, software can poll the status change endpoint to detect which ports currently have devices attached to them.
Bus Bandwidth
Host software must also verify that the bus bandwidth required by the USB device can be satisfied. Each configuration defines the set of endpoints that must be accessible by client software. Each endpoint descriptor specifies the maximum amount of USB bandwidth it requires. If sufficient bandwidth is available for all endpoints, a communications pipe is setup by software, reserving the specified bus bandwidth for each device endpoint. After successfully allocating bandwidth to all endpoints within the device, the device can be configured.
If the bus bandwidth needed is not available, then other configurations are checked. If every configuration exceeds the bus bandwidth available, the device is not configured.

  • USB Device Configuration

Prior to configuring a device, the hub to which the device is attached must have already been configured and power must be applied to the port. Next, the hub and configuration software must detect the connected device:
• The hub recognizes that a device has been attached by monitoring the Dand D+ port signals.
• The hub sets status information for the port indicating device connect and speed.
• Configuration software reads port status and recognizes that a full-speed device is connected.
• Software then enables the port so that the hub will pass bus traffic to the device.
• Configuration software then issues a Reset Port request, forcing the device into its default state. In the default state the device is unconfigured and responds only to accesses targeted for device zero and endpoint zero.
Configuration software can now begin the device configuration process. This process is similar to that used when configuring a hub.
• Host queries device’s control endpoint (zero) at address zero to determine maximum payload supported by the default pipe.
• Host assigns unique address to USB device.
• Host reads and evaluates configuration information from descriptors.
• Host verifies that the USB resources needed by the device are available.
• Host issues a configuration value to USB device specifying how it’s to be used. When the configuration value is received, the device assumes its described characteristics. Device is now ready to be accessed by client software and can draw the amount of Vbus power described in the configuration.
• Device Descriptor — 关于设备的通用信息,如厂商的ID,产品ID,支持设备的类,子类和适用的协议以及默认端点的最大包的大小。
• Configuration Descriptors — 吃配置中的接口数,支持的挂起和恢复能力,以及功率要求。
• Interface Descriptors — 接口类,子类和适用的协议,接口备用配置的数目和端点数。
• Endpoint Descriptors — 端点地址,方向和类型,支持的最大包的大小,如果是中断类型的端点则还包含轮询的频率。
• String Descriptors — 在其他描述符中会为某些字段提供字符串索引,他们可以被用来检索描述性字符串,可以以多种语言形式提供。
• Class-Specific Descriptors — a given device class may require additional descriptors as defined by a particular device class specification.

for example:
Hub Class-Specific Reset Port Request:
Once the hub client has detected the device, it must issue a port reset request, and when this happens, the attached device is reset. Port reset is accomplished via a control transfer delivered to the hub, called SetPortFeature. The format of the 8-byte setup transaction is shown in Table below.
Image:Hub Class-Specific Reset Port Request.jpg
发送过程如下:
然后程序根据上表的格式发送一个命令:

static int set_port_feature(struct usb_device *hdev, int port1, int feature)
{
return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, //USB_REQ_SET_FEATURE = 0x03
//USB_RT_PORT = 00100011B; feature = 0x4
NULL, 0, 1000);
}

命令的结构体为:

struct usb_ctrlrequest {
__u8 bRequestType;
__u8 bRequest;
__le16 wValue;
__le16 wIndex;
__le16 wLength;
} __attribute__ ((packed));

定义变量,给变量赋值,发送出去:

int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
__u8 requesttype, __u16 value, __u16 index, void *data,
__u16 size, int timeout)
{
…………
struct usb_ctrlrequest *dr;
dr->bRequestType = requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16p(&value);
dr->wIndex = cpu_to_le16p(&index);
dr->wLength = cpu_to_le16p(&size);
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
//(在函数usb_internal_control_msg里,申请了一个urb内存空间,然后根据需要填充,
//最后由usb_submit_urb向USB核心子系统提交一个异步请求,添加到发送队列里)
………………

endpoint,interfaces,configurations

usb规范中规定的标准概念由Linux USB core 来实现处理。
端点endpoint:
端点是USB总线传输最基本的概念,一个端点可以单方向传输数据。可以把端点看作是一个单方向的管道。
接口interfaces:
若干端点可以捆绑起来,成为一个端口,端口可以作为完整的逻辑设备连接,例如鼠标设备,键盘设备。
需要指出的是,一个硬件设备可以包含多个逻辑设备。
接口可以有多个预设值,用来指定不同的参数。
配置configurations:
接口捆绑起来形成配置,一个usb设备可以在不同的配置之间切换,一次只能激活一个配置。

可结合下图.


Linux中USB设备驱动的核心数据结构


在Linux的USB内核子系统中,提供了几个与设备驱动开发密切相关的数据结构,它们在实现USB 的体系结构、完成USB设备的即插即用、构建驱动程序的框架方面都起着灵魂的作用。

  • struct usb_driver

struct usb_driver是对USB 设备的最高层次的抽象。这个结构用于向USBD层注册USB 设备驱动程序。总线上有设备接入的时候,USBD通过该结构查找相关的设备驱动程序,而对于断开操作,USBD同样通过这个结构来断开设备与驱动的连接。 与其它驱动结构最大的不同就在于它指向probe和disconnect 的指针,当驱动正确安装以后,如果相应的USB 设备接入主机,系统自动调用probe进行探测,设备卸载时disconnect函数被调用。这2个函数作为USB 设备安装和卸载的入口点,保证了USB 设备的即插即用。下面给出一个在系统中注册的usb_driver结构:

static struct usb_driver d12_usb_driver = {
name : "d12usb", //驱动名字
probe : d12_usb_probe, //探测函数进入指针
disconnect : d12_usb_disconnect, //撤销函数进入指针
fops : &d12_fops, //设备的操作列表指针
minor :192, //次设备号必须为16的倍数。
//主设备号可以通过cat /proc/device可以看到,180:usb,189:usb device
id_table : &d12_usb_id, //描述该驱动所适用设备信息的指针,包含着厂商的ID号和设备的ID号。
};

struct usb_device是对系统中所有USB设备的抽象,这个数据结构不仅包含了USB设备必要的硬件信息,而且据此可以了解到USB设备具体的配置信息。 USB标准中以层次化的结构定义设备的描述符。一个USB设备只能有一个设备描述符,内容直接由具体的硬件提供,但是却可以有多个配置描述符,每个配置描 述符又由一个或多个接口描述符以及相应的端点描述符构成。Linux中的USB核心子系统通过几个数据结构之间的对应关系充分体现了这种层次化的结构。具 体如下图对比所示。

Image:Interface endpoint.jpg

  • struct urb USB数据请求块

USB信息传输包含4种传输类型:控制传输,等时传输,中断传输,批量传输。为了给设备驱动完成USB通信提供统一的接口,USB设备驱动与 USBD,以及USBD与HCD之间的数据传输都是通过数据结构URB来实现的。因此URB中包含了数据传输在各个层次中的必要信息,下面列出结构中的部 分定义,其中的pipe参数代表了进行传输的逻辑通道,直接反映了该URB所发生的数据端点,以及传输类型。

typedef struct urb{ … 
struct usb_device *dev; //请求的设备
unsigned int pipe; //传输管道
int status; //返回状态
unsigned int transfer_flags; //传输标志
void *transfer_buffer; //传输数据
int transfer_buffer_length; //传输数据长度
int actual_length; //实际长度
int timeout; //超时期限
… }

对于这个结构的处理通常由4个函数来进行:
(1)purb_t usb_alloc_urb(int iso_packets) 为USB传输分配URB结构,参数iso_packets是用于等时传输的数据包数目,对于其他传输该参数为0。
(2)void usb_free-urb(purb_t purb) 释放URB数据结构。
(3)int usb_submit_urb(purb_t purb) 用于向USB核心子系统提交一个异步请求。
(4)int usb_unlink_urb(purb_t purb) 在URB没有处理之前,通过这个函数取消相关的数据处理。



USB内核子系统提供的接口API

USBD层为USB设备驱动提供了统一接口的API,方便了用户自己编写适合的驱动程序。

  • 注册和注销驱动程序

为了实现USB设备即插即用的特性,所有的USB设备驱动都要在USBD中注册或注销。具体由函数usb_register和 usb_deregister来实现。当驱动程序调用int usb_register(struct usb_driver *new_driver)时,系统将这个新的驱动程序加入驱动链表(usb_driver_list)的尾部完成注册,同时扫描总线上的所有设备,与驱动 程序关联。注销函数的功能与此刚好相反,usb_deregister()关闭设备,撤销为设备在内核中分配的一切资源,然后把驱动结构从驱动链表中摘 除。
使用实例如下所示:

int init_module(void) 
{
if(usb_register(&d12_usb_driver)<0){
printk("unable to register device !\n");
return -1;
}
return 0;
}
  • 标准设备请求

USB协议定义了一系列的标准设备请求用来完成USB设备的枚举、配置等操作。USB设备以缺省的控制管道响应主机的请求。USBD提供了部分接口 函数支持USB标准请求,其余的控制传输由函数usb_control_msg完成。表1列出了USB设备请求与对应的接口函数。下表描述标准设备请求接 口:

Image:Request interface.JPG

  • USB数据传输

USBD提供了3种用于数据传输的接口:usb_control_msg (用于控制传输);usb_bulk_msg(用于批量传输);直接提交URB。但其实在usb_control_msg()、 usb_bulk_msg()内部,也是由提交URB 来完成的,只不过填充请求的工作由系统来完成。以批量传输为例介绍USB设备读写模块的设计与具体实现。

static int usb_write(struct file * file, char * buf, size_t count, loff_t *ppos) 
{ int this_write;
int partial;//实际写的长度
int result;//操作结果
if(device_plug_1==0){
printk(“No device in!\n”);
return -1;
}
while(count>0){
this_write = (count >= OBUF_SIZE)?OBUFSIZE :count
result=usb_bulk_msg(d12->dev, usb_sndbulkpipe(d12-> dev,2),d12->obuf,
this_write , HZ*TIMEOUT);
…//根据result的结果进行相应处理
if(partial != thiswrite) {…}
//判断是否成功写入,并进行相应的处理
…}//end while
return 1;
}

用户调用标准接口usb_bulk_msg完成批量传输。填充好相应的URB结构后,进入下面的调用序列——usb_bulk_msg() > usb_start_wait_urb() > usb_submit_urb() > uhci_submit_urb() > uhci_submit_bulk()——USB控制器把具体的请求转化为交互队列(假设USB驱动采用UHCI层面)根据总线时间、带宽、传输类型等综 合因素调度队列,执行相应的总线动作与设备进行交互,完成通信任务。下图给出了USB设备与主机的通信模型。
Image:Module conn device host.jpg

  • USB设备的安装和卸载

USB设备之所以可以即插即用,就是因为USB内核子系统即时对总线反馈的设备状态做出相应的处理。相应地在设备驱动方面也要提供probe和disconnect函数对设备进行初始化和断开操作。
USB设备接入主机后,主机通过总线枚举来识别和管理必要的设备状态变化。首先检测设备在总线上的上拉电阻判断是否有新设备连接,并获悉该设备是全速设备 还是低速设备,然后主机向该端口发送一个复位信号。设备只有在收到这个复位信号后,才能对总线的处理做出响应。此时设备采用的是默认地址(00H),主机 接收到设备对默认地址(00H)的响应,就为设备分配一个空闲的地址,以后设备就只对这个地址进行响应。接下来,主机读取USB设备描述符,确认USB设 备的属性。根据读取的设备描述符对设备进行配置,设备如果可以达到要求就发送配置完毕的信号给主机。然后调用设备驱动的probe函数对设备进行初始化。 下面给出一个简单的probe函数的写法。

 static void *naked_usb_probe(struct usb_interface *intf, struct usb_device_id *id) 
{//检查硬件定义与驱动是否相符
#if 0
if(dev->descriptor.idVendor==0x0471 && dev->descriptor. idProduct == 0x0222)
{
device_plug_in = 1;//设备插入标志
//初始化设备相关资源
if(d12->obuf=(char*)kmalloc(OBUF_SIZE,GFP_KERNEL)){…}
d12->dev=dev;

printk("My usb device pluged in.\n");
return ;
}
#endif
if (usb_usual_check_type(id, USB_US_TYPE_STOR))
return -ENXIO;
 } 

USB设备卸载的时候,将释放HCD层为该设备分配的资源,调用设备驱动的disconnect函数断开与设备的连接。

  • USB驱动的使用

在2.4内核中,虽然引进了devfs设备文件系统,但是对设备的管理主要还是采用主、次设备号的方法。为了使设备在系统中可以被应用程序访问,必 须建立一个设备文件节点。可以通过“mknod /dev/usb d12usb c 180 192”命令添加自己设备的节点,相对地在应用程序中通过系统调用open(“/dev/usb/d12usb”,O_RDWR)打开设备,之后就可以根 据需要对设备进行读写操作。

Linux下USB驱动函数快速参考


#include  

所有和 USB 相关的头文件. 它必须被所有的 USB 设备驱动包含.

struct usb_driver; 
描述 USB 驱动的结构.
struct usb_device_id; 
描述这个驱动支持的 USB 设备的结构.
int usb_register(struct usb_driver *d); 
用来从USB核心注册和注销一个 USB 驱动的函数.
struct usb_device *interface_to_usbdev(struct usb_interface *intf); 
从 struct usb_interface 获取控制 struct usb_device *.
#define interface_to_usbdev(intf) \
container_of(intf->dev.parent, struct usb_device, dev)
struct usb_device; 
控制完整 USB 设备的结构.
struct usb_interface; 
主 USB 设备结构, 所有的 USB 驱动用来和 USB 核心通讯的.
static inline void usb_set_intfdata(struct usb_interface *intf, void *data);
static inline void *usb_get_intfdata(struct usb_interface *intf)
{.... return dev->driver_data; ....}
设置和获取在 struct usb_interface 中的私有数据指针部分的函数.
struct usb_class_driver; 
描述 USB 驱动的一个结构, 这个驱动要使用 USB 主编号来和用户空间程序通讯.
int usb_register_dev(struct usb_interface *intf, struct usb_class_driver *class_driver); 
void usb_deregister_dev(struct usb_interface *intf, struct usb_class_driver *class_driver);
用来注册和注销一个特定 struct usb_interface * 结构到 struct usb_class_driver 结构的函数.
struct urb; 
描述一个 USB 数据传输的结构.
struct urb *usb_alloc_urb(int iso_packets, int mem_flags); 
void usb_free_urb(struct urb *urb);
用来创建和销毁一个 struct usb urb*的函数.
int usb_submit_urb(struct urb *urb, int mem_flags); 
int usb_kill_urb(struct urb *urb);
int usb_unlink_urb(struct urb *urb);
用来启动和停止一个 USB 数据传输的函数.
对usb_unlink_urb而言,如果urb结构体中的URB_ASYNC_UNLINK(即异步unlink)的标志被置位,则对该urb的usb_unlink_urb()调用将立即返回,具体的unlink动作将在后台进行,否则,此函数一直等到urb被解开连接或结束时才返回。usb_kill_urb()会彻底终止urb的生命周期,它通常是在设备的disconnect()函数中被调用。
void usb_fill_int_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void 
*transfer_buffer, int buffer_length, usb_complete_t complete, void *context, int interval);
void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void
*transfer_buffer, int buffer_length, usb_complete_t complete, void *context);
void usb_fill_control_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
unsigned char *setup_packet, void *transfer_buffer, int buffer_ length, usb_complete_t
complete, void *context);
用来在被提交给 USB 核心之前初始化一个 struct urb 的函数.
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int  
*actual_length, int timeout);
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8
requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
用来发送和接受 USB 数据的函数, 不必使用一个 struct urb.

bulk,iso,control,int

在USB的数据传送的方式下,有四种的传输方式:控制(Control)同步(isochronous)中断(interrupt)大量 (bulk)。如果你是从硬件开始来设计整个的系统,你还要正确选择传送的方式,而作为一个驱动程序的书写者,就只需要弄清楚他是采用的什么工作方式就行 了。 通常所有的传送方式下的主动权都在host边。
控制(Control)方式传送:控制传送是双向传送,数据量通常较小。USB系统软件用来主要进行查询、配置和给USB设备发送通用的命令。控制传送方 式可以包括8、16、32和64字节的数据,这依赖于设备和传输速度。控制传输典型地用在主计算机和USB外设之间的端点(Endpoint)0之间的传 输,但是指定供应商的控制传输可能用到其它的端点。

同步(isochronous)方式传送:同步传输提供了确定的带宽和间隔时间(latency)。它被用于时间严格并具有较强容错性的流 数据传输,或者用于要求恒定的数据传送率的即时应用中。例如执行即时通话的网络电话应用时,使用同步传输模式是很好的选择。同步数据要求确定的带宽值和确 定的最大传送次数。对于同步传送来说,即时的数据传递比完美的精度和数据的完整性更重要一些。

中断(interrupt)方式传送:中断方式传输主要用于定时查询设备是否有中断数据要传送。设备的端点模式器的结构决定了它的查询频 率,从1到255ms之间。这种传输方式典型的应用在少量的分散的、不可预测数据的传输。键盘、操纵杆和鼠标就属于这一类型。中断方式传送是单向的并且对 于host来说只有输入的方式。

大量(bulk)传送:主要应用在数据大量传送传送和接受数据上,同时又没有带宽和间隔时间要求的情况下,要求保证传输。打印机和扫描仪属于这种类型。这种类型的设备适合于传输非常慢和大量被延迟的传输,可以等到所有其它类型的数据的传送完成之后再传送和接收数据。

USB将其有效的带宽分成各个不同的桢(frame),每桢通常是1ms时间长。每个设备每桢只能传送一个同步的传送包。在完成了系统的配 置信息和连接之后,USB的host就会对不同的传送点和传送方式做一个统筹安排,用来适应整个的USB的带宽。通常情况下,同步方式和中断方式的传送会 占据整个带宽的90%,剩下的就安排给控制方式传送数据。

驱动编程上的区别:
使用usb_alloc_urb创建号urb后可使用系统提供的函数初始化:
1. usb_fill_int_urb是用于初始化中断urb:

static inline void usb_fill_int_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context,
int interval)
{
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
urb->complete = complete_fn;
urb->context = context;
if (dev->speed == USB_SPEED_HIGH)
urb->interval = 1 << (interval - 1);
else
urb->interval = interval;
urb->start_frame = -1;
}


dev指向这个urb要发送的设备;pipe是这个urb要发送的usb设备的特定端点;transfer_buffer是指向发送数据或 接受数据的缓冲区指针,和urb一样它也不能是静态缓冲区,必须使用kmalloc()来分配,buffer_length是 transfer_buffer指针所指向缓冲区的大小;complete指针指向当这个urb完成时被调用的完成处理函数,context是完成处理函 数的“上下文”;interval是这个urb应当被调度的时间间隔。
上述函数参数中的pipe使用usb_sndintpipe()或usb_rcvintpipe()创建。
2. usb_fill_bulk_urb是用于初始化批量urb:

static inline void usb_fill_bulk_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
{
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
urb->complete = complete_fn;
urb->context = context;
}

除了没有对应的调度时间间隔的interval参数以外,该函数的参数和usb_fill_int_urb()函数的参数含义相同。

上述函数参数中的pipe使用usb_sndbulkpipe()或usb_rcvbulkpipe()创建。

3. usb_fill_control_urb是用于初始化控制urb:

static inline void usb_fill_control_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
unsigned char *setup_packet,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
{
urb->dev = dev;
urb->pipe = pipe;
urb->setup_packet = setup_packet;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
urb->complete = complete_fn;
urb->context = context;
}

除了增加了新的setup_packet参数以外,该函数的参数和usb_fill_bulk_urb()函数是的参数含义是相同的,setup_packet参数是指向即将被发送到端点的设置数据包。
上述函数参数中的pipe使用usb_sndctrlpipe()或usb_rcvctrlpipe()创建。
4. 等时urb没有像中断那样子的初始化函数,我们只能手动的初始化urb,而后才能提交给usb核心。(可参考drivers/media/video/usbvideo/usbvideo.c中的1767~1783行,(linux_kernel_2.6.26)
urb 处理流程:
Image:Urb flow.jpg

usb相关命令

1. 我们通过cat /proc/bus/usb/devices得到当前系统探测到的USB总线上的设备信息。它包括Vendor、ProdID、Product等。下面是我是插入一个hub后的信息片断:

T:  Bus=03 Lev=01 Prnt=01 Port=04 Cnt=01 Dev#=  2 Spd=480 MxCh= 4
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=058f ProdID=6254 Rev= 1.00
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=256ms

2. 厂商的ID号也可以通过lsusb命令获取:

Bus 001 Device 001: ID 0000:0000
Bus 003 Device 002: ID 058f:6254 Alcor Micro Corp.
Bus 003 Device 001: ID 0000:0000
Bus 002 Device 001: ID 0000:0000


3. lspci查看PCI插槽信息

00:03.0 USB Controller: Silicon Integrated Systems [SiS] USB 1.0 Controller (rev 0f)
00:03.1 USB Controller: Silicon Integrated Systems [SiS] USB 1.0 Controller (rev 0f)
00:03.3 USB Controller: Silicon Integrated Systems [SiS] USB 2.0 Controller

4. 在有些板子上没有上述命令或上述文件,也可以通过/sys/bus/usb/devices 中的文件来分析:

当在板子上插上一个hub时,会在/sys/bus/usb/devices文件夹下多出一个目录1-1,在这个目录下包含了该hub的所有信息。

如:厂商ID和产品ID

cat idProduct idVendor
6254
058f
阅读(9446) | 评论(1) | 转发(2) |
给主人留下些什么吧!~~

xlz452014-09-01 10:59:33

文章写的很好,可惜配图都看不了