Linux USB 详解

 

Linux USB 详解

To understand all the Linux-USB framework, you'll use these resources:
    * This source code.
       "make pdfdocs",
       "usb.pdf" for host side
             "gadget.pdf" for peripheral side
    * The USB 2.0 specification (from www.usb.org).
    * Chip specifications for USB controllers. host controllers (on PCs, servers, and more);
       peripheral controllers (in devices with Linux firmware, like printers or cell phones);
       hard-wired peripherals like Ethernet adapters.
    * Specifications for other protocols implemented by USB peripheral functions. 
       Some are vendor-specific;
       others are vendor-neutral but just standardized outside of the www.usb.org team.

Here is a list of what each subdirectory here is, and what is contained in them.

core/  - This is for the core USB host code, including the usbfs files and the hub class driver ("khubd").

host/  - This is for USB host controller drivers.  This includes UHCI, OHCI, EHCI, and others that might
    be used with more specialized "embedded" systems.

gadget/ - This is for USB peripheral controller drivers and the various gadget drivers which talk to them.


Individual USB driver directories.  A new driver should be added to the first subdirectory in the list below that it fits into.

image/ - This is for still image drivers, like scanners or digital cameras.
input/ - This is for any driver that uses the input subsystem,like keyboard, mice, touchscreens, tablets, etc.
media/ - This is for multimedia drivers, like video cameras,radios, and any other drivers that talk to the v4l subsystem.
net/  - This is for network drivers.
serial/ - This is for USB to serial drivers.
storage/ - This is for USB mass-storage drivers.
atm/  - Automatic
mon/  - Monitor
class/ - This is for all USB device drivers that do not fit into any of the above categories, and work for a range
    of USB Class specified devices.
misc/  - This is for all USB device drivers that do not fit into any of the above categories.

驱动结构:
 USB 设备驱动 : USB设备和主机通讯      Gadget 驱动 :具体USB设备功能的实现,使设备表现出"网络连接"
             "打印机""USB Mass Storage"的特性

 USB Core : 定义一些数据结构,宏和功能函数.提供上下层的API   Gadget API : Callback API 的简单包装
      通过全局变量维护系统的USB信息,HotPlug控制,总线数据传输 

 USB 主机驱动 : 控制插入的USB设备      UDC 驱动 :控制USB设备和HOST的底层通讯,向上提供Callback API

 USB控制器硬件OHCI/EHCI/UHCI    <<-->> USB Bus <<-->>  USB控制器硬件OHCI/EHCI/UHCI

数据结构的定义: in /kernel/include/linux/usb_ch9.h
/*
 * This file holds USB constants and structures that are needed for USB
 * device APIs.  These are used by the USB device model, which is defined
 * in chapter 9 of the USB 2.0 specification.  Linux has several APIs in C
 * that need these:
 *
 * - the master/host side Linux-USB kernel driver API;
 * - the "usbfs" user space API; and
 * - the Linux "gadget" slave/device/peripheral side driver API.
 *
 * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
 * act either as a USB master/host or as a USB slave/device.  That means
 * the master and slave side APIs benefit from working well together.
 *
 * There's also "Wireless USB", using low power short range radios for
 * peripheral interconnection but otherwise building on the USB framework.
 */
/* USB_DT_DEVICE: Device descriptor */
 struct usb_device_descriptor {   设备描述符    如USB扬声器
  __u8  bLength;    描述符的长度
  __u8  bDescriptorType;   描述符类型的编号

  __le16 bcdUSB;    USB版本号
  __u8  bDeviceClass;    USB的设备类code
  __u8  bDeviceSubClass;   USB的子类code
  __u8  bDeviceProtocol;   USB的协议code
  __u8  bMaxPacketSize0;   默认端口端口0的最大包大小
  __le16 idVendor;    厂商编号
  __le16 idProduct;    产品编号
  __le16 bcdDevice;    设备出厂的编号
  __u8  iManufacturer;    描述厂商的字符串的索引
  __u8  iProduct;    描述产品的字符串的索引
  __u8  iSerialNumber;    描述设备序列号的字符串的索引
  __u8  bNumConfigurations;   可能的配置数量
 } __attribute__ ((packed));
 struct usb_config_descriptor {   多个配置描述符    
  __u8  bLength;    描述符的长度
  __u8  bDescriptorType;   描述符类型的编号

  __le16 wTotalLength;    配置 所返回的所有数据的大小
  __u8  bNumInterfaces;   配置 所支持的interface数
  __u8  bConfigurationValue;   Set_Configuration命令需要的参数值
  __u8  iConfiguration;   描述该配置的字符串的索引值
  __u8  bmAttributes;    供电模式的选择
  __u8  bMaxPower;    设备从总线提取的最大电流
 } __attribute__ ((packed));
 /* USB_DT_INTERFACE: Interface descriptor */
 struct usb_interface_descriptor {  多个接口描述符    如音频接口,旋钮和按钮接口
  __u8  bLength;    描述符的长度
  __u8  bDescriptorType;   描述符类型的编号

  __u8  bInterfaceNumber;   接口的编号
  __u8  bAlternateSetting;   备用的接口描述符编号,提供不同质量的服务参数.
  __u8  bNumEndpoints;    该接口所使用的端口数,不包括端口0
  __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;   端点号:0-3是端口点,第7位是方向(0-OUT,1-IN)
  __u8  bmAttributes;    端口属性:bit[0:1] 00:控制端点 01:同步传输端点 02:批量传输端点 03:中断端点
  __le16 wMaxPacketSize;   数据包的最大容量
  __u8  bInterval;    轮询数据传送端点的时间间隔,即中断传送时轮询间隔,此域为1-255
        批量和控制传送时,此域忽略
        同步传送时,为1
        
  /* NOTE:  these two are _only_ in audio endpoints. */
  /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
  __u8  bRefresh;    
  __u8  bSynchAddress;
 } __attribute__ ((packed));
 /* USB_DT_STRING: String descriptor */
 struct usb_string_descriptor {   字符串描述符
  __u8  bLength;    描述符长度
  __u8  bDescriptorType;   描述符类型

  __le16 wData[1];    /* UTF-16LE encoded */
 } __attribute__ ((packed));

1,USB主机驱动:  OHCI: Open Host Controller Interface,None PC or SiS/ALi chip PC USB
   UHCI: Universal,Used by PC USB
   EHCI: Enhanced usb2.0
   一,数据结构: in /kernel/drivers/usb/core/hcd.h
 /*-------------------------------------------------------------------------*/
 /*
  * USB Host Controller Driver (usb_hcd) framework
  *
  * Since "struct usb_bus" is so thin, you can't share much code in it.
  * This framework is a layer over that, and should be more sharable.
  */
 /*-------------------------------------------------------------------------*/

 1,struct usb_hcd { /* usb_bus.hcpriv points to this */  描述USB的Host Controller Driver
  /*
   *  housekeeping   家务管理
  */
  struct usb_bus self;  /* hcd is-a bus */   所代表的USB Bus

  const char *product_desc; /* product/vendor string */  产品字符串
  char irq_descr[24];  /* driver + bus # */   驱动+总线

  struct timer_list rh_timer; /* drives root-hub polling */ 根hub轮询
  struct urb *status_urb; /* the current status urb */ 目前的状态urb
  /*
   * hardware info/state  硬件资源/状态
   */
  const struct hc_driver *driver; /* hw-specific hooks */ 硬件特定的钩子函数,操作HC硬件
  unsigned saw_irq : 1;      
  unsigned can_wakeup:1; /* hw supports wakeup? */
  unsigned remote_wakeup:1; /* sw should use wakeup? */
  unsigned rh_registered:1; /* is root hub registered? */

  /* The next flag is a stopgap"权益之计", to be removed when all the HCDs
   * support the new root-hub polling mechanism. */
  unsigned uses_new_polling:1;     支持新的根hub轮询?
  unsigned poll_rh:1;  /* poll for rh status? */  轮询根hub状态?
  unsigned poll_pending:1; /* status has changed? */  状态已改变?

  int irq;   /* irq allocated */   被分配的irq
  void __iomem *regs;  /* device memory/io */  设备的IO内存
  u64 rsrc_start;  /* memory/io resource start */ IO内存起始地址
  u64 rsrc_len;   /* memory/io resource length */ IO内存长度
  unsigned power_budget; /* in mA, 0 = no limit */  最大电流

  #define HCD_BUFFER_POOLS 4
  struct dma_pool *pool [HCD_BUFFER_POOLS];    

  int state;  状态
  #define __ACTIVE 0x01
  #define __SUSPEND 0x04
  #define __TRANSIENT 0x80

  #define HC_STATE_HALT 0
  #define HC_STATE_RUNNING (__ACTIVE)
  #define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
  #define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
  #define HC_STATE_SUSPENDED (__SUSPEND)

  #define HC_IS_RUNNING(state) ((state) & __ACTIVE)  宏
  #define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)

  /* more shared queuing code would be good; it should support
   * smarter scheduling, handle transaction translators, etc;
   * input size of periodic table to an interrupt scheduler.
   * (ohci 32, uhci 1024, ehci 256/512/1024).
   */
  /* The HC driver's private data is stored at the end of
   * this structure. 私有数据
   */
  unsigned long hcd_priv[0]
   __attribute__ ((aligned (sizeof(unsigned long))));
 };

 2,struct hc_driver {
  const char *description;  /* "ehci-hcd" etc */  ehci-hcd等 
  const char *product_desc; /* product/vendor string */ 产品字符串
  size_t  hcd_priv_size; /* size of private data */ 私有数据的size

  /* irq handler */
  irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs);中断处理函数

  int flags;
  #define HCD_MEMORY 0x0001  /* HC regs use memory (else I/O) */ HC的寄存器使用的内存或I/O
  #define HCD_USB11 0x0010  /* USB 1.1 */   
  #define HCD_USB2 0x0020  /* USB 2.0 */

  /* called to init HCD and root hub */
  int (*reset) (struct usb_hcd *hcd);    初始化HCD
  int (*start) (struct usb_hcd *hcd);    初始化根Hub 

  /* NOTE:  these suspend/resume calls relate to the HC as
   * a whole, not just the root hub; they're for bus glue.
   */
  /* called after all devices were suspended */
  int (*suspend) (struct usb_hcd *hcd, pm_message_t message);挂起Hub,进入D3(etc)前调用 

  /* called before any devices get resumed */   
  int (*resume) (struct usb_hcd *hcd);    进入D0(etc)后,恢复Hub

  /* cleanly make HCD stop writing memory and doing I/O */ 
  void (*stop) (struct usb_hcd *hcd);    HCD停止MM和IO

  /* return current frame number */
  int (*get_frame_number) (struct usb_hcd *hcd);  返回目前帧数

  /* manage i/o requests, device state */
  int (*urb_enqueue) (struct usb_hcd *hcd,   插入和退出urb队列
     struct usb_host_endpoint *ep,
     struct urb *urb,
     unsigned mem_flags);
  int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);

  /* hw synch, freeing endpoint resources that urb_dequeue can't */
  void  (*endpoint_disable)(struct usb_hcd *hcd,   释放endpoint资源
    struct usb_host_endpoint *ep);

  /* root hub support */      根Hub操作
  int (*hub_status_data) (struct usb_hcd *hcd, char *buf); 
  int (*hub_control) (struct usb_hcd *hcd,
     u16 typeReq, u16 wValue, u16 wIndex,
     char *buf, u16 wLength);
  int (*hub_suspend)(struct usb_hcd *);
  int (*hub_resume)(struct usb_hcd *);
  int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
  void (*hub_irq_enable)(struct usb_hcd *);
  /* Needed only if port-change IRQs are level-triggered */
 };

 /**
  * usb_create_hcd - create and initialize an HCD structure
  * @driver: HC driver that will use this hcd
  * @dev: device for this HC, stored in hcd->self.controller
  * @bus_name: value to store in hcd->self.bus_name
  * Context: !in_interrupt()
  *
  * Allocate a struct usb_hcd, with extra space at the end for the
  * HC driver's private data.  Initialize the generic members of the
  * hcd structure.
  *
  * If memory is unavailable, returns NULL.
  */
 3,struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name)
 
 /**
   * usb_add_hcd - finish generic HCD structure initialization and register
  * @hcd: the usb_hcd structure to initialize
  * @irqnum: Interrupt line to allocate
  * @irqflags: Interrupt type flags
  *
  * Finish the remaining parts of generic HCD initialization: allocate the
  * buffers of consistent memory, register the bus, request the IRQ line,
  * and call the driver's reset() and start() routines.
  */
 4,int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags)

 /**
  * usb_remove_hcd - shutdown processing for generic HCDs
  * @hcd: the usb_hcd structure to remove
  * Context: !in_interrupt()
  *
  * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
  * invoking the HCD's stop() method.
  */
 5,void usb_remove_hcd(struct usb_hcd *hcd);

 /*
  * This is the full ohci controller description
  *
  * Note how the "proper" USB information is just
  * a subset of what the full implementation needs. (Linus)
  */

 6,struct ohci_hcd {      作为usb_hcd结构体的hcd_priv
  spinlock_t  lock;
  /*
   * I/O memory used to communicate with the HC (dma-consistent)
   */
  struct ohci_regs __iomem *regs;    与主机控制器通信的IO内存(DMA 一致)

  /*
   * main memory used to communicate with the HC (dma-consistent).
   * hcd adds to schedule for a live hc any time, but removals finish
   * only at the start of the next frame.
   */
  struct ohci_hcca *hcca;     与主机控制器通信的主存(DMA 一致)
  dma_addr_t  hcca_dma;       

  struct ed  *ed_rm_list;  /* to be removed */ 将移除的OHCI Endpoint Descriptor (ED)

  struct ed  *ed_bulktail;  /* last in bulk list */ 批量队列尾
  struct ed  *ed_controltail; /* last in ctrl list */ 控制队列尾
   struct ed  *periodic [NUM_INTS];/* shadow int_table */ ??

  /*
   * OTG controllers and transceivers need software interaction;
   * other external transceivers should be software-transparent
   */
  struct otg_transceiver *transceiver;   OTG控制器和收发器需要软件交互,其他的外部收发器应该是软件透明的.

  /*
   * memory management for queue data structures  队列数据的内存管理
   */
  struct dma_pool *td_cache;
  struct dma_pool *ed_cache;
  struct td  *td_hash [TD_HASH_SIZE];
  struct list_head pending;

  /*
   * driver state      状态
   */
  int   load [NUM_INTS];
  u32    hc_control;  /* copy of hc control reg */ 主机控制器控制寄存器的复制
  unsigned long  next_statechange; /* suspend/resume */ 
  u32   fminterval;  /* saved register */ 被保存的寄存器

  struct work_struct rh_resume;
  struct notifier_block reboot_notifier;

  unsigned long flags;      /* for HC bugs */
  #define OHCI_QUIRK_AMD756 0x01   /* erratum #4 */
  #define OHCI_QUIRK_SUPERIO 0x02   /* natsemi */
  #define OHCI_QUIRK_INITRESET 0x04   /* SiS, OPTi, ... */
  #define OHCI_BIG_ENDIAN 0x08   /* big endian HC */
  #define OHCI_QUIRK_ZFMICRO 0x10   /* Compaq ZFMicro chipset*/
  // there are also chip quirks/bugs in init logic
 };

 7,struct ohci_hcd *hcd_to_ohci(struct usb_hcd *hcd);  内联函数usb_hcd与ohci_hcd的转换,得到私有数据
   struct usb_hcd  *ohci_to_hcd(const struct ohci_hcd *ohci); 通过conainer_of()从结构体成员获得所在结构体指针

 8,static int ohci_init (struct ohci_hcd *ohci);  初始化
   static int ohci_run (struct ohci_hcd *ohci)   开启
   static void ohci_stop (struct usb_hcd *hcd);   停止
   static void ohci_usb_reset (struct ohci_hcd *ohci)  复位 

   二,S3c2410主机驱动实例:
 S3c2410的集成的USB主机控制器兼容并实现OCHI1.0,USB1.1协议层.
 0x4900 0000 OHCI HcRevision
    HcControl
    HcCommonStatus
    HcInterruptStatus
    HcInterruptDisable
    HcHCCA
    HcPeriodCuttentED
    HcControlHeadED
    HcControlCurrentED
    HcBulkHeadED
    HcBulkCurrentED
    HcDoneHead
    HcRmInterval
    HcFmRemaining
    HcFmNumber
    HcPeriodicStart
    HcLSThreshold
    HcRhDescriptorA
    HcRhDescriptorB
    HcRhStatus
    HcRhportStatus1
    HcRhPortStatus2

  定义:static const struct hc_driver ohci_s3c2410_hc_driver = {
  .description = hcd_name,
  .product_desc = "S3C24XX OHCI",
  .hcd_priv_size = sizeof(struct ohci_hcd),
  /*
   * generic hardware linkage   通用硬件连接
   */
  .irq =   ohci_irq,
  .flags =  HCD_USB11 | HCD_MEMORY,
  /*
   * basic lifecycle operations  基本生命周期操作
   */
  .start =  ohci_s3c2410_start,
  .stop =  ohci_stop,
  /*
   * managing i/o requests and associated device resources I/O操作
   */
  .urb_enqueue = ohci_urb_enqueue,
  .urb_dequeue = ohci_urb_dequeue,
  .endpoint_disable = ohci_endpoint_disable,
  /*
   * scheduling support   调度
   */
  .get_frame_number = ohci_get_frame,
  /*
   * root hub support    根Hub操作
   */
  .hub_status_data = ohci_s3c2410_hub_status_data,
  .hub_control = ohci_s3c2410_hub_control,

  #if defined(CONFIG_USB_SUSPEND) && 0 挂起和恢复
  .hub_suspend = ohci_hub_suspend,
  .hub_resume =  ohci_hub_resume,
  #endif
 };
  实现函数: 
 static int ohci_s3c2410_start (struct usb_hcd *hcd)
 {
  struct ohci_hcd *ohci = hcd_to_ohci (hcd);
  int ret;

  if ((ret = ohci_init(ohci)) < 0)
   return ret;

  if ((ret = ohci_run (ohci)) < 0) {
   err ("can't start %s", hcd->self.bus_name);
   ohci_stop (hcd);
   return ret;
  }
  return 0;
 }

2,Linux的USB设备驱动
 USB设备文件 usbdevfs,usbfs 是动态产生的 /dev/ttyUSBn (串口Major188)
 挂载:  在/etc/fstab 加入 none /proc/bus/usb usbfs defaults
  或输入: mount -t usbfs none /proc/bus/usb
 显示:  cat /proc/bus/usb/devices
  拓扑,带宽,产品ID,Device Des,Config Des,Interface Des,Endpoint Des,Char Des.
 sysfs:/sys/bus/usb ->devices
    ->drivers -> hub
        -> usb
        -> usbfs 
  /sys/devices
  /sys/drivers
 
usb_driver:USB设备驱动描述
 /**
  * struct usb_driver - identifies USB driver to usbcore
  * @owner: Pointer to the module owner of this driver; initialize
  * it using THIS_MODULE.
  * @name: The driver name should be unique among USB drivers,
  * and should normally be the same as the module name.
  * @probe: Called to see if the driver is willing to manage a particular
  * interface on a device.  If it is, probe returns zero and uses
  * dev_set_drvdata() to associate driver-specific data with the
  * interface.  It may also use usb_set_interface() to specify the
  * appropriate altsetting.  If unwilling to manage the interface,
  * return a negative errno value.
  * @disconnect: Called when the interface is no longer accessible, usually
  * because its device has been (or is being) disconnected or the
  * driver module is being unloaded.
  * @ioctl: Used for drivers that want to talk to userspace through
  * the "usbfs" filesystem.  This lets devices provide ways to
  * expose information to user space regardless of where they
  * do (or don't) show up otherwise in the filesystem.
  * @suspend: Called when the device is going to be suspended by the system.
  * @resume: Called when the device is being resumed by the system.
  * @id_table: USB drivers use ID table to support hotplugging.
  * Export this with MODULE_DEVICE_TABLE(usb,...).  This must be set
  * or your driver's probe function will never get called.
  * @driver: the driver model core driver structure.
  *
  * USB drivers must provide a name, probe() and disconnect() methods,
  * and an id_table.  Other driver fields are optional.
  *
  * The id_table is used in hotplugging.  It holds a set of descriptors,
  * and specialized data may be associated with each entry.  That table
  * is used by both user and kernel mode hotplugging support.
  *
  * The probe() and disconnect() methods are called in a context where
  * they can sleep, but they should avoid abusing the privilege.  Most
  * work to connect to a device should be done when the device is opened,
  * and undone at the last close.  The disconnect code needs to address
  * concurrency issues with respect to open() and close() methods, as
  * well as forcing all pending I/O requests to complete (by unlinking
  * them as necessary, and blocking until the unlinks complete).
  */
 struct usb_driver { USB Core 总线部分
  struct module *owner;        内核模块
  const char *name;         唯一的USB设备名

  int (*probe) (struct usb_interface *intf, const struct usb_device_id *id); 探测函数
  void (*disconnect) (struct usb_interface *intf);    断开函数
  int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf); IO控制函数
  int (*suspend) (struct usb_interface *intf, pm_message_t message);  挂起
  int (*resume) (struct usb_interface *intf);     恢复
  const struct usb_device_id *id_table;      hotplugging探测设备表

  struct device_driver driver;       驱动模块core
 };
  
 usb_device
 usb_interface
 usb_host_interface
 usb_host_endpoint

linux下usb驱动编写(内核2.4)——2.6与此接口有区别
我们知道了在Linux下如何去使用一些最常见的USB设备。但对于做系统设计的程序员来说,我们还需要具有驱动程序的阅读、修改和开发能力。

USB骨架程序(usb-skeleton),是USB驱动架构。/driver/usb/usb-skeleton.c

那些linux下不支持的USB设备几乎都是生产厂商特定的产品。他们需要特定的驱动程序。有些生产厂商根本不公开他们的USB协议。因为每一个不同的协议都会产生一个新的驱动程序,所以就有了这个通用的USB驱动骨架程序,它是以pci 骨架为模板的。

如果你准备写一个linux驱动程序,首先要熟悉USB协议规范。还要有USB urbs的概念。

Linux USB 骨架驱动程序:
1,Init,并在USB Core子系统里注册,将这个驱动程序支持那种设备,当被支持的设备从系统插入或拔出时,会有哪些动作等信息都传送到USB Core子系统中.
   module_init (usb_skel_init);   初始化包括usb_register
 usb_register(&skel_driver);
 static struct usb_driver skel_driver = {
  name: "skeleton",     对驱动程序进行描述
  probe: skel_probe,     函数指针,当设备与在id_table 中变量信息匹配时,此函数被调用。
  disconnect: skel_disconnect,   函数指针
  fops: &skel_fops,
  minor: USB_SKEL_MINOR_BASE,
  id_table: skel_table,
 };
 fops和minor变量是可选的。
   大多usb驱动程序钩住另外一个驱动系统,例如SCSI,网络或者tty子系统。这些驱动程序在其他驱动系统中注册,同时任何用户空间的交互操作通  过那些接口提供,比如我们把SCSI设备驱动作为我们USB驱动所钩住的另外一个驱动系统,那么我们此USB设备的read、write等操作,就相应按SCSI设备的  read、write函数进行访问。
  但是对于扫描仪等驱动程序来说,并没有一个匹配的驱动系统可以使用,那我们就要自己处理与用户空间的read、write等交互函数。
  Usb子系统提供一种方法去注册一个次设备号和file_operations函数指针,这样就可以与用户空间实现方便地交互。

2,probe当usb设备插入时,为了使linux-hotplug(PCI、USB等设备热插拔支持)系统自动装载驱动程序,你需要创建一个MODULE_DEVICE_TABLE。代码如下(这个模块仅支持某一特定设备):
 /* table of devices that work with this driver */
 static struct usb_device_id skel_table [] = {
  { USB_DEVICE(USB_SKEL_VENDOR_ID,   USB_DEVICE宏利用厂商ID和产品ID提供了一个设备的唯一标识。
       USB_SKEL_PRODUCT_ID) },
    { } /* Terminating entry */
  };
 MODULE_DEVICE_TABLE (usb, skel_table);

 当插入一个ID匹配的USB设备到USB总线时,驱动会在USB core中注册。驱动程序中probe 函数也就会被调用。
 static int skel_probe( struct usb_interface *interface,   接口指针
     const struct usb_device_id *id)  接口ID
 {
  struct usb_skel *dev = NULL;    设备资源
  struct usb_host_interface *iface_desc;
  struct usb_endpoint_descriptor *endpoint;
  size_t buffer_size;
  int i;
  int retval = -ENOMEM;

  /* allocate memory for our device state and initialize it */
  dev = kmalloc(sizeof(*dev), GFP_KERNEL);   申请资源
  if (dev == NULL) {
   err("Out of memory");
   goto error;
  }
  memset(dev, 0x00, sizeof(*dev));    初始化资源
  kref_init(&dev->kref);     引用计数初始化
  dev->udev = usb_get_dev(interface_to_usbdev(interface));usb_device
  dev->interface = interface;     usb_interface

  /* set up the endpoint information */   设置端点信息
  /* use only the first bulk-in and bulk-out endpoints */只使用第一个批量IN和批量OUT端点
  iface_desc = interface->cur_altsetting;
  for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
   endpoint = &iface_desc->endpoint[i].desc;
   if ( !dev->bulk_in_endpointAddr &&
    ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
        ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) ) {
    /* we found a bulk in endpoint */  找到一个批量IN端点
    buffer_size = le16_to_cpu( endpoint->wMaxPacketSize );
    dev->bulk_in_size = buffer_size;
    dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
    dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
    if ( !dev->bulk_in_buffer ) {
     err("Could not allocate bulk_in_buffer");
     goto error;
    }
   }

   if (!dev->bulk_out_endpointAddr &&
       ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
       ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) {
    /* we found a bulk out endpoint */   找到一个批量OUT端点
    dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
   }
  }
  if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
   err("Could not find both bulk-in and bulk-out endpoints");
   goto error;
  }

  /* save our data pointer in this interface device */  把usb_skel保存到interface
  usb_set_intfdata(interface, dev);    

  /* we can register the device now, as it is ready */
  retval = usb_register_dev(interface, &skel_class); 注册设备到USB Core,
          1,ask for a minor number.
          2,creates the devfs file for the usb device,devfs_mk_cdev().
                  class_device_create()
          3,creates a usb class device in the sysfs tree.
  if (retval) {
   /* something prevented us from registering this driver */
   err("Not able to get a minor for this device.");
   usb_set_intfdata(interface, NULL);
   goto error;
  }

  /* let the user know what node this device is now attached to */
  info("USB Skeleton device now attached to USBSkel-%d", interface->minor);
  return 0;

 error:
  if (dev)
   kref_put(&dev->kref, skel_delete);
  return retval;
 }
 /* Structure to hold all of our device specific stuff */
 struct usb_skel {      自定义的数据结构usb_skel
  struct usb_device *udev;    /* the usb device for this device */
  struct usb_interface *interface;   /* the interface for this device */
  unsigned char *bulk_in_buffer;   /* the buffer to receive data */
  size_t  bulk_in_size;    /* the size of the receive buffer */
  __u8  bulk_in_endpointAddr;  /* the address of the bulk in endpoint */
  __u8  bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
  struct kref kref;
 };
 /*
  * usb class driver info in order to get a minor number from the usb core,
  * and to have the device registered with devfs and the driver core
  */
 static struct usb_class_driver skel_class = {
  .name = "usb/skel%d",
  .fops = &skel_fops,
  .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
  .minor_base = USB_SKEL_MINOR_BASE,
 };
 static struct file_operations skel_fops = {
  .owner = THIS_MODULE,
  .read =  skel_read,
  .write = skel_write,
  .open =  skel_open,
  .release = skel_release,
 };
 驱动程序需要确认插入的设备是否可以被接受,如果不接受,或者在初始化的过程中发生任何错误,probe函数返回一个NULL值。否则返回一个含有设备驱动程序状 态的指针。通过这个指针,就可以访问所有结构中的回调函数。

3, 如果设备从usb总线拔掉,设备指针会调用disconnect函数。驱动程序就需要清除那些被分配了的所有私有数据、关闭urbs,并且释放设备文件devfs句柄。
 usb_set_intfdata(interface, NULL);
 usb_deregister_dev(interface, &skel_class);
 kref_put(&dev->kref, skel_delete);

4,注销,当要从系统卸载驱动程序时,需要注销usb子系统。即需要usb_unregister函数处理:
 module_exit(usb_skel_exit);
 static void __exit usb_skel_exit(void)
 {
  /* deregister this driver with the USB subsystem */
  usb_deregister(&skel_driver);
 }
5,skeleton驱动就已经和设备绑定上了,任何用户态程序要操作此设备都可以通过file_operations结构所定义的函数进行了。
 static struct file_operations skel_fops = {
 .owner = THIS_MODULE,
 .read =  skel_read,
 .write = skel_write,
 .open = skel_open,
 .release = skel_release,
 };
 1,static int skel_open(struct inode *inode, struct file *file)
  struct usb_skel *dev;
  dev = usb_get_intfdata(interface);
  /* increment our usage count for the device */
  kref_get(&dev->kref);
  /* save our object in the file's private structure */  
  file->private_data = dev;

 2,static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
  dev = (struct usb_skel *)file->private_data;
  /* do a blocking bulk read to get data from the device */
  retval = usb_bulk_msg(dev->udev,     对usb设备进行一次读或写,这个函数能够不需要创建urbs和操作urb函数
            usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
            dev->bulk_in_buffer,
            min(dev->bulk_in_size, count),
            &bytes_read, 10000);
 3,static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) 利用urbs批量写
  /* 建立一个urb及其buffer,复制user_buffer到urb */
  urb = usb_alloc_urb(0, GFP_KERNEL);
  buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
  if (copy_from_user(buf, user_buffer, count)) {
   retval = -EFAULT;
   goto error;
  }
  /* 设定urb */
  usb_fill_bulk_urb(urb, dev->udev,
       usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
       buf, count, skel_write_bulk_callback, dev);
  urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
  /* send the data out the bulk port */
  retval = usb_submit_urb(urb, GFP_KERNEL);
  /* release our reference to this urb, the USB core will eventually free it entirely */
  usb_free_urb(urb);
 exit:
  return count;

 4,static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
  skel_write_bulk的回调函数

 5,static void skel_delete(struct kref *kref)
 6,static int skel_release(struct inode *inode, struct file *file)

 
 7,USB请求块 urbs

数据结构分析:
 /usb/core
  config.c
   void usb_release_interface_cache(struct kref *ref)
   int usb_get_configuration(struct usb_device *dev)
   void usb_destroy_configuration(struct usb_device *dev)
  buffer.c
   int hcd_buffer_create ( struct usb_hcd *hcd )
   void *hcd_buffer_alloc ( struct usb_bus *bus, size_t size, unsigned mem_flags, dma_addr_t *dma )
   void hcd_buffer_free ( struct usb_bus *bus,size_t size, void *addr,dma_addr_t dma )
   void hcd_buffer_destroy ( struct usb_hcd *hcd )
  devices.c
   void usbfs_conn_disc_event(void)
   struct file_operations usbfs_devices_fops = {
    .llseek = usb_device_lseek,
    .read = usb_device_read,
    .poll = usb_device_poll,
    .open = usb_device_open,
    .release = usb_device_release,
   };
  devio.c
   struct file_operations usbfs_device_file_operations = {
    .llseek = usbdev_lseek,
    .read = usbdev_read,
    .poll = usbdev_poll,
    .ioctl = usbdev_ioctl,
    .open = usbdev_open,
    .release = usbdev_release,
   };
  file.c
   int usb_major_init(void)
   void usb_major_cleanup(void)
   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)
  inode.c
   void usbfs_update_special (void)
   void usbfs_add_bus(struct usb_bus *bus)
   void usbfs_remove_bus(struct usb_bus *bus)
   void usbfs_add_device(struct usb_device *dev)
   void usbfs_remove_device(struct usb_device *dev)
   int __init usbfs_init(void)
   void usbfs_cleanup(void)
  sysfs.c
   void usb_create_sysfs_dev_files (struct usb_device *udev)
   void usb_remove_sysfs_dev_files (struct usb_device *udev)
   void usb_create_sysfs_intf_files (struct usb_interface *intf)
   void usb_remove_sysfs_intf_files (struct usb_interface *intf)
  message.c
   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)
   int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
      void *data, int len, int *actual_length, int timeout)
   int usb_sg_init (
    struct usb_sg_request *io,
    struct usb_device *dev,
    unsigned  pipe,
    unsigned  period,
    struct scatterlist *sg,
    int   nents,
    size_t   length,
    unsigned  mem_flags
   )
   void usb_sg_wait (struct usb_sg_request *io)
   void usb_sg_cancel (struct usb_sg_request *io)
   int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
   int usb_get_string(struct usb_device *dev, unsigned short langid,
      unsigned char index, void *buf, int size)
   int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
   int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
   int usb_get_status(struct usb_device *dev, int type, int target, void *data)
   int usb_clear_halt(struct usb_device *dev, int pipe)
   void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
   void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf)
   void usb_disable_device(struct usb_device *dev, int skip_ep0)
   int usb_set_interface(struct usb_device *dev, int interface, int alternate)
   int usb_reset_configuration(struct usb_device *dev)
   int usb_set_configuration(struct usb_device *dev, int configuration)
  urb.c
   void usb_init_urb(struct urb *urb)
   void usb_free_urb(struct urb *urb)
   int usb_submit_urb(struct urb *urb, unsigned mem_flags)
   int usb_unlink_urb(struct urb *urb)
   void usb_kill_urb(struct urb *urb)
  usb.c
   int usb_register(struct usb_driver *new_driver)
   void usb_deregister(struct usb_driver *driver)
   struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
   struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,unsigned int altnum)
   int usb_driver_claim_interface(struct usb_driver *driver,struct usb_interface *iface, void* priv)
   void usb_driver_release_interface(struct usb_driver *driver,struct usb_interface *iface)
   const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
   struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
   struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
   struct usb_device *usb_get_dev(struct usb_device *dev)
   void usb_put_dev(struct usb_device *dev)
   void usb_put_intf(struct usb_interface *intf)
   void usb_lock_device(struct usb_device *udev)
   int usb_trylock_device(struct usb_device *udev)
   int usb_lock_device_for_reset(struct usb_device *udev,
   void usb_unlock_device(struct usb_device *udev)
   void usb_lock_all_devices(void)
   void usb_unlock_all_devices(void)
   struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
   int usb_get_current_frame_number(struct usb_device *dev)
   int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
   void *usb_buffer_alloc (struct usb_device *dev, size_t size,unsigned mem_flags,dma_addr_t *dma )
   void usb_buffer_free (
    struct usb_device *dev,
    size_t size,
    void *addr,
    dma_addr_t dma
   )
   int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,struct scatterlist *sg, int nents)
   void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,struct scatterlist *sg, int n_hw_ents)
   struct bus_type usb_bus_type = {
    .name = "usb",
    .match = usb_device_match,
    .hotplug = usb_hotplug,
    .suspend = usb_generic_suspend,
    .resume = usb_generic_resume,
   };
   int usb_disabled(void)
  hub.c
   void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
   void usb_set_device_state(struct usb_device *udev,enum usb_device_state new_state)
   void usb_disconnect(struct usb_device **pdev)
   int usb_new_device(struct usb_device *udev)
   int usb_suspend_device(struct usb_device *udev, pm_message_t state)
   int usb_resume_device(struct usb_device *udev)
   void usb_resume_root_hub(struct usb_device *hdev)
   int usb_suspend_device(struct usb_device *udev, pm_message_t state)
   int usb_hub_init(void)
   void usb_hub_cleanup(void)
   int usb_reset_device(struct usb_device *udev)
  hcd.c
   struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,struct device *dev, char *bus_name)
    创建一个usb_hcd结构体并初始化.
    usb_hcd,usb_bus,hc_driver,timer_list,device
    usb_devmap,usb_operations,usb_device,dentry,class_device,mon_bus
   int usb_add_hcd(struct usb_hcd *hcd,unsigned int irqnum, unsigned long irqflags)
    复位    retval = hcd->driver->reset(hcd) 
    定位一段usb DMA,   retval = hcd_buffer_create(hcd)
    register the bus,   usb_register_bus(&hcd->self)
    request the IRQ line, request_irq(irqnum, &usb_hcd_irq, irqflags,hcd->irq_descr, hcd))
    start().   rhdev = usb_alloc_dev(NULL, &hcd->self, 0) hcd->driver->start(hcd)
    usb_device
   void usb_remove_hcd(struct usb_hcd *hcd)
        usb_disconnect(&hcd->self.root_hub);
        free_irq(hcd->irq, hcd);
        usb_deregister_bus(&hcd->self);
        hcd_buffer_destroy(hcd);
   void usb_hcd_poll_rh_status(struct usb_hcd *hcd)  Root hub中断后的定时传输函数
    static void rh_timer_func (unsigned long _hcd)
    {
     usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
    }

   struct usb_bus *usb_bus_get(struct usb_bus *bus)
   void usb_bus_put(struct usb_bus *bus)
   int usb_host_init(void)
   void usb_enable_root_hub_irq (struct usb_bus *bus)
   long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
   int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
   void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
   void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
   void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
   int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
   void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
   irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
   void usb_hc_died (struct usb_hcd *hcd)
   void usb_put_hcd (struct usb_hcd *hcd)

   int usb_mon_register (struct usb_mon_operations *ops)
   void usb_mon_deregister (void)
  hcd-api.c
   int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
   void usb_hcd_pci_remove (struct pci_dev *dev)
   int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
   int usb_hcd_pci_resume (struct pci_dev *dev)
 /usb/host
  
 /usb/gadget

 

3,USB固件驱动
 UDC
 Gadger API
 Gadget

你可能感兴趣的:(usb,linux,struct,interface,descriptor,buffer,structure)