📄 s3c2410_udc.c
字号:
nuke (dev, ep); len = read_fifo_crq(&crq); if (len != sizeof(crq)) { dprintk("setup begin: fifo READ ERROR" " wanted %d bytes got %d. Stalling out...\n", sizeof(crq), len); set_ep0_ss(); return; } /* 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) { /* hardware restricts gadget drivers here! */ case USB_REQ_SET_CONFIGURATION: dprintk("USB_REQ_SET_CONFIGURATION ... \n"); if (crq.bRequestType == USB_RECIP_DEVICE) {config_change: dev->req_config = 1; clear_ep_state(dev); set_ep0_de_out(); } break; /* ... and here, even more ... */ case USB_REQ_SET_INTERFACE: dprintk("USB_REQ_SET_INTERFACE ... \n"); if (crq.bRequestType == USB_RECIP_INTERFACE) { goto config_change; } break; /* hardware was supposed to hide this */ case USB_REQ_SET_ADDRESS: dprintk("USB_REQ_SET_ADDRESS ... \n"); if (crq.bRequestType == USB_RECIP_DEVICE) { tmp = crq.wValue & 0x7F; dev->address = tmp; __raw_writel((tmp | 0x80), S3C2410_UDC_FUNC_ADDR_REG); set_ep0_de_out(); return; } break; default: clear_ep0_opr(); 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("config change %02x fail %d?\n", crq.bRequest, ret); return; } if (ret == -EOPNOTSUPP) dprintk("Operation not supported\n"); else dprintk("dev->driver->setup failed. (%d)\n",ret); dev->ep0state = EP0_STALL; /* deferred i/o == no response yet */ } else if (dev->req_pending) { dprintk("dev->req_pending... what now?\n"); dev->req_pending=0; } dprintk("ep0state %s\n",ep0states[dev->ep0state]); } break; case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ dprintk("EP0_IN_DATA_PHASE ... what now?\n"); if (!(ep0csr & 2) && req) { write_fifo(ep, req); } break; case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ dprintk("EP0_OUT_DATA_PHASE ... what now?\n"); if ((ep0csr & 1) && req ) { read_fifo(ep,req); } break; case EP0_END_XFER: dprintk("EP0_END_XFER ... what now?\n"); dev->ep0state=EP0_IDLE; break; case EP0_STALL: set_ep0_ss(); break; }}/* * handle_ep - Manage I/O endpoints */static void handle_ep(struct s3c2410_ep *ep){ struct s3c2410_request *req; int is_in = ep->bEndpointAddress & USB_DIR_IN; u32 ep_csr1; u32 idx; if (likely (!list_empty(&ep->queue))) req = list_entry(ep->queue.next, struct s3c2410_request, queue); else req = 0; idx = (u32)(ep->bEndpointAddress&0x7F); if (is_in) { __raw_writel(idx, S3C2410_UDC_INDEX_REG); ep_csr1 = __raw_readl(S3C2410_UDC_IN_CSR1_REG); dprintk("ep%01d write csr:%02x ",idx,ep_csr1); if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) { dprintk("st\n"); __raw_writel(idx, S3C2410_UDC_INDEX_REG); __raw_writel(0x00,S3C2410_UDC_IN_CSR1_REG); return; } if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) { write_fifo(ep,req); } } else { __raw_writel(idx, S3C2410_UDC_INDEX_REG); ep_csr1 = __raw_readl(S3C2410_UDC_OUT_CSR1_REG); dprintk("ep%01d read csr:%02x\n",idx,ep_csr1); if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) { __raw_writel(idx, S3C2410_UDC_INDEX_REG); __raw_writel(0x00,S3C2410_UDC_OUT_CSR1_REG); return; } if( (ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) { read_fifo(ep,req); } }}/* * s3c2410_udc_irq - interrupt handler */static irqreturn_ts3c2410_udc_irq(int irq, void *_dev, struct pt_regs *r){ struct s3c2410_udc *dev = _dev; int usb_status; int usbd_status; int pwr_reg; int ep0csr; int i; u32 idx = __raw_readl(S3C2410_UDC_INDEX_REG); usb_status = __raw_readl(S3C2410_UDC_USB_INT_REG); usbd_status = __raw_readl(S3C2410_UDC_EP_INT_REG); pwr_reg = __raw_readl(S3C2410_UDC_PWR_REG); S3C2410_UDC_SETIX(EP0); ep0csr = __raw_readl(S3C2410_UDC_IN_CSR1_REG); dprintk("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 */ /* RESET */ if (usb_status & S3C2410_UDC_USBINT_RESET) { dprintk("USB reset\n"); __raw_writel(0x00, S3C2410_UDC_PWR_REG); S3C2410_UDC_SETIX(EP0); __raw_writel(S3C2410_UDC_MAXP_8, S3C2410_UDC_MAXP_REG); __raw_writel(0x80, S3C2410_UDC_FUNC_ADDR_REG);// clear_ep0_opr(); /* clear interrupt */ __raw_writel(S3C2410_UDC_USBINT_RESET, S3C2410_UDC_USB_INT_REG); dev->gadget.speed = USB_SPEED_FULL; dev->ep0state = EP0_IDLE; } /* RESUME */ if (usb_status & S3C2410_UDC_USBINT_RESUME) { dprintk("USB resume\n"); /* clear interrupt */ __raw_writel(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("USB suspend\n"); /* clear interrupt */ __raw_writel(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("USB ep0 irq\n"); /* Clear the interrupt bit by setting it to 1 */ __raw_writel(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG); handle_ep0(dev); } /* endpoint data transfers */ for (i = 1; i < S3C2410_ENDPOINTS; i++) { u32 tmp = 1 << i; if (usbd_status & tmp) { dprintk("USB ep%d irq\n", i); /* Clear the interrupt bit by setting it to 1 */ __raw_writel(tmp, S3C2410_UDC_EP_INT_REG); handle_ep(&dev->ep[i]); } } dprintk("irq: %d done.\n", irq); __raw_writel(idx,S3C2410_UDC_INDEX_REG); return IRQ_HANDLED; }/* * udc_reinit */static void udc_reinit(struct s3c2410_udc *dev){ u32 i; /* device/ep0 records init */ INIT_LIST_HEAD (&dev->gadget.ep_list); INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); dev->ep0state = EP0_IDLE; /* basic endpoint records init */ for (i = 0; i < S3C2410_ENDPOINTS; i++) { struct s3c2410_ep *ep = &dev->ep[i]; if (i != 0) list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); ep->desc = 0; INIT_LIST_HEAD (&ep->queue); }}/*------------------------- s3c2410_ep_ops ----------------------------------*//* * s3c2410_ep_enable */static ints3c2410_ep_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc){ struct s3c2410_udc *dev; struct s3c2410_ep *ep; u32 max, tmp; unsigned long flags; u32 csr1,csr2; u32 int_en_reg; ep = container_of (_ep, struct s3c2410_ep, ep); if (!_ep || !desc || ep->desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; dev = ep->dev; if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff; spin_lock_irqsave (&dev->lock, flags); _ep->maxpacket = max & 0x7ff; ep->desc = desc; ep->bEndpointAddress = desc->bEndpointAddress; /* set max packet */ __raw_writel(ep->num, S3C2410_UDC_INDEX_REG); __raw_writel(max>>3,S3C2410_UDC_MAXP_REG); /* set type, direction, address; reset fifo counters */ if (desc->bEndpointAddress & USB_DIR_IN) { csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT; csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN; __raw_writel(ep->num, S3C2410_UDC_INDEX_REG); __raw_writel(csr1,S3C2410_UDC_IN_CSR1_REG); __raw_writel(ep->num, S3C2410_UDC_INDEX_REG); __raw_writel(csr2,S3C2410_UDC_IN_CSR2_REG); } else { /* don't flush he in fifo or there will be an interrupt for that * endpoint */ csr1 = S3C2410_UDC_ICSR1_CLRDT; csr2 = S3C2410_UDC_ICSR2_DMAIEN; __raw_writel(ep->num, S3C2410_UDC_INDEX_REG); __raw_writel(csr1,S3C2410_UDC_IN_CSR1_REG); __raw_writel(ep->num, S3C2410_UDC_INDEX_REG); __raw_writel(csr2,S3C2410_UDC_IN_CSR2_REG); csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT; csr2 = S3C2410_UDC_OCSR2_DMAIEN; __raw_writel(ep->num, S3C2410_UDC_INDEX_REG); __raw_writel(csr1,S3C2410_UDC_OUT_CSR1_REG); __raw_writel(ep->num, S3C2410_UDC_INDEX_REG); __raw_writel(csr2,S3C2410_UDC_OUT_CSR2_REG); } /* enable irqs */ int_en_reg = __raw_readl(S3C2410_UDC_EP_INT_EN_REG); __raw_writel(int_en_reg | (1<<ep->num),S3C2410_UDC_EP_INT_EN_REG); /* print some debug message */ tmp = desc->bEndpointAddress; dprintk ("enable %s(%d) ep%x%s-blk max %02x\n", _ep->name,ep->num, tmp, desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max); spin_unlock_irqrestore (&dev->lock, flags); return 0;}/* * s3c2410_ep_disable */static int s3c2410_ep_disable (struct usb_ep *_ep){ struct s3c2410_ep *ep = container_of(_ep, struct s3c2410_ep, ep); unsigned long flags; if (!_ep || !ep->desc) { dprintk("%s not enabled\n", _ep ? ep->ep.name : NULL); return -EINVAL; } spin_lock_irqsave(&ep->dev->lock, flags); ep->desc = 0; nuke (ep->dev, ep); ep->ep.maxpacket = EP_FIFO_SIZE; spin_unlock_irqrestore(&ep->dev->lock, flags); dprintk("%s disabled\n", _ep->name); return 0;}/* * s3c2410_alloc_request */static struct usb_request *s3c2410_alloc_request (struct usb_ep *_ep, int mem_flags){ struct s3c2410_ep *ep; struct s3c2410_request *req; printk("s3c2410_alloc_request(ep=%p,flags=%d)\n", _ep, mem_flags); ep = container_of (_ep, struct s3c2410_ep, ep); if (!_ep) return 0; req = kmalloc (sizeof *req, mem_flags); if (!req) return 0; memset (req, 0, sizeof *req); INIT_LIST_HEAD (&req->queue); return &req->req;}/* * s3c2410_free_request */static voids3c2410_free_request (struct usb_ep *_ep, struct usb_request *_req){ struct s3c2410_ep *ep; struct s3c2410_request *req; printk("s3c2410_free_request(ep=%p,req=%p)\n", _ep, _req); ep = container_of (_ep, struct s3c2410_ep, ep); if (!ep || !_req || (!ep->desc && _ep->name != ep0name)) return; req = container_of (_req, struct s3c2410_request, req); WARN_ON (!list_empty (&req->queue)); kfree (req);}/* * s3c2410_alloc_buffer */static void *s3c2410_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, int mem_flags){ char *retval; printk("s3c2410_alloc_buffer()\n"); if (!the_controller->driver)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -