日期:2014-05-16  浏览次数:20937 次

Linux USB Gadget--设备枚举
        前面介绍了Linux USB Gadget的软件结构与各软件层的整合过程。经过各种注册函数,Gadget功能驱动层,USB设备层与UDC底层结合在了一起形成了一个完整的USB设备。而这个设备已经准备好了接受主机的枚举。在介绍USB设备枚举之前。先熟悉一下各层通信所用的数据结构,在USB主机端编写USB设备驱动程序,最重要的结构就是URB了,我们只需要将各种URB提交给USB核心,核心就会自动给我们的数据发送到指定的设备。而对于设备端也有这样一个类似的重要的数据结构。这个数据结构就是urt--usb_request。每一个端点都有一个urt链表,上面挂着各种urt。在底层的UDC的中断处理程序中,针对不同的端点调用不同的处理函数,总之是处理端点上的urt链表,处理完一个urt就调用预先设置好的回调函数。这就是设备端数据处理的流程。下面分析一下usb_request结构:
struct usb_request {
	void			*buf;
	unsigned		length;
	dma_addr_t		dma;

	unsigned		no_interrupt:1;
	unsigned		zero:1;
	unsigned		short_not_ok:1;

	void			(*complete)(struct usb_ep *ep,
					struct usb_request *req);
	void			*context;
	struct list_head	list;

	int			status;
	unsigned		actual;
};
    (1)buf 字段是要接受或者发送数据存储的地方,而length代表了数据的长度。
    (2)dma 是dma_addr_t类型的,有DMA传输有关。虽然s3c2440的USB设备控制器支持DMA操作,但是底层UDC驱动没有实现,所以不用管这个字段了。
    (3)三个位域分别代表了:
    (4)(*complete)(struct usb_ep *ep, struct usb_request *req); 这个是回调函数,在端点处理完一个urt的时候调用,非常重要
    (5)context
    (6)list 作用是将自己链接在端点链表
    (7)status 状态
    (8)actual 实际传输的字节
一. USB设备枚举
        分析完urt,那么就实际进入主机识别USB设备的最关键的设备枚举。这里主要分析设备怎么相应主机,对于主机究竟是怎么完成这些操作的还的找一种主机控制器来研究一下。首先先回顾一下USB设备枚举都要完成那些步骤吧:
(1)设备插入主机,主机检测到设备。复位设备
(2)主机向设备控制端点发送Get_Descriptor来了解设备默认管道的大小。
(3)主机指定一个地址,发送Set_Address标准请求设置设备的地址
(4)主机使用新的地址,再次发送Get_Descriptor或得各种描述符
(5)主机加载一个USB设备驱动
(6)USB设备驱动再发送Set_Confuration标准设备请求配置设备
        以上就是USB设备枚举的过程。USB设备必须正确的相应主机的要求才能顺利的完成设备枚举。我们知道USB是主从式总线结构,全部通信都是由主机发起,设备没有一点自主权。s3c2440 USB设备控制器,当主机向USB设备发送一个包时,USB设备控制器就会产生相应的中断。当出现传输错误的时候,也会以中断的形式来通知。所以理解USB设备控制器的中断是理解USB通信过程的关键。在s3c2410_udc.c在设备初始化的时候已经注册了中断处理程序:
static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
{
//这个是在设备控制器初始化的时候注册中断处理程序的语句:retval = request_irq(IRQ_USBD, s3c2410_udc_irq, IRQF_DISABLED, gadget_name, udc); 最后一个参数udc是一个struct s3c2410_udc
//的结构体,代表了一个USB设备控制器也就是s3c2410的设备控制器,这个结构体指针指向了一个已经初始化好了的struct s3c2410_udc变量。所以在中断处理程序开始在参数中提取了这个指针。  
	struct s3c2410_udc *dev = _dev;
	int usb_status;
	int usbd_status;
	int pwr_reg;
	int ep0csr;
	int i;
	u32 idx;
	unsigned long flags;
//自旋锁,保护dev这个结构避免并发引起的竞态,因为是单处理器。这里的自旋锁退化成了一个禁止内核抢占的开关,上锁就是禁止内核抢占
	spin_lock_irqsave(&dev->lock, flags);

	/* Driver connected ? */
//当没有初始化好USB设备而发生中断时,清除中断标志
	if (!dev->driver) {
		/* Clear interrupts */
		udc_write(udc_read(S3C2410_UDC_USB_INT_REG),
				S3C2410_UDC_USB_INT_REG);
		udc_write(udc_read(S3C2410_UDC_EP_INT_REG),
				S3C2410_UDC_EP_INT_REG);
	}
//s3c2440 USB设备控制器,因为有五个端点,每个端点的寄存器都相似。所以硬件设计的时候将寄存器分组了,名称一样但是物理寄存器不同。S3C2410_UDC_INDEX_REG寄存器代表了哪个组
	/* Save index */
	idx = udc_read(S3C2410_UDC_INDEX_REG);
//读取状态寄存器的值到局部变量中
	/* Read status registers */
	usb_status = udc_read(S3C2410_UDC_USB_INT_REG);
	usbd_status = udc_read(S3C2410_UDC_EP_INT_REG);
	pwr_reg = udc_read(S3C2410_UDC_PWR_REG);
//
	udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
	ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
//打印调试信息
	dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n",
		usb_status, usbd_status, pwr_reg, ep0csr);

	/*
	 * Now, handle interrupts. There's two types :
	 * - Reset, Resume, Suspend coming -> usb_int_reg
	 * - EP -> ep_int_reg
	 */
//下面就是不同的中断处理,复位对应这设备枚举的(1)
	/* RESET */
	if (usb_status & S3C2410_UDC_USBINT_RESET) {
		/* two kind of reset :
		 * - reset start -> pwr reg = 8
		 * - reset end   -> pwr reg = 0
		 **/
		dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n",
			ep0csr, pwr_reg);

		dev->gadget.speed = USB_SPEED_UNKNOWN;
		udc_write(0x00, S3C2410_UDC_INDEX_REG);
		udc_write((dev->ep[0].ep.maxpacket & 0x7ff) >> 3,
				S3C2410_UDC_MAXP_REG);
		dev->address = 0;

		dev->ep0state = EP0_IDLE;
		dev->gadget.speed = USB_SPEED_FULL;

		/* clear interrupt */