📄 usb-musb.c
字号:
return s->ep[ep].type[1]; case MUSB_HDRC_RXINTERVAL: return s->ep[ep].interval[1]; case (MUSB_HDRC_FIFOSIZE & ~1): return 0x00; case MUSB_HDRC_FIFOSIZE: return ep ? s->ep[ep].fifosize : s->ep[ep].config; default: printf("%s: unknown register at %02x\n", __FUNCTION__, addr); return 0x00; };}static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value){ struct musb_s *s = (struct musb_s *) opaque; switch (addr) { case MUSB_HDRC_TXTYPE: s->ep[ep].type[0] = value; break; case MUSB_HDRC_TXINTERVAL: s->ep[ep].interval[0] = value; musb_ep_frame_cancel(&s->ep[ep], 0); break; case MUSB_HDRC_RXTYPE: s->ep[ep].type[1] = value; break; case MUSB_HDRC_RXINTERVAL: s->ep[ep].interval[1] = value; musb_ep_frame_cancel(&s->ep[ep], 1); break; case (MUSB_HDRC_FIFOSIZE & ~1): break; case MUSB_HDRC_FIFOSIZE: printf("%s: somebody messes with fifosize (now %i bytes)\n", __FUNCTION__, value); s->ep[ep].fifosize = value; break; default: printf("%s: unknown register at %02x\n", __FUNCTION__, addr); };}static uint16_t musb_ep_readh(void *opaque, int ep, int addr){ struct musb_s *s = (struct musb_s *) opaque; uint16_t ret; switch (addr) { case MUSB_HDRC_TXMAXP: return s->ep[ep].maxp[0]; case MUSB_HDRC_TXCSR: return s->ep[ep].csr[0]; case MUSB_HDRC_RXMAXP: return s->ep[ep].maxp[1]; case MUSB_HDRC_RXCSR: ret = s->ep[ep].csr[1]; /* TODO: This and other bits probably depend on * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR. */ if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR) s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY; return ret; case MUSB_HDRC_RXCOUNT: return s->ep[ep].rxcount; default: return musb_ep_readb(s, ep, addr) | (musb_ep_readb(s, ep, addr | 1) << 8); };}static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value){ struct musb_s *s = (struct musb_s *) opaque; switch (addr) { case MUSB_HDRC_TXMAXP: s->ep[ep].maxp[0] = value; break; case MUSB_HDRC_TXCSR: if (ep) { s->ep[ep].csr[0] &= value & 0xa6; s->ep[ep].csr[0] |= value & 0xff59; } else { s->ep[ep].csr[0] &= value & 0x85; s->ep[ep].csr[0] |= value & 0xf7a; } musb_ep_frame_cancel(&s->ep[ep], 0); if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) || (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) { s->ep[ep].fifolen[0] = 0; s->ep[ep].fifostart[0] = 0; if (ep) s->ep[ep].csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY); else s->ep[ep].csr[0] &= ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY); } if ( (ep &&#ifdef CLEAR_NAK (value & MGC_M_TXCSR_TXPKTRDY) && !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) ||#else (value & MGC_M_TXCSR_TXPKTRDY)) ||#endif (!ep &&#ifdef CLEAR_NAK (value & MGC_M_CSR0_TXPKTRDY) && !(value & MGC_M_CSR0_H_NAKTIMEOUT)))#else (value & MGC_M_CSR0_TXPKTRDY)))#endif musb_tx_rdy(s, ep); if (!ep && (value & MGC_M_CSR0_H_REQPKT) &&#ifdef CLEAR_NAK !(value & (MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_RXPKTRDY)))#else !(value & MGC_M_CSR0_RXPKTRDY))#endif musb_rx_req(s, ep); break; case MUSB_HDRC_RXMAXP: s->ep[ep].maxp[1] = value; break; case MUSB_HDRC_RXCSR: /* (DMA mode only) */ if ( (value & MGC_M_RXCSR_H_AUTOREQ) && !(value & MGC_M_RXCSR_RXPKTRDY) && (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY)) value |= MGC_M_RXCSR_H_REQPKT; s->ep[ep].csr[1] &= 0x102 | (value & 0x4d); s->ep[ep].csr[1] |= value & 0xfeb0; musb_ep_frame_cancel(&s->ep[ep], 1); if (value & MGC_M_RXCSR_FLUSHFIFO) { s->ep[ep].fifolen[1] = 0; s->ep[ep].fifostart[1] = 0; s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY); /* If double buffering and we have two packets ready, flush * only the first one and set up the fifo at the second packet. */ }#ifdef CLEAR_NAK if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR))#else if (value & MGC_M_RXCSR_H_REQPKT)#endif musb_rx_req(s, ep); break; case MUSB_HDRC_RXCOUNT: s->ep[ep].rxcount = value; break; default: musb_ep_writeb(s, ep, addr, value & 0xff); musb_ep_writeb(s, ep, addr | 1, value >> 8); };}/* Generic control */static uint32_t musb_readb(void *opaque, target_phys_addr_t addr){ struct musb_s *s = (struct musb_s *) opaque; int ep, i; uint8_t ret; switch (addr) { case MUSB_HDRC_FADDR: return s->faddr; case MUSB_HDRC_POWER: return s->power; case MUSB_HDRC_INTRUSB: ret = s->intr; for (i = 0; i < sizeof(ret) * 8; i ++) if (ret & (1 << i)) musb_intr_set(s, i, 0); return ret; case MUSB_HDRC_INTRUSBE: return s->mask; case MUSB_HDRC_INDEX: return s->idx; case MUSB_HDRC_TESTMODE: return 0x00; case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): return musb_ep_readb(s, s->idx, addr & 0xf); case MUSB_HDRC_DEVCTL: return s->devctl; case MUSB_HDRC_TXFIFOSZ: case MUSB_HDRC_RXFIFOSZ: case MUSB_HDRC_VCTRL: /* TODO */ return 0x00; case MUSB_HDRC_HWVERS: return (1 << 10) | 400; case (MUSB_HDRC_VCTRL | 1): case (MUSB_HDRC_HWVERS | 1): case (MUSB_HDRC_DEVCTL | 1): return 0x00; case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): ep = (addr >> 3) & 0xf; return musb_busctl_readb(s, ep, addr & 0x7); case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): ep = (addr >> 4) & 0xf; return musb_ep_readb(s, ep, addr & 0xf); default: printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); return 0x00; };}static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value){ struct musb_s *s = (struct musb_s *) opaque; int ep; switch (addr) { case MUSB_HDRC_FADDR: s->faddr = value & 0x7f; break; case MUSB_HDRC_POWER: s->power = (value & 0xef) | (s->power & 0x10); /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */ if ((value & MGC_M_POWER_RESET) && s->port.dev) { usb_send_msg(s->port.dev, USB_MSG_RESET); /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set. */ if ((value & MGC_M_POWER_HSENAB) && s->port.dev->speed == USB_SPEED_HIGH) s->power |= MGC_M_POWER_HSMODE; /* Success */ /* Restart frame counting. */ } if (value & MGC_M_POWER_SUSPENDM) { /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND * is set, also go into low power mode. Frame counting stops. */ /* XXX: Cleared when the interrupt register is read */ } if (value & MGC_M_POWER_RESUME) { /* Wait 20ms and signal resuming on the bus. Frame counting * restarts. */ } break; case MUSB_HDRC_INTRUSB: break; case MUSB_HDRC_INTRUSBE: s->mask = value & 0xff; break; case MUSB_HDRC_INDEX: s->idx = value & 0xf; break; case MUSB_HDRC_TESTMODE: break; case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): musb_ep_writeb(s, s->idx, addr & 0xf, value); break; case MUSB_HDRC_DEVCTL: s->session = !!(value & MGC_M_DEVCTL_SESSION); musb_session_update(s, !!s->port.dev, !!(s->devctl & MGC_M_DEVCTL_SESSION)); /* It seems this is the only R/W bit in this register? */ s->devctl &= ~MGC_M_DEVCTL_SESSION; s->devctl |= value & MGC_M_DEVCTL_SESSION; break; case MUSB_HDRC_TXFIFOSZ: case MUSB_HDRC_RXFIFOSZ: case MUSB_HDRC_VCTRL: /* TODO */ break; case (MUSB_HDRC_VCTRL | 1): case (MUSB_HDRC_DEVCTL | 1): break; case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): ep = (addr >> 3) & 0xf; musb_busctl_writeb(s, ep, addr & 0x7, value); break; case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): ep = (addr >> 4) & 0xf; musb_ep_writeb(s, ep, addr & 0xf, value); break; default: printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); };}static uint32_t musb_readh(void *opaque, target_phys_addr_t addr){ struct musb_s *s = (struct musb_s *) opaque; int ep, i; uint16_t ret; switch (addr) { case MUSB_HDRC_INTRTX: ret = s->tx_intr; /* Auto clear */ for (i = 0; i < sizeof(ret) * 8; i ++) if (ret & (1 << i)) musb_tx_intr_set(s, i, 0); return ret; case MUSB_HDRC_INTRRX: ret = s->rx_intr; /* Auto clear */ for (i = 0; i < sizeof(ret) * 8; i ++) if (ret & (1 << i)) musb_rx_intr_set(s, i, 0); return ret; case MUSB_HDRC_INTRTXE: return s->tx_mask; case MUSB_HDRC_INTRRXE: return s->rx_mask; case MUSB_HDRC_FRAME: /* TODO */ return 0x0000; case MUSB_HDRC_TXFIFOADDR: return s->ep[s->idx].fifoaddr[0]; case MUSB_HDRC_RXFIFOADDR: return s->ep[s->idx].fifoaddr[1]; case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): return musb_ep_readh(s, s->idx, addr & 0xf); case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): ep = (addr >> 3) & 0xf; return musb_busctl_readh(s, ep, addr & 0x7); case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): ep = (addr >> 4) & 0xf; return musb_ep_readh(s, ep, addr & 0xf); default: return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8); };}static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value){ struct musb_s *s = (struct musb_s *) opaque; int ep; switch (addr) { case MUSB_HDRC_INTRTXE: s->tx_mask = value; /* XXX: the masks seem to apply on the raising edge like with * edge-triggered interrupts, thus no need to update. I may be * wrong though. */ break; case MUSB_HDRC_INTRRXE: s->rx_mask = value; break; case MUSB_HDRC_FRAME: /* TODO */ break; case MUSB_HDRC_TXFIFOADDR: s->ep[s->idx].fifoaddr[0] = value; s->ep[s->idx].buf[0] = s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1)); break; case MUSB_HDRC_RXFIFOADDR: s->ep[s->idx].fifoaddr[1] = value; s->ep[s->idx].buf[1] = s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1)); break; case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): musb_ep_writeh(s, s->idx, addr & 0xf, value); break; case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): ep = (addr >> 3) & 0xf; musb_busctl_writeh(s, ep, addr & 0x7, value); break; case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): ep = (addr >> 4) & 0xf; musb_ep_writeh(s, ep, addr & 0xf, value); break; default: musb_writeb(s, addr, value & 0xff); musb_writeb(s, addr | 1, value >> 8); };}static uint32_t musb_readw(void *opaque, target_phys_addr_t addr){ struct musb_s *s = (struct musb_s *) opaque; struct musb_ep_s *ep; int epnum; switch (addr) { case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; ep = s->ep + epnum; if (ep->fifolen[1] >= 16) { /* We have a FIFO underrun */ printf("%s: EP%i FIFO is now empty, stop reading\n", __FUNCTION__, epnum); return 0x00000000; } /* In DMA mode clear RXPKTRDY and set REQPKT automatically * (if AUTOREQ is set) */ ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL; return ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++]; default: printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); return 0x00000000; };}static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value){ struct musb_s *s = (struct musb_s *) opaque; struct musb_ep_s *ep; int epnum; switch (addr) { case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; ep = s->ep + epnum; if (ep->fifolen[0] >= 16) { /* We have a FIFO overrun */ printf("%s: EP%i FIFO exceeded 64 bytes, stop feeding data\n", __FUNCTION__, epnum); break; } ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value; if (epnum) ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY; break; default: printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); };}CPUReadMemoryFunc *musb_read[] = { musb_readb, musb_readh, musb_readw,};CPUWriteMemoryFunc *musb_write[] = { musb_writeb, musb_writeh, musb_writew,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -