USB Gadget设备驱动开发(一) USB Gadget软件结构

USB Gadget软件结构总共分为三层,其软件架构图如下

USB Gadget设备驱动开发(一) USB Gadget软件结构_第1张图片

一. UDC层
   这一层是与硬件相关层。相关文件ambarella_udc.c ambarella_udc.h。ambarella设备控制器作为一个linux设备在这一层是作为platform设备而注册到linux设备模型中的。相关数据结构以及相关函数如下:

1 数据结构ambarella_udc

struct ambarella_udc {

    spinlock_t        lock;

    struct device        *dev;

    void __iomem         *base_reg;

    void __iomem         *reset_reg;

    int            irq;

    struct usb_phy           *phy;

 

    structproc_dir_entry       *proc_file;

    structwork_struct       uevent_work;

    structtimer_list    vbus_timer;

    enumusb_device_state       pre_state;

 

    structusb_gadget    gadget;

    structusb_gadget_driver *driver;

 

    struct dma_pool          *desc_dma_pool;

 

    structambarella_ep      ep[EP_NUM_MAX];

    u32           setup[2];

    dma_addr_t        setup_addr;

    structambarella_setup_desc *setup_buf;

    dma_addr_t        dummy_desc_addr;

    structambarella_data_desc  *dummy_desc;

 

    u16           cur_config;

    u16           cur_intf;

    u16            cur_alt;

 

    unsigned          auto_ack_0_pkt : 1,

                  remote_wakeup_en  : 1,

                  host_suspended: 1,

                  sys_suspended: 1,

                  reset_by_host: 1,

                  vbus_status: 1,

                  udc_is_enabled: 1;

 

    /* dma_fix isonly used for S2 chip, due to its DMA engine fault */

    u32           dma_fix;

};

 

2 函数platform设备需要注册一个platform_driver的结构体:

static struct platform_driver ambarella_udc_driver = {

        .driver        = {

               .name   = "ambarella-udc",

               .owner  = THIS_MODULE,

               .of_match_table = ambarella_udc_dt_ids,

        },

        .remove        = ambarella_udc_remove,

#ifdef CONFIG_PM

        .suspend       = ambarella_udc_suspend,

        .resume        = ambarella_udc_resume,

#endif

};

结构体中的相关函数最关键的函数就是ambarella_udc_probe函数,其实现在module_platform_driver_probe(ambarella_udc_driver,ambarella_udc_probe)中。这个函数在platform总线为驱动程序找到合适的设备后调用,在函数内初始化设备的时钟,申请io资源以及irq资源初始化platform设备结构体struct ambarella_udc。

以上的数据结构以及函数是UDC的硬件层,不同的UDC采取不同的策略。Ambarella就是采用platform驱动的形式来注册的。如果系统是外接的USB设备控制器,那么则会采用相应总线的注册形式,比如PCI等。platform驱动的唯一目的就是分配资源以及初级初始化硬件,对于USB设备层和功能驱动层都没有影响。UDC层与USB设备层是通过另外的数据结构进行交互的。这种方式就是使用两个结构体与两个函数, 两个结构体分别是struct usb_gadget与struct usb_gadget_driver,他们都是嵌入在struct ambarella_udc结构中的,但是是由不同软件层的代码初始化的。structusb_gadget是在ambarella_udc_probe函数调用ambarella_init_gadget(udc, pdev)的时候就进行了初始化,是在UDC层中初始化的。而struct usb_gadget_driver是在USB设备层中初始化的,他是通过usb_gadget_probe_driver(structusb_gadget_driver *driver)函数从USB设备层传过来然后赋值给ambarella_udc结构体。这里出现一个关键的函数usb_gadget_probe_driver(structusb_gadget_driver *driver)这个函数就是UDC层与USB设备层进行交互的函数。设备设备层通过调用它与UDC层联系在一起。这个函数将usb_gadget与usb_gadget_driver联系在一起。向USB设备层提供usb_gadget_probe_driver(structusb_gadget_driver *driver)是UDC层的基本任务,但是UDC层要做的不仅如此,UDC层还需要提供为usb_gadget服务的相关函数,这些函数会通过usb_gadget传递给USB设备层。UDC层还需要提供USB设备的中断处理程序,中断处理尤其重要。因为所有的USB传输都是由主机发起,而有没有USB传输完全由USB中断判定,所以USB中断处理程序是整个软件架构的核心。UDC层主要提供以下的函数与数据结构:

(1)usb_gadget操作函数集合,其实现在ambarella_init_gadget函数体中。

static const structusb_gadget_ops ambarella_ops = {

    .get_frame    = ambarella_udc_get_frame,

    .wakeup           = ambarella_udc_wakeup,

    .pullup           = ambarella_udc_pullup,

    .vbus_session     = ambarella_udc_vbus_session,

    /*.set_selfpowered:Always selfpowered */

    .udc_start    = ambarella_udc_start,

    .udc_stop     = ambarella_udc_stop,

};       

这些函数都是由UDC层来实现的。


(2) 端点操作函数集合,其实现在ambarella_init_gadget函数体中。

static const struct usb_ep_ops ambarella_ep_ops = {

    .enable       = ambarella_udc_ep_enable,

    .disable   = ambarella_udc_ep_disable,

 

    .alloc_request    = ambarella_udc_alloc_request,

    .free_request = ambarella_udc_free_request,

 

    .queue     = ambarella_udc_queue,

    .dequeue   = ambarella_udc_dequeue,

 

    .set_halt  = ambarella_udc_set_halt,

    /* fifo ops notimplemented */

};

 

(3)在ambarella_udc_probe中调用devm_request_irq申请USB中断处理程序

static irqreturn_t ambarella_udc_irq(int irq, void *_dev)

 

(4) 其他相关辅助函数,比如调试相关函数。


二 USB设备层
 USB设备层,虽然名字上与设备相关。但是属于硬件无关层。这一层相关的代码是composite.c,composite.h。这一层的功能是隔离Gadget功能驱动与硬件相关层。使得功能驱动直接与USB设备层交互不用考虑硬件的相关细节。还有USB设备层提供了USB设备的一些基本数据结构,不同的Gadget功能驱动可以共同调用。如果没有这一层,则每一个功能驱动都需要实现自己的USB设备,导致了代码重用率很高。这一层向下与UDC层进行交互,向上与Gadget功能驱动层进行交互。在UDC层已经介绍了USB设备层向下与UDC层交互方式主要是通过调用usb_gadget_probe_driver(struct usb_gadget_driver *driver),这个函数是composite中实现,而在Gadget功能驱动中调用usb_composite_probe来初始化。而这个函数传递的参数就是一个usb_gadget_driver的结构体。以下是这个结构体定义:

struct usb_gadget_driver {

    char          *function;

    enumusb_device_speed    max_speed;

    int        (*bind)(struct usb_gadget *gadget,

                  structusb_gadget_driver *driver);

    void          (*unbind)(struct usb_gadget *);

    int        (*setup)(structusb_gadget *,

                  conststruct usb_ctrlrequest *);

    void          (*disconnect)(struct usb_gadget *);

    void          (*suspend)(struct usb_gadget *);

    void          (*resume)(struct usb_gadget *);

 

    /* FIXME supportsafe rmmod */

    structdevice_driver driver;

};

 

 在composite.c中声明了一个这样的一个结构体变量:composite_driver_template,这个结构体变量就是传给usb_gadget_probe_driver(structusb_gadget_driver *driver)的参数。

static const struct usb_gadget_drivercomposite_driver_template = {

    .bind      = composite_bind,

    .unbind       = composite_unbind,

 

    .setup     = composite_setup,

    .disconnect   = composite_disconnect,

 

    .suspend   = composite_suspend,

    .resume       = composite_resume,

 

    .driver    = {

       .owner     = THIS_MODULE,

    },

};

  Composite主要实现这些功能函数,这些函数的大部分参数都是usb_gadget。可以看出这些函数都是与UDC层相关的。以上数据结构是与UDC进行交互的,下面的数据结构以及函数是USB设备层与Gadget功能驱动层进行交互的。

(1)数据结构

struct usb_composite_dev {

    structusb_gadget    *gadget;

    structusb_request       *req;

 

    structusb_configuration *config;

 

    /* private: */

    /* internals */

    unsigned int         suspended:1;

    struct usb_device_descriptor    desc;

    struct list_head     configs;

    struct list_head     gstrings;

    structusb_composite_driver *driver;

    u8            next_string_id;

    char              *def_manufacturer;

 

    /* the gadgetdriver won't enable the data pullup

     * while the deactivation count is nonzero.

     */

    unsigned          deactivations;

 

    /* the compositedriver won't complete the control transfer's

     * data/status stages till delayed_status iszero.

     */

    int           delayed_status;

 

    /* protectsdeactivations and delayed_status counts*/

    spinlock_t        lock;

};

 

  这个结构代表一个USB设备。可以看出结构体中有设备描述符以及配置。还有指向usb_gadget与usb_compsite_driver的指针。说明这个结构体联系了UDC层与功能驱动层。这个结构内嵌在了usb_gadget中,是在composite_bind函数中分配与初始化的。

struct usb_composite_driver {

    const char           *name;

    const structusb_device_descriptor *dev;

    structusb_gadget_strings       **strings;

    enumusb_device_speed           max_speed;

    unsigned      needs_serial:1;

 

    int        (*bind)(struct usb_composite_dev *cdev);

    int        (*unbind)(struct usb_composite_dev *);

 

    void          (*disconnect)(struct usb_composite_dev*);

 

    /* globalsuspend hooks */

    void          (*suspend)(struct usb_composite_dev*);

    void          (*resume)(struct usb_composite_dev *);

    structusb_gadget_driver    gadget_driver;

};

 

  这个结构体代表一个USB设备驱动,是联系功能驱动的主要数据结构。由功能驱动层声明并初始化。
(2) 函数

int usb_composite_probe(struct usb_composite_driver*driver)

{

    structusb_gadget_driver *gadget_driver;

 

    if (!driver ||!driver->dev || !driver->bind)

       return-EINVAL;

 

    if(!driver->name)

       driver->name= "composite";

 

    driver->gadget_driver= composite_driver_template;

    gadget_driver =&driver->gadget_driver;

 

    gadget_driver->function=  (char *) driver->name;

    gadget_driver->driver.name= driver->name;

    gadget_driver->max_speed= driver->max_speed;

 

    returnusb_gadget_probe_driver(gadget_driver);

}

 

  这个函数是由Gadget功能驱动层调用的,他简单初始化了usb_composite_driver。然后调用usb_gadget_probe_driver。在webcam_init函数中,webcam_driver是usb_composite_drver类型的全局指针,这里赋值了功能驱动传递过来的usb_gadget_driver。所以功能驱动层与USB设备层联系在了一起,usb_gadget_probe_driver调用后UDC层与USB设备层联系到了一起。usb_composite_register是在功能驱动的模块初始化的函数中进行的调用。所以只要功能驱动一加载,三个软件层就通过数据结构联系在了一起。


三 Gadget 功能驱动层
 Gadget 功能驱动层是USB Gadget软件结构的最上层。主要是实现USB设备的功能,这一层通常与linux内核的其他层有密切的联系。这里主要介绍webcam  的Gadget 功能驱动。这一层包webcam.c。该驱动是作为一个模块注册到内核的,首先看一下他的模块初始化函数:

static int __init

webcam_init(void)

{

    returnusb_composite_probe(&webcam_driver);

}

 调用了usb_composite_probe,上面已经说到这个函数一旦调用三个软件层就联系到了一起。函数的参数是webcam_driver。这是一个usb_composite_driver的结构体,有如下声明:

static __refdata struct usb_composite_driverwebcam_driver = {

    .name      = "g_webcam",

    .dev       = &webcam_device_descriptor,

    .strings   = webcam_device_strings,

    .max_speed = USB_SPEED_HIGH,

    .bind      = webcam_bind,

    .unbind       = webcam_unbind,

};

   Webcam主要实现上面的函数集合,至此Linux下USB Gadget软件结构就分析完了。


你可能感兴趣的:(Linux设备驱动开发)