usb驱动

来源:互联网 发布:照片变卡通软件 编辑:程序博客网 时间:2024/03/29 19:14

USB  


如果你面试BIOS 工程师,那么关于USB是一定要问的。

先深入讨论一下四种传输类型, control, bulk, interrupt, isochronous. 每种传输类型都有其自身的特点,不同的应用场合应该选择不同的传输类型。



四种传输都是作为USB2_HC的的一个成员函数:




控制传输(control transfer)

控制传输有两方面的作用,控制传输可以携带host 用于控制以及探测device 的标准请求,第二个是携带厂商自定义的请求信息。

第一个USB device 是root hub. 它是usb 控制器,一般是包含在一个PCI device 里面,之所以叫控制器(controller) 是因为它管理着整个连在它上面的bus. 当然,它也是这根bus 上面的第一个usb device.

主要用来传递一些配置信息和控制信息。


所有root hub  都有一个usb core 给它分配的唯一编号。

它在代码里的实现是这样的:




他主要还是分两步:创建urb , 然后提交URB;

  Urb = EhcCreateUrb (          Ehc,          DeviceAddress,          Endpoint,          DeviceSpeed,          0,          MaximumPacketLength,          Translator,          EHC_CTRL_TRANSFER,          Request,          Data,          *DataLength,          NULL,          NULL,          1          );

 EhcExecTransfer (Ehc, Urb, TimeOut);


块传输(bulk transfer)

当需要传输大量数据(一般对传输时间不敏感)时候,用块传输。


中断传输(interrupt transfer)

中断传输一般用来传送对时间要求比图严格,但信息量比较小的数据。


同步传输(isochronous transfer)

一般用来传递实时数据(比如QQ聊天时视频).


以U盘为例,当我们要使用U盘的时候,我们先用控制传输来发起对U盘的访问,然后使用块

传输copy U盘里面的内容。键盘使用中断传输以便及时响应对键盘的敲击。


地址

     在usb 拓扑结构中,每一个usb device 都叫一个endpoint, 每个一个endpoint 都会有一个唯一的地址。每一个

endpoint 都会有其相应的传输类型,endpoint 0 只用来配置devie.

  

     一个endpoint 即可以upstream(由usb device 向hub 方向传)也可以downstream.


USB 在很多方面和I2C很相似

1.它们都使用master-slave 协议

2.都是使用自己私有的7bit 存放地址

3.device 中的内存不会映射到memoy地址空间或者I/O地址空间,因此它们都不消耗CPU资源。


USB 在很多方面和PCI也很相似

1,都可以做到hotplug

2,USB的主控制器和PCI控制器一样,通常集成了一个可以控制总线的DMA 处理器。

3,都支持multifunction device, 每个function 可以认为是一个逻辑上的设备。



关于USB几个重要的数据结构

当你写一个USB驱动的时候,不可避免了要和这些数据结构打交道,我们首先看看最重要的一个:

usb_device Strucute

在系统内部,每一个usb device 都用一个usb_device来表示

/** * struct usb_device - kernel's representation of a USB device * @devnum: device number; address on a USB bus * @devpath: device ID string for use in messages (e.g., /port/...) * @route: tree topology hex string for use with xHCI * @state: device state: configured, not attached, etc. * @speed: device speed: high/full/low (or error) * @tt: Transaction Translator info; used with low/full speed dev, highspeed hub * @ttport: device port on that tt hub * @toggle: one bit for each endpoint, with ([0] = IN, [1] = OUT) endpoints * @parent: our hub, unless we're the root * @bus: bus we're part of * @ep0: endpoint 0 data (default control pipe) * @dev: generic device interface * @descriptor: USB device descriptor * @bos: USB device BOS descriptor set * @config: all of the device's configs * @actconfig: the active configuration * @ep_in: array of IN endpoints * @ep_out: array of OUT endpoints * @rawdescriptors: raw descriptors for each config * @bus_mA: Current available from the bus * @portnum: parent port number (origin 1) * @level: number of USB hub ancestors * @can_submit: URBs may be submitted * @persist_enabled:  USB_PERSIST enabled for this device * @have_langid: whether string_langid is valid * @authorized: policy has said we can use it; *(user space) policy determines if we authorize this device to be *used or not. By default, wired USB devices are authorized. *WUSB devices are not, until we authorize them from user space. *FIXME -- complete doc * @authenticated: Crypto authentication passed * @wusb: device is Wireless USB * @lpm_capable: device supports LPM * @usb2_hw_lpm_capable: device can perform USB2 hardware LPM * @usb2_hw_lpm_besl_capable: device can perform USB2 hardware BESL LPM * @usb2_hw_lpm_enabled: USB2 hardware LPM is enabled * @usb2_hw_lpm_allowed: Userspace allows USB 2.0 LPM to be enabled * @usb3_lpm_enabled: USB3 hardware LPM enabled * @string_langid: language ID for strings * @product: iProduct string, if present (static) * @manufacturer: iManufacturer string, if present (static) * @serial: iSerialNumber string, if present (static) * @filelist: usbfs files that are open to this device * @maxchild: number of ports if hub * @quirks: quirks of the whole device * @urbnum: number of URBs submitted for the whole device * @active_duration: total time device is not suspended * @connect_time: time device was first connected * @do_remote_wakeup:  remote wakeup should be enabled * @reset_resume: needs reset instead of resume * @port_is_suspended: the upstream port is suspended (L2 or U3) * @wusb_dev: if this is a Wireless USB device, link to the WUSB *specific data for the device. * @slot_id: Slot ID assigned by xHCI * @removable: Device can be physically removed from this port * @l1_params: best effor service latency for USB2 L1 LPM state, and L1 timeout. * @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout. * @u2_params: exit latencies for USB3 U2 LPM state, and hub-initiated timeout. * @lpm_disable_count: Ref count used by usb_disable_lpm() and usb_enable_lpm() *to keep track of the number of functions that require USB 3.0 Link Power *Management to be disabled for this usb_device.  This count should only *be manipulated by those functions, with the bandwidth_mutex is held. * * Notes: * Usbcore drivers should not set usbdev->state directly.  Instead use * usb_set_device_state(). */struct usb_device {intdevnum;chardevpath[16];u32route;enum usb_device_statestate;enum usb_device_speedspeed;struct usb_tt*tt;intttport;unsigned int toggle[2];struct usb_device *parent;struct usb_bus *bus;struct usb_host_endpoint ep0;struct device dev;struct usb_device_descriptor descriptor;struct usb_host_bos *bos;struct usb_host_config *config;struct usb_host_config *actconfig;struct usb_host_endpoint *ep_in[16];struct usb_host_endpoint *ep_out[16];char **rawdescriptors;unsigned short bus_mA;u8 portnum;u8 level;unsigned can_submit:1;unsigned persist_enabled:1;unsigned have_langid:1;unsigned authorized:1;unsigned authenticated:1;unsigned wusb:1;unsigned lpm_capable:1;unsigned usb2_hw_lpm_capable:1;unsigned usb2_hw_lpm_besl_capable:1;unsigned usb2_hw_lpm_enabled:1;unsigned usb2_hw_lpm_allowed:1;unsigned usb3_lpm_enabled:1;int string_langid;/* static strings from the device */char *product;char *manufacturer;char *serial;struct list_head filelist;int maxchild;u32 quirks;atomic_t urbnum;unsigned long active_duration;#ifdef CONFIG_PMunsigned long connect_time;unsigned do_remote_wakeup:1;unsigned reset_resume:1;unsigned port_is_suspended:1;#endifstruct wusb_dev *wusb_dev;int slot_id;enum usb_device_removable removable;struct usb2_lpm_parameters l1_params;struct usb3_lpm_parameters u1_params;struct usb3_lpm_parameters u2_params;unsigned lpm_disable_count;};#defineto_usb_device(d) container_of(d, struct usb_device, dev)


第二个重要的结构体自然是urb(USB Request Block), urb在USB传输过程中最重要的角色。

 这里我们还是先贴出来:

/** * struct urb - USB Request Block * @urb_list: For use by current owner of the URB. * @anchor_list: membership in the list of an anchor * @anchor: to anchor URBs to a common mooring * @ep: Points to the endpoint's data structure.  Will eventually *replace @pipe. * @pipe: Holds endpoint number, direction, type, and more. *Create these values with the eight macros available; *usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl" *(control), "bulk", "int" (interrupt), or "iso" (isochronous). *For example usb_sndbulkpipe() or usb_rcvintpipe().  Endpoint *numbers range from zero to fifteen.  Note that "in" endpoint two *is a different endpoint (and pipe) from "out" endpoint two. *The current configuration controls the existence, type, and *maximum packet size of any given endpoint. * @stream_id: the endpoint's stream ID for bulk streams * @dev: Identifies the USB device to perform the request. * @status: This is read in non-iso completion functions to get the *status of the particular request.  ISO requests only use it *to tell whether the URB was unlinked; detailed status for *each frame is in the fields of the iso_frame-desc. * @transfer_flags: A variety of flags may be used to affect how URB *submission, unlinking, or operation are handled.  Different *kinds of URB can use different flags. * @transfer_buffer:  This identifies the buffer to (or from) which the I/O *request will be performed unless URB_NO_TRANSFER_DMA_MAP is set *(however, do not leave garbage in transfer_buffer even then). *This buffer must be suitable for DMA; allocate it with *kmalloc() or equivalent.  For transfers to "in" endpoints, contents *of this buffer will be modified.  This buffer is used for the data *stage of control transfers. * @transfer_dma: When transfer_flags includes URB_NO_TRANSFER_DMA_MAP, *the device driver is saying that it provided this DMA address, *which the host controller driver should use in preference to the *transfer_buffer. * @sg: scatter gather buffer list, the buffer size of each element in * the list (except the last) must be divisible by the endpoint's * max packet size if no_sg_constraint isn't set in 'struct usb_bus' * @num_mapped_sgs: (internal) number of mapped sg entries * @num_sgs: number of entries in the sg list * @transfer_buffer_length: How big is transfer_buffer.  The transfer may *be broken up into chunks according to the current maximum packet *size for the endpoint, which is a function of the configuration *and is encoded in the pipe.  When the length is zero, neither *transfer_buffer nor transfer_dma is used. * @actual_length: This is read in non-iso completion functions, and *it tells how many bytes (out of transfer_buffer_length) were *transferred.  It will normally be the same as requested, unless *either an error was reported or a short read was performed. *The URB_SHORT_NOT_OK transfer flag may be used to make such *short reads be reported as errors. * @setup_packet: Only used for control transfers, this points to eight bytes *of setup data.  Control transfers always start by sending this data *to the device.  Then transfer_buffer is read or written, if needed. * @setup_dma: DMA pointer for the setup packet.  The caller must not use *this field; setup_packet must point to a valid buffer. * @start_frame: Returns the initial frame for isochronous transfers. * @number_of_packets: Lists the number of ISO transfer buffers. * @interval: Specifies the polling interval for interrupt or isochronous *transfers.  The units are frames (milliseconds) for full and low *speed devices, and microframes (1/8 millisecond) for highspeed *and SuperSpeed devices. * @error_count: Returns the number of ISO transfers that reported errors. * @context: For use in completion functions.  This normally points to *request-specific driver context. * @complete: Completion handler. This URB is passed as the parameter to the *completion function.  The completion function may then do what *it likes with the URB, including resubmitting or freeing it. * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to *collect the transfer status for each buffer. * * This structure identifies USB transfer requests.  URBs must be allocated by * calling usb_alloc_urb() and freed with a call to usb_free_urb(). * Initialization may be done using various usb_fill_*_urb() functions.  URBs * are submitted using usb_submit_urb(), and pending requests may be canceled * using usb_unlink_urb() or usb_kill_urb(). * * Data Transfer Buffers: * * Normally drivers provide I/O buffers allocated with kmalloc() or otherwise * taken from the general page pool.  That is provided by transfer_buffer * (control requests also use setup_packet), and host controller drivers * perform a dma mapping (and unmapping) for each buffer transferred.  Those * mapping operations can be expensive on some platforms (perhaps using a dma * bounce buffer or talking to an IOMMU), * although they're cheap on commodity x86 and ppc hardware. * * Alternatively, drivers may pass the URB_NO_TRANSFER_DMA_MAP transfer flag, * which tells the host controller driver that no such mapping is needed for * the transfer_buffer since * the device driver is DMA-aware.  For example, a device driver might * allocate a DMA buffer with usb_alloc_coherent() or call usb_buffer_map(). * When this transfer flag is provided, host controller drivers will * attempt to use the dma address found in the transfer_dma * field rather than determining a dma address themselves. * * Note that transfer_buffer must still be set if the controller * does not support DMA (as indicated by bus.uses_dma) and when talking * to root hub. If you have to trasfer between highmem zone and the device * on such controller, create a bounce buffer or bail out with an error. * If transfer_buffer cannot be set (is in highmem) and the controller is DMA * capable, assign NULL to it, so that usbmon knows not to use the value. * The setup_packet must always be set, so it cannot be located in highmem. * * Initialization: * * All URBs submitted must initialize the dev, pipe, transfer_flags (may be * zero), and complete fields.  All URBs must also initialize * transfer_buffer and transfer_buffer_length.  They may provide the * URB_SHORT_NOT_OK transfer flag, indicating that short reads are * to be treated as errors; that flag is invalid for write requests. * * Bulk URBs may * use the URB_ZERO_PACKET transfer flag, indicating that bulk OUT transfers * should always terminate with a short packet, even if it means adding an * extra zero length packet. * * Control URBs must provide a valid pointer in the setup_packet field. * Unlike the transfer_buffer, the setup_packet may not be mapped for DMA * beforehand. * * Interrupt URBs must provide an interval, saying how often (in milliseconds * or, for highspeed devices, 125 microsecond units) * to poll for transfers.  After the URB has been submitted, the interval * field reflects how the transfer was actually scheduled. * The polling interval may be more frequent than requested. * For example, some controllers have a maximum interval of 32 milliseconds, * while others support intervals of up to 1024 milliseconds. * Isochronous URBs also have transfer intervals.  (Note that for isochronous * endpoints, as well as high speed interrupt endpoints, the encoding of * the transfer interval in the endpoint descriptor is logarithmic. * Device drivers must convert that value to linear units themselves.) * * If an isochronous endpoint queue isn't already running, the host * controller will schedule a new URB to start as soon as bandwidth * utilization allows.  If the queue is running then a new URB will be * scheduled to start in the first transfer slot following the end of the * preceding URB, if that slot has not already expired.  If the slot has * expired (which can happen when IRQ delivery is delayed for a long time), * the scheduling behavior depends on the URB_ISO_ASAP flag.  If the flag * is clear then the URB will be scheduled to start in the expired slot, * implying that some of its packets will not be transferred; if the flag * is set then the URB will be scheduled in the first unexpired slot, * breaking the queue's synchronization.  Upon URB completion, the * start_frame field will be set to the (micro)frame number in which the * transfer was scheduled.  Ranges for frame counter values are HC-specific * and can go from as low as 256 to as high as 65536 frames. * * Isochronous URBs have a different data transfer model, in part because * the quality of service is only "best effort".  Callers provide specially * allocated URBs, with number_of_packets worth of iso_frame_desc structures * at the end.  Each such packet is an individual ISO transfer.  Isochronous * URBs are normally queued, submitted by drivers to arrange that * transfers are at least double buffered, and then explicitly resubmitted * in completion handlers, so * that data (such as audio or video) streams at as constant a rate as the * host controller scheduler can support. * * Completion Callbacks: * * The completion callback is made in_interrupt(), and one of the first * things that a completion handler should do is check the status field. * The status field is provided for all URBs.  It is used to report * unlinked URBs, and status for all non-ISO transfers.  It should not * be examined before the URB is returned to the completion handler. * * The context field is normally used to link URBs back to the relevant * driver or request state. * * When the completion callback is invoked for non-isochronous URBs, the * actual_length field tells how many bytes were transferred.  This field * is updated even when the URB terminated with an error or was unlinked. * * ISO transfer status is reported in the status and actual_length fields * of the iso_frame_desc array, and the number of errors is reported in * error_count.  Completion callbacks for ISO transfers will normally * (re)submit URBs to ensure a constant transfer rate. * * Note that even fields marked "public" should not be touched by the driver * when the urb is owned by the hcd, that is, since the call to * usb_submit_urb() till the entry into the completion routine. */struct urb {/* private: usb core and host controller only fields in the urb */struct kref kref;/* reference count of the URB */void *hcpriv;/* private data for host controller */atomic_t use_count;/* concurrent submissions counter */atomic_t reject;/* submissions will fail */int unlinked;/* unlink error code *//* public: documented fields in the urb that can be used by drivers */struct list_head urb_list;/* list head for use by the urb's * current owner */struct list_head anchor_list;/* the URB may be anchored */struct usb_anchor *anchor;struct usb_device *dev;/* (in) pointer to associated device */struct usb_host_endpoint *ep;/* (internal) pointer to endpoint */unsigned int pipe;/* (in) pipe information */unsigned int stream_id;/* (in) stream ID */int status;/* (return) non-ISO status */unsigned int transfer_flags;/* (in) URB_SHORT_NOT_OK | ...*/void *transfer_buffer;/* (in) associated data buffer */dma_addr_t transfer_dma;/* (in) dma addr for transfer_buffer */struct scatterlist *sg;/* (in) scatter gather buffer list */int num_mapped_sgs;/* (internal) mapped sg entries */int num_sgs;/* (in) number of entries in the sg list */u32 transfer_buffer_length;/* (in) data buffer length */u32 actual_length;/* (return) actual transfer length */unsigned char *setup_packet;/* (in) setup packet (control only) */dma_addr_t setup_dma;/* (in) dma addr for setup_packet */int start_frame;/* (modify) start frame (ISO) */int number_of_packets;/* (in) number of ISO packets */int interval;/* (modify) transfer interval * (INT/ISO) */int error_count;/* (return) number of ISO errors */void *context;/* (in) context for completion */usb_complete_t complete;/* (in) completion routine */struct usb_iso_packet_descriptor iso_frame_desc[0];/* (in) ISO ONLY */};


要使用URB,需要三个步骤:先(create)创建一个urb, 然后给每个成员赋值(populate) ,最后提交(submit)。

创建一个URB,使用usb_alloc_urb(). 这个函数负责分配一个合适的空间给URB,并把每个成员初始化为0.

还有使用spinlock去保护URB.




管道(Pipe)

管道是由下面几个成员构成:

endpoint 的地址

数据传输的方向

数据传输的类型(control, interrupt, bulk, isochronous)



描述符(Descriptor Strucuture)

USB Spec 定义了一系列的描述符,用来描述一个设备各方面的信息,描述符大致可以分为四类:

设备描述符(device descriptor),对应的结构体为 usb_config_descriptor, 里面放了有一个设备最general的信息,

比如 product ID, vendor ID.


配置描述符,对应的结构体为usb_config_descriptor, 里面放着不同的配置模式,比如是bus powered, 还是

self-powered. 


接口描述符,正是这个描述符使得USB device 可以支持多种功能,它对应的结构体为usb_interface_descriptor.


Endpoint 描述符,对应的结构体为usb_endpoint_descriptor, 用来描述最终的endpoint.


Enumeration(枚举过程)

一个usb的生命周期可以从它插入电脑的时候算起,当它插入后内核第一个动作就是检测到它

并且去配置它,这个过程叫枚举(enumeration),主要由hub driver负责。

枚举过程主要分这么几个步骤:

1.当一个usb device 插入的时候,usb hub 就会检测到状态的变化,然后它就会去唤醒khubd.

2. khubd 解析到是哪个port 有新的device 插入。

3.khubd从1到127中选择一个地址分配给它。

4, khubd 从endpoint 0 抓到它的描述符。

5.khubd 请求usb core 将这个device 绑定到合适的driver上面。


当枚举结束并且device和相应的驱动绑定之后, khubd 调用这个driver 的 probe函数。

0 0
原创粉丝点击