Linux USB子系统之阅读笔记

本文介绍了Linux USB子系统,包括USB Device Driver Framework的注册过程、数据结构和主要入口点。USB驱动通过注册probe和disconnect函数与系统交互,当设备连接或断开时,这些函数会被调用。此外,还讨论了USB设备驱动的数据结构,如模块名、文件操作指针和minor number等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux USB Subsystem

 

Linux 包括了一个 USB Core 的子系统。其包含了一组特定的API函数来支持USB设备和主机控制器。

USB Core 中包含了通用于所有 USB 设备和主机控制器驱动程序的函数。这些函数可以划分成上层和底层API。

从下图可以看出,一类API是为USB设备驱动程序服务,另一类为主机控制器驱动程序服务。

 

 

 

\includegraphics [width=\linewidth]{usbcore}

USB Device Driver Framework

USB设备驱动通过USB子系统框架进行注册/注销。每个USB设备驱动应该注册两个入口点和入口名字,并且注册一组文件操作指针和一个minor number。

所有USB设备的 major number 都是 180。

 

Framework Data Structures

所有USB相关函数或数据结构都遵从相同的命名规则,且以usb_ 为前缀。

 

下图列出了注册usb驱动到USB子系统的数据结构。

\begin{figure}\centering\index{struct usb\_driver}\begin{verbatim}struct usb...... void *buf);const struct usb_device_id *id_table;};\end{verbatim}\end{figure}
  • name: 模块名
  • probe: 侦测函数入口
  • disconnect: 断开函数入口
  • driver_list: 子系统内部使用
  • fops:  驱动程序通用文件操作列表
  • minor:  被分配给该驱动的 minor number 基值(该值应该是16的倍数)。
  • serialize:  串行化
  • ioctl:  I/O接口控制
  • id_table:

 

Framewor Entry Point

USB驱动框架针对常规设备驱动增加了两个入口函数。

  • void *probe(struct usb_device *dev, unsigned int interface, const struct usb_device_id *id_table);

        当新设备被连接上总线时,该入口函数被调用。驱动将为新设备创建其内部数据结构的实例。

        dev 参数指定了设备上下文, 包含了所有 USB 描述符的指针。

        interface 参数指定了接口值。 如果usb驱动希望去绑定一个特定的设备和接口,它将返回一个指针;该指针指向了驱动程序的上下文数据结构。

        probe 函数通常检查 usb 供应商和产品信息,或者usb class 和 subclass 定义。如果和驱动支持的接口数值进行比较后其相等,将继续解析更多的 USB 描述符。

 

       一个简单的 probe 函数示例如下:

\begin{figure}\centering\index{probe function}\begin{verbatim}void *probe(s......tance context */return context;}return NULL;}\end{verbatim}\end{figure}

 

  • void disconnect(struct usb_device *dev, void *drv_context);

         当USB驱动服务的设备被拔出时,  disconnect() 函数被调用。

         dev 参数指定了设备上下文。

         drv_context 参数返回一个指向先前由 probe() 函数注册的 drv_context 指针。

         一旦 disconnect() 函数返回, USB 框架将释放所有关联该设备的数据结构。 usb_driver 数据结构不能再被驱动使用。

        一个简单的 disconnect() 函数示例如下:

\begin{figure}\centering\index{disconnect function}\begin{verbatim}static vo......e */free_driver_resources(s);MOD_DEC_USE_COUNT;}\end{verbatim}\end{figure}

 

 

Framework Functions

  • int usb_register(struct usb_driver *drv);

         usb_register() 函数注册一个新的usb 驱动到子系统中。
         drv 参数指向一个已被初始化的 usb_driver 数据结构。

     

  • void usb_deregister(struct usb_driver *drv);

        usb_deregister() 从子系统中注销一个已注册的USB设备驱动。

  • void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *drv_context);

         如果usb 设备驱动需要声明多于一个的接口, usb_driver_claim_interface() 函数被调用。

      

  • int usb_interface_claimed(struct usb_interface *iface);

         usb_interface_claimed() 函数检查是否驱动程序已经声明了该接口。

  • void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface);

        usb_driver_relese_interface() 函数释放先前声明的接口。

        disconnect() 函数不需要释放先前被 probe() 函数声明的接口。

     

  • const struct usb_device_id *usb_match_id( struct usb_device *dev, struct usb_interface *interface, const struct usb_device_id *id);

     

    Configuring USB Devices

    USB子系统框架提供了一系列的可以选择/查询设备描述符、配置和可选设定的 API 函数。

    所有标准操作都是通过对设备的控制传输来完成。

     

    Descriptor Data Structures

    Linux USB 子系统通过扩展或内嵌的方式,在设备描述符结构中包含了标准USB描述符。

    描述符数据结构存储了指向被选定的配置和接口的指针。

     

    struct usb_device{
      ...
      struct usb_config_descriptor *actconfig;/* the active configuration */
      ...
      struct usb_device_descriptor descriptor;/* Descriptor */
      struct usb_config_descriptor *config;	/* All of the configs */
    }
    


    usb_device 结构是所有 USB特定描述符之根本。有时,为了配置设备或设置传输请求,USB驱动有必要解析该结构。

    • 访问所有有效的配置描述符
    for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
      struct usb_config_descriptor *cfg = &dev->config[i];
      ...
    }
    

     

    • 访问一个特定配置的所有有效接口描述符
    for (j = 0; j < cfg->bNumInterfaces; j++) {
      struct usb_interface *ifp = &cfg->interface[j];
      ...
    }
    

           为启动活动配置的解析,使用 dev->actconfig 指针。

    • 访问一个特定接口的所有可选设定
    for (k = 0; k < ifp->num_altsetting; k++) {
      struct usb_interface_descriptor *as = &ifp->altsetting[k];
      ...
    }
    

            活动可选设定可以通过如下方式访问: 

            *as = &ifp->altsetting[ifp->act_altsetting]

    • 访问一个特定可选设定的所有端点
    for(l = 0; l < as->bNumEndpoints; l++) {
      struct usb_endpoint_descriptor *ep=&as->endpoint[k];
      ...
    }
    

    Standard Device Requests

      

  • int usb_set_configuration(struct usb_device *dev, int configuration);

    To activate a particular configuration use this function.
    The argument is of
    0 <= configuration < dev->descriptor.bNumConfigurations.
    Configuration 0 is selected by default after the device is attached to the bus.

  • int usb_set_interface(struct usb_device *dev, int interface, int alternate);

    This function activates an alternate setting of a specified interface.

    The argument interface is of
    0 <= interface < dev->actconfig->bNumInterfaces.
    The argument alternate is of
    0 <= alternate < dev->actconfig->interface[interface].num_altsetting

  • int usb_get_device_descriptor(struct usb_device *dev);

    This function rereads the complete descriptor tree from a particular device.

    It is called automatically whenever a device is attached to the bus or it may be called whenever a USB descriptor has changed.

  • int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned char descindex, void *buf, int size);

    Single USB descriptors can be read as raw data from a device. This function can be used to parse extended or vendor specific descriptors.

  • int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size);

    If a device, configuration or interface descriptor references a string index value, this function can be used to retrieve the string descriptor.

    According to the specification USB strings are coded as Unicode. If successful the function returns 0 otherwise an error code is returned.

  • int usb_string(struct usb_device *dev, int index, char *buf, size_t size);

    This function simplifies usb_get_string by converting Unicode strings into ASCII strings.

  • int usb_get_status(struct usb_device *dev, int type, int target, void *data);

  • int usb_clear_halt(struct usb_device *dev, int pipe);

    If an endpoint is stalled , call this function to clear the STALL condition.

    STALL indicates that a function is unable to transmit or receive data, or that a control pipe request is not supported.

    The argument endpoint defines a pipe handle.

  • int usb_get_protocol(struct usb_device *dev, int ifnum);

  • int usb_set_protocol(struct usb_device *dev, int protocol, int ifnum);

  • int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, int ifnum, void *buf, int size);

  • int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id);

     

    USB Transfer

    包括了所有数据结构,宏和与总线数据传输相关的函数。以及如何设置,提交和处理传输请求。

     

    Transfer Data Structures & Macros

    Linux USB子系统使用唯一的数据传输结构URB ( USB Request Block)。该数据结构包含了设置任何usb传输类型所需的全部参数。

    所有数据传输请求以异步方式发送给 USB Core, 传输请求完成则通过回调函数通知。

     

    \begin{figure}
\centering\index{struct urb}
\index{URB}
\begin{verbatim}typede...
...desc[0]; // optional iso descriptors
} urb_t, *purb_t;\end{verbatim}\end{figure}

    上图中,

    • C 标记表示所有传输类型都通用的元素。
    • > 表示输入参数
    • < 表示返回值
    • M 表示强制参数
    • O 表示可选参数
    • T 表示双向参数 ( 可输入,可输出)
    • 所有非通用元素,标记有三列。分别代表控制,中断,实时传输。如果对应列有一个 X 标记,表示该元素被用于该传输类型。

     

    URB 结构参数介绍如下:

    • dev (强制输入参数) :     指向 usb_device 结构体的指针
    • pipe (强制输入参数):  pipe 用来编码端点值和属性
      • pipe=usb_sndctrlpipe(dev,endpoint)
        pipe=usb_rcvctrlpipe(dev,endpoint)

                            创建下行 (snd ) 和上行 ( rcv)控制传输到到指定的端点。

      • pipe=usb_sndbulkpipe(dev,endpoint)
        pipe=usb_rcvbulkpipe(dev, endpoint)

                            创建下行 (snd ) 和上行 ( rcv)块传输到到指定的端点。

      • pipe=usb_sndintpipe(dev,endpoint)
        pipe=usb_rcvintopipe(dev,endpoint

        创建下行 (snd ) 和上行 ( rcv)中断传输到到指定的端点。
      • pipe=usb_sndisopipe(dev,endpoint)
        pipe=usb_rcvisopipe(dev, endpoint)

         

        创建下行 (snd ) 和上行 ( rcv)实时传输到到指定的端点。

    • transfer_buffer (强制输入参数)
    • transfer_buffer_length (强制输入参数)
    • complete (可选输入参数):  提供给调用者的函数指针。当传输请求完成后,该函数被调用。通过此回调方式,调用者可以在传输完成后进行特定的操作。
    • context (可选输入参数)
    • transfer_flags (可选输入参数和返回值)
      • USB_DISABLE_SPD
      • USB_NO_FSBR
      • USB_ISO_ASAP
      • USB_ASYNC_UNLINK
      • USB_TIMEOUT_KILLED
      • USB_QUEUE_BULK
    • next (可选输入参数)
    • status (返回值)
    • actual_length (返回值)

    URB Functions

    USB Core 一共有四个函数处理 URB数据结构。

    • purb_t usb_alloc_urb(int iso_packets);

               usb_alloc_urb() 用于创建一个新的 URB 数据结构实例。

               iso_packets 参数: 表示  iso_frame_desc 结构的数目。用于实时传输类型。

    • void usb_free_urb (purb_t purb);

               usb_free_urb() 释放由 usb_alloc_urb() 分配的 URB 结构。 

     

    • int usb_submit_urb(purb_t purb);

               usb_submit_urb() 以异步方式提交传输请求到 USB Core 中去。

     

    • int usb_unlink_urb(purb_t purb);

               usb_unlink_urb() 取消一个已提交但未完成的传输请求。

              usb_unlink_urb() 也被用来停止中断传输类型的URB。

     

    URB Macros

    2.x 内核中有如下 URB 宏用于填充 URB 结构体。

    至少3.4.x 内核中,已经转化成对应的函数形式填充 URB 结构体。

    • FILL_CONTROL_URB(purb, dev, pipe, setup_packet, transfer_buffer, transfer_buffer_length, complete, context);

    • FILL_BULK_URB(purb, dev, pipe, transfer_buffer, transfer_buffer_length, complete, context);

    • FILL_INT_URB(purb, dev, pipe, transfer_buffer, transfer_buffer_length, complete, context, interval);

    • FILL_CONTROL_URB_TO();

    • FILL_BULK_URB_TO();

    Compatibility Wrappers

    The USB core contains a number of higher level functions which were introduced as compatibility wrappers for the older APIs. Some of these functions can still be used to issue blocking control or bulk transfers.

    • 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);

      Issues a blocking standard control request.

    • int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *actual_length, int timeout);

      Issues a blocking bulk transfer.

    在 3.4.5 内核中,对应有

    • 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_control_msg() 创建一个简单的控制传输urb结构, 发送它到一个指定的端点并且等待该消息完成。

      • dev:                       指向此消息将要发送到的usb设备指针
      • pipe:                      指向次消息将要发送到的端点
      • request:                 USB消息请求值
      • requesttype:          USB消息类型
      • value                     USB消息值
      • index                     USB消息索引值
      • data                       被发送的数据的指针
      • size                       被发送的数据字节长度
      • timeout                 消息完成之前超时等待的时间 (毫秒数)

                usb_control_msg() 不可用于中断上下文,例如中断底半部。

                如果需要一个异步消息,或者需要在中断上下文使用,使用 usb_submit_urb()。

                如果usb驱动程序线程中调用了 usb_control_msg(), 请确保等待其完成后再调用 disconnect() 函数。

                因为没有 URB 的句柄,该请求不能被撤消。

    • int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)

                usb_interrupt_msg() 创建一个简单的中断传输urb结构, 发送它到一个指定的端点并且等待该消息完成。

                usb_interrupt_msg() 不可用于中断上下文,例如中断底半部。

     

    • int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)

                usb_bulk_msg() 创建一个简单的中断传输urb结构, 发送它到一个指定的端点并且等待该消息完成。

                usb_bulk_msg() 不可用于中断上下文,例如中断底半部。

     

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值