📄 tc86c001.c
字号:
static struct tq_struct tc_task = { routine:tc_do_task};static voidtc_start_out (unsigned int ep){ struct usb_endpoint_instance *endpoint = ep_endpoints[ep]; struct urb *urb = endpoint->rcv_urb; int size; if (!urb) { dbg_rx (2, "no rcv_urb"); dbg_rx (1, "ep%d no rcv_urb available. try again.", ep); set_bit (ep, &tc_do_task_ep); schedule_task (&tc_task); // XXX could we call usbd_fill_rcv() here? return; } if (!nodma && ep == UDC_MSTWR_ENDPOINT) { /* DMA endpoint */ if (urb->actual_length == 0) { if (ep_dmaaddrs[ep]) { printk (KERN_ERR UDC_NAME ": receive DMA busy.\n"); //return; } ep_dmaaddrs[ep] = pci_map_single (udc_pci_dev, urb->buffer, urb->buffer_length, PCI_DMA_FROMDEVICE); dbg_rx (2, "rx dmaaddr(%d) %x", ep, ep_dmaaddrs[ep]); if (!ep_dmaaddrs[ep]) { printk (KERN_ERR UDC_NAME ": pci_map_single failed.\n"); usbd_rcv_complete_irq (endpoint, 0, 1); return; } } /* start DMA (master write) */ /* check short packet without following three SOFs... */ size = tc_read_epxsize (ep); if (size == endpoint->rcv_packetSize) { /* fulll packet: transfer continuous packets */ size = min ((int) (urb->buffer_length - urb->actual_length), endpoint->rcv_transferSize); } tc_mstwr_start (ep_dmaaddrs[ep] + urb->actual_length, size); return; } /* check EPx_DSETA */ if (!(readl (&tc_udcregs->DataSet[0]) & (1 << (ep * 2)))) { printk (KERN_ERR UDC_NAME ": ep%d FIFO empty\n", ep); return; } size = tc_read_epxsize (ep); if (size == 0) { printk (KERN_ERR UDC_NAME ": ep%d SIZE 0\n", ep); return; } dbg_rx (2, "ep%d rx size 0x%x (status %x)", ep, size, readl (&tc_udcregs->EPxStatus[ep])); tc_read_buffer (ep, urb->buffer + urb->actual_length, size); usbd_rcv_complete_irq (endpoint, size, 0);}static voidtc_end_out (unsigned int ep, int tout){ struct usb_endpoint_instance *endpoint = ep_endpoints[ep]; struct urb *urb = endpoint->rcv_urb; int size; int org_buffer_length; if (!ep_dmaaddrs[ep] || !urb) { dbg_rx (0, "not mstwr"); return; } size = readl (&tc_regs->MstWrCurr) + 1 - ep_dmaaddrs[ep]; dbg_rx (2, "mstwr end (size 0x%x tout %d)", size, tout); org_buffer_length = urb->buffer_length; while (size > 0) { int len = min (size, endpoint->rcv_packetSize); if (endpoint->rcv_urb != urb) { dbg_rx (0, "BUG: rcv_urb consumed!!!"); break; } usbd_rcv_complete_irq (endpoint, len, 0); size -= len; if (size == 0 && len == endpoint->rcv_packetSize && endpoint->rcv_urb == urb) { /* null packet (send current rcv_urb to function driver) */ usbd_rcv_complete_irq (endpoint, 0, 0); } } if (endpoint->rcv_urb != urb) { pci_unmap_single (udc_pci_dev, ep_dmaaddrs[ep], org_buffer_length, PCI_DMA_FROMDEVICE); ep_dmaaddrs[ep] = 0; }}/* *********************************************************************** *//* Bulk IN (tx) *//** * start_in - start transmit * @ep: */static voidtc_start_in (unsigned int ep){ struct usb_endpoint_instance *endpoint = ep_endpoints[ep]; struct urb *urb = endpoint->tx_urb; if (!nodma) { if (ep_dmaaddrs[ep]) { dbg_tx (0, "ep%d DMA busy", ep); return; } if (readl (&tc_regs->MstSetting) & MST_RD_ENA) { dbg_tx (0, "ep%d DMARD busy", ep); return; } } usbd_tx_complete_irq (endpoint, 0); /* send next urb */ if ((urb = endpoint->tx_urb) != NULL) { if (!nodma && ep == UDC_MSTRD_ENDPOINT) { /* start DMA (master read) */ if (endpoint->sent == 0) { ep_dmaaddrs[ep] = pci_map_single (udc_pci_dev, urb->buffer, urb->buffer_length, PCI_DMA_TODEVICE); dbg_tx (2, "tx dmaaddr(%d) %x", ep, ep_dmaaddrs[ep]); if (!ep_dmaaddrs[ep]) { printk (KERN_ERR UDC_NAME ": pci_map_single failed.\n"); endpoint->last = urb->actual_length; usbd_tx_complete_irq (endpoint, 0); return; } } /* invoke master read for whole urb buffer */ endpoint->last = urb->actual_length - endpoint->sent; if (endpoint->last == 0) { /* send NULL packet */ dbg_tx (2, "ep%d EOPB", ep); writel ((readl (&tc_regs-> MstSetting) & MST_RW_BITS) | MST_RD_EOPB, &tc_regs->MstSetting); while (readl (&tc_regs->MstSetting) & MST_RD_EOPB); } else { /* disable EOP if transfersize is multiple of packetsize */ int eop = (endpoint->last % endpoint->tx_packetSize != 0); tc_mstrd_start (ep_dmaaddrs[ep] + endpoint->sent, endpoint->last, eop); } return; } /* check EPx_DSETA */ if (readl (&tc_udcregs->DataSet[0]) & (1 << (ep * 2))) { printk (KERN_ERR UDC_NAME ": ep%d FIFO not empty" " (urb length %d sent %d)\n", ep, urb->actual_length, endpoint->sent); return; } if ((urb->actual_length - endpoint->sent) > 0) { endpoint->last = min_t (int, urb->actual_length - endpoint->sent, endpoint->tx_packetSize); dbg_tx (2, "ep%d tx size 0x%x", ep, endpoint->last); tc_write_buffer (ep, urb->buffer + endpoint->sent, endpoint->last); if (endpoint->last < endpoint->tx_packetSize) { dbg_tx (2, "EOP %d", ep); writel (~(1 << ep), &tc_udcregs->EOP); } } else { // XXX ZLP endpoint->last = 0; dbg_tx (2, "EOP %d", ep); writel (~(1 << ep), &tc_udcregs->EOP); } } else if (nodma && (endpoint->last == endpoint->tx_packetSize)) { // XXX ZLP dbg_tx (2, "EOP %d (last %d)", ep, endpoint->last); endpoint->last = 0; writel (~(1 << ep), &tc_udcregs->EOP); }}static voidtc_end_in (unsigned int ep){ struct usb_endpoint_instance *endpoint = ep_endpoints[ep]; struct urb *urb = endpoint->tx_urb; if (!ep_dmaaddrs[ep] || !urb) return; dbg_tx (2, "mstrd end (size 0x%x)", readl (&tc_regs->MstRdCurr) + 1 - ep_dmaaddrs[ep]); if (endpoint->sent + endpoint->last >= urb->actual_length) { pci_unmap_single (udc_pci_dev, ep_dmaaddrs[ep], urb->buffer_length, PCI_DMA_TODEVICE); ep_dmaaddrs[ep] = 0; } /* complete current tx packet and start next transmit (if exists) */ tc_start_in (ep);}/* *********************************************************************** *//* Interrupt Handler */static voidtc_setup_descram_if (struct usb_device_instance *device, int port, int nconf, int nint, int *ofs){ struct usb_interface_instance *iinst; int nalt; iinst = usbd_device_interface_instance (device, port, nconf, nint); if (!iinst) return; for (nalt = 0; nalt < iinst->alternates; nalt++) { struct usb_interface_descriptor *idesc; struct usb_alternate_instance *ainst; int nclass, nep; ainst = usbd_device_alternate_instance (device, port, nconf, nint, nalt); if (!ainst) break; idesc = ainst->interface_descriptor; copy_descram (idesc, sizeof (*idesc), ofs); for (nclass = 0; nclass < ainst->classes; nclass++) { struct usb_class_descriptor *cldesc; cldesc = usbd_device_class_descriptor_index (device, port, nconf, nint, nalt, nclass); if (!cldesc) break; copy_descram (cldesc, cldesc->descriptor.generic.bFunctionLength, ofs); } for (nep = 0; nep < ainst->endpoints; nep++) { struct usb_endpoint_descriptor *edesc; edesc = usbd_device_endpoint_descriptor_index (device, port, nconf, nint, nalt, nep); if (!edesc) break; copy_descram (edesc, sizeof (*edesc), ofs); } }}static voidtc_setup_descram_str (int *ofs){ u8 bLength[4] = { 0, 0, 0, 0 }; copy_descram (&bLength, 4, ofs);}static voidtc_setup_descram (void){ struct usb_device_descriptor *ddesc; int ofs = 0, nconf; int i; ddesc = usbd_device_device_descriptor (udc_device, 0); if (!ddesc) return; copy_descram (ddesc, sizeof (*ddesc), &ofs); for (nconf = 0; nconf < ddesc->bNumConfigurations; nconf++) { struct usb_configuration_descriptor *cdesc; int nint; cdesc = usbd_device_configuration_descriptor (udc_device, 0, nconf); if (!cdesc) break; copy_descram (cdesc, sizeof (*cdesc), &ofs); for (nint = 0; nint < cdesc->bNumInterfaces; nint++) { tc_setup_descram_if (udc_device, 0, nconf, nint, &ofs); } } tc_setup_descram_str (&ofs); for (i = ofs; i < UDC_DESCRAM_SIZE; i++) writel (0, &tc_ramregs->DescRam[i]); for (i = 0; i < ofs; i += 8) dbg_udc (2, "Descram: %02x %02x %02x %02x %02x %02x %02x %02x", readl (&tc_ramregs->DescRam[i + 0]), readl (&tc_ramregs->DescRam[i + 1]), readl (&tc_ramregs->DescRam[i + 2]), readl (&tc_ramregs->DescRam[i + 3]), readl (&tc_ramregs->DescRam[i + 4]), readl (&tc_ramregs->DescRam[i + 5]), readl (&tc_ramregs->DescRam[i + 6]), readl (&tc_ramregs->DescRam[i + 7]));}static voidtc_power_detected (void){ int i; u8 bcs, single; if (readl (&tc_regs->PowerDetect) & PW_DETECT) { /* power detected */ dbg_udc (1, "Power detected"); usbd_device_event_irq (udc_device, DEVICE_HUB_CONFIGURED, 0); /* assert reset */ writel (0, &tc_regs->PowerDetect); readl (&tc_regs->IntStatus); /* wbflush */ udelay (1); /* deassert reset (USB_RESET still disabled) */ writel (MST_EOPB_ENA | MST_TIMEOUT_ENA, &tc_regs->MstSetting); writel (PW_RESETB, &tc_regs->PowerDetect); writel (STDREQ_S_CONFIG | STDREQ_G_CONFIG | STDREQ_G_DESCRIPT, &tc_udcregs->StdReqMode); /* EP[2:1]:DMA access, EP[3]:CPU access (single) */ bcs = single = 0; for (i = 1; i < 4; i++) { single |= 0x11 << i; bcs |= ((i == 3 || nodma) ? 0x11 /*CPU*/ : 0x10 /*DMA*/) << i; } writel (single, &tc_udcregs->EPxSingle[0]); writel (bcs, &tc_udcregs->EPxBCS[0]); tc_setup_descram (); /* enable USB_RESET detection */ writel (0, &tc_udcregs->UsbReady); } else { /* power down */ dbg_udc (1, "Power down"); usbd_device_event_irq (udc_device, DEVICE_RESET, 0); usbd_device_event_irq (udc_device, DEVICE_POWER_INTERRUPTION, 0); usbd_device_event_irq (udc_device, DEVICE_HUB_RESET, 0); }}/** * int_hndlr - interrupt handler * */static voidtc_int_hndlr (int irq, void *dev_id, struct pt_regs *regs){ int count, i; u32 stat, mask; udc_interrupts++; for (count = 0; count < 10; count++) { stat = readl (&tc_regs->IntStatus); mask = readl (&tc_regs->IntEnable); if ((stat & mask) == 0) break; dbg_udc (3, "stat %x mask %x", stat, mask); stat &= mask; if (stat & INT_ERR) { writel (~INT_ERR, &tc_regs->IntStatus); printk (KERN_ERR UDC_NAME ": ERR interrupt.\n"); continue; } if (stat & INT_SYSERROR) { writel (~INT_SYSERROR, &tc_regs->IntStatus); printk (KERN_ERR UDC_NAME ": SYSERROR interrupt.\n"); continue; } if (stat & INT_PWRDETECT) { writel (~INT_PWRDETECT, &tc_regs->IntStatus); if (!udc_device) continue; //udc_cable_event(); tc_power_detected (); continue; } if (stat & INT_USBRESET) { writel (~INT_USBRESET, &tc_regs->IntStatus); if (!udc_device) continue; /* USBRESET received */ usbd_device_event_irq (udc_device, DEVICE_RESET, 0); /* enable pull-up */ dbg_udc (1, "Enabling pullup"); writel (PW_RESETB | PW_PLLUPENB, &tc_regs->PowerDetect); continue; } if (stat & INT_SUSPEND) { writel (~INT_SUSPEND, &tc_regs->IntStatus); if (!udc_device) continue;#if 0 if (udc_device->device_state == STATE_UNKNOWN || udc_device->device_state == STATE_INIT || udc_device->device_state == STATE_ATTACHED) continue;#endif if (readl (&tc_udcregs->EPxStatus[0]) & EPxSTATUS_SUSPEND) { dbg_udc (1, "Suspend"); usbd_device_event (udc_device, DEVICE_BUS_INACTIVE, 0); } else { dbg_udc (1, "Resume"); usbd_device_event (udc_device, DEVICE_BUS_ACTIVITY, 0); } continue; } if (stat & INT_SETUP) { dbg_udc (1, "Setup"); writel (~INT_SETUP, &tc_regs->IntStatus); tc_ep0_setup (); continue; } if (stat & INT_ENDPOINT0) { writel (~INT_ENDPOINT0, &tc_regs->IntStatus); usbd_tx_complete_irq (ep_endpoints[0], 0); tc_in_ep0 (ep_endpoints[0]); // XXX how about control write? continue; } if (stat & INT_MSTWRTMOUT) { writel (~INT_MSTWRTMOUT, &tc_regs->IntStatus); tc_end_out (UDC_MSTWR_ENDPOINT, 1); continue; } if (stat & INT_MSTWREND) { writel (~INT_MSTWREND, &tc_regs->IntStatus); tc_end_out (UDC_MSTWR_ENDPOINT, 0); continue; } if (stat & INT_MSTWRSET) { writel (~INT_MSTWRSET, &tc_regs->IntStatus); /* start master write */ tc_start_out (UDC_MSTWR_ENDPOINT); continue; } if (stat & INT_MSTRDEND) { writel (~INT_MSTRDEND, &tc_regs->IntStatus); tc_end_in (UDC_MSTRD_ENDPOINT); continue; } for (i = 1; i < 4; i++) { if (stat & INT_EPxDATASET (i)) { writel (~INT_EPxDATASET (i), &tc_regs->IntStatus); if (!ep_endpoints[i]) continue; if (ep_endpoints[i]->endpoint_address & USB_DIR_IN) { tc_start_in (i); } else { tc_start_out (i); } } } }}/* *********************************************************************** */static int __devinitudc_probe (struct pci_dev *pdev, const struct pci_device_id *ent){ void *mmio; if (udc_pci_dev) { /* multiple instance is not supported */ return -ENODEV; } /* make sure PCI base addr 0 is MMIO */ if (!(pci_resource_flags (pdev, 0) & IORESOURCE_MEM)) { printk (KERN_ERR UDC_NAME ": region #0 not an MMIO resource, aborting\n"); return -ENODEV; } if (request_irq (pdev->irq, &tc_int_hndlr, SA_SHIRQ | SA_SAMPLE_RANDOM, UDC_NAME, pdev)) { printk (KERN_ERR UDC_NAME " could not request irq %d\n", pdev->irq); return -EBUSY; } if (pci_request_regions (pdev, UDC_NAME)) { printk (KERN_ERR UDC_NAME " could not request regions\n"); free_irq (pdev->irq, pdev); return -EBUSY; } pci_set_master (pdev); mmio = ioremap (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0)); if (mmio == NULL) { printk (KERN_ERR UDC_NAME " could not remap 0x%08lx(0x%lx)\n", pci_resource_start (pdev, 0), pci_resource_len (pdev, 0)); free_irq (pdev->irq, pdev); pci_release_regions (pdev); return -EBUSY; } tc_regs = mmio; tc_udcregs = (struct tc_udc_udcregs *) (mmio + 0x200); tc_ramregs = (struct tc_udc_ramregs *) (mmio + 0x800); printk (KERN_DEBUG UDC_NAME " found at %p irq %d (%s)\n", mmio, pdev->irq, nodma ? "PIO" : "DMA"); udc_pci_dev = pdev; return 0;}static void __devexitudc_remove (struct pci_dev *pdev){ if (tc_regs) iounmap (tc_regs); pci_release_regions (pdev); free_irq (pdev->irq, pdev); tc_regs = NULL; tc_udcregs = NULL; tc_ramregs = NULL; udc_pci_dev = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -