Linux USB Gadget--软件结构

USB Gadget是分层的软件结构,本文分析的是2.6.32.2版本的Gadget软件结构,这个软件结构与以前版本的变化很大。USB Gadget软件结构总共分为三层:
一. UDC层
        这一层是与硬件相关层。相关文件s3c2410_udc.c s3c2410_udc.h。s3c2410设备控制器作为一个linux设备在这一层是作为platform设备而注册到linux设备模型中的。相关数据结构以及相关函数如下:
1 数据结构
  1. struct s3c2410_udc {  
  2.     spinlock_t          lock;  
  3.   
  4.     struct s3c2410_ep       ep[S3C2410_ENDPOINTS];  
  5.     int             address;  
  6.     struct usb_gadget       gadget;  
  7.     struct usb_gadget_driver    *driver;  
  8.     struct s3c2410_request      fifo_req;  
  9.     u8              fifo_buf[EP_FIFO_SIZE];  
  10.     u16             devstatus;  
  11.   
  12.     u32             port_status;  
  13.     int             ep0state;  
  14.   
  15.     unsigned            got_irq : 1;  
  16.   
  17.     unsigned            req_std : 1;  
  18.     unsigned            req_config : 1;  
  19.     unsigned            req_pending : 1;  
  20.     u8              vbus;  
  21.     struct dentry           *regs_info;  
  22. };  
struct s3c2410_udc {
	spinlock_t			lock;

	struct s3c2410_ep		ep[S3C2410_ENDPOINTS];
	int				address;
	struct usb_gadget		gadget;
	struct usb_gadget_driver	*driver;
	struct s3c2410_request		fifo_req;
	u8				fifo_buf[EP_FIFO_SIZE];
	u16				devstatus;

	u32				port_status;
	int				ep0state;

	unsigned			got_irq : 1;

	unsigned			req_std : 1;
	unsigned			req_config : 1;
	unsigned			req_pending : 1;
	u8				vbus;
	struct dentry			*regs_info;
};
        s3c2410_udc.c中声明了一个结构体变量memory,这儿变量代表了S3C2410的USB设备控制器,包括各种信息。
  1. static struct s3c2410_udc memory = {  
  2.     .gadget = {  
  3.         .ops        = &s3c2410_ops,  
  4.         .ep0        = &memory.ep[0].ep,  
  5.         .name       = gadget_name,  
  6.         .dev = {  
  7.             .init_name  = "gadget",  
  8.         },  
  9.     },  
  10.   
  11.     /* control endpoint */  
  12.     .ep[0] = {  
  13.         .num        = 0,  
  14.         .ep = {  
  15.             .name       = ep0name,  
  16.             .ops        = &s3c2410_ep_ops,  
  17.             .maxpacket  = EP0_FIFO_SIZE,  
  18.         },  
  19.         .dev        = &memory,  
  20.     },  
  21.   
  22.     /* first group of endpoints */  
  23.     .ep[1] = {  
  24.         .num        = 1,  
  25.         .ep = {  
  26.             .name       = "ep1-bulk",  
  27.             .ops        = &s3c2410_ep_ops,  
  28.             .maxpacket  = EP_FIFO_SIZE,  
  29.         },  
  30.         .dev        = &memory,  
  31.         .fifo_size  = EP_FIFO_SIZE,  
  32.         .bEndpointAddress = 1,  
  33.         .bmAttributes   = USB_ENDPOINT_XFER_BULK,  
  34.     },  
  35.     .ep[2] = {  
  36.         .num        = 2,  
  37.         .ep = {  
  38.             .name       = "ep2-bulk",  
  39.             .ops        = &s3c2410_ep_ops,  
  40.             .maxpacket  = EP_FIFO_SIZE,  
  41.         },  
  42.         .dev        = &memory,  
  43.         .fifo_size  = EP_FIFO_SIZE,  
  44.         .bEndpointAddress = 2,  
  45.         .bmAttributes   = USB_ENDPOINT_XFER_BULK,  
  46.     },  
  47.     .ep[3] = {  
  48.         .num        = 3,  
  49.         .ep = {  
  50.             .name       = "ep3-bulk",  
  51.             .ops        = &s3c2410_ep_ops,  
  52.             .maxpacket  = EP_FIFO_SIZE,  
  53.         },  
  54.         .dev        = &memory,  
  55.         .fifo_size  = EP_FIFO_SIZE,  
  56.         .bEndpointAddress = 3,  
  57.         .bmAttributes   = USB_ENDPOINT_XFER_BULK,  
  58.     },  
  59.     .ep[4] = {  
  60.         .num        = 4,  
  61.         .ep = {  
  62.             .name       = "ep4-bulk",  
  63.             .ops        = &s3c2410_ep_ops,  
  64.             .maxpacket  = EP_FIFO_SIZE,  
  65.         },  
  66.         .dev        = &memory,  
  67.         .fifo_size  = EP_FIFO_SIZE,  
  68.         .bEndpointAddress = 4,  
  69.         .bmAttributes   = USB_ENDPOINT_XFER_BULK,  
  70.     }  
  71.   
  72. };  
static struct s3c2410_udc memory = {
	.gadget = {
		.ops		= &s3c2410_ops,
		.ep0		= &memory.ep[0].ep,
		.name		= gadget_name,
		.dev = {
			.init_name	= "gadget",
		},
	},

	/* control endpoint */
	.ep[0] = {
		.num		= 0,
		.ep = {
			.name		= ep0name,
			.ops		= &s3c2410_ep_ops,
			.maxpacket	= EP0_FIFO_SIZE,
		},
		.dev		= &memory,
	},

	/* first group of endpoints */
	.ep[1] = {
		.num		= 1,
		.ep = {
			.name		= "ep1-bulk",
			.ops		= &s3c2410_ep_ops,
			.maxpacket	= EP_FIFO_SIZE,
		},
		.dev		= &memory,
		.fifo_size	= EP_FIFO_SIZE,
		.bEndpointAddress = 1,
		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
	},
	.ep[2] = {
		.num		= 2,
		.ep = {
			.name		= "ep2-bulk",
			.ops		= &s3c2410_ep_ops,
			.maxpacket	= EP_FIFO_SIZE,
		},
		.dev		= &memory,
		.fifo_size	= EP_FIFO_SIZE,
		.bEndpointAddress = 2,
		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
	},
	.ep[3] = {
		.num		= 3,
		.ep = {
			.name		= "ep3-bulk",
			.ops		= &s3c2410_ep_ops,
			.maxpacket	= EP_FIFO_SIZE,
		},
		.dev		= &memory,
		.fifo_size	= EP_FIFO_SIZE,
		.bEndpointAddress = 3,
		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
	},
	.ep[4] = {
		.num		= 4,
		.ep = {
			.name		= "ep4-bulk",
			.ops		= &s3c2410_ep_ops,
			.maxpacket	= EP_FIFO_SIZE,
		},
		.dev		= &memory,
		.fifo_size	= EP_FIFO_SIZE,
		.bEndpointAddress = 4,
		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
	}

};
2 函数
        platform设备需要注册一个platform_driver的结构体:
  1. static struct platform_driver udc_driver_2410 = {  
  2.     .driver     = {  
  3.         .name   = "s3c2410-usbgadget",  
  4.         .owner  = THIS_MODULE,  
  5.     },  
  6.     .probe      = s3c2410_udc_probe,  
  7.     .remove     = s3c2410_udc_remove,  
  8.     .suspend    = s3c2410_udc_suspend,  
  9.     .resume     = s3c2410_udc_resume,  
  10. };  
static struct platform_driver udc_driver_2410 = {
	.driver		= {
		.name	= "s3c2410-usbgadget",
		.owner	= THIS_MODULE,
	},
	.probe		= s3c2410_udc_probe,
	.remove		= s3c2410_udc_remove,
	.suspend	= s3c2410_udc_suspend,
	.resume		= s3c2410_udc_resume,
};
        结构体中的相关函数需要自己实现。最关键的函数就是s3c2410_udc_probe。这个函数在platform总线为驱动程序找到合适的设备后调用,在函数内初始化设备的时钟,申请io资源以及irq资源初始化platform设备结构体struct s3c2410_udc memory。

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

(1) usb_gadget操作函数集合 

  1. static const struct usb_gadget_ops s3c2410_ops = {  
  2.     .get_frame      = s3c2410_udc_get_frame,  
  3.     .wakeup         = s3c2410_udc_wakeup,  
  4.     .set_selfpowered    = s3c2410_udc_set_selfpowered,  
  5.     .pullup         = s3c2410_udc_pullup,  
  6.     .vbus_session       = s3c2410_udc_vbus_session,  
  7.     .vbus_draw      = s3c2410_vbus_draw,  
  8. };  
static const struct usb_gadget_ops s3c2410_ops = {
	.get_frame		= s3c2410_udc_get_frame,
	.wakeup			= s3c2410_udc_wakeup,
	.set_selfpowered	= s3c2410_udc_set_selfpowered,
	.pullup			= s3c2410_udc_pullup,
	.vbus_session		= s3c2410_udc_vbus_session,
	.vbus_draw		= s3c2410_vbus_draw,
};
        这些函数都是由UDC层来实现的。
(2) 端点操作函数集合
  1. static const struct usb_ep_ops s3c2410_ep_ops = {  
  2.     .enable     = s3c2410_udc_ep_enable,  
  3.     .disable    = s3c2410_udc_ep_disable,  
  4.   
  5.     .alloc_request  = s3c2410_udc_alloc_request,  
  6.     .free_request   = s3c2410_udc_free_request,  
  7.   
  8.     .queue      = s3c2410_udc_queue,  
  9.     .dequeue    = s3c2410_udc_dequeue,  
  10.   
  11.     .set_halt   = s3c2410_udc_set_halt,  
  12. };  
static const struct usb_ep_ops s3c2410_ep_ops = {
	.enable		= s3c2410_udc_ep_enable,
	.disable	= s3c2410_udc_ep_disable,

	.alloc_request	= s3c2410_udc_alloc_request,
	.free_request	= s3c2410_udc_free_request,

	.queue		= s3c2410_udc_queue,
	.dequeue	= s3c2410_udc_dequeue,

	.set_halt	= s3c2410_udc_set_halt,
};
(3) USB 中断处理程序
  1. static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)  
static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
(4) 其他相关辅助函数,比如调试相关函数。
二 USB设备层
        USB设备层,虽然名字上与设备相关。但是属于硬件无关层。这一层相关的代码是composite.c,composite.h。这一层的功能是隔离Gadget功能驱动与硬件相关层。使得功能驱动直接与USB设备层交互不用考虑硬件的相关细节。还有USB设备层提供了USB设备的一些基本数据结构,不同的Gadget功能驱动可以共同调用。如果没有这一层,则每一个功能驱动都需要实现自己的USB设备,导致了代码重用率很高。这一层向下与UDC层进行交互,向上与Gadget功能驱动层进行交互。在UDC层已经介绍了USB设备层向下与UDC层交互方式主要是通过调用usb_gadget_register_driver(struct usb_gadget_driver *driver),这个函数是UDC层提供的。而这个函数传递的参数就是一个usb_gadget_driver的结构体。以下是这个结构体定义:
  1. struct usb_gadget_driver {  
  2.     char            *function;  
  3.     enum usb_device_speed   speed;  
  4.     int         (*bind)(struct usb_gadget *);  
  5.     void            (*unbind)(struct usb_gadget *);  
  6.     int         (*setup)(struct usb_gadget *,  
  7.                     const struct usb_ctrlrequest *);  
  8.     void            (*disconnect)(struct usb_gadget *);  
  9.     void            (*suspend)(struct usb_gadget *);  
  10.     void            (*resume)(struct usb_gadget *);  
  11.   
  12.     /* FIXME support safe rmmod */  
  13.     struct device_driver    driver;  
  14. };  
struct usb_gadget_driver {
	char			*function;
	enum usb_device_speed	speed;
	int			(*bind)(struct usb_gadget *);
	void			(*unbind)(struct usb_gadget *);
	int			(*setup)(struct usb_gadget *,
					const struct usb_ctrlrequest *);
	void			(*disconnect)(struct usb_gadget *);
	void			(*suspend)(struct usb_gadget *);
	void			(*resume)(struct usb_gadget *);

	/* FIXME support safe rmmod */
	struct device_driver	driver;
};
        在composite.c中声明了一个这样的一个结构体变量:composite_driver,这个结构体变量就是传给usb_gadget_register_driver(struct usb_gadget_driver *driver)的参数。
  1. static struct usb_gadget_driver composite_driver = {  
  2.     .speed      = USB_SPEED_HIGH,  
  3.   
  4.     .bind       = composite_bind,  
  5.     .unbind     = __exit_p(composite_unbind),  
  6.   
  7.     .setup      = composite_setup,  
  8.     .disconnect = composite_disconnect,  
  9.   
  10.     .suspend    = composite_suspend,  
  11.     .resume     = composite_resume,  
  12.   
  13.     .driver = {  
  14.         .owner      = THIS_MODULE,  
  15.     },  
  16. };  
static struct usb_gadget_driver composite_driver = {
	.speed		= USB_SPEED_HIGH,

	.bind		= composite_bind,
	.unbind		= __exit_p(composite_unbind),

	.setup		= composite_setup,
	.disconnect	= composite_disconnect,

	.suspend	= composite_suspend,
	.resume		= composite_resume,

	.driver	= {
		.owner		= THIS_MODULE,
	},
};
        以上所有的函数集都需要自己实现,这些函数的大部分参数都是usb_gadget。可以看出这些函数都是与UDC层相关的。以上数据结构是与UDC进行交互的,下面的数据结构以及函数是USB设备层与Gadget功能驱动层进行交互的。

(1) 数据结构

  1. struct usb_composite_dev {  
  2.     struct usb_gadget       *gadget;  
  3.     struct usb_request      *req;  
  4.     unsigned            bufsiz;  
  5.   
  6.     struct usb_configuration    *config;  
  7.   
  8.     /* private: */  
  9.     /* internals */  
  10.     struct usb_device_descriptor    desc;  
  11.     struct list_head        configs;  
  12.     struct usb_composite_driver *driver;  
  13.     u8              next_string_id;  
  14.   
  15.     /* the gadget driver won't enable the data pullup 
  16.      * while the deactivation count is nonzero. 
  17.      */  
  18.     unsigned            deactivations;  
  19.   
  20.     /* protects at least deactivation count */  
  21.     spinlock_t          lock;  
  22. };  
struct usb_composite_dev {
	struct usb_gadget		*gadget;
	struct usb_request		*req;
	unsigned			bufsiz;

	struct usb_configuration	*config;

	/* private: */
	/* internals */
	struct usb_device_descriptor	desc;
	struct list_head		configs;
	struct usb_composite_driver	*driver;
	u8				next_string_id;

	/* the gadget driver won't enable the data pullup
	 * while the deactivation count is nonzero.
	 */
	unsigned			deactivations;

	/* protects at least deactivation count */
	spinlock_t			lock;
};
         这个结构代表一个USB设备。可以看出结构体中有设备描述符以及配置。还有指向usb_gadget与usb_compsite_driver的指针。说明这个结构体联系了UDC层与功能驱动层。这个结构内嵌在了usb_gadget中,是在composite_bind函数中分配与初始化的。
  1. struct usb_composite_driver {  
  2.     const char              *name;  
  3.     const struct usb_device_descriptor  *dev;  
  4.     struct usb_gadget_strings       **strings;  
  5.   
  6.     /* REVISIT:  bind() functions can be marked __init, which 
  7.      * makes trouble for section mismatch analysis.  See if 
  8.      * we can't restructure things to avoid mismatching... 
  9.      */  
  10.   
  11.     int         (*bind)(struct usb_composite_dev *);  
  12.     int         (*unbind)(struct usb_composite_dev *);  
  13.   
  14.     /* global suspend hooks */  
  15.     void            (*suspend)(struct usb_composite_dev *);  
  16.     void            (*resume)(struct usb_composite_dev *);  
  17. };  
struct usb_composite_driver {
	const char				*name;
	const struct usb_device_descriptor	*dev;
	struct usb_gadget_strings		**strings;

	/* REVISIT:  bind() functions can be marked __init, which
	 * makes trouble for section mismatch analysis.  See if
	 * we can't restructure things to avoid mismatching...
	 */

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

	/* global suspend hooks */
	void			(*suspend)(struct usb_composite_dev *);
	void			(*resume)(struct usb_composite_dev *);
};
        这个结构体代表一个USB设备驱动,是联系功能驱动的主要数据结构。由功能驱动层声明并初始化。
(2) 函数
  1.  int __init usb_composite_register(struct usb_composite_driver *driver)  
  2. {  
  3.     if (!driver || !driver->dev || !driver->bind || composite)  
  4.         return -EINVAL;  
  5.   
  6.     if (!driver->name)  
  7.         driver->name = "composite";  
  8.     composite_driver.function =  (char *) driver->name;  
  9.     composite_driver.driver.name = driver->name;  
  10.     composite = driver;  
  11.   
  12.     return usb_gadget_register_driver(&composite_driver);  
  13. }  
 int __init usb_composite_register(struct usb_composite_driver *driver)
{
	if (!driver || !driver->dev || !driver->bind || composite)
		return -EINVAL;

	if (!driver->name)
		driver->name = "composite";
	composite_driver.function =  (char *) driver->name;
	composite_driver.driver.name = driver->name;
	composite = driver;

	return usb_gadget_register_driver(&composite_driver);
}
        这个函数是由Gadget功能驱动层调用的,他简单初始化了composite_driver。然后调用usb_gadget_register_driver。composite是usb_composite_drver类型的全局指针这里赋值了功能驱动传递过来的driver。所以功能驱动层与USB设备层联系在了一起,usb_gadget_register_driver调用后UDC层与USB设备层联系到了一起。usb_composite_register是在功能驱动的模块初始化的函数中进行的调用。所以只要功能驱动一加载,三个软件层就通过数据结构联系在了一起。
三 Gadget 功能驱动层
        Gadget 功能驱动层是USB Gadget软件结构的最上层。主要是实现USB设备的功能,这一层通常与linux内核的其他层有密切的联系。模拟U盘的gadget就与文件系统层与块IO层有着联系。这里主要介绍最简单的Gadget 功能驱动zero。这一层包括zero.c。该驱动是作为一个模块注册到内核的,首先看一下他的模块初始化函数:
  1. static int __init init(void)  
  2. {  
  3.     return usb_composite_register(&zero_driver);  
  4. }  
static int __init init(void)
{
	return usb_composite_register(&zero_driver);
}
        非常简单,只调用了usb_composite_register,上面已经说到这个函数一旦调用三个软件层就联系到了一起。函数的参数是zero_driver。这是一个usb_composite_driver的结构体,有如下声明:
  1. static struct usb_composite_driver zero_driver = {  
  2.     .name       = "zero",  
  3.     .dev        = &device_desc,  
  4.     .strings    = dev_strings,  
  5.     .bind       = zero_bind,  
  6.     .unbind     = zero_unbind,  
  7.     .suspend    = zero_suspend,  
  8.     .resume     = zero_resume,  
  9. };  
static struct usb_composite_driver zero_driver = {
	.name		= "zero",
	.dev		= &device_desc,
	.strings	= dev_strings,
	.bind		= zero_bind,
	.unbind		= zero_unbind,
	.suspend	= zero_suspend,
	.resume		= zero_resume,
};
        zero只要实现上面的函数集合就可以了,至此Linux下USB Gadget软件结构就分析完了。这个只是三层怎样联系起来的,但是数据怎样传输的还得另行分析。主要软件结构如下图所示:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值