USB子系统学习笔记(二) Gadget驱动框架

一、抓住两个点
  • 描述符:表示自己(设备需要bind描述符)

  • endpoint:数据传输

    • 基本的功能:按照USB规范进行数据的传输,不提供具体的数据(data filed)
      • 由硬件层的驱动来实现(设备需要bind到udc)
    • 特定的功能:什么时候把什么数据按什么规则组织后进行传输
      • 这样在某一具体情境下,我们规定的这样的数据有一个具体的含义
      • 比如:usb存储设备接收到主机的存储指令时,把主机发来的数据接收,按照文件系统要求的规则组织后存储。
      • 这里由接口层来实现(设备需要bind功能)
  • 特例:ep0

    假设host发起两个这样的传输:设置地址、读取描述符。这两个传输都是访问端点0,但是一个的数据、请求是底层提供的,另一个的数据(描述符)是由上层提供的

    • 设置地址:usb_gadget即可实现,这时数据由底层(usb_gadget)即可提供
    • 读取描述符:描述符由开发者提供,传输描述符是通用的操作已由内核实现(由usb_gadget_driver实现)
      • host想要读取描述符,usb设备至少需要实现两个功能:提供描述符(usbcomposite_driver)、传输描述符(usb_gadget_driver)
二、总体认识

usb复合设备用描述符来表示自己

由usb_composite_driver提供:


  • 设备描述符
  • 配置描述符

由usb_function_driver提供:


  • 接口描述符
  • 端点描述符
    • function实现特定功能定义的端点的操作函数、实现数据传输
    • 对于一般的端点的包的传输功能,由usb_udc实现
三、框架分析

在这里插入图片描述

usb_function_driver

  • 接口描述符
  • 端点描述符

usb_composite_driver

  • 设备描述符
  • 配置描述符

usb_gadget_driver

  • 实现更高层的endpoint0的传输

  • 如:实现描述符的传输,描述符由上层提供


usb_gadget:硬件层的驱动(以上三层都是软件层的驱动),实现了符合USB规范规定的USB传输的功能

​ 核心:endpoint数据传输

  • 设置usb_gadget结构体

    • 定义了endpoint的操作函数

      • out端点(接收数据)

        建立请求,把接收到的数据放入请求的某个buffer中,请求的回调函数调用ep的操作函数放入ep的某一个队列中

      • in端点(提供数据)

        建立请求,请求的回调函数调用ep的操作函数把数据放入请求的某个buffer中

  • 分配设置udc结构体

    • udc->gadget=usb_gadget
      
  • 把udc结构体加入udc_list

    • udc_list->next=udc
      

层次结构:

udc_list->udc->udc->udc

  • udc
    • usb_gadget
      • endpoint
        • ep_opr

四、驱动分析
  • 分配usb_composite_driver结构体

    • struct usb_composite_driver zero_driver
      
    • 包含设备描述符和配置描述符

在这里插入图片描述

  • 注册usb_composite_driver结构体

    • module_usb_composite_driver(zero_driver)
          这个函数进一步调用usb_composite_driver_probe() 
      
  • 调用usb_composite_driver_probe() ,将会找到一个udc结构体

    • 寻找udc结构体的目的是将usb_gadget_driver加入udc结构体,所以先要初始化一个udc结构体。将会调用usb_composite_driver=template
      • temptate是一个模板,usb_composite_driver类型定义了bind成员,template将bind初始化为composite_bind
    • 这个函数会return usb_gadget_probe_driver,这个函数寻找udc列表,找到一个udc
    • 继续调用udc_bind_to_driverusb_gadget_driver绑定到udc
  • udc_bind_to_driver内部执行usb_gadget_driver->bind,即调用composite_bind函数

  • composite_bind

    • 分配usb_composite_dev结构体
    • 设置usb_composite_dev结构体部分信息(设备描述符、usb_gadget)
    • 调用zero_bind
  • zero_bind添加功能

    • 获取function实例、根据实例获取function实体、添加配置、将function添加进配置
    • 通过function的名字,获取function实例。
      在这里插入图片描述
五、获取描述符

​ 当Host启动控制传输想要获取描述符时,Gadget驱动框架是如何处理的呢?

​ 首先,Gadget驱动框架使用中断服务程序来处理控制传输中,setup阶段的请求。当中断发生时,Gadget会由下而上的依次递交这个请求,直到有相应的setup函数能够处理它。这个层次结构是这样的:
在这里插入图片描述

​ 上图中,最下层是mp157的udc和6ull的udc。标红的是对应各层的setup函数,他们处理控制传输setup阶段中的data数据包,完成对数据的解析并做对应的处理。发生中断后,Gadget设备首先调用底层的setup函数进行处理,如不能处理这个请求,则会调用到更上层的setup函数。各层setup函数能够处理的请求如下:

  • UDC驱动程序:类似"设置地址"的控制传输,在底层的UDC驱动程序里就可以处理,

    • 这类请求有:

      USB_REQ_SET_ADDRESS
      USB_REQ_SET_FEATURE     // 有一些请求可能需要上报改gadget driver
      USB_REQ_CLEAR_FEATURE   // 有一些请求可能需要上报改gadget driver
      USB_REQ_GET_STATUS      // 有一些请求可能需要上报改gadget driver
      
    • 驱动程序位置

      IMX6ULL: Linux-4.9.88\drivers\usb\chipidea\udc.c, 函数isr_setup_packet_handler
      STM32MP157: Linux-5.4\drivers\usb\dwc2\gadget.c, 函数dwc2_hsotg_complete_setup
      
  • gadget driver:涉及描述符的操作

    • 这类请求有:

      USB_REQ_GET_DESCRIPTOR
      USB_REQ_SET_CONFIGURATION
      USB_REQ_GET_CONFIGURATION
      USB_REQ_SET_INTERFACE
      USB_REQ_GET_INTERFACE
      USB_REQ_GET_STATUS     // 底层UDC驱动无法处理的话, gadget driver来处理
      USB_REQ_CLEAR_FEATURE  // 底层UDC驱动无法处理的话, gadget driver来处理
      USB_REQ_SET_FEATURE    // 底层UDC驱动无法处理的话, gadget driver来处理
      
    • 驱动程序位置

      文件:drivers\usb\gadget\composite.c
      函数:composite_setup
      
  • usb_configuration或usb_function的处理:这是二选一的。大部分设备使用控制传输实现标准的USB请求,但是也可以用控制传输来进行实现相关的请求,对于这些非标准的请求,就需要上层驱动来处理。

六、数据传输的过程

​ USB传输中,参与数据传输的对象是端点。在功能的驱动中,会提出对端点的要求,而usb_udc会根据function中提出的要求去为function分配端点(只有硬件呢能够满足function的端点的要求功能才能使用,端点才能分配成功),有了端点以后,function就能进行数据传输了。

​ 在USB协议中,永远是Host主动发起传输。作为一个Gadget驱动程序,它永远都是这样:

  • 想接收数据:

    • 先构造好usb_request:分配buffer、设置回调函数
    • 把usb_request放入队列
    • UDC和Host完成USB传输,在usb_request中填充数据,并触发中断调用usb_request的回调函数
  • 想发送数据:

    • 先构造好usb_request:分配buffer、在buffer里填充数据、设置回调函数
    • 把usb_request放入队列
    • UDC和Host完成USB传输,把usb_request的数据发给Host,并触发中断调用usb_request的回调函数

    Gadget设备侧分析一个数据传输流程:

在这里插入图片描述

​ 那么何时去构造一个usb_request呢?

​ **猜想:**因为传输总由Host发起,所以USB设备会建立一个特殊的usb_request持续等待Host的关于传输启动的包。接收到这个包后进行一系列的传输,比如建立请求让主机读数据、接收到主机的数据后在回调函数中对数据作处理。最后,所有的工作完成后,在回调函数中重新建立这个usb_request,回到待命的状态。

  • 32
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Linux USB gadget驱动编写有如下几个步骤: 1. 确定USB gadget功能:首先需要确定所需实现的USB gadget功能,例如以USB设备的形式提供存储、网络、音频等服务。这样可以决定需要实现的USB gadget驱动类型和功能。 2. 编写USB驱动框架:基于Linux内核框架,编写USB gadget驱动的基本框架。这包括注册USB gadget驱动和常用的函数接口等。 3. 实现USB gadget子系统:根据所需的功能,实现USB gadget子系统的模块,如存储、网络或音频子系统等。这些子系统需要封装底层的USB通信协议和数据传输,供应用程序调用。 4. 配置USB gadget驱动:根据具体需求,在系统配置文件中进行必要的配置,以启用和配置USB gadget驱动。这包括配置端点、描述符和功能等。 5. 移植和编译:将驱动程序编译成内核模块,然后将其移植到目标设备上。对于嵌入式设备,可能需要修改硬件相关的代码,以适应硬件平台。 6. 测试和调试:编写测试用例,对USB gadget驱动进行测试和调试,确保其正常工作。这包括对设备和主机之间的数据传输进行验证,以及处理异常情况和错误处理。 总之,编写Linux USB gadget驱动需要明确所需实现的功能、基于内核框架编写驱动框架、实现USB gadget子系统、配置以及移植和编译。最后进行测试和调试,确保驱动程序的正常运行。通过以上步骤,可以实现各种USB设备功能的驱动。 ### 回答2: Linux USB gadget驱动是用于实现USB设备的功能的驱动程序。它使得Linux设备可以作为一个USB设备与其他主机进行通信。在编写Linux USB gadget驱动时,需要完成以下几个步骤。 首先,需要确定设备的功能和属性。USB设备可以有多种功能,如储存设备、键盘、鼠标等。根据设备的类型和规格,确定设备的操作和数据传输方式。 其次,在驱动程序中定义设备的USB描述符。USB描述符包括设备描述符、接口描述符和端点描述符等,它们是USB协议的一部分,用于描述设备的属性和功能。 然后,在驱动程序中实现设备的相关功能。根据设备的类型和规格,编写相应的功能代码。例如,如果设备是一个键盘,就需要实现按键事件的处理逻辑;如果设备是一个储存设备,就需要实现读写数据的逻辑。 最后,编译和加载驱动程序。使用Linux内核提供的工具链,将驱动程序编译为可执行文件,并将其加载到Linux内核中运行。加载驱动程序后,系统即可识别设备,并根据驱动程序中定义的功能和属性来处理设备的操作和数据传输。 总之,编写Linux USB gadget驱动需要确定设备的功能和属性、定义USB描述符、实现设备的相关功能,最后编译和加载驱动程序。通过这些步骤,我们可以在Linux系统中实现USB设备的功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值