📄 net2280.c
字号:
t = snprintf (next, size, "%s version " DRIVER_VERSION ", chiprev %04x, dma %s\n\n" "devinit %03x fifoctl %08x gadget '%s'\n" "pci irqenb0 %02x irqenb1 %08x " "irqstat0 %04x irqstat1 %08x\n", driver_name, dev->chiprev, use_dma ? (use_dma_chaining ? "chaining" : "enabled") : "disabled", readl (&dev->regs->devinit), readl (&dev->regs->fifoctl), s, readl (&dev->regs->pciirqenb0), readl (&dev->regs->pciirqenb1), readl (&dev->regs->irqstat0), readl (&dev->regs->irqstat1)); size -= t; next += t; /* USB Control Registers */ t1 = readl (&dev->usb->usbctl); t2 = readl (&dev->usb->usbstat); if (t1 & (1 << VBUS_PIN)) { if (t2 & (1 << HIGH_SPEED)) s = "high speed"; else if (dev->gadget.speed == USB_SPEED_UNKNOWN) s = "powered"; else s = "full speed"; /* full speed bit (6) not working?? */ } else s = "not attached"; t = snprintf (next, size, "stdrsp %08x usbctl %08x usbstat %08x " "addr 0x%02x (%s)\n", readl (&dev->usb->stdrsp), t1, t2, readl (&dev->usb->ouraddr), s); size -= t; next += t; /* PCI Master Control Registers */ /* DMA Control Registers */ /* Configurable EP Control Registers */ for (i = 0; i < 7; i++) { struct net2280_ep *ep; ep = &dev->ep [i]; if (i && !ep->desc) continue; t1 = readl (&ep->regs->ep_cfg); t2 = readl (&ep->regs->ep_rsp) & 0xff; t = snprintf (next, size, "\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s" "irqenb %02x\n", ep->ep.name, t1, t2, (t2 & (1 << CLEAR_NAK_OUT_PACKETS)) ? "NAK " : "", (t2 & (1 << CLEAR_EP_HIDE_STATUS_PHASE)) ? "hide " : "", (t2 & (1 << CLEAR_EP_FORCE_CRC_ERROR)) ? "CRC " : "", (t2 & (1 << CLEAR_INTERRUPT_MODE)) ? "interrupt " : "", (t2 & (1<<CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)) ? "status " : "", (t2 & (1 << CLEAR_NAK_OUT_PACKETS_MODE)) ? "NAKmode " : "", (t2 & (1 << CLEAR_ENDPOINT_TOGGLE)) ? "DATA1 " : "DATA0 ", (t2 & (1 << CLEAR_ENDPOINT_HALT)) ? "HALT " : "", readl (&ep->regs->ep_irqenb)); size -= t; next += t; t = snprintf (next, size, "\tstat %08x avail %04x " "(ep%d%s-%s)%s\n", readl (&ep->regs->ep_stat), readl (&ep->regs->ep_avail), t1 & 0x0f, DIR_STRING (t1), type_string (t1 >> 8), ep->stopped ? "*" : ""); size -= t; next += t; if (!ep->dma) continue; t = snprintf (next, size, " dma\tctl %08x stat %08x count %08x\n" "\taddr %08x desc %08x\n", readl (&ep->dma->dmactl), readl (&ep->dma->dmastat), readl (&ep->dma->dmacount), readl (&ep->dma->dmaaddr), readl (&ep->dma->dmadesc)); size -= t; next += t; } /* Indexed Registers */ // none yet /* Statistics */ t = snprintf (next, size, "\nirqs: "); size -= t; next += t; for (i = 0; i < 7; i++) { struct net2280_ep *ep; ep = &dev->ep [i]; if (i && !ep->irqs) continue; t = snprintf (next, size, " %s/%lu", ep->ep.name, ep->irqs); size -= t; next += t; } t = snprintf (next, size, "\n"); size -= t; next += t; spin_unlock_irqrestore (&dev->lock, flags); return PAGE_SIZE - size;}static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);static ssize_tshow_queues (struct device *_dev, char *buf){ struct net2280 *dev; char *next; unsigned size; unsigned long flags; int i; dev = dev_get_drvdata (_dev); next = buf; size = PAGE_SIZE; spin_lock_irqsave (&dev->lock, flags); for (i = 0; i < 7; i++) { struct net2280_ep *ep = &dev->ep [i]; struct net2280_request *req; int t; if (i != 0) { const struct usb_endpoint_descriptor *d; d = ep->desc; if (!d) continue; t = d->bEndpointAddress; t = snprintf (next, size, "\n%s (ep%d%s-%s) max %04x %s fifo %d\n", ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK, (t & USB_DIR_IN) ? "in" : "out", ({ char *val; switch (d->bmAttributes & 0x03) { case USB_ENDPOINT_XFER_BULK: val = "bulk"; break; case USB_ENDPOINT_XFER_INT: val = "intr"; break; default: val = "iso"; break; }; val; }), le16_to_cpu (d->wMaxPacketSize) & 0x1fff, ep->dma ? "dma" : "pio", ep->fifo_size ); } else /* ep0 should only have one transfer queued */ t = snprintf (next, size, "ep0 max 64 pio %s\n", ep->is_in ? "in" : "out"); if (t <= 0 || t > size) goto done; size -= t; next += t; if (list_empty (&ep->queue)) { t = snprintf (next, size, "\t(nothing queued)\n"); if (t <= 0 || t > size) goto done; size -= t; next += t; continue; } list_for_each_entry (req, &ep->queue, queue) { if (ep->dma && req->td_dma == readl (&ep->dma->dmadesc)) t = snprintf (next, size, "\treq %p len %d/%d " "buf %p (dmacount %08x)\n", &req->req, req->req.actual, req->req.length, req->req.buf, readl (&ep->dma->dmacount)); else t = snprintf (next, size, "\treq %p len %d/%d buf %p\n", &req->req, req->req.actual, req->req.length, req->req.buf); if (t <= 0 || t > size) goto done; size -= t; next += t; if (ep->dma) { struct net2280_dma *td; td = req->td; t = snprintf (next, size, "\t td %08x " " count %08x buf %08x desc %08x\n", req->td_dma, td->dmacount, td->dmaaddr, td->dmadesc); if (t <= 0 || t > size) goto done; size -= t; next += t; } } }done: spin_unlock_irqrestore (&dev->lock, flags); return PAGE_SIZE - size;}static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL);#else#define device_create_file(a,b) do {} while (0)#define device_remove_file device_create_file#endif/*-------------------------------------------------------------------------*//* another driver-specific mode might be a request type doing dma * to/from another device fifo instead of to/from memory. */static void set_fifo_mode (struct net2280 *dev, int mode){ /* keeping high bits preserves BAR2 */ writel ((0xffff << PCI_BASE2_RANGE) | mode, &dev->regs->fifoctl); /* always ep-{a,b,e,f} ... maybe not ep-c or ep-d */ INIT_LIST_HEAD (&dev->gadget.ep_list); list_add_tail (&dev->ep [1].ep.ep_list, &dev->gadget.ep_list); list_add_tail (&dev->ep [2].ep.ep_list, &dev->gadget.ep_list); switch (mode) { case 0: list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list); list_add_tail (&dev->ep [4].ep.ep_list, &dev->gadget.ep_list); dev->ep [1].fifo_size = dev->ep [2].fifo_size = 1024; break; case 1: dev->ep [1].fifo_size = dev->ep [2].fifo_size = 2048; break; case 2: list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list); dev->ep [1].fifo_size = 2048; dev->ep [2].fifo_size = 1024; break; } /* fifo sizes for ep0, ep-c, ep-d, ep-e, and ep-f never change */ list_add_tail (&dev->ep [5].ep.ep_list, &dev->gadget.ep_list); list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);}/** * net2280_set_fifo_mode - change allocation of fifo buffers * @gadget: access to the net2280 device that will be updated * @mode: 0 for default, four 1kB buffers (ep-a through ep-d); * 1 for two 2kB buffers (ep-a and ep-b only); * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c). * * returns zero on success, else negative errno. when this succeeds, * the contents of gadget->ep_list may have changed. * * you may only call this function when endpoints a-d are all disabled. * use it whenever extra hardware buffering can help performance, such * as before enabling "high bandwidth" interrupt endpoints that use * maxpacket bigger than 512 (when double buffering would otherwise * be unavailable). */int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode){ int i; struct net2280 *dev; int status = 0; unsigned long flags; if (!gadget) return -ENODEV; dev = container_of (gadget, struct net2280, gadget); spin_lock_irqsave (&dev->lock, flags); for (i = 1; i <= 4; i++) if (dev->ep [i].desc) { status = -EINVAL; break; } if (mode < 0 || mode > 2) status = -EINVAL; if (status == 0) set_fifo_mode (dev, mode); spin_unlock_irqrestore (&dev->lock, flags); if (status == 0) { if (mode == 1) DEBUG (dev, "fifo: ep-a 2K, ep-b 2K\n"); else if (mode == 2) DEBUG (dev, "fifo: ep-a 2K, ep-b 1K, ep-c 1K\n"); /* else all are 1K */ } return status;}EXPORT_SYMBOL (net2280_set_fifo_mode);/*-------------------------------------------------------------------------*//* keeping it simple: * - one bus driver, initted first; * - one function driver, initted second * * most of the work to support multiple net2280 controllers would * be to associate this gadget driver (yes?) with all of them, or * perhaps to bind specific drivers to specific devices. */static struct net2280 *the_controller;static void usb_reset (struct net2280 *dev){ u32 tmp; /* force immediate bus disconnect, and synch through pci */ writel (0, &dev->usb->usbctl); dev->gadget.speed = USB_SPEED_UNKNOWN; (void) readl (&dev->usb->usbctl); net2280_led_init (dev); /* disable automatic responses, and irqs */ writel (0, &dev->usb->stdrsp); writel (0, &dev->regs->pciirqenb0); writel (0, &dev->regs->pciirqenb1); /* clear old dma and irq state */ for (tmp = 0; tmp < 4; tmp++) { struct net2280_ep *ep = &dev->ep [tmp + 1]; if (ep->dma) abort_dma (ep); } writel (~0, &dev->regs->irqstat0), writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1), /* reset, and enable pci */ tmp = readl (&dev->regs->devinit) | (1 << PCI_ENABLE) | (1 << FIFO_SOFT_RESET) | (1 << USB_SOFT_RESET) | (1 << M8051_RESET); writel (tmp, &dev->regs->devinit); /* standard fifo and endpoint allocations */ set_fifo_mode (dev, (fifo_mode <= 2) ? fifo_mode : 0);}static void usb_reinit (struct net2280 *dev){ u32 tmp; int init_dma; /* use_dma changes are ignored till next device re-init */ init_dma = use_dma; /* basic endpoint init */ for (tmp = 0; tmp < 7; tmp++) { struct net2280_ep *ep = &dev->ep [tmp]; ep->ep.name = ep_name [tmp]; ep->dev = dev; ep->num = tmp; if (tmp > 0 && tmp <= 4) { ep->fifo_size = 1024; if (init_dma) ep->dma = &dev->dma [tmp - 1]; } else ep->fifo_size = 64; ep->regs = &dev->epregs [tmp]; ep_reset (dev->regs, ep); } dev->ep [0].ep.maxpacket = 64; dev->ep [5].ep.maxpacket = 64; dev->ep [6].ep.maxpacket = 64; dev->gadget.ep0 = &dev->ep [0].ep; dev->ep [0].stopped = 0; INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); /* we want to prevent lowlevel/insecure access from the USB host, * but erratum 0119 means this enable bit is ignored */ for (tmp = 0; tmp < 5; tmp++) writel (EP_DONTUSE, &dev->dep [tmp].dep_cfg);}static void ep0_start (struct net2280 *dev){ writel ( (1 << CLEAR_EP_HIDE_STATUS_PHASE) | (1 << CLEAR_NAK_OUT_PACKETS) | (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) , &dev->epregs [0].ep_rsp); /* * hardware optionally handles a bunch of standard requests * that the API hides from drivers anyway. have it do so. * endpoint status/features are handled in software, to * help pass tests for some dubious behavior. */ writel ( (1 << SET_TEST_MODE) | (1 << SET_ADDRESS) | (1 << DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP) | (1 << GET_DEVICE_STATUS) | (1 << GET_INTERFACE_STATUS) , &dev->usb->stdrsp); writel ( (1 << USB_ROOT_PORT_WAKEUP_ENABLE) | (1 << SELF_POWERED_USB_DEVICE) | (1 << REMOTE_WAKEUP_SUPPORT) | (1 << USB_DETECT_ENABLE) | (1 << SELF_POWERED_STATUS) , &dev->usb->usbctl); /* enable irqs so we can see ep0 and general operation */ writel ( (1 << SETUP_PACKET_INTERRUPT_ENABLE) | (1 << ENDPOINT_0_INTERRUPT_ENABLE) , &dev->regs->pciirqenb0); writel ( (1 << PCI_INTERRUPT_ENABLE) | (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE) | (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE) | (1 << PCI_RETRY_ABORT_INTERRUPT_ENABLE) | (1 << VBUS_INTERRUPT_ENABLE) | (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) , &dev->regs->pciirqenb1); /* don't leave any writes posted */ (void) readl (&dev->usb->usbctl);}/* when a driver is successfully registered, it will receive * control requests including set_configuration(), which enables * non-control requests. then usb traffic follows until a * disconnect is reported. then a host may connect again, or * the driver might get unbound. */int usb_gadget_register_driver (struct usb_gadget_driver *driver){ struct net2280 *dev = the_controller; int retval; unsigned i; /* insist on high speed support from the driver, since * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE) * "must not be used in normal operation" */ if (!driver || driver->speed != USB_SPEED_HIGH || !driver->bind || !driver->unbind || !driver->setup) return -EINVAL; if (!dev) return -ENODEV; if (dev->driver) return -EBUSY; for (i = 0; i < 7; i++) dev->ep [i].irqs = 0; /* hook up the driver ... */ dev->driver = driver;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -