📄 superh_udc.c
字号:
ctrl_inb(USBEPSZ0O), ctrl_inb(USBEPSZ1), ctrl_inb(USBDASTS), ctrl_inb(USBDMA)); size -= t; next += t; t = snprintf(next, size, "epstl %02X, xvercr %02X\n", ctrl_inb(USBEPSTL), ctrl_inb(USBXVERCR)); size -= t; next += t; if (!is_usb_connected || !dev->driver) goto done; t = snprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu; irq0s %lu; irq1s %lu\n\n", dev->stats.write.bytes, dev->stats.write.ops, dev->stats.read.bytes, dev->stats.read.ops, dev->stats.irq0s, dev->stats.irq1s); size -= t; next += t; /* dump endpoint queues */ for (i = 0; i < 4; i++) { struct superh_ep *ep = &dev->ep [i]; struct superh_request *req; int t; if (i != 0) { const struct usb_endpoint_descriptor *d; d = ep->desc; if (!d) continue; t = snprintf(next, size, "%s max %d %s\n", ep->ep.name, le16_to_cpu (d->wMaxPacketSize), (ep->dma >= 0) ? "dma" : "pio"); } else /* ep0 should only have one transfer queued */ t = snprintf(next, size, "ep0 max 8 pio\n"); 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) {#ifdef USE_DMA if (ep->dma >= 0 && req->queue.prev == &ep->queue) t = snprintf(next, size, "\treq %p len %d/%d " "buf %p (dma%d dcmd %08x)\n", &req->req, req->req.actual, req->req.length, req->req.buf, ep->dma, DCMD(ep->dma) // low 13 bits == bytes-to-go ); else#endif 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; } }done: local_irq_restore(flags); return count - size;}#endif /* UDC_PROC_FILE *//*-------------------------------------------------------------------------*//* * udc_disable - disable USB device controller */static void udc_disable(struct superh_udc *dev){ /* block all irqs */ ctrl_outb( 0, USBIER0); ctrl_outb( 0, USBIER1); /* Disable the USB module */ or_b(0x80, STBCR3); /* Disable the USB clock */ ctrl_outw(0xA500, UCLKCR); ep0_idle (dev); dev->gadget.speed = USB_SPEED_UNKNOWN;}/* * udc_reinit - initialize software state */static void udc_reinit(struct superh_udc *dev){ u32 i; /* device/ep0 records init */ INIT_LIST_HEAD (&dev->gadget.ep_list); dev->gadget.ep0 = &dev->ep[0].ep; INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); dev->ep0state = EP0_IDLE; /* basic endpoint records init */ for (i = 0; i < 4; i++) { struct superh_ep *ep = &dev->ep[i]; ep->ep.name = ep_name[i]; ep->ep.ops = &superh_ep_ops; if (i != 0) list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); ep->dev = dev; ep->desc = 0; ep->stopped = 0; ep->halted = 0; ep->dma = -1; INIT_LIST_HEAD (&ep->queue); /* address may need USB_DIR_IN, attributes likely wrong */ ep->bEndpointAddress = i; ep->bmAttributes = USB_ENDPOINT_XFER_BULK; } /* TODO at least from here on, static initialization * would work just as well and would need less code space */ /* ep0 == control */ dev->ep[ 0].ep.maxpacket = EP0_FIFO_SIZE; dev->ep[ 0].data_present_mask = EP0i_DE; dev->ep[ 0].stall_mask = EP0_STL; dev->ep[ 0].interrupt_mask = EP0o_TS | EP0i_TR | EP0i_TS; dev->ep[ 0].interrupt_reg = USBIER0; dev->ep[ 0].clear_mask = EP0i_CLEAR | EP0o_CLEAR; dev->ep[ 0].fifo_reg = 0; dev->ep[ 0].packet_enable_mask = 0; dev->ep[ 1].ep.maxpacket = BULK_FIFO_SIZE; dev->ep[ 1].bEndpointAddress |= USB_DIR_OUT; dev->ep[ 1].data_present_mask = 0x00; dev->ep[ 1].stall_mask = EP1_STL; dev->ep[ 1].interrupt_mask = EP1_FULL; dev->ep[ 1].interrupt_reg = USBIER0; dev->ep[ 1].clear_mask = EP1_CLEAR; dev->ep[ 1].fifo_reg = 0; dev->ep[ 1].packet_enable_mask = 0; dev->ep[ 2].ep.maxpacket = BULK_FIFO_SIZE; dev->ep[ 2].bEndpointAddress |= USB_DIR_IN; dev->ep[ 2].data_present_mask = EP2_DE; dev->ep[ 2].stall_mask = EP2_STL; dev->ep[ 2].interrupt_mask = EP2_TR | EP2_EMPTY; dev->ep[ 2].interrupt_reg = USBIER0; dev->ep[ 2].clear_mask = EP2_CLEAR; dev->ep[ 2].fifo_reg = USBEPDR2; dev->ep[ 2].packet_enable_mask = EP2_PKTE; dev->ep[ 3].ep.maxpacket = INT_FIFO_SIZE; dev->ep[ 3].bEndpointAddress |= USB_DIR_IN; dev->ep[ 3].data_present_mask = EP3_DE; dev->ep[ 3].stall_mask = EP3_STL; dev->ep[ 3].interrupt_mask = EP3_TR | EP3_TS; dev->ep[ 3].interrupt_reg = USBIER1; dev->ep[ 3].clear_mask = EP3_CLEAR; dev->ep[ 3].fifo_reg = USBEPDR3; dev->ep[ 3].packet_enable_mask = EP3_PKTE;}/* until it's enabled, this UDC should be completely invisible * to any USB host. */static void udc_enable (struct superh_udc *dev){#if defined(CONFIG_CPU_SUBTYPE_SH7727) // Reset and then Select Function USB1_pwr_en out (USB) c.f. Section 26, Table 26.1 PTE2 and_w(PN_PB2_MSK, PECR); or_w(PN_PB2_OF, PECR); // Reset and then Select Function UCLK c.f. Section 26, Table 26.1, PTD6 and_w(PN_PB6_MSK, PDCR); or_w(PN_PB6_OF, PDCR); // Stop USB module prior to setting clocks c.f. Section 9.2.3 and_b(~MSTP14, STBCR3); or_b(MSTP14, STBCR3); // Select external clock, 1/1 divisor c.f. Section 11.3.1 or_b(USBDIV_11|USBCKS_EC, EXCPGCR); // Start USB c.f. Section 9.2.3 and_b(~MSTP14, STBCR3); // Disable pullup c.f. Section 23.5.19 or_b(PULLUP_E, USBDMA); //and_b(~PULLUP_E, USBDMA); // Set port 1 to function, disabled c.f. Section 22.2.1 or_w(USB_TRANS_TRAN | USB_SEL_FUNC, EXPFC); // Enable pullup c.f. Section 23.5.19a and_b(~PULLUP_E, USBDMA); //or_b(PULLUP_E, USBDMA);#elif defined(CONFIG_CPU_SUBTYPE_SH7705) /* Disable the USB module */ or_b(0x80, STBCR3); /* Set the clock to external & enable */ ctrl_outw(0xA5E0, UCLKCR); /* Enable the USB module */ and_b(0x7f, STBCR3); /* Enable USB pins. */ ctrl_outw(0x01FD, PMCR); /* VBUS */ or_b(PULLUP_E, PMDR);#endif dev->gadget.speed = USB_SPEED_UNKNOWN; dev->stats.irqs = 0; dev->stats.irq0s = 0; dev->stats.irq1s = 0; // reset fifo's and stall's or_b( EP3_CLEAR | EP1_CLEAR | EP2_CLEAR | EP0o_CLEAR | EP0i_CLEAR, USBFCLR); or_b(0, USBEPSTL); /* Setup interrupt priority by using the interrupt select registers */ ctrl_outb(F0_LOW, USBISR0); ctrl_outb(F1_LOW, USBISR1); /* Enable some interrupts */ or_b( BRST | SETUP_TS | EP0o_TS | EP0i_TR | EP0i_TS, USBIER0); or_b( VBUSF, USBIER1);}/* 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 superh_udc *dev = the_controller; int retval; if (!driver /*|| driver->speed != USB_SPEED_FULL || !driver->bind || !driver->unbind || !driver->disconnect || !driver->setup*/) return -EINVAL; if (!dev) return -ENODEV; if (dev->driver) return -EBUSY; /* first hook up the driver ... */ dev->driver = driver; retval = driver->bind(&dev->gadget); if (retval) { DMSG("bind to driver %s --> error %d\n", driver->driver.name, retval); dev->driver = 0; return retval; } /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. * NOTE: this shouldn't power up until later. */ udc_enable(dev); DMSG("registered gadget driver '%s'\n", driver->driver.name); dump_state(dev); return 0;}EXPORT_SYMBOL(usb_gadget_register_driver);static voidstop_activity(struct superh_udc *dev, struct usb_gadget_driver *driver){ int i; /* don't disconnect drivers more than once */ if (dev->gadget.speed == USB_SPEED_UNKNOWN) driver = 0; dev->gadget.speed = USB_SPEED_UNKNOWN; /* prevent new request submissions, kill any outstanding requests */ for (i = 0; i < 4; i++) { struct superh_ep *ep = &dev->ep[i]; ep->stopped = 1; nuke(ep, -ESHUTDOWN); } del_timer_sync(&dev->timer); /* report disconnect; the driver is already quiesced */ if (driver) driver->disconnect(&dev->gadget); /* re-init driver-visible data structures */ udc_reinit(dev);}int usb_gadget_unregister_driver(struct usb_gadget_driver *driver){ struct superh_udc *dev = the_controller; if (!dev) return -ENODEV; if (!driver || driver != dev->driver) return -EINVAL; local_irq_disable(); udc_disable(dev); stop_activity(dev, driver); driver->unbind(&dev->gadget); dev->driver = 0; local_irq_enable(); DMSG("unregistered gadget driver '%s'\n", driver->driver.name); dump_state(dev); return 0;}EXPORT_SYMBOL(usb_gadget_unregister_driver);/*-------------------------------------------------------------------------*/#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,40)MODULE_DESCRIPTION(driver_desc);#endifMODULE_AUTHOR("Julian Back");MODULE_LICENSE("GPL");/* * cleanup - free resources allocated during init */static void /*__exit and */ __init cleanup(void){ struct superh_udc *dev = the_controller; if (!dev) return; udc_disable(dev);#ifdef UDC_PROC_FILE remove_proc_entry(proc_node_name, NULL);#endif usb_gadget_unregister_driver(dev->driver); if (dev->got_irq0) { free_irq(USBF0_IRQ, dev); dev->got_irq0 = 0; } if (dev->got_irq1) { free_irq(USBF1_IRQ, dev); dev->got_irq1 = 0; } the_controller = 0;}module_exit (cleanup);/* * init - allocate resources */static int __init init(void){ static struct superh_udc memory; struct superh_udc *dev; int retval; printk(KERN_DEBUG "%s: version %s\n", driver_name, DRIVER_VERSION); /* initialize data */ dev = &memory; memset(dev, 0, sizeof *dev); dev->gadget.ops = &superh_udc_ops; dev->gadget.name = driver_name; dev->gadget.dev.bus_id = "udc"; dev->gadget.speed = USB_SPEED_UNKNOWN; dev->vbusmn = 0; atomic_set(&dev->in_interrupt, 0); the_controller = dev; udc_disable(dev); udc_reinit(dev); /* irq setup after old hardware state is cleaned up */ retval = request_irq(USBF0_IRQ, superh_udc_irq_f0, 0/*SA_INTERRUPT | SA_SAMPLE_RANDOM*/, driver_name, dev); if (retval != 0) { printk(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, USBF0_IRQ, retval); goto failed; } dev->got_irq0 = 1; retval = request_irq(USBF1_IRQ, superh_udc_irq_f1, 0/*SA_INTERRUPT | SA_SAMPLE_RANDOM*/, driver_name, dev); if (retval != 0) { printk(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, USBF1_IRQ, retval); goto failed; } dev->got_irq1 = 1; printk(KERN_INFO "%s, IRQs %d %d\n", driver_desc, USBF0_IRQ, USBF1_IRQ); dump_state(dev); dev->setup_countdown = DEFAULT_SETUP_COUNT;#ifdef UDC_PROC_FILE create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);#endif return 0;failed: cleanup(); return retval;}module_init (init);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -