前面介绍了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)
- {
-
-
- struct s3c2410_udc *dev = _dev;
- int usb_status;
- int usbd_status;
- int pwr_reg;
- int ep0csr;
- int i;
- u32 idx;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
-
-
-
- if (!dev->driver) {
-
- 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);
- }
-
-
- idx = udc_read(S3C2410_UDC_INDEX_REG);
-
-
- 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);
-
-
-
-
-
-
-
-
- if (usb_status & S3C2410_UDC_USBINT_RESET) {
-
-
-
-
- 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;
-
-
- udc_write(S3C2410_UDC_USBINT_RESET,
- S3C2410_UDC_USB_INT_REG);
-
- udc_write(idx, S3C2410_UDC_INDEX_REG);
- spin_unlock_irqrestore(&dev->lock, flags);
- return IRQ_HANDLED;
- }
-
-
- if (usb_status & S3C2410_UDC_USBINT_RESUME) {
- dprintk(DEBUG_NORMAL, "USB resume\n");
-
-
- udc_write(S3C2410_UDC_USBINT_RESUME,
- S3C2410_UDC_USB_INT_REG);
-
- if (dev->gadget.speed != USB_SPEED_UNKNOWN
- && dev->driver
- && dev->driver->resume)
- dev->driver->resume(&dev->gadget);
- }
-
-
- if (usb_status & S3C2410_UDC_USBINT_SUSPEND) {
- dprintk(DEBUG_NORMAL, "USB suspend\n");
-
-
- udc_write(S3C2410_UDC_USBINT_SUSPEND,
- S3C2410_UDC_USB_INT_REG);
-
- if (dev->gadget.speed != USB_SPEED_UNKNOWN
- && dev->driver
- && dev->driver->suspend)
- dev->driver->suspend(&dev->gadget);
-
- dev->ep0state = EP0_IDLE;
- }
-
-
-
-
-
-
- if (usbd_status & S3C2410_UDC_INT_EP0) {
- dprintk(DEBUG_VERBOSE, "USB ep0 irq\n");
-
- udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);
- s3c2410_udc_handle_ep0(dev);
- }
-
-
- for (i = 1; i < S3C2410_ENDPOINTS; i++) {
- u32 tmp = 1 << i;
- if (usbd_status & tmp) {
- dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i);
-
-
- udc_write(tmp, S3C2410_UDC_EP_INT_REG);
- s3c2410_udc_handle_ep(&dev->ep[i]);
- }
- }
-
- dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD);
-
-
- udc_write(idx, S3C2410_UDC_INDEX_REG);
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return IRQ_HANDLED;
- }
这个函数根据不同的中断类型进行处理。设备枚举的时候USB设备控制器产生的中断都是端点0的,所以调用s3c2410_udc_handle_ep0(dev)函数。这个函数也定义在s3c2410_udc.c中,如下:- static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev)
- {
- u32 ep0csr;
- struct s3c2410_ep *ep = &dev->ep[0];
- struct s3c2410_request *req;
- struct usb_ctrlrequest crq;
-
- if (list_empty(&ep->queue))
- req = NULL;
- else
- req = list_entry(ep->queue.next, struct s3c2410_request, queue);
-
-
-
-
- udc_write(0, S3C2410_UDC_INDEX_REG);
- ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
-
- dprintk(DEBUG_NORMAL, "ep0csr %x ep0state %s\n",
- ep0csr, ep0states[dev->ep0state]);
-
-
- if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
- s3c2410_udc_nuke(dev, ep, -EPIPE);
- dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n");
- s3c2410_udc_clear_ep0_sst(base_addr);
- dev->ep0state = EP0_IDLE;
- return;
- }
-
-
- if (ep0csr & S3C2410_UDC_EP0_CSR_SE) {
- dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n");
- s3c2410_udc_nuke(dev, ep, 0);
- s3c2410_udc_clear_ep0_se(base_addr);
- dev->ep0state = EP0_IDLE;
- }
-
- switch (dev->ep0state) {
- case EP0_IDLE:
- s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr);
- break;
-
- case EP0_IN_DATA_PHASE:
- dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n");
- if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) {
- s3c2410_udc_write_fifo(ep, req);
- }
- break;
-
- case EP0_OUT_DATA_PHASE:
- dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n");
- if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) {
- s3c2410_udc_read_fifo(ep,req);
- }
- break;
-
- case EP0_END_XFER:
- dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n");
- dev->ep0state = EP0_IDLE;
- break;
-
- case EP0_STALL:
- dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n");
- dev->ep0state = EP0_IDLE;
- break;
- }
- }
看这个函数之前,先要看一个struct s3c2410_ep这个数据结构,这个数据结构代表一个s3c2410 usb设备控制器的一个端点。结构如下: - struct s3c2410_ep {
- struct list_head queue;
- unsigned long last_io;
- struct usb_gadget *gadget;
- struct s3c2410_udc *dev;
- const struct usb_endpoint_descriptor *desc;
- struct usb_ep ep;
- u8 num;
-
- unsigned short fifo_size;
- u8 bEndpointAddress;
- u8 bmAttributes;
-
- unsigned halted : 1;
- unsigned already_seen : 1;
- unsigned setup_stage : 1;
- };
这结构的成员一部分是在定义的时候静态初始化的,端点0在定义的时候如下初始化:- .ep[0] = {
- .num = 0,
- .ep = {
- .name = ep0name,
- .ops = &s3c2410_ep_ops,
- .maxpacket = EP0_FIFO_SIZE,
- },
- .dev = &memory,
- },
看完struct s3c2410_ep结构后,再来分析s3c2410_udc_handle_ep0这个函数。函数首先判断ep的queue是否为空,这个字段链接了struct s3c2410_request结构的链表,struct s3c2410_request是struct usb_request的简单封装,代表一个一次usb传输。如果不为空那么,取到这个成员赋值给req变量。接下来读取端点0的状态寄存器EP0_CSR,这个寄存器反映了端点0的状态。将端点0的状态读到ep0csr局部变量中。这时在中断处理程序中。按照USB设备枚举的过程,最先发生的中断是复位。然后USB主机就会发起一次控制传输来获得设备描述符。这个控制传输是Get_Descriptor标准设备请求。我们知道USB控制传输有数据传输的分为三个阶段,没有数据传输的分为两个阶段。而Get_Descriptor是有数据传输的,USB设备要返回设备描述符号。所以有三个阶段:分别是建立阶段,数据阶段,状态阶段。建立阶段分为三个USB数据包:分别是setup包,data包,与握手包。当建立阶段完毕后,data包的数据会写入端点0的FIFO,s3c2410 USB设备控制器就会产生中断,对应的EP0_CSR的SETUP_END 位就会置位。这时可以判断这个状态。然后调用相应的函数读取在FIFO的数据,判断是控制传输的类型,然后针对不同的类型采取不同的操作,或接受数据,或发送数据。现在针对Get_Descriptor这个USB标准请求来分析一下s3c2410_udc_handle_ep0函数中代码的执行:(1)首先,建立阶段完成中断,执行如下代码:- if (ep0csr & S3C2410_UDC_EP0_CSR_SE) {
- dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n");
- s3c2410_udc_nuke(dev, ep, 0);
- s3c2410_udc_clear_ep0_se(base_addr);
- dev->ep0state = EP0_IDLE;
-
(2)然后,因为dev->ep0state = EP0_IDLE所以执行如下代码:- case EP0_IDLE:
- s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr);
- break;
s3c2410_udc_handle_ep0_idle函数也定义在s3c2410_udc.c中,如下:- static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,
- struct s3c2410_ep *ep,
- struct usb_ctrlrequest *crq,
- u32 ep0csr)
- {
- int len, ret, tmp;
-
-
- if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY))
- return;
-
- s3c2410_udc_nuke(dev, ep, -EPROTO);
-
- len = s3c2410_udc_read_fifo_crq(crq);
- if (len != sizeof(*crq)) {
- dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR"
- " wanted %d bytes got %d. Stalling out...\n",
- sizeof(*crq), len);
- s3c2410_udc_set_ep0_ss(base_addr);
- return;
- }
-
- dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n",
- crq->bRequest, crq->bRequestType, crq->wLength);
-
-
- dev->req_std = (crq->bRequestType & USB_TYPE_MASK)
- == USB_TYPE_STANDARD;
- dev->req_config = 0;
- dev->req_pending = 1;
-
- switch (crq->bRequest) {
- case USB_REQ_SET_CONFIGURATION:
- dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n");
-
- if (crq->bRequestType == USB_RECIP_DEVICE) {
- dev->req_config = 1;
- s3c2410_udc_set_ep0_de_out(base_addr);
- }
- break;
-
- case USB_REQ_SET_INTERFACE:
- dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n");
-
- if (crq->bRequestType == USB_RECIP_INTERFACE) {
- dev->req_config = 1;
- s3c2410_udc_set_ep0_de_out(base_addr);
- }
- break;
-
- case USB_REQ_SET_ADDRESS:
- dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n");
-
- if (crq->bRequestType == USB_RECIP_DEVICE) {
- tmp = crq->wValue & 0x7F;
- dev->address = tmp;
- udc_write((tmp | S3C2410_UDC_FUNCADDR_UPDATE),
- S3C2410_UDC_FUNC_ADDR_REG);
- s3c2410_udc_set_ep0_de_out(base_addr);
- return;
- }
- break;
-
- case USB_REQ_GET_STATUS:
- dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n");
- s3c2410_udc_clear_ep0_opr(base_addr);
-
- if (dev->req_std) {
- if (!s3c2410_udc_get_status(dev, crq)) {
- return;
- }
- }
- break;
-
- case USB_REQ_CLEAR_FEATURE:
- s3c2410_udc_clear_ep0_opr(base_addr);
-
- if (crq->bRequestType != USB_RECIP_ENDPOINT)
- break;
-
- if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)
- break;
-
- s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 0);
- s3c2410_udc_set_ep0_de_out(base_addr);
- return;
-
- case USB_REQ_SET_FEATURE:
- s3c2410_udc_clear_ep0_opr(base_addr);
-
- if (crq->bRequestType != USB_RECIP_ENDPOINT)
- break;
-
- if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)
- break;
-
- s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 1);
- s3c2410_udc_set_ep0_de_out(base_addr);
- return;
-
- default:
- s3c2410_udc_clear_ep0_opr(base_addr);
- break;
- }
-
- if (crq->bRequestType & USB_DIR_IN)
- dev->ep0state = EP0_IN_DATA_PHASE;
- else
- dev->ep0state = EP0_OUT_DATA_PHASE;
-
- ret = dev->driver->setup(&dev->gadget, crq);
- if (ret < 0) {
- if (dev->req_config) {
- dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n",
- crq->bRequest, ret);
- return;
- }
-
- if (ret == -EOPNOTSUPP)
- dprintk(DEBUG_NORMAL, "Operation not supported\n");
- else
- dprintk(DEBUG_NORMAL,
- "dev->driver->setup failed. (%d)\n", ret);
-
- udelay(5);
- s3c2410_udc_set_ep0_ss(base_addr);
- s3c2410_udc_set_ep0_de_out(base_addr);
- dev->ep0state = EP0_IDLE;
-
- } else if (dev->req_pending) {
- dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n");
- dev->req_pending=0;
- }
-
- dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]);
- }
这个函数所做的主要工作就是读取端点0 FIFO中的数据,这里的数据就是控制传输的类型。然后通过一个switch语句来判断到底是什么控制传输。根据控制传输的不同类型采用不同的操作。这里我们假设的是Get_Descriptor。那么switch语句都不执行,执行下面的语句,这些是针对有数据传输的控制传输。Get_Descriptor的方向是IN,所以dev->ep0state = EP0_IN_DATA_PHASE设备端点状态。然后执行下面的预计 ret = dev->driver->setup(&dev->gadget, crq);在这里dev->driver->setup已经初始化好了是composite_setup,在composite.c中定义,如下:- static int
- composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
- {
- struct usb_composite_dev *cdev = get_gadget_data(gadget);
- struct usb_request *req = cdev->req;
- int value = -EOPNOTSUPP;
- u16 w_index = le16_to_cpu(ctrl->wIndex);
- u8 intf = w_index & 0xFF;
- u16 w_value = le16_to_cpu(ctrl->wValue);
- u16 w_length = le16_to_cpu(ctrl->wLength);
- struct usb_function *f = NULL;
-
-
-
-
-
- req->zero = 0;
- req->complete = composite_setup_complete;
- req->length = USB_BUFSIZ;
- gadget->ep0->driver_data = cdev;
-
- switch (ctrl->bRequest) {
-
-
- case USB_REQ_GET_DESCRIPTOR:
- if (ctrl->bRequestType != USB_DIR_IN)
- goto unknown;
- switch (w_value >> 8) {
-
- case USB_DT_DEVICE:
- cdev->desc.bNumConfigurations =
- count_configs(cdev, USB_DT_DEVICE);
- value = min(w_length, (u16) sizeof cdev->desc);
- memcpy(req->buf, &cdev->desc, value);
- break;
- case USB_DT_DEVICE_QUALIFIER:
- if (!gadget_is_dualspeed(gadget))
- break;
- device_qual(cdev);
- value = min_t(int, w_length,
- sizeof(struct usb_qualifier_descriptor));
- break;
- case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget_is_dualspeed(gadget))
- break;
-
- case USB_DT_CONFIG:
- value = config_desc(cdev, w_value);
- if (value >= 0)
- value = min(w_length, (u16) value);
- break;
- case USB_DT_STRING:
- value = get_string(cdev, req->buf,
- w_index, w_value & 0xff);
- if (value >= 0)
- value = min(w_length, (u16) value);
- break;
- }
- break;
-
-
- case USB_REQ_SET_CONFIGURATION:
- if (ctrl->bRequestType != 0)
- goto unknown;
- if (gadget_is_otg(gadget)) {
- if (gadget->a_hnp_support)
- DBG(cdev, "HNP available\n");
- else if (gadget->a_alt_hnp_support)
- DBG(cdev, "HNP on another port\n");
- else
- VDBG(cdev, "HNP inactive\n");
- }
- spin_lock(&cdev->lock);
- value = set_config(cdev, ctrl, w_value);
- spin_unlock(&cdev->lock);
- break;
- case USB_REQ_GET_CONFIGURATION:
- if (ctrl->bRequestType != USB_DIR_IN)
- goto unknown;
- if (cdev->config)
- *(u8 *)req->buf = cdev->config->bConfigurationValue;
- else
- *(u8 *)req->buf = 0;
- value = min(w_length, (u16) 1);
- break;
-
-
-
-
- case USB_REQ_SET_INTERFACE:
- if (ctrl->bRequestType != USB_RECIP_INTERFACE)
- goto unknown;
- if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
- break;
- f = cdev->config->interface[intf];
- if (!f)
- break;
- if (w_value && !f->set_alt)
- break;
- value = f->set_alt(f, w_index, w_value);
- break;
- case USB_REQ_GET_INTERFACE:
- if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
- goto unknown;
- if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
- break;
- f = cdev->config->interface[intf];
- if (!f)
- break;
-
- value = f->get_alt ? f->get_alt(f, w_index) : 0;
- if (value < 0)
- break;
- *((u8 *)req->buf) = value;
- value = min(w_length, (u16) 1);
- break;
- default:
- unknown:
- VDBG(cdev,
- "non-core control req%02x.%02x v%04x i%04x l%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
-
-
-
-
-
-
-
-
-
- if ((ctrl->bRequestType & USB_RECIP_MASK)
- == USB_RECIP_INTERFACE) {
- f = cdev->config->interface[intf];
- if (f && f->setup)
- value = f->setup(f, ctrl);
- else
- f = NULL;
- }
- if (value < 0 && !f) {
- struct usb_configuration *c;
-
- c = cdev->config;
- if (c && c->setup)
- value = c->setup(c, ctrl);
- }
-
- goto done;
- }
-
-
- if (value >= 0) {
- req->length = value;
- req->zero = value < w_length;
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
- if (value < 0) {
- DBG(cdev, "ep_queue --> %d\n", value);
- req->status = 0;
- composite_setup_complete(gadget->ep0, req);
- }
- }
-
- done:
-
- return value;
- }
这个函数首先提取出USB控制请求的各个字段,然后初始化了端点0的struct usb_request结构。设置了完成回调函数composite_setup_complete。这时通过switch语句来判断是何种控制传输。比如这里是Get_Descriptor,而且设备枚举的时候这时只获取设备描述符的前八个字节以了解端点0的FIFO深度。所以下面的代码执行:- cdev->desc.bNumConfigurations =
- count_configs(cdev, USB_DT_DEVICE);
- value = min(w_length, (u16) sizeof cdev->desc);
- memcpy(req->buf, &cdev->desc, value);
这段代码就是复制设备描述符到req的缓冲区。然后执行下面的代码:- if (value >= 0) {
- req->length = value;
- req->zero = value < w_length;
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
- if (value < 0) {
- DBG(cdev, "ep_queue --> %d\n", value);
- req->status = 0;
- composite_setup_complete(gadget->ep0, req);
- }
- }
这时value不为0,所以if里面的语句执行。usb_ep_queue函数主要作用就是将req中的数据写入到FIFO中。函数如下定义:- static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,
- gfp_t gfp_flags)
- {
- struct s3c2410_request *req = to_s3c2410_req(_req);
- struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
- struct s3c2410_udc *dev;
- u32 ep_csr = 0;
- int fifo_count = 0;
- unsigned long flags;
-
- if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
- dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__);
- return -EINVAL;
- }
-
- dev = ep->dev;
- if (unlikely (!dev->driver
- || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
- return -ESHUTDOWN;
- }
-
- local_irq_save (flags);
-
- if (unlikely(!_req || !_req->complete
- || !_req->buf || !list_empty(&req->queue))) {
- if (!_req)
- dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__);
- else {
- dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n",
- __func__, !_req->complete,!_req->buf,
- !list_empty(&req->queue));
- }
-
- local_irq_restore(flags);
- return -EINVAL;
- }
-
- _req->status = -EINPROGRESS;
- _req->actual = 0;
-
- dprintk(DEBUG_VERBOSE, "%s: ep%x len %d\n",
- __func__, ep->bEndpointAddress, _req->length);
-
- if (ep->bEndpointAddress) {
- udc_write(ep->bEndpointAddress & 0x7F, S3C2410_UDC_INDEX_REG);
- ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN)
- ? S3C2410_UDC_IN_CSR1_REG
- : S3C2410_UDC_OUT_CSR1_REG);
-
- fifo_count = s3c2410_udc_fifo_count_out();
- } else {
- udc_write(0, S3C2410_UDC_INDEX_REG);
- ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
- fifo_count = s3c2410_udc_fifo_count_out();
- }
-
-
- if (list_empty(&ep->queue) && !ep->halted) {
- if (ep->bEndpointAddress == 0 ) {
- switch (dev->ep0state) {
- case EP0_IN_DATA_PHASE:
- if (!(ep_csr&S3C2410_UDC_EP0_CSR_IPKRDY)
- && s3c2410_udc_write_fifo(ep,
- req)) {
- dev->ep0state = EP0_IDLE;
- req = NULL;
- }
- break;
-
-
- case EP0_OUT_DATA_PHASE:
- if ((!_req->length)
- || ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)
- && s3c2410_udc_read_fifo(ep,
- req))) {
- dev->ep0state = EP0_IDLE;
- req = NULL;
- }
- break;
-
- default:
- local_irq_restore(flags);
- return -EL2HLT;
- }
- } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
- && (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY))
- && s3c2410_udc_write_fifo(ep, req)) {
- req = NULL;
- } else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)
- && fifo_count
- && s3c2410_udc_read_fifo(ep, req)) {
- req = NULL;
- }
- }
-
-
- if (likely (req != 0))
- list_add_tail(&req->queue, &ep->queue);
-
- local_irq_restore(flags);
-
- dprintk(DEBUG_VERBOSE, "%s ok\n", __func__);
- return 0;
- }
函数返回到了composite_setup中,再把代码贴上来:- if (value >= 0) {
- req->length = value;
- req->zero = value < w_length;
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
- if (value < 0) {
- DBG(cdev, "ep_queue --> %d\n", value);
- req->status = 0;
- composite_setup_complete(gadget->ep0, req);
- }
- }
现在执行到了if (value < 0) { 这里对于上面的分析value是0所以下面的代码不执行。composite_setup函数也就返回了。返回到了 s3c2410_udc_handle_ep0_idle。因为没有出错, s3c2410_udc_handle_ep0_idle函数也返回了。返回到了s3c2410_udc_handle_ep0中,这时dev->ep0state还是EP0_IDLE状态。所以s3c2410_udc_handle_ep0也返回了。最后中断返回完成了这个控制传输。至于控制传输的状态阶段是由硬件来完成的。当我们向FIFO中写入了全部的数据,就可以设置EP0_CSR寄存器的DATA_END为1,硬件将自动完成状态阶段。还有一点,控制传输的urt回调函数非常简单,只打印一些调试信息,当最后一次调用s3c2410_udc_read_fifo时,s3c2410_udc_read_fifo会在函数里面调用urt的回调函数。 以上分析了USB设备枚举过程中的第二步:Get_Descriptor阶段的控制传输。其他的步骤大同小异,都是主机端发起,然后USB设备通过中端来处理。依次经过文中最前面提到的六步,USB主机就识别咱们的设备了 。
阅读(800) | 评论(0) | 转发(0) |