- 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;
- };
(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 */
- 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;
- }
- /* RESUME */
- if (usb_status & S3C2410_UDC_USBINT_RESUME) {
- dprintk(DEBUG_NORMAL, "USB resume\n");
- /* clear interrupt */
- 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);
- }
- /* SUSPEND */
- if (usb_status & S3C2410_UDC_USBINT_SUSPEND) {
- dprintk(DEBUG_NORMAL, "USB suspend\n");
- /* clear interrupt */
- 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;
- }
- /* EP */
- /* control traffic */
- /* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready
- * generate an interrupt
- */
- if (usbd_status & S3C2410_UDC_INT_EP0) {
- dprintk(DEBUG_VERBOSE, "USB ep0 irq\n");
- /* Clear the interrupt bit by setting it to 1 */
- udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);
- s3c2410_udc_handle_ep0(dev);
- }
- /* endpoint data transfers */
- for (i = 1; i < S3C2410_ENDPOINTS; i++) {
- u32 tmp = 1 << i;
- if (usbd_status & tmp) {
- dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i);
- /* Clear the interrupt bit by setting it to 1 */
- 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);
- /* Restore old index */
- udc_write(idx, S3C2410_UDC_INDEX_REG);
- spin_unlock_irqrestore(&dev->lock, flags);
- return IRQ_HANDLED;
- }
- 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);
- /* We make the assumption that S3C2410_UDC_IN_CSR1_REG equal to
- * S3C2410_UDC_EP0_CSR_REG when index is zero */
- 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]);
- /* clear stall status */
- 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;
- }
- /* clear setup end */
- 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: /* GET_DESCRIPTOR etc */
- 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: /* SET_DESCRIPTOR etc */
- 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 {
- struct list_head queue;
- unsigned long last_io; /* jiffies timestamp */
- 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;
- };
- .ep[0] = {
- .num = 0,
- .ep = {
- .name = ep0name,
- .ops = &s3c2410_ep_ops,
- .maxpacket = EP0_FIFO_SIZE,
- },
- .dev = &memory,
- },
(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;
- case EP0_IDLE:
- s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr);
- break;
- 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;
- /* start control request? */
- 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);
- /* cope with automagic for some standard requests. */
- 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;
- /* deferred i/o == no response yet */
- } 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]);
- }
- 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;
- /* partial re-init of the response message; the function or the
- * gadget might need to intercept e.g. a control-OUT completion
- * when we delegate to it.
- */
- req->zero = 0;
- req->complete = composite_setup_complete;
- req->length = USB_BUFSIZ;
- gadget->ep0->driver_data = cdev;
- switch (ctrl->bRequest) {
- /* we handle all standard USB descriptors */
- 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;
- /* FALLTHROUGH */
- 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;
- /* any number of configs can work */
- 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;
- /* function drivers must handle get/set altsetting; if there's
- * no get() method, we know only altsetting zero works.
- */
- 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;
- /* lots of interfaces only need altsetting zero... */
- 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);
- /* functions always handle their interfaces ... punt other
- * recipients (endpoint, other, WUSB, ...) to the current
- * configuration code.
- *
- * REVISIT it could make sense to let the composite device
- * take such requests too, if that's ever needed: to work
- * in config 0, etc.
- */
- 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;
- }
- /* respond with data transfer before status phase? */
- 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:
- /* device either stalls (value < 0) or reports success */
- return value;
- }
- cdev->desc.bNumConfigurations =
- count_configs(cdev, USB_DT_DEVICE);
- value = min(w_length, (u16) sizeof cdev->desc);
- memcpy(req->buf, &cdev->desc, value);
- 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);
- }
- }
- 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) { //以下是针对普通端点的,对于端点0执行else以后的语句
- 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 { //端点0
- udc_write(0, S3C2410_UDC_INDEX_REG);
- ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
- fifo_count = s3c2410_udc_fifo_count_out(); //读出当前fifo的位置
- }
- /* kickstart this i/o queue? */
- if (list_empty(&ep->queue) && !ep->halted) { //如果端点的urt链表为空,而端点正常,执行下面的语句,这正是目前的情况,所以下面的语句执行
- if (ep->bEndpointAddress == 0 /* ep0 */) {
- switch (dev->ep0state) {
- case EP0_IN_DATA_PHASE: //对于Get_Descriptor,在s3c2410_udc_handle_ep0_idle中已经设置dev->ep0state为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;
- //以上代码才真正的将urt的数据写入USB设备控制器端点0的FIFO,这里有一个条件就是S3C2410_UDC_EP0_CSR_IPKRDY应该为0,USB设备控制器将FIFO中的内容发送出去会设置S3C2410_UDC_EP0_CSR_IPKRDY
- //为0,当我们将数据写入FIFO中,设置S3C2410_UDC_EP0_CSR_IPKRDY为1。s3c2410_udc_write_fifo函数完成的就是这个功能
- 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;
- }
- }
- /* pio or dma irq handler advances the queue. */
- if (likely (req != 0)) //对于控制传输这时req为0所以一下代码不执行,这里likely说明req不为0的情况居多,这是针对普通端点来说的
- list_add_tail(&req->queue, &ep->queue);
- local_irq_restore(flags);
- dprintk(DEBUG_VERBOSE, "%s ok\n", __func__);
- return 0;
- }
- 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);
- }
- }
以上分析了USB设备枚举过程中的第二步:Get_Descriptor阶段的控制传输。其他的步骤大同小异,都是主机端发起,然后USB设备通过中端来处理。依次经过文中最前面提到的六步,USB主机就识别咱们的设备了 。