📄 m66592-udc.c
字号:
disable_irq_empty(m66592, ep->pipenum); pipe_start(m66592, ep->pipenum); tmp = m66592_read(m66592, ep->fifoctr); if (unlikely((tmp & M66592_FRDY) == 0)) pipe_irq_enable(m66592, ep->pipenum); else irq_packet_write(ep, req);}static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req){ struct m66592 *m66592 = ep->m66592; u16 pipenum = ep->pipenum; if (ep->pipenum == 0) { m66592_mdfy(m66592, M66592_PIPE0, (M66592_ISEL | M66592_CURPIPE), M66592_CFIFOSEL); m66592_write(m66592, M66592_BCLR, ep->fifoctr); pipe_start(m66592, pipenum); pipe_irq_enable(m66592, pipenum); } else { if (ep->use_dma) { m66592_bset(m66592, M66592_TRCLR, ep->fifosel); pipe_change(m66592, pipenum); m66592_bset(m66592, M66592_TRENB, ep->fifosel); m66592_write(m66592, (req->req.length + ep->ep.maxpacket - 1) / ep->ep.maxpacket, ep->fifotrn); } pipe_start(m66592, pipenum); /* trigger once */ pipe_irq_enable(m66592, pipenum); }}static void start_packet(struct m66592_ep *ep, struct m66592_request *req){ if (ep->desc->bEndpointAddress & USB_DIR_IN) start_packet_write(ep, req); else start_packet_read(ep, req);}static void start_ep0(struct m66592_ep *ep, struct m66592_request *req){ u16 ctsq; ctsq = m66592_read(ep->m66592, M66592_INTSTS0) & M66592_CTSQ; switch (ctsq) { case M66592_CS_RDDS: start_ep0_write(ep, req); break; case M66592_CS_WRDS: start_packet_read(ep, req); break; case M66592_CS_WRND: control_end(ep->m66592, 0); break; default: printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq); break; }}static void init_controller(struct m66592 *m66592){ m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND), M66592_PINCFG); m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG); m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); msleep(3); m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG); msleep(1); m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG); m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1); m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, M66592_DMA0CFG);}static void disable_controller(struct m66592 *m66592){ m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); udelay(1); m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG); udelay(1); m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG); udelay(1); m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);}static void m66592_start_xclock(struct m66592 *m66592){ u16 tmp; tmp = m66592_read(m66592, M66592_SYSCFG); if (!(tmp & M66592_XCKE)) m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);}/*-------------------------------------------------------------------------*/static void transfer_complete(struct m66592_ep *ep, struct m66592_request *req, int status)__releases(m66592->lock)__acquires(m66592->lock){ int restart = 0; if (unlikely(ep->pipenum == 0)) { if (ep->internal_ccpl) { ep->internal_ccpl = 0; return; } } list_del_init(&req->queue); if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN) req->req.status = -ESHUTDOWN; else req->req.status = status; if (!list_empty(&ep->queue)) restart = 1; spin_unlock(&ep->m66592->lock); req->req.complete(&ep->ep, &req->req); spin_lock(&ep->m66592->lock); if (restart) { req = list_entry(ep->queue.next, struct m66592_request, queue); if (ep->desc) start_packet(ep, req); }}static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req){ int i; u16 tmp; unsigned bufsize; size_t size; void *buf; u16 pipenum = ep->pipenum; struct m66592 *m66592 = ep->m66592; pipe_change(m66592, pipenum); m66592_bset(m66592, M66592_ISEL, ep->fifosel); i = 0; do { tmp = m66592_read(m66592, ep->fifoctr); if (i++ > 100000) { printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus" "conflict. please power off this controller."); return; } ndelay(1); } while ((tmp & M66592_FRDY) == 0); /* prepare parameters */ bufsize = get_buffer_size(m66592, pipenum); buf = req->req.buf + req->req.actual; size = min(bufsize, req->req.length - req->req.actual); /* write fifo */ if (req->req.buf) { if (size > 0) m66592_write_fifo(m66592, ep->fifoaddr, buf, size); if ((size == 0) || ((size % ep->ep.maxpacket) != 0)) m66592_bset(m66592, M66592_BVAL, ep->fifoctr); } /* update parameters */ req->req.actual += size; /* check transfer finish */ if ((!req->req.zero && (req->req.actual == req->req.length)) || (size % ep->ep.maxpacket) || (size == 0)) { disable_irq_ready(m66592, pipenum); disable_irq_empty(m66592, pipenum); } else { disable_irq_ready(m66592, pipenum); enable_irq_empty(m66592, pipenum); } pipe_start(m66592, pipenum);}static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req){ u16 tmp; unsigned bufsize; size_t size; void *buf; u16 pipenum = ep->pipenum; struct m66592 *m66592 = ep->m66592; pipe_change(m66592, pipenum); tmp = m66592_read(m66592, ep->fifoctr); if (unlikely((tmp & M66592_FRDY) == 0)) { pipe_stop(m66592, pipenum); pipe_irq_disable(m66592, pipenum); printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum); return; } /* prepare parameters */ bufsize = get_buffer_size(m66592, pipenum); buf = req->req.buf + req->req.actual; size = min(bufsize, req->req.length - req->req.actual); /* write fifo */ if (req->req.buf) { m66592_write_fifo(m66592, ep->fifoaddr, buf, size); if ((size == 0) || ((size % ep->ep.maxpacket) != 0) || ((bufsize != ep->ep.maxpacket) && (bufsize > size))) m66592_bset(m66592, M66592_BVAL, ep->fifoctr); } /* update parameters */ req->req.actual += size; /* check transfer finish */ if ((!req->req.zero && (req->req.actual == req->req.length)) || (size % ep->ep.maxpacket) || (size == 0)) { disable_irq_ready(m66592, pipenum); enable_irq_empty(m66592, pipenum); } else { disable_irq_empty(m66592, pipenum); pipe_irq_enable(m66592, pipenum); }}static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req){ u16 tmp; int rcv_len, bufsize, req_len; int size; void *buf; u16 pipenum = ep->pipenum; struct m66592 *m66592 = ep->m66592; int finish = 0; pipe_change(m66592, pipenum); tmp = m66592_read(m66592, ep->fifoctr); if (unlikely((tmp & M66592_FRDY) == 0)) { req->req.status = -EPIPE; pipe_stop(m66592, pipenum); pipe_irq_disable(m66592, pipenum); printk(KERN_ERR "read fifo not ready"); return; } /* prepare parameters */ rcv_len = tmp & M66592_DTLN; bufsize = get_buffer_size(m66592, pipenum); buf = req->req.buf + req->req.actual; req_len = req->req.length - req->req.actual; if (rcv_len < bufsize) size = min(rcv_len, req_len); else size = min(bufsize, req_len); /* update parameters */ req->req.actual += size; /* check transfer finish */ if ((!req->req.zero && (req->req.actual == req->req.length)) || (size % ep->ep.maxpacket) || (size == 0)) { pipe_stop(m66592, pipenum); pipe_irq_disable(m66592, pipenum); finish = 1; } /* read fifo */ if (req->req.buf) { if (size == 0) m66592_write(m66592, M66592_BCLR, ep->fifoctr); else m66592_read_fifo(m66592, ep->fifoaddr, buf, size); } if ((ep->pipenum != 0) && finish) transfer_complete(ep, req, 0);}static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb){ u16 check; u16 pipenum; struct m66592_ep *ep; struct m66592_request *req; if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) { m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS); m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE, M66592_CFIFOSEL); ep = &m66592->ep[0]; req = list_entry(ep->queue.next, struct m66592_request, queue); irq_packet_read(ep, req); } else { for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) { check = 1 << pipenum; if ((status & check) && (enb & check)) { m66592_write(m66592, ~check, M66592_BRDYSTS); ep = m66592->pipenum2ep[pipenum]; req = list_entry(ep->queue.next, struct m66592_request, queue); if (ep->desc->bEndpointAddress & USB_DIR_IN) irq_packet_write(ep, req); else irq_packet_read(ep, req); } } }}static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb){ u16 tmp; u16 check; u16 pipenum; struct m66592_ep *ep; struct m66592_request *req; if ((status & M66592_BEMP0) && (enb & M66592_BEMP0)) { m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS); ep = &m66592->ep[0]; req = list_entry(ep->queue.next, struct m66592_request, queue); irq_ep0_write(ep, req); } else { for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) { check = 1 << pipenum; if ((status & check) && (enb & check)) { m66592_write(m66592, ~check, M66592_BEMPSTS); tmp = control_reg_get(m66592, pipenum); if ((tmp & M66592_INBUFM) == 0) { disable_irq_empty(m66592, pipenum); pipe_irq_disable(m66592, pipenum); pipe_stop(m66592, pipenum); ep = m66592->pipenum2ep[pipenum]; req = list_entry(ep->queue.next, struct m66592_request, queue); if (!list_empty(&ep->queue)) transfer_complete(ep, req, 0); } } } }}static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)__releases(m66592->lock)__acquires(m66592->lock){ struct m66592_ep *ep; u16 pid; u16 status = 0; u16 w_index = le16_to_cpu(ctrl->wIndex); switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: status = 1 << USB_DEVICE_SELF_POWERED; break; case USB_RECIP_INTERFACE: status = 0; break; case USB_RECIP_ENDPOINT: ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; pid = control_reg_get_pid(m66592, ep->pipenum); if (pid == M66592_PID_STALL) status = 1 << USB_ENDPOINT_HALT; else status = 0; break; default: pipe_stall(m66592, 0); return; /* exit */ } m66592->ep0_data = cpu_to_le16(status); m66592->ep0_req->buf = &m66592->ep0_data; m66592->ep0_req->length = 2; /* AV: what happens if we get called again before that gets through? */ spin_unlock(&m66592->lock); m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL); spin_lock(&m66592->lock);}static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl){ switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: control_end(m66592, 1); break; case USB_RECIP_INTERFACE: control_end(m66592, 1); break; case USB_RECIP_ENDPOINT: { struct m66592_ep *ep; struct m66592_request *req; u16 w_index = le16_to_cpu(ctrl->wIndex); ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; pipe_stop(m66592, ep->pipenum); control_reg_sqclr(m66592, ep->pipenum); control_end(m66592, 1); req = list_entry(ep->queue.next, struct m66592_request, queue); if (ep->busy) { ep->busy = 0; if (list_empty(&ep->queue)) break; start_packet(ep, req); } else if (!list_empty(&ep->queue)) pipe_start(m66592, ep->pipenum); } break; default: pipe_stall(m66592, 0); break; }}static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl){ switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: control_end(m66592, 1); break; case USB_RECIP_INTERFACE: control_end(m66592, 1); break; case USB_RECIP_ENDPOINT: { struct m66592_ep *ep; u16 w_index = le16_to_cpu(ctrl->wIndex); ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; pipe_stall(m66592, ep->pipenum); control_end(m66592, 1); } break; default: pipe_stall(m66592, 0); break; }}/* if return value is true, call class driver's setup() */static int setup_packet(struct m66592 *m66592, struct usb_ctrlrequest *ctrl){ u16 *p = (u16 *)ctrl; unsigned long offset = M66592_USBREQ; int i, ret = 0; /* read fifo */ m66592_write(m66592, ~M66592_VALID, M66592_INTSTS0); for (i = 0; i < 4; i++) p[i] = m66592_read(m66592, offset + i*2); /* check request */ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { switch (ctrl->bRequest) { case USB_REQ_GET_STATUS: get_status(m66592, ctrl); break; case USB_REQ_CLEAR_FEATURE: clear_feature(m66592, ctrl); break; case USB_REQ_SET_FEATURE: set_feature(m66592, ctrl); break; default: ret = 1; break; } } else ret = 1; return ret;}static void m66592_update_usb_speed(struct m66592 *m66592){ u16 speed = get_usb_speed(m66592); switch (speed) { case M66592_HSMODE: m66592->gadget.speed = USB_SPEED_HIGH; break; case M66592_FSMODE: m66592->gadget.speed = USB_SPEED_FULL; break; default: m66592->gadget.speed = USB_SPEED_UNKNOWN; printk(KERN_ERR "USB speed unknown\n"); }}static void irq_device_state(struct m66592 *m66592){ u16 dvsq; dvsq = m66592_read(m66592, M66592_INTSTS0) & M66592_DVSQ; m66592_write(m66592, ~M66592_DVST, M66592_INTSTS0); if (dvsq == M66592_DS_DFLT) { /* bus reset */ m66592->driver->disconnect(&m66592->gadget); m66592_update_usb_speed(m66592); } if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG) m66592_update_usb_speed(m66592); if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) && m66592->gadget.speed == USB_SPEED_UNKNOWN) m66592_update_usb_speed(m66592); m66592->old_dvsq = dvsq;}static void irq_control_stage(struct m66592 *m66592)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -