From 76f4af8efc72b6091d230cbe718cedca06d2d79e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 5 Apr 2005 11:56:54 -0400 Subject: [PATCH] USB: g_file_storage: Consolidate min()s This patch simplifies the g_file_storage driver by consolidating a bunch of min() calculations at a single spot. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index a9be85103d23..507a24924177 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1312,7 +1312,7 @@ static int class_setup_req(struct fsg_dev *fsg, } VDBG(fsg, "get max LUN\n"); *(u8 *) req->buf = fsg->nluns - 1; - value = min(w_length, (u16) 1); + value = 1; break; } } @@ -1360,7 +1360,6 @@ static int standard_setup_req(struct fsg_dev *fsg, int value = -EOPNOTSUPP; u16 w_index = ctrl->wIndex; u16 w_value = ctrl->wValue; - u16 w_length = ctrl->wLength; /* Usually this just stores reply data in the pre-allocated ep0 buffer, * but config change events will also reconfigure hardware. */ @@ -1374,7 +1373,7 @@ static int standard_setup_req(struct fsg_dev *fsg, case USB_DT_DEVICE: VDBG(fsg, "get device descriptor\n"); - value = min(w_length, (u16) sizeof device_desc); + value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -1382,7 +1381,7 @@ static int standard_setup_req(struct fsg_dev *fsg, VDBG(fsg, "get device qualifier\n"); if (!fsg->gadget->is_dualspeed) break; - value = min(w_length, (u16) sizeof dev_qualifier); + value = sizeof dev_qualifier; memcpy(req->buf, &dev_qualifier, value); break; @@ -1401,8 +1400,6 @@ static int standard_setup_req(struct fsg_dev *fsg, req->buf, w_value >> 8, w_value & 0xff); - if (value >= 0) - value = min(w_length, (u16) value); break; case USB_DT_STRING: @@ -1411,8 +1408,6 @@ static int standard_setup_req(struct fsg_dev *fsg, /* wIndex == language code */ value = usb_gadget_get_string(&stringtab, w_value & 0xff, req->buf); - if (value >= 0) - value = min(w_length, (u16) value); break; } break; @@ -1438,7 +1433,7 @@ static int standard_setup_req(struct fsg_dev *fsg, break; VDBG(fsg, "get configuration\n"); *(u8 *) req->buf = fsg->config; - value = min(w_length, (u16) 1); + value = 1; break; case USB_REQ_SET_INTERFACE: @@ -1466,14 +1461,14 @@ static int standard_setup_req(struct fsg_dev *fsg, } VDBG(fsg, "get interface\n"); *(u8 *) req->buf = 0; - value = min(w_length, (u16) 1); + value = 1; break; default: VDBG(fsg, "unknown control req %02x.%02x v%04x i%04x l%u\n", ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); + w_value, w_index, ctrl->wLength); } return value; @@ -1485,6 +1480,7 @@ static int fsg_setup(struct usb_gadget *gadget, { struct fsg_dev *fsg = get_gadget_data(gadget); int rc; + int w_length = ctrl->wLength; ++fsg->ep0_req_tag; // Record arrival of a new request fsg->ep0req->context = NULL; @@ -1498,8 +1494,9 @@ static int fsg_setup(struct usb_gadget *gadget, /* Respond with data/status or defer until later? */ if (rc >= 0 && rc != DELAYED_STATUS) { + rc = min(rc, w_length); fsg->ep0req->length = rc; - fsg->ep0req->zero = (rc < ctrl->wLength && + fsg->ep0req->zero = (rc < w_length && (rc % gadget->ep0->maxpacket) == 0); fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); -- cgit v1.2.3 From d794ac7ae3613c2abfb678617ac7d74c8ff0099c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 18 Apr 2005 12:43:25 -0400 Subject: [PATCH] USB: g_file_storage: export "stall" parameter This patch changes the g_file_storage driver to make the "stall" module parameter generally available; currently it is available only if the testing version of the module has been configured. It also fixes a typo in a comment -- thanks, Pat! Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 507a24924177..f5ce45c4b2a3 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -81,6 +81,10 @@ * removable Default false, boolean for removable media * luns=N Default N = number of filenames, number of * LUNs to support + * stall Default determined according to the type of + * USB device controller (usually true), + * boolean to permit the driver to halt + * bulk endpoints * transport=XXX Default BBB, transport name (CB, CBI, or BBB) * protocol=YYY Default SCSI, protocol name (RBC, 8020 or * ATAPI, QIC, UFI, 8070, or SCSI; @@ -91,14 +95,10 @@ * buflen=N Default N=16384, buffer size used (will be * rounded down to a multiple of * PAGE_CACHE_SIZE) - * stall Default determined according to the type of - * USB device controller (usually true), - * boolean to permit the driver to halt - * bulk endpoints * * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", - * "removable", and "luns" options are available; default values are used - * for everything else. + * "removable", "luns", and "stall" options are available; default values + * are used for everything else. * * The pathnames of the backing files and the ro settings are available in * the attribute files "file" and "ro" in the lun subdirectory of the @@ -342,14 +342,15 @@ static struct { int num_ros; unsigned int nluns; + int removable; + int can_stall; + char *transport_parm; char *protocol_parm; - int removable; unsigned short vendor; unsigned short product; unsigned short release; unsigned int buflen; - int can_stall; int transport_type; char *transport_name; @@ -360,11 +361,11 @@ static struct { .transport_parm = "BBB", .protocol_parm = "SCSI", .removable = 0, + .can_stall = 1, .vendor = DRIVER_VENDOR_ID, .product = DRIVER_PRODUCT_ID, .release = 0xffff, // Use controller chip type .buflen = 16384, - .can_stall = 1, }; @@ -380,6 +381,9 @@ MODULE_PARM_DESC(luns, "number of LUNs"); module_param_named(removable, mod_data.removable, bool, S_IRUGO); MODULE_PARM_DESC(removable, "true to simulate removable media"); +module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); +MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); + /* In the non-TEST version, only the module parameters listed above * are available. */ @@ -404,9 +408,6 @@ MODULE_PARM_DESC(release, "USB release number"); module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); MODULE_PARM_DESC(buflen, "I/O buffer size"); -module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); -MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); - #endif /* CONFIG_USB_FILE_STORAGE_TEST */ @@ -2657,7 +2658,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, } } - /* Check that the LUN values are oonsistent */ + /* Check that the LUN values are consistent */ if (transport_is_bbb()) { if (fsg->lun != lun) DBG(fsg, "using LUN %d from CBW, " -- cgit v1.2.3 From 313980c92724cf42877a7bdafdef439ee9d68ccb Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 11 Apr 2005 15:38:25 -0700 Subject: [PATCH] USB: omap_udc updates (mostly cleanups) Various USB patches, mostly for portability: - Fifo mode 1 didn't work previously (oopsed), so now it's fixed and (why not) defines even more endpoints for composite devices. - OMAP 1710 doesn't have an internal transceiver. - Small PM update: if the USB link is suspended, don't disconnect on entry to deep sleep. - Be more correct about handling zero length control reads. OMAP seems to mis-handle that protocol peculiarity though; best avoided. - Platform device resources (for UDC and OTG controllers) now use physical addresses, so /proc/iomem is more consistent. - Minor cleanups, notably (by volume) for "sparse" NULL warnings. Signed-off-by: David Brownell --- arch/arm/mach-omap/usb.c | 8 +-- drivers/usb/gadget/omap_udc.c | 150 ++++++++++++++++++++++++++---------------- 2 files changed, 97 insertions(+), 61 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/arch/arm/mach-omap/usb.c b/arch/arm/mach-omap/usb.c index 6e805d451d0e..7f37857b1a28 100644 --- a/arch/arm/mach-omap/usb.c +++ b/arch/arm/mach-omap/usb.c @@ -288,8 +288,8 @@ static void usb_release(struct device *dev) static struct resource udc_resources[] = { /* order is significant! */ { /* registers */ - .start = IO_ADDRESS(UDC_BASE), - .end = IO_ADDRESS(UDC_BASE + 0xff), + .start = UDC_BASE, + .end = UDC_BASE + 0xff, .flags = IORESOURCE_MEM, }, { /* general IRQ */ .start = IH2_BASE + 20, @@ -355,8 +355,8 @@ static struct platform_device ohci_device = { static struct resource otg_resources[] = { /* order is significant! */ { - .start = IO_ADDRESS(OTG_BASE), - .end = IO_ADDRESS(OTG_BASE + 0xff), + .start = OTG_BASE, + .end = OTG_BASE + 0xff, .flags = IORESOURCE_MEM, }, { .start = IH2_BASE + 8, diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 98cbcbc16cc1..4ec91a68f96c 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -52,7 +52,6 @@ #include #include -#include #include #include "omap_udc.h" @@ -253,7 +252,7 @@ static int omap_ep_disable(struct usb_ep *_ep) } spin_lock_irqsave(&ep->udc->lock, flags); - ep->desc = 0; + ep->desc = NULL; nuke (ep, -ESHUTDOWN); ep->ep.maxpacket = ep->maxpacket; ep->has_dma = 0; @@ -388,8 +387,8 @@ done(struct omap_ep *ep, struct omap_req *req, int status) /*-------------------------------------------------------------------------*/ -#define FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL) -#define FIFO_UNWRITABLE (UDC_EP_HALTED | FIFO_FULL) +#define UDC_FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL) +#define UDC_FIFO_UNWRITABLE (UDC_EP_HALTED | UDC_FIFO_FULL) #define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY) #define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY) @@ -433,7 +432,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req) /* PIO-IN isn't double buffered except for iso */ ep_stat = UDC_STAT_FLG_REG; - if (ep_stat & FIFO_UNWRITABLE) + if (ep_stat & UDC_FIFO_UNWRITABLE) return 0; count = ep->ep.maxpacket; @@ -504,7 +503,7 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req) if (ep_stat & UDC_EP_HALTED) break; - if (ep_stat & FIFO_FULL) + if (ep_stat & UDC_FIFO_FULL) avail = ep->ep.maxpacket; else { avail = UDC_RXFSTAT_REG; @@ -856,7 +855,7 @@ static void dma_channel_release(struct omap_ep *ep) if (!list_empty(&ep->queue)) req = container_of(ep->queue.next, struct omap_req, queue); else - req = 0; + req = NULL; active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0; @@ -997,18 +996,19 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) UDC_IRQ_EN_REG = irq_en; } - /* STATUS is reverse direction */ - UDC_EP_NUM_REG = is_in - ? UDC_EP_SEL - : (UDC_EP_SEL|UDC_EP_DIR); + /* STATUS for zero length DATA stages is + * always an IN ... even for IN transfers, + * a wierd case which seem to stall OMAP. + */ + UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR); UDC_CTRL_REG = UDC_CLR_EP; UDC_CTRL_REG = UDC_SET_FIFO_EN; - UDC_EP_NUM_REG = udc->ep0_in ? 0 : UDC_EP_DIR; + UDC_EP_NUM_REG = UDC_EP_DIR; /* cleanup */ udc->ep0_pending = 0; done(ep, req, 0); - req = 0; + req = NULL; /* non-empty DATA stage */ } else if (is_in) { @@ -1029,7 +1029,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) (is_in ? next_in_dma : next_out_dma)(ep, req); else if (req) { if ((is_in ? write_fifo : read_fifo)(ep, req) == 1) - req = 0; + req = NULL; deselect_ep(); if (!is_in) { UDC_CTRL_REG = UDC_SET_FIFO_EN; @@ -1041,7 +1041,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) irq_wait: /* irq handler advances the queue */ - if (req != 0) + if (req != NULL) list_add_tail(&req->queue, &ep->queue); spin_unlock_irqrestore(&udc->lock, flags); @@ -1238,6 +1238,8 @@ static int can_pullup(struct omap_udc *udc) static void pullup_enable(struct omap_udc *udc) { + udc->gadget.dev.parent->power.power_state = PMSG_ON; + udc->gadget.dev.power.power_state = PMSG_ON; UDC_SYSCON1_REG |= UDC_PULLUP_EN; #ifndef CONFIG_USB_OTG if (!cpu_is_omap15xx()) @@ -1382,7 +1384,7 @@ static void update_otg(struct omap_udc *udc) static void ep0_irq(struct omap_udc *udc, u16 irq_src) { struct omap_ep *ep0 = &udc->ep[0]; - struct omap_req *req = 0; + struct omap_req *req = NULL; ep0->irqs++; @@ -1438,7 +1440,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) if (req) done(ep0, req, 0); } - req = 0; + req = NULL; } else if (stat & UDC_STALL) { UDC_CTRL_REG = UDC_CLR_HALT; UDC_EP_NUM_REG = UDC_EP_DIR; @@ -1511,9 +1513,6 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) u.word[3] = UDC_DATA_REG; UDC_EP_NUM_REG = 0; } while (UDC_IRQ_SRC_REG & UDC_SETUP); - le16_to_cpus (&u.r.wValue); - le16_to_cpus (&u.r.wIndex); - le16_to_cpus (&u.r.wLength); /* Delegate almost all control requests to the gadget driver, * except for a handful of ch9 status/feature requests that @@ -1566,6 +1565,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) UDC_CTRL_REG = UDC_SET_FIFO_EN; ep->ackwait = 1 + ep->double_buf; } + /* NOTE: assumes the host behaves sanely, + * only clearing real halts. Else we may + * need to kill pending transfers and then + * restart the queue... very messy for DMA! + */ } VDBG("%s halt cleared by host\n", ep->name); goto ep0out_status_stage; @@ -2013,7 +2017,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) udc->softconnect = 1; /* hook up the driver */ - driver->driver.bus = 0; + driver->driver.bus = NULL; udc->driver = driver; udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); @@ -2021,8 +2025,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) status = driver->bind (&udc->gadget); if (status) { DBG("bind to %s --> %d\n", driver->driver.name, status); - udc->gadget.dev.driver = 0; - udc->driver = 0; + udc->gadget.dev.driver = NULL; + udc->driver = NULL; goto done; } DBG("bound to driver %s\n", driver->driver.name); @@ -2035,8 +2039,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (status < 0) { ERR("can't bind to transceiver\n"); driver->unbind (&udc->gadget); - udc->gadget.dev.driver = 0; - udc->driver = 0; + udc->gadget.dev.driver = NULL; + udc->driver = NULL; goto done; } } else { @@ -2071,7 +2075,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) omap_vbus_session(&udc->gadget, 0); if (udc->transceiver) - (void) otg_set_peripheral(udc->transceiver, 0); + (void) otg_set_peripheral(udc->transceiver, NULL); else pullup_disable(udc); @@ -2080,9 +2084,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) spin_unlock_irqrestore(&udc->lock, flags); driver->unbind(&udc->gadget); - udc->gadget.dev.driver = 0; - udc->driver = 0; - + udc->gadget.dev.driver = NULL; + udc->driver = NULL; DBG("unregistered driver '%s'\n", driver->driver.name); return status; @@ -2178,7 +2181,7 @@ static int proc_otg_show(struct seq_file *s) tmp = OTG_REV_REG; trans = USB_TRANSCEIVER_CTRL_REG; - seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n", + seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %03x\n", tmp >> 4, tmp & 0xf, trans); tmp = OTG_SYSCON_1_REG; seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," @@ -2235,6 +2238,7 @@ static int proc_otg_show(struct seq_file *s) seq_printf(s, "otg_outctrl %04x" "\n", tmp); tmp = OTG_TEST_REG; seq_printf(s, "otg_test %04x" "\n", tmp); + return 0; } static int proc_udc_show(struct seq_file *s, void *_) @@ -2378,7 +2382,7 @@ static int proc_udc_show(struct seq_file *s, void *_) static int proc_udc_open(struct inode *inode, struct file *file) { - return single_open(file, proc_udc_show, 0); + return single_open(file, proc_udc_show, NULL); } static struct file_operations proc_ops = { @@ -2399,7 +2403,7 @@ static void create_proc_file(void) static void remove_proc_file(void) { - remove_proc_entry(proc_filename, 0); + remove_proc_entry(proc_filename, NULL); } #else @@ -2505,7 +2509,7 @@ static void omap_udc_release(struct device *dev) { complete(udc->done); kfree (udc); - udc = 0; + udc = NULL; } static int __init @@ -2577,23 +2581,33 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) case 1: OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); + OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); + OMAP_BULK_EP("ep3in", USB_DIR_IN | 3); OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4); + OMAP_INT_EP("ep10in", USB_DIR_IN | 10, 16); OMAP_BULK_EP("ep5in", USB_DIR_IN | 5); OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5); + OMAP_INT_EP("ep11in", USB_DIR_IN | 11, 16); + OMAP_BULK_EP("ep6in", USB_DIR_IN | 6); OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6); + OMAP_INT_EP("ep12in", USB_DIR_IN | 12, 16); OMAP_BULK_EP("ep7in", USB_DIR_IN | 7); OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7); + OMAP_INT_EP("ep13in", USB_DIR_IN | 13, 16); + OMAP_INT_EP("ep13out", USB_DIR_OUT | 13, 16); + OMAP_BULK_EP("ep8in", USB_DIR_IN | 8); OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8); + OMAP_INT_EP("ep14in", USB_DIR_IN | 14, 16); + OMAP_INT_EP("ep14out", USB_DIR_OUT | 14, 16); + + OMAP_BULK_EP("ep15in", USB_DIR_IN | 15); + OMAP_BULK_EP("ep15out", USB_DIR_OUT | 15); - OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); - OMAP_INT_EP("ep10out", USB_DIR_IN | 10, 16); - OMAP_INT_EP("ep11in", USB_DIR_IN | 9, 16); - OMAP_INT_EP("ep12out", USB_DIR_IN | 10, 16); break; #ifdef USE_ISO @@ -2640,8 +2654,8 @@ static int __init omap_udc_probe(struct device *dev) struct platform_device *odev = to_platform_device(dev); int status = -ENODEV; int hmc; - struct otg_transceiver *xceiv = 0; - const char *type = 0; + struct otg_transceiver *xceiv = NULL; + const char *type = NULL; struct omap_usb_config *config = dev->platform_data; /* NOTE: "knows" the order of the resources! */ @@ -2678,6 +2692,15 @@ static int __init omap_udc_probe(struct device *dev) } else { hmc = HMC_1610; switch (hmc) { + case 0: /* POWERUP DEFAULT == 0 */ + case 4: + case 12: + case 20: + if (!cpu_is_omap1710()) { + type = "integrated"; + break; + } + /* FALL THROUGH */ case 3: case 11: case 16: @@ -2688,21 +2711,15 @@ static int __init omap_udc_probe(struct device *dev) DBG("external transceiver not registered!\n"); if (config->otg) goto cleanup0; - type = "(unknown external)"; + type = "unknown"; } else type = xceiv->label; break; - case 0: /* POWERUP DEFAULT == 0 */ - case 4: - case 12: - case 20: - type = "INTEGRATED"; - break; case 21: /* internal loopback */ - type = "(loopback)"; + type = "loopback"; break; case 14: /* transceiverless */ - type = "(none)"; + type = "no"; break; default: @@ -2710,14 +2727,14 @@ static int __init omap_udc_probe(struct device *dev) return -ENODEV; } } - INFO("hmc mode %d, transceiver %s\n", hmc, type); + INFO("hmc mode %d, %s transceiver\n", hmc, type); /* a "gadget" abstracts/virtualizes the controller */ status = omap_udc_setup(odev, xceiv); if (status) { goto cleanup0; } - xceiv = 0; + xceiv = NULL; // "udc" is now valid pullup_disable(udc); #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) @@ -2765,7 +2782,7 @@ cleanup2: cleanup1: kfree (udc); - udc = 0; + udc = NULL; cleanup0: if (xceiv) @@ -2788,7 +2805,7 @@ static int __exit omap_udc_remove(struct device *dev) pullup_disable(udc); if (udc->transceiver) { put_device(udc->transceiver->dev); - udc->transceiver = 0; + udc->transceiver = NULL; } UDC_SYSCON1_REG = 0; @@ -2809,13 +2826,32 @@ static int __exit omap_udc_remove(struct device *dev) return 0; } -static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level) +/* suspend/resume/wakeup from sysfs (echo > power/state) or when the + * system is forced into deep sleep + * + * REVISIT we should probably reject suspend requests when there's a host + * session active, rather than disconnecting, at least on boards that can + * report VBUS irqs (UDC_DEVSTAT_REG.UDC_ATT). And in any case, we need to + * make host resumes and VBUS detection trigger OMAP wakeup events; that + * may involve talking to an external transceiver (e.g. isp1301). + */ +static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level) { - if (level != 0) + u32 devstat; + + if (level != SUSPEND_POWER_DOWN) return 0; + devstat = UDC_DEVSTAT_REG; + + /* we're requesting 48 MHz clock if the pullup is enabled + * (== we're attached to the host) and we're not suspended, + * which would prevent entry to deep sleep... + */ + if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) { + WARN("session active; suspend requires disconnect\n"); + omap_pullup(&udc->gadget, 0); + } - DBG("suspend, state %d\n", state); - omap_pullup(&udc->gadget, 0); udc->gadget.dev.power.power_state = PMSG_SUSPEND; udc->gadget.dev.parent->power.power_state = PMSG_SUSPEND; return 0; @@ -2823,7 +2859,7 @@ static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level) static int omap_udc_resume(struct device *dev, u32 level) { - if (level != 0) + if (level != RESUME_POWER_ON) return 0; DBG("resume + wakeup/SRP\n"); -- cgit v1.2.3 From bc96c0ad1ed0c938fefc0423aa99f086c5a2a1ea Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 25 Apr 2005 11:21:31 -0400 Subject: [PATCH] ohci-omap, sl811, dummy: remove hub_set_power_budget This patch changes the HCDs that used the old hub_set_power_budget call, making them use the new hcd->power_budget field instead. Signed-off-by: Alan Stern Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 6 +++--- drivers/usb/host/ohci-hcd.c | 2 -- drivers/usb/host/ohci-omap.c | 4 ++-- drivers/usb/host/ohci.h | 1 - drivers/usb/host/sl811-hcd.c | 7 +++---- 5 files changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c039d2fbe7ab..9d37fc771b27 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1646,6 +1646,9 @@ static int dummy_start (struct usb_hcd *hcd) if (!root) return -ENOMEM; + /* only show a low-power port: just 8mA */ + hcd->power_budget = 8; + /* root hub enters addressed state... */ hcd->state = HC_STATE_RUNNING; root->speed = USB_SPEED_HIGH; @@ -1655,9 +1658,6 @@ static int dummy_start (struct usb_hcd *hcd) goto err1; } - /* only show a low-power port: just 8mA */ - hub_set_power_budget (root, 8); - if ((retval = dummy_register_udc (dum)) != 0) goto err2; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 32120042ab65..0da996191251 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -699,8 +699,6 @@ retry: ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); return -ENODEV; } - if (ohci->power_budget) - hub_set_power_budget(udev, ohci->power_budget); register_reboot_notifier (&ohci->reboot_notifier); create_debug_files (ohci); diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 8aab5907afe9..b62d69937694 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -181,7 +181,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) if (config->otg) { ohci_to_hcd(ohci)->self.otg_port = config->otg; /* default/minimum OTG power budget: 8 mA */ - ohci->power_budget = 8; + ohci_to_hcd(ohci)->power_budget = 8; } /* boards can use OTG transceivers in non-OTG modes */ @@ -230,7 +230,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) /* TPS2045 switch for internal transceiver (port 1) */ if (machine_is_omap_osk()) { - ohci->power_budget = 250; + ohci_to_hcd(ohci)->power_budget = 250; rh &= ~RH_A_NOCP; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 3dbc7c0eed43..71cdd2262860 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -371,7 +371,6 @@ struct ohci_hcd { * other external transceivers should be software-transparent */ struct otg_transceiver *transceiver; - unsigned power_budget; /* * memory management for queue data structures diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 99d43f758ad0..1f2d00fe983a 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1574,8 +1574,10 @@ sl811h_start(struct usb_hcd *hcd) udev->speed = USB_SPEED_FULL; hcd->state = HC_STATE_RUNNING; - if (sl811->board) + if (sl811->board) { hcd->can_wakeup = sl811->board->can_wakeup; + hcd->power_budget = sl811->board->power * 2; + } if (usb_hcd_register_root_hub(udev, hcd) != 0) { usb_put_dev(udev); @@ -1583,9 +1585,6 @@ sl811h_start(struct usb_hcd *hcd) return -ENODEV; } - if (sl811->board && sl811->board->power) - hub_set_power_budget(udev, sl811->board->power * 2); - /* enable power and interupts */ port_power(sl811, 1); -- cgit v1.2.3 From 247f3105636caa9d1d8a4c3dfb755de42633bc80 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 25 Apr 2005 11:28:04 -0400 Subject: [PATCH] USB HCDs: no longer need to register root hub This patch changes the host controller drivers; they no longer need to register their root hubs because usbcore will take care of it for them. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 24 ++---------------------- drivers/usb/host/ehci-hcd.c | 31 ------------------------------- drivers/usb/host/isp116x-hcd.c | 16 ---------------- drivers/usb/host/ohci-hcd.c | 30 ++---------------------------- drivers/usb/host/sl811-hcd.c | 13 ------------- drivers/usb/host/uhci-hcd.c | 25 ------------------------- 6 files changed, 4 insertions(+), 135 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 9d37fc771b27..1918d10f7569 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1625,7 +1625,6 @@ static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); static int dummy_start (struct usb_hcd *hcd) { struct dummy *dum; - struct usb_device *root; int retval; dum = hcd_to_dummy (hcd); @@ -1642,35 +1641,16 @@ static int dummy_start (struct usb_hcd *hcd) INIT_LIST_HEAD (&dum->urbp_list); - root = usb_alloc_dev (NULL, &hcd->self, 0); - if (!root) - return -ENOMEM; + if ((retval = dummy_register_udc (dum)) != 0) + return retval; /* only show a low-power port: just 8mA */ hcd->power_budget = 8; - - /* root hub enters addressed state... */ hcd->state = HC_STATE_RUNNING; - root->speed = USB_SPEED_HIGH; - - /* ...then configured, so khubd sees us. */ - if ((retval = usb_hcd_register_root_hub (root, hcd)) != 0) { - goto err1; - } - - if ((retval = dummy_register_udc (dum)) != 0) - goto err2; /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ device_create_file (dummy_dev(dum), &dev_attr_urbs); return 0; - - err2: - usb_disconnect (&hcd->self.root_hub); - err1: - usb_put_dev (root); - hcd->state = HC_STATE_QUIESCING; - return retval; } static void dummy_stop (struct usb_hcd *hcd) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index bc69bd7acebe..527abc693b17 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -492,8 +492,6 @@ static int ehci_start (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp; - struct usb_device *udev; - struct usb_bus *bus; int retval; u32 hcc_params; u8 sbrn = 0; @@ -631,17 +629,6 @@ static int ehci_start (struct usb_hcd *hcd) /* set async sleep time = 10 us ... ? */ - /* wire up the root hub */ - bus = hcd_to_bus (hcd); - udev = first ? usb_alloc_dev (NULL, bus, 0) : bus->root_hub; - if (!udev) { -done2: - ehci_mem_cleanup (ehci); - return -ENOMEM; - } - udev->speed = USB_SPEED_HIGH; - udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED; - /* * Start, enabling full USB 2.0 functionality ... usb 1.1 devices * are explicitly handed to companion controller(s), so no TT is @@ -664,24 +651,6 @@ done2: first ? "initialized" : "restarted", temp >> 8, temp & 0xff, DRIVER_VERSION); - /* - * From here on, khubd concurrently accesses the root - * hub; drivers will be talking to enumerated devices. - * (On restart paths, khubd already knows about the root - * hub and could find work as soon as we wrote FLAG_CF.) - * - * Before this point the HC was idle/ready. After, khubd - * and device drivers may start it running. - */ - if (first && usb_hcd_register_root_hub (udev, hcd) != 0) { - if (hcd->state == HC_STATE_RUNNING) - ehci_quiesce (ehci); - ehci_reset (ehci); - usb_put_dev (udev); - retval = -ENODEV; - goto done2; - } - writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ if (first) diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 1183988fdf54..ff0a168e8eed 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1547,7 +1547,6 @@ static int isp116x_start(struct usb_hcd *hcd) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct isp116x_platform_data *board = isp116x->board; - struct usb_device *udev; u32 val; unsigned long flags; @@ -1609,24 +1608,9 @@ static int isp116x_start(struct usb_hcd *hcd) isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS); isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf); - spin_unlock_irqrestore(&isp116x->lock, flags); - - udev = usb_alloc_dev(NULL, &hcd->self, 0); - if (!udev) { - isp116x_stop(hcd); - return -ENOMEM; - } - udev->speed = USB_SPEED_FULL; hcd->state = HC_STATE_RUNNING; - if (usb_hcd_register_root_hub(udev, hcd) != 0) { - isp116x_stop(hcd); - usb_put_dev(udev); - return -ENODEV; - } - - spin_lock_irqsave(&isp116x->lock, flags); /* Set up interrupts */ isp116x->intenb = HCINT_MIE | HCINT_RHSC | HCINT_UE; if (board->remote_wakeup_enable) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 0da996191251..13cd2177b557 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -505,13 +505,10 @@ static int ohci_init (struct ohci_hcd *ohci) /* Start an OHCI controller, set the BUS operational * resets USB and controller * enable interrupts - * connect the virtual root hub */ static int ohci_run (struct ohci_hcd *ohci) { u32 mask, temp; - struct usb_device *udev; - struct usb_bus *bus; int first = ohci->fminterval == 0; disable (ohci); @@ -672,36 +669,13 @@ retry: // POTPGT delay is bits 24-31, in 2 ms units. mdelay ((temp >> 23) & 0x1fe); - bus = &ohci_to_hcd(ohci)->self; ohci_to_hcd(ohci)->state = HC_STATE_RUNNING; ohci_dump (ohci, 1); - udev = bus->root_hub; - if (udev) { - return 0; - } - - /* connect the virtual root hub */ - udev = usb_alloc_dev (NULL, bus, 0); - if (!udev) { - disable (ohci); - ohci->hc_control &= ~OHCI_CTRL_HCFS; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - return -ENOMEM; - } - - udev->speed = USB_SPEED_FULL; - if (usb_hcd_register_root_hub (udev, ohci_to_hcd(ohci)) != 0) { - usb_put_dev (udev); - disable (ohci); - ohci->hc_control &= ~OHCI_CTRL_HCFS; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - return -ENODEV; - } + if (ohci_to_hcd(ohci)->self.root_hub == NULL) + create_debug_files (ohci); - register_reboot_notifier (&ohci->reboot_notifier); - create_debug_files (ohci); return 0; } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 1f2d00fe983a..6c3f910bc307 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1563,15 +1563,8 @@ static int sl811h_start(struct usb_hcd *hcd) { struct sl811 *sl811 = hcd_to_sl811(hcd); - struct usb_device *udev; /* chip has been reset, VBUS power is off */ - - udev = usb_alloc_dev(NULL, &hcd->self, 0); - if (!udev) - return -ENOMEM; - - udev->speed = USB_SPEED_FULL; hcd->state = HC_STATE_RUNNING; if (sl811->board) { @@ -1579,12 +1572,6 @@ sl811h_start(struct usb_hcd *hcd) hcd->power_budget = sl811->board->power * 2; } - if (usb_hcd_register_root_hub(udev, hcd) != 0) { - usb_put_dev(udev); - sl811h_stop(hcd); - return -ENODEV; - } - /* enable power and interupts */ port_power(sl811, 1); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 6b87bd74b046..fdf54295da73 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -562,7 +562,6 @@ static int uhci_start(struct usb_hcd *hcd) int retval = -EBUSY; int i; dma_addr_t dma_handle; - struct usb_device *udev; struct dentry *dentry; hcd->uses_new_polling = 1; @@ -626,14 +625,6 @@ static int uhci_start(struct usb_hcd *hcd) goto err_create_qh_pool; } - /* Initialize the root hub */ - - udev = usb_alloc_dev(NULL, &hcd->self, 0); - if (!udev) { - dev_err(uhci_dev(uhci), "unable to allocate root hub\n"); - goto err_alloc_root_hub; - } - uhci->term_td = uhci_alloc_td(uhci); if (!uhci->term_td) { dev_err(uhci_dev(uhci), "unable to allocate terminating TD\n"); @@ -713,24 +704,11 @@ static int uhci_start(struct usb_hcd *hcd) configure_hc(uhci); start_rh(uhci); - - udev->speed = USB_SPEED_FULL; - - if (usb_hcd_register_root_hub(udev, hcd) != 0) { - dev_err(uhci_dev(uhci), "unable to start root hub\n"); - retval = -ENOMEM; - goto err_start_root_hub; - } - return 0; /* * error exits: */ -err_start_root_hub: - reset_hc(uhci); - del_timer_sync(&uhci->stall_timer); - err_alloc_skelqh: for (i = 0; i < UHCI_NUM_SKELQH; i++) if (uhci->skelqh[i]) { @@ -742,9 +720,6 @@ err_alloc_skelqh: uhci->term_td = NULL; err_alloc_term_td: - usb_put_dev(udev); - -err_alloc_root_hub: dma_pool_destroy(uhci->qh_pool); uhci->qh_pool = NULL; -- cgit v1.2.3 From 340600ab4cf0cc41efd01a65af97ebb7d35a7f85 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 28 Apr 2005 13:45:25 -0700 Subject: [PATCH] USB: rndis updates (mostly cleanup) Some bugfixes and lots of cleanup (net code shrink): - On reset, force the RNDIS state machine its initial state - Hook up the RNDIS (outgoing) filters to the CDC mechanism - Lots of cleanup: * Eliminate duplicate copy of OID table; * Unify handlying of the OID "query" response data pointer; * Reduce code duplication for calculating query response lengths; * Remove some checks for "can't happen" errors; * Get rid of debugging #ifdefs by making the debug flag an integer level Most of the patch, by volume, relates to those query response cleanups. It incidentally shaves off a few hundred bytes of object code. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 11 +- drivers/usb/gadget/ndis.h | 14 +- drivers/usb/gadget/rndis.c | 509 +++++++++++++++++++++++---------------------- drivers/usb/gadget/rndis.h | 95 +-------- 4 files changed, 285 insertions(+), 344 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 3f783cbdc7c3..a766c29c3ec9 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -94,8 +94,9 @@ static const char driver_desc [] = DRIVER_DESC; #ifdef CONFIG_USB_ETH_RNDIS #include "rndis.h" #else -#define rndis_init() 0 -#define rndis_exit() do{}while(0) +#define rndis_init() 0 +#define rndis_uninit(x) do{}while(0) +#define rndis_exit() do{}while(0) #endif /* CDC and RNDIS support the same host-chosen outgoing packet filters. */ @@ -395,7 +396,8 @@ static inline int BITRATE(struct usb_gadget *g) #define STRING_SUBSET 8 #define STRING_RNDIS 9 -#define USB_BUFSIZ 256 /* holds our biggest descriptor */ +/* holds our biggest descriptor (or RNDIS response) */ +#define USB_BUFSIZ 256 /* * This device advertises one configuration, eth_config, unless RNDIS @@ -1124,6 +1126,7 @@ static void eth_reset_config (struct eth_dev *dev) netif_stop_queue (dev->net); netif_carrier_off (dev->net); + rndis_uninit(dev->rndis_config); /* disable endpoints, forcing (synchronous) completion of * pending i/o. then free the requests. @@ -2565,7 +2568,7 @@ fail0: /* these set up a lot of the OIDs that RNDIS needs */ rndis_set_host_mac (dev->rndis_config, dev->host_mac); if (rndis_set_param_dev (dev->rndis_config, dev->net, - &dev->stats)) + &dev->stats, &dev->cdc_filter)) goto fail0; if (rndis_set_param_vendor (dev->rndis_config, vendorID, manufacturer)) diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h index c553bbf68cab..09e3ee4eeae1 100644 --- a/drivers/usb/gadget/ndis.h +++ b/drivers/usb/gadget/ndis.h @@ -47,17 +47,17 @@ struct NDIS_PM_WAKE_UP_CAPABILITIES { #define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 struct NDIS_PNP_CAPABILITIES { - u32 Flags; + __le32 Flags; struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities; }; struct NDIS_PM_PACKET_PATTERN { - u32 Priority; - u32 Reserved; - u32 MaskSize; - u32 PatternOffset; - u32 PatternSize; - u32 PatternFlags; + __le32 Priority; + __le32 Reserved; + __le32 MaskSize; + __le32 PatternOffset; + __le32 PatternSize; + __le32 PatternFlags; }; diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 7457268d5f28..c9a0af29ecb6 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -41,6 +41,7 @@ #undef RNDIS_PM +#undef RNDIS_WAKEUP #undef VERBOSE #include "rndis.h" @@ -60,7 +61,7 @@ } while (0) static int rndis_debug = 0; -module_param (rndis_debug, bool, 0); +module_param (rndis_debug, int, 0); MODULE_PARM_DESC (rndis_debug, "enable debugging"); #else @@ -78,22 +79,103 @@ static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS]; static const __le32 rndis_driver_version = __constant_cpu_to_le32 (1); /* Function Prototypes */ -static int rndis_init_response (int configNr, rndis_init_msg_type *buf); -static int rndis_query_response (int configNr, rndis_query_msg_type *buf); -static int rndis_set_response (int configNr, rndis_set_msg_type *buf); -static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf); -static int rndis_keepalive_response (int configNr, - rndis_keepalive_msg_type *buf); - static rndis_resp_t *rndis_add_response (int configNr, u32 length); +/* supported OIDs */ +static const u32 oid_supported_list [] = +{ + /* the general stuff */ + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_PHYSICAL_MEDIUM, +#if 0 + OID_GEN_RNDIS_CONFIG_PARAMETER, +#endif + + /* the statistical stuff */ + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, +#ifdef RNDIS_OPTIONAL_STATS + OID_GEN_DIRECTED_BYTES_XMIT, + OID_GEN_DIRECTED_FRAMES_XMIT, + OID_GEN_MULTICAST_BYTES_XMIT, + OID_GEN_MULTICAST_FRAMES_XMIT, + OID_GEN_BROADCAST_BYTES_XMIT, + OID_GEN_BROADCAST_FRAMES_XMIT, + OID_GEN_DIRECTED_BYTES_RCV, + OID_GEN_DIRECTED_FRAMES_RCV, + OID_GEN_MULTICAST_BYTES_RCV, + OID_GEN_MULTICAST_FRAMES_RCV, + OID_GEN_BROADCAST_BYTES_RCV, + OID_GEN_BROADCAST_FRAMES_RCV, + OID_GEN_RCV_CRC_ERROR, + OID_GEN_TRANSMIT_QUEUE_LENGTH, +#endif /* RNDIS_OPTIONAL_STATS */ + + /* mandatory 802.3 */ + /* the general stuff */ + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAC_OPTIONS, + OID_802_3_MAXIMUM_LIST_SIZE, + + /* the statistical stuff */ + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, +#ifdef RNDIS_OPTIONAL_STATS + OID_802_3_XMIT_DEFERRED, + OID_802_3_XMIT_MAX_COLLISIONS, + OID_802_3_RCV_OVERRUN, + OID_802_3_XMIT_UNDERRUN, + OID_802_3_XMIT_HEARTBEAT_FAILURE, + OID_802_3_XMIT_TIMES_CRS_LOST, + OID_802_3_XMIT_LATE_COLLISIONS, +#endif /* RNDIS_OPTIONAL_STATS */ + +#ifdef RNDIS_PM + /* PM and wakeup are mandatory for USB: */ + + /* power management */ + OID_PNP_CAPABILITIES, + OID_PNP_QUERY_POWER, + OID_PNP_SET_POWER, + +#ifdef RNDIS_WAKEUP + /* wake up host */ + OID_PNP_ENABLE_WAKE_UP, + OID_PNP_ADD_WAKE_UP_PATTERN, + OID_PNP_REMOVE_WAKE_UP_PATTERN, +#endif /* RNDIS_WAKEUP */ +#endif /* RNDIS_PM */ +}; + + /* NDIS Functions */ -static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) +static int +gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, + rndis_resp_t *r) { int retval = -ENOTSUPP; - u32 length = 0; - __le32 *tmp; + u32 length = 4; /* usually */ + __le32 *outbuf; int i, count; rndis_query_cmplt_type *resp; @@ -101,7 +183,22 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) resp = (rndis_query_cmplt_type *) r->buf; if (!resp) return -ENOMEM; - + + if (buf_len && rndis_debug > 1) { + DEBUG("query OID %08x value, len %d:\n", OID, buf_len); + for (i = 0; i < buf_len; i += 16) { + DEBUG ("%03d: %08x %08x %08x %08x\n", i, + le32_to_cpup((__le32 *)&buf[i]), + le32_to_cpup((__le32 *)&buf[i + 4]), + le32_to_cpup((__le32 *)&buf[i + 8]), + le32_to_cpup((__le32 *)&buf[i + 12])); + } + } + + /* response goes here, right after the header */ + outbuf = (__le32 *) &resp[1]; + resp->InformationBufferOffset = __constant_cpu_to_le32 (16); + switch (OID) { /* general oids (table 4-1) */ @@ -111,42 +208,36 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__); length = sizeof (oid_supported_list); count = length / sizeof (u32); - tmp = (__le32 *) ((u8 *)resp + 24); for (i = 0; i < count; i++) - tmp[i] = cpu_to_le32 (oid_supported_list[i]); + outbuf[i] = cpu_to_le32 (oid_supported_list[i]); retval = 0; break; /* mandatory */ case OID_GEN_HARDWARE_STATUS: DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__); - length = 4; /* Bogus question! * Hardware must be ready to receive high level protocols. * BTW: * reddite ergo quae sunt Caesaris Caesari * et quae sunt Dei Deo! */ - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_SUPPORTED: DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr].medium); + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_IN_USE: DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__); - length = 4; /* one medium, one transport... (maybe you do it better) */ - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr].medium); + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); retval = 0; break; @@ -154,25 +245,21 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_MAXIMUM_FRAME_SIZE: DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_LINK_SPEED: -// DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); - length = 4; + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); if (rndis_per_dev_params [configNr].media_state - == NDIS_MEDIA_STATE_DISCONNECTED) - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + == NDIS_MEDIA_STATE_DISCONNECTED) + *outbuf = __constant_cpu_to_le32 (0); else - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].speed); retval = 0; break; @@ -181,8 +268,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_TRANSMIT_BLOCK_SIZE: DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); retval = 0; } @@ -192,8 +278,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_RECEIVE_BLOCK_SIZE: DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); retval = 0; } @@ -202,8 +287,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_GEN_VENDOR_ID: DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].vendorID); retval = 0; break; @@ -212,51 +296,44 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_VENDOR_DESCRIPTION: DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__); length = strlen (rndis_per_dev_params [configNr].vendorDescr); - memcpy ((u8 *) resp + 24, + memcpy (outbuf, rndis_per_dev_params [configNr].vendorDescr, length); retval = 0; break; case OID_GEN_VENDOR_DRIVER_VERSION: DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__); - length = 4; /* Created as LE */ - *((__le32 *) resp + 6) = rndis_driver_version; + *outbuf = rndis_driver_version; retval = 0; break; /* mandatory */ case OID_GEN_CURRENT_PACKET_FILTER: DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params[configNr].filter); + *outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter); retval = 0; break; /* mandatory */ case OID_GEN_MAXIMUM_TOTAL_SIZE: DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32( - RNDIS_MAX_TOTAL_SIZE); + *outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_CONNECT_STATUS: - DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .media_state); retval = 0; break; case OID_GEN_PHYSICAL_MEDIUM: DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; @@ -266,8 +343,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) */ case OID_GEN_MAC_OPTIONS: /* from WinME */ DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32( + *outbuf = __constant_cpu_to_le32( NDIS_MAC_OPTION_RECEIVE_SERIALIZED | NDIS_MAC_OPTION_FULL_DUPLEX); retval = 0; @@ -277,62 +353,49 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_GEN_XMIT_OK: - DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].stats->tx_packets - rndis_per_dev_params [configNr].stats->tx_errors - rndis_per_dev_params [configNr].stats->tx_dropped); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_RCV_OK: - DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].stats->rx_packets - rndis_per_dev_params [configNr].stats->rx_errors - rndis_per_dev_params [configNr].stats->rx_dropped); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_XMIT_ERROR: - DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_errors); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_RCV_ERROR: - DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_errors); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -340,13 +403,9 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_RCV_NO_BUFFER: DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_dropped); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -359,8 +418,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) * divided by weight of Alpha Centauri */ if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( (rndis_per_dev_params [configNr] .stats->tx_packets - rndis_per_dev_params [configNr] @@ -369,9 +427,6 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) .stats->tx_dropped) * 123); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -379,8 +434,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__); /* dito */ if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( (rndis_per_dev_params [configNr] .stats->tx_packets - rndis_per_dev_params [configNr] @@ -389,144 +443,105 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) .stats->tx_dropped) / 123); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_MULTICAST_BYTES_XMIT: DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast*1234); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_MULTICAST_FRAMES_XMIT: DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_BYTES_XMIT: DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_packets/42*255); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_FRAMES_XMIT: DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_packets/42); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_DIRECTED_BYTES_RCV: DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__); - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; case OID_GEN_DIRECTED_FRAMES_RCV: DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__); - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; case OID_GEN_MULTICAST_BYTES_RCV: DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast * 1111); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_MULTICAST_FRAMES_RCV: DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_BYTES_RCV: DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_packets/42*255); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_FRAMES_RCV: DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_packets/42); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_RCV_CRC_ERROR: DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_crc_errors); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_TRANSMIT_QUEUE_LENGTH: DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__); - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; #endif /* RNDIS_OPTIONAL_STATS */ @@ -538,13 +553,10 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { length = ETH_ALEN; - memcpy ((u8 *) resp + 24, + memcpy (outbuf, rndis_per_dev_params [configNr].host_mac, length); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -553,7 +565,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { length = ETH_ALEN; - memcpy ((u8 *) resp + 24, + memcpy (outbuf, rndis_per_dev_params [configNr].host_mac, length); retval = 0; @@ -563,18 +575,16 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_802_3_MULTICAST_LIST: DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); - length = 4; /* Multicast base address only */ - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000); + *outbuf = __constant_cpu_to_le32 (0xE0000000); retval = 0; break; /* mandatory */ case OID_802_3_MAXIMUM_LIST_SIZE: DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); - length = 4; /* Multicast base address only */ - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (1); + *outbuf = __constant_cpu_to_le32 (1); retval = 0; break; @@ -587,11 +597,8 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_802_3_RCV_ERROR_ALIGNMENT: DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__); - if (rndis_per_dev_params [configNr].stats) - { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + if (rndis_per_dev_params [configNr].stats) { + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_frame_errors); retval = 0; } @@ -600,16 +607,14 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_802_3_XMIT_ONE_COLLISION: DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; /* mandatory */ case OID_802_3_XMIT_MORE_COLLISIONS: DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; @@ -655,27 +660,18 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_PNP_CAPABILITIES: DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__); - /* just PM, and remote wakeup on link status change - * (not magic packet or pattern match) - */ + /* for now, no wakeup capabilities */ length = sizeof (struct NDIS_PNP_CAPABILITIES); - memset (resp, 0, length); - { - struct NDIS_PNP_CAPABILITIES *caps = (void *) resp; - - caps->Flags = NDIS_DEVICE_WAKE_UP_ENABLE; - caps->WakeUpCapabilities.MinLinkChangeWakeUp - = NdisDeviceStateD3; - - /* FIXME then use usb_gadget_wakeup(), and - * set USB_CONFIG_ATT_WAKEUP in config desc - */ - } + memset(outbuf, 0, length); retval = 0; break; case OID_PNP_QUERY_POWER: - DEBUG("%s: OID_PNP_QUERY_POWER\n", __FUNCTION__); - /* sure, handle any power state that maps to USB suspend */ + DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__, + le32_to_cpup((__le32 *) buf) - 1); + /* only suspend is a real power state, and + * it can't be entered by OID_PNP_SET_POWER... + */ + length = 0; retval = 0; break; #endif @@ -684,11 +680,12 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", __FUNCTION__, OID); } + if (retval < 0) + length = 0; - resp->InformationBufferOffset = __constant_cpu_to_le32 (16); resp->InformationBufferLength = cpu_to_le32 (length); - resp->MessageLength = cpu_to_le32 (24 + length); - r->length = 24 + length; + r->length = length + sizeof *resp; + resp->MessageLength = cpu_to_le32 (r->length); return retval; } @@ -705,45 +702,40 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, if (!resp) return -ENOMEM; - DEBUG("set OID %08x value, len %d:\n", OID, buf_len); - for (i = 0; i < buf_len; i += 16) { - DEBUG ("%03d: " - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - "\n", - i, - buf[i], buf [i+1], - buf[i+2], buf[i+3], - buf[i+4], buf [i+5], - buf[i+6], buf[i+7], - buf[i+8], buf [i+9], - buf[i+10], buf[i+11], - buf[i+12], buf [i+13], - buf[i+14], buf[i+15]); + if (buf_len && rndis_debug > 1) { + DEBUG("set OID %08x value, len %d:\n", OID, buf_len); + for (i = 0; i < buf_len; i += 16) { + DEBUG ("%03d: %08x %08x %08x %08x\n", i, + le32_to_cpup((__le32 *)&buf[i]), + le32_to_cpup((__le32 *)&buf[i + 4]), + le32_to_cpup((__le32 *)&buf[i + 8]), + le32_to_cpup((__le32 *)&buf[i + 12])); + } } + params = &rndis_per_dev_params [configNr]; switch (OID) { case OID_GEN_CURRENT_PACKET_FILTER: - params = &rndis_per_dev_params [configNr]; - retval = 0; - /* FIXME use these NDIS_PACKET_TYPE_* bitflags to - * set the cdc_filter; it's not RNDIS-specific + /* these NDIS_PACKET_TYPE_* bitflags are shared with + * cdc_filter; it's not RNDIS-specific * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in: * PROMISCUOUS, DIRECTED, * MULTICAST, ALL_MULTICAST, BROADCAST */ - params->filter = le32_to_cpup((__le32 *)buf); + *params->filter = (u16) le32_to_cpup((__le32 *)buf); DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", - __FUNCTION__, params->filter); + __FUNCTION__, *params->filter); /* this call has a significant side effect: it's * what makes the packet flow start and stop, like * activating the CDC Ethernet altsetting. */ - if (params->filter) { +#ifdef RNDIS_PM +update_linkstate: +#endif + retval = 0; + if (*params->filter) { params->state = RNDIS_DATA_INITIALIZED; netif_carrier_on(params->dev); if (netif_running(params->dev)) @@ -776,21 +768,34 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, #ifdef RNDIS_PM case OID_PNP_SET_POWER: - DEBUG ("OID_PNP_SET_POWER\n"); - /* sure, handle any power state that maps to USB suspend */ - retval = 0; - break; - - case OID_PNP_ENABLE_WAKE_UP: - /* always-connected ... */ - DEBUG ("OID_PNP_ENABLE_WAKE_UP\n"); - retval = 0; + /* The only real power state is USB suspend, and RNDIS requests + * can't enter it; this one isn't really about power. After + * resuming, Windows forces a reset, and then SET_POWER D0. + * FIXME ... then things go batty; Windows wedges itself. + */ + i = le32_to_cpup((__force __le32 *)buf); + DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1); + switch (i) { + case NdisDeviceStateD0: + *params->filter = params->saved_filter; + goto update_linkstate; + case NdisDeviceStateD3: + case NdisDeviceStateD2: + case NdisDeviceStateD1: + params->saved_filter = *params->filter; + retval = 0; + break; + } break; - // no PM resume patterns supported (specified where?) - // so OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN always fails +#ifdef RNDIS_WAKEUP + // no wakeup support advertised, so wakeup OIDs always fail: + // - OID_PNP_ENABLE_WAKE_UP + // - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN #endif +#endif /* RNDIS_PM */ + default: printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", __FUNCTION__, OID, buf_len); @@ -811,13 +816,10 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf) if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type)); - - if (!r) return -ENOMEM; - + if (!r) + return -ENOMEM; resp = (rndis_init_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; - resp->MessageType = __constant_cpu_to_le32 ( REMOTE_NDIS_INITIALIZE_CMPLT); resp->MessageLength = __constant_cpu_to_le32 (52); @@ -857,20 +859,22 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf) * oid_supported_list is the largest answer */ r = rndis_add_response (configNr, sizeof (oid_supported_list)); - - if (!r) return -ENOMEM; + if (!r) + return -ENOMEM; resp = (rndis_query_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; - resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT); - resp->MessageLength = __constant_cpu_to_le32 (24); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ - - if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), r)) { + + if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), + le32_to_cpu(buf->InformationBufferOffset) + + 8 + (u8 *) buf, + le32_to_cpu(buf->InformationBufferLength), + r)) { /* OID not supported */ resp->Status = __constant_cpu_to_le32 ( RNDIS_STATUS_NOT_SUPPORTED); + resp->MessageLength = __constant_cpu_to_le32 (sizeof *resp); resp->InformationBufferLength = __constant_cpu_to_le32 (0); resp->InformationBufferOffset = __constant_cpu_to_le32 (0); } else @@ -889,10 +893,9 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf) rndis_resp_t *r; r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type)); - - if (!r) return -ENOMEM; + if (!r) + return -ENOMEM; resp = (rndis_set_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; BufLength = le32_to_cpu (buf->InformationBufferLength); BufOffset = le32_to_cpu (buf->InformationBufferOffset); @@ -930,10 +933,9 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf) rndis_resp_t *r; r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type)); - - if (!r) return -ENOMEM; + if (!r) + return -ENOMEM; resp = (rndis_reset_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT); resp->MessageLength = __constant_cpu_to_le32 (16); @@ -957,8 +959,9 @@ static int rndis_keepalive_response (int configNr, /* host "should" check only in RNDIS_DATA_INITIALIZED state */ r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type)); + if (!r) + return -ENOMEM; resp = (rndis_keepalive_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; resp->MessageType = __constant_cpu_to_le32 ( REMOTE_NDIS_KEEPALIVE_CMPLT); @@ -987,10 +990,9 @@ static int rndis_indicate_status_msg (int configNr, u32 status) r = rndis_add_response (configNr, sizeof (rndis_indicate_status_msg_type)); - if (!r) return -ENOMEM; - + if (!r) + return -ENOMEM; resp = (rndis_indicate_status_msg_type *) r->buf; - if (!resp) return -ENOMEM; resp->MessageType = __constant_cpu_to_le32 ( REMOTE_NDIS_INDICATE_STATUS_MSG); @@ -1021,6 +1023,15 @@ int rndis_signal_disconnect (int configNr) RNDIS_STATUS_MEDIA_DISCONNECT); } +void rndis_uninit (int configNr) +{ + if (configNr >= RNDIS_MAX_CONFIGS) + return; + rndis_per_dev_params [configNr].used = 0; + rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED; + return; +} + void rndis_set_host_mac (int configNr, const u8 *addr) { rndis_per_dev_params [configNr].host_mac = addr; @@ -1046,9 +1057,13 @@ int rndis_msg_parser (u8 configNr, u8 *buf) return -ENOTSUPP; params = &rndis_per_dev_params [configNr]; + /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for + * rx/tx statistics and link status, in addition to KEEPALIVE traffic + * and normal HC level polling to see if there's any IN traffic. + */ + /* For USB: responses may take up to 10 seconds */ - switch (MsgType) - { + switch (MsgType) { case REMOTE_NDIS_INITIALIZE_MSG: DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", __FUNCTION__ ); @@ -1082,10 +1097,9 @@ int rndis_msg_parser (u8 configNr, u8 *buf) case REMOTE_NDIS_KEEPALIVE_MSG: /* For USB: host does this every 5 seconds */ -#ifdef VERBOSE - DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", - __FUNCTION__ ); -#endif + if (rndis_debug > 1) + DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", + __FUNCTION__ ); return rndis_keepalive_response (configNr, (rndis_keepalive_msg_type *) buf); @@ -1152,7 +1166,8 @@ void rndis_deregister (int configNr) } int rndis_set_param_dev (u8 configNr, struct net_device *dev, - struct net_device_stats *stats) + struct net_device_stats *stats, + u16 *cdc_filter) { DEBUG("%s:\n", __FUNCTION__ ); if (!dev || !stats) return -1; @@ -1160,6 +1175,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev, rndis_per_dev_params [configNr].dev = dev; rndis_per_dev_params [configNr].stats = stats; + rndis_per_dev_params [configNr].filter = cdc_filter; return 0; } @@ -1178,7 +1194,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr) int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed) { - DEBUG("%s:\n", __FUNCTION__ ); + DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed); if (configNr >= RNDIS_MAX_CONFIGS) return -1; rndis_per_dev_params [configNr].medium = medium; @@ -1242,6 +1258,7 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length) { rndis_resp_t *r; + /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */ r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC); if (!r) return NULL; diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h index 2b5b55df3cfd..95b4c6326100 100644 --- a/drivers/usb/gadget/rndis.h +++ b/drivers/usb/gadget/rndis.h @@ -69,90 +69,6 @@ #define OID_PNP_ENABLE_WAKE_UP 0xFD010106 -/* supported OIDs */ -static const u32 oid_supported_list [] = -{ - /* the general stuff */ - OID_GEN_SUPPORTED_LIST, - OID_GEN_HARDWARE_STATUS, - OID_GEN_MEDIA_SUPPORTED, - OID_GEN_MEDIA_IN_USE, - OID_GEN_MAXIMUM_FRAME_SIZE, - OID_GEN_LINK_SPEED, - OID_GEN_TRANSMIT_BLOCK_SIZE, - OID_GEN_RECEIVE_BLOCK_SIZE, - OID_GEN_VENDOR_ID, - OID_GEN_VENDOR_DESCRIPTION, - OID_GEN_VENDOR_DRIVER_VERSION, - OID_GEN_CURRENT_PACKET_FILTER, - OID_GEN_MAXIMUM_TOTAL_SIZE, - OID_GEN_MEDIA_CONNECT_STATUS, - OID_GEN_PHYSICAL_MEDIUM, -#if 0 - OID_GEN_RNDIS_CONFIG_PARAMETER, -#endif - - /* the statistical stuff */ - OID_GEN_XMIT_OK, - OID_GEN_RCV_OK, - OID_GEN_XMIT_ERROR, - OID_GEN_RCV_ERROR, - OID_GEN_RCV_NO_BUFFER, -#ifdef RNDIS_OPTIONAL_STATS - OID_GEN_DIRECTED_BYTES_XMIT, - OID_GEN_DIRECTED_FRAMES_XMIT, - OID_GEN_MULTICAST_BYTES_XMIT, - OID_GEN_MULTICAST_FRAMES_XMIT, - OID_GEN_BROADCAST_BYTES_XMIT, - OID_GEN_BROADCAST_FRAMES_XMIT, - OID_GEN_DIRECTED_BYTES_RCV, - OID_GEN_DIRECTED_FRAMES_RCV, - OID_GEN_MULTICAST_BYTES_RCV, - OID_GEN_MULTICAST_FRAMES_RCV, - OID_GEN_BROADCAST_BYTES_RCV, - OID_GEN_BROADCAST_FRAMES_RCV, - OID_GEN_RCV_CRC_ERROR, - OID_GEN_TRANSMIT_QUEUE_LENGTH, -#endif /* RNDIS_OPTIONAL_STATS */ - - /* mandatory 802.3 */ - /* the general stuff */ - OID_802_3_PERMANENT_ADDRESS, - OID_802_3_CURRENT_ADDRESS, - OID_802_3_MULTICAST_LIST, - OID_802_3_MAC_OPTIONS, - OID_802_3_MAXIMUM_LIST_SIZE, - - /* the statistical stuff */ - OID_802_3_RCV_ERROR_ALIGNMENT, - OID_802_3_XMIT_ONE_COLLISION, - OID_802_3_XMIT_MORE_COLLISIONS, -#ifdef RNDIS_OPTIONAL_STATS - OID_802_3_XMIT_DEFERRED, - OID_802_3_XMIT_MAX_COLLISIONS, - OID_802_3_RCV_OVERRUN, - OID_802_3_XMIT_UNDERRUN, - OID_802_3_XMIT_HEARTBEAT_FAILURE, - OID_802_3_XMIT_TIMES_CRS_LOST, - OID_802_3_XMIT_LATE_COLLISIONS, -#endif /* RNDIS_OPTIONAL_STATS */ - -#ifdef RNDIS_PM - /* PM and wakeup are mandatory for USB: */ - - /* power management */ - OID_PNP_CAPABILITIES, - OID_PNP_QUERY_POWER, - OID_PNP_SET_POWER, - - /* wake up host */ - OID_PNP_ENABLE_WAKE_UP, - OID_PNP_ADD_WAKE_UP_PATTERN, - OID_PNP_REMOVE_WAKE_UP_PATTERN, -#endif -}; - - typedef struct rndis_init_msg_type { __le32 MessageType; @@ -309,15 +225,18 @@ typedef struct rndis_resp_t typedef struct rndis_params { u8 confignr; - int used; + u8 used; + u16 saved_filter; enum rndis_state state; - u32 filter; u32 medium; u32 speed; u32 media_state; + const u8 *host_mac; + u16 *filter; struct net_device *dev; struct net_device_stats *stats; + u32 vendorID; const char *vendorDescr; int (*ack) (struct net_device *); @@ -329,7 +248,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf); int rndis_register (int (*rndis_control_ack) (struct net_device *)); void rndis_deregister (int configNr); int rndis_set_param_dev (u8 configNr, struct net_device *dev, - struct net_device_stats *stats); + struct net_device_stats *stats, + u16 *cdc_filter); int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr); int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); @@ -338,6 +258,7 @@ int rndis_rm_hdr (struct sk_buff *skb); u8 *rndis_get_next_response (int configNr, u32 *length); void rndis_free_response (int configNr, u8 *buf); +void rndis_uninit (int configNr); int rndis_signal_connect (int configNr); int rndis_signal_disconnect (int configNr); int rndis_state (int configNr); -- cgit v1.2.3 From 907cba35f7f24587f0eff60073e1f4e1e01c976d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 28 Apr 2005 13:48:09 -0700 Subject: [PATCH] USB: ethernet gadget updates (mostly cleanup) Some cleanup for the the Ethernet part of the Ethernet/RNDIS gadget driver: - Remove remnants of ancient endpoint init logic; this is simpler, clearer - Save a smidgeon of space in the object file - Get rid of some #ifdeffery, mostly by using some newish inlines - Reset more driver state as part of USB reset - Remove a needless wrapper around an RNDIS call - Improve and comment the status interrupt handling: * RNDIS sometimes needs to queue these transfers (rarely in normal cases, but reproducibly while Windows was deadlocking its USB stack) * Mark requests as busy/not - Enable the SET_NETDEV_DEV() call; sysfs seems to behave sanely now This is a net shrink of source code. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 287 +++++++++++++++++---------------------------- 1 file changed, 107 insertions(+), 180 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index a766c29c3ec9..3830a0a0fd50 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -84,7 +84,7 @@ */ #define DRIVER_DESC "Ethernet Gadget" -#define DRIVER_VERSION "Equinox 2004" +#define DRIVER_VERSION "May Day 2005" static const char shortname [] = "ether"; static const char driver_desc [] = DRIVER_DESC; @@ -141,9 +141,6 @@ struct eth_dev { * It also ASSUMES a self-powered device, without remote wakeup, * although remote wakeup support would make sense. */ -static const char *EP_IN_NAME; -static const char *EP_OUT_NAME; -static const char *EP_STATUS_NAME; /*-------------------------------------------------------------------------*/ @@ -313,6 +310,7 @@ static inline int rndis_active(struct eth_dev *dev) #define FS_BPS (19 * 64 * 1 * 1000 * 8) #ifdef CONFIG_USB_GADGET_DUALSPEED +#define DEVSPEED USB_SPEED_HIGH static unsigned qmult = 5; module_param (qmult, uint, S_IRUGO|S_IWUSR); @@ -331,6 +329,8 @@ static inline int BITRATE(struct usb_gadget *g) } #else /* full speed (low speed doesn't do bulk) */ +#define DEVSPEED USB_SPEED_FULL + #define qlen(gadget) DEFAULT_QLEN static inline int BITRATE(struct usb_gadget *g) @@ -540,7 +540,7 @@ static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { .bDataInterface = 0x01, }; -static struct usb_cdc_acm_descriptor acm_descriptor = { +static const struct usb_cdc_acm_descriptor acm_descriptor = { .bLength = sizeof acm_descriptor, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_ACM_TYPE, @@ -848,7 +848,7 @@ static const struct usb_descriptor_header *hs_rndis_function [] = { #else /* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) fs +#define ep_desc(g,hs,fs) (((void)(g)), (fs)) static inline void __init hs_subset_descriptors(void) { @@ -948,10 +948,31 @@ config_buf (enum usb_device_speed speed, static void eth_start (struct eth_dev *dev, int gfp_flags); static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags); -#ifdef DEV_CONFIG_CDC -static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep) +static int +set_ether_config (struct eth_dev *dev, int gfp_flags) { - const struct usb_endpoint_descriptor *d; + int result = 0; + struct usb_gadget *gadget = dev->gadget; + + /* status endpoint used for RNDIS and (optionally) CDC */ + if (!subset_active(dev) && dev->status_ep) { + dev->status = ep_desc (gadget, &hs_status_desc, + &fs_status_desc); + dev->status_ep->driver_data = dev; + + result = usb_ep_enable (dev->status_ep, dev->status); + if (result != 0) { + DEBUG (dev, "enable %s --> %d\n", + dev->status_ep->name, result); + goto done; + } + } + + dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); + dev->in_ep->driver_data = dev; + + dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); + dev->out_ep->driver_data = dev; /* With CDC, the host isn't allowed to use these two data * endpoints in the default altsetting for the interface. @@ -961,135 +982,33 @@ static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep) * a side effect of setting a packet filter. Deactivation is * from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG. */ - - /* one endpoint writes data back IN to the host */ - if (strcmp (ep->name, EP_IN_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); - ep->driver_data = dev; - dev->in = d; - - /* one endpoint just reads OUT packets */ - } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); - ep->driver_data = dev; - dev->out = d; - - /* optional status/notification endpoint */ - } else if (EP_STATUS_NAME && - strcmp (ep->name, EP_STATUS_NAME) == 0) { - int result; - - d = ep_desc (dev->gadget, &hs_status_desc, &fs_status_desc); - result = usb_ep_enable (ep, d); - if (result < 0) - return result; - - ep->driver_data = dev; - dev->status = d; - } - return 0; -} -#endif - -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) -static inline int ether_ep_setup (struct eth_dev *dev, struct usb_ep *ep) -{ - int result; - const struct usb_endpoint_descriptor *d; - - /* CDC subset is simpler: if the device is there, - * it's live with rx and tx endpoints. - * - * Do this as a shortcut for RNDIS too. - */ - - /* one endpoint writes data back IN to the host */ - if (strcmp (ep->name, EP_IN_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); - result = usb_ep_enable (ep, d); - if (result < 0) - return result; - - ep->driver_data = dev; - dev->in = d; - - /* one endpoint just reads OUT packets */ - } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); - result = usb_ep_enable (ep, d); - if (result < 0) - return result; - - ep->driver_data = dev; - dev->out = d; - } - - return 0; -} -#endif - -static int -set_ether_config (struct eth_dev *dev, int gfp_flags) -{ - int result = 0; - struct usb_ep *ep; - struct usb_gadget *gadget = dev->gadget; - - gadget_for_each_ep (ep, gadget) { -#ifdef DEV_CONFIG_CDC - if (!dev->rndis && dev->cdc) { - result = ether_alt_ep_setup (dev, ep); - if (result == 0) - continue; + if (!cdc_active(dev)) { + result = usb_ep_enable (dev->in_ep, dev->in); + if (result != 0) { + DEBUG(dev, "enable %s --> %d\n", + dev->in_ep->name, result); + goto done; } -#endif -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis && strcmp (ep->name, EP_STATUS_NAME) == 0) { - const struct usb_endpoint_descriptor *d; - d = ep_desc (gadget, &hs_status_desc, &fs_status_desc); - result = usb_ep_enable (ep, d); - if (result == 0) { - ep->driver_data = dev; - dev->status = d; - continue; - } - } else -#endif - - { -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) - result = ether_ep_setup (dev, ep); - if (result == 0) - continue; -#endif + result = usb_ep_enable (dev->out_ep, dev->out); + if (result != 0) { + DEBUG (dev, "enable %s --> %d\n", + dev->in_ep->name, result); + goto done; } - - /* stop on error */ - ERROR (dev, "can't enable %s, result %d\n", ep->name, result); - break; } - if (!result && (!dev->in_ep || !dev->out_ep)) - result = -ENODEV; +done: if (result == 0) result = alloc_requests (dev, qlen (gadget), gfp_flags); /* on error, disable any endpoints */ if (result < 0) { -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (dev->status) + if (!subset_active(dev)) (void) usb_ep_disable (dev->status_ep); -#endif dev->status = NULL; -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) - if (dev->rndis || !dev->cdc) { - if (dev->in) - (void) usb_ep_disable (dev->in_ep); - if (dev->out) - (void) usb_ep_disable (dev->out_ep); - } -#endif + (void) usb_ep_disable (dev->in_ep); + (void) usb_ep_disable (dev->out_ep); dev->in = NULL; dev->out = NULL; } else @@ -1097,8 +1016,7 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) /* activate non-CDC configs right away * this isn't strictly according to the RNDIS spec */ -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) - if (dev->rndis || !dev->cdc) { + if (!cdc_active (dev)) { netif_carrier_on (dev->net); if (netif_running (dev->net)) { spin_unlock (&dev->lock); @@ -1106,7 +1024,6 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) spin_lock (&dev->lock); } } -#endif if (result == 0) DEBUG (dev, "qlen %d\n", qlen (gadget)); @@ -1153,6 +1070,8 @@ static void eth_reset_config (struct eth_dev *dev) if (dev->status) { usb_ep_disable (dev->status_ep); } + dev->rndis = 0; + dev->cdc_filter = 0; dev->config = 0; } @@ -1165,9 +1084,6 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) int result = 0; struct usb_gadget *gadget = dev->gadget; - if (number == dev->config) - return 0; - if (gadget_is_sa1100 (gadget) && dev->config && atomic_read (&dev->tx_qlen) != 0) { @@ -1177,12 +1093,8 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) } eth_reset_config (dev); - /* default: pass all packets, no multicast filtering */ - dev->cdc_filter = DEFAULT_FILTER; - switch (number) { case DEV_CONFIG_VALUE: - dev->rndis = 0; result = set_ether_config (dev, gfp_flags); break; #ifdef CONFIG_USB_ETH_RNDIS @@ -1234,6 +1146,13 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) #ifdef DEV_CONFIG_CDC +/* The interrupt endpoint is used in CDC networking models (Ethernet, ATM) + * only to notify the host about link status changes (which we support) or + * report completion of some encapsulated command (as used in RNDIS). Since + * we want this CDC Ethernet code to be vendor-neutral, we don't use that + * command mechanism; and only one status request is ever queued. + */ + static void eth_status_complete (struct usb_ep *ep, struct usb_request *req) { struct usb_cdc_notification *event = req->buf; @@ -1262,7 +1181,7 @@ static void eth_status_complete (struct usb_ep *ep, struct usb_request *req) } else if (value != -ECONNRESET) DEBUG (dev, "event %02x --> %d\n", event->bNotificationType, value); - event->bmRequestType = 0xff; + req->context = NULL; } static void issue_start_status (struct eth_dev *dev) @@ -1279,6 +1198,8 @@ static void issue_start_status (struct eth_dev *dev) * a "cancel the whole queue" primitive since any * unlink-one primitive has way too many error modes. * here, we "know" toggle is already clear... + * + * FIXME iff req->context != null just dequeue it */ usb_ep_disable (dev->status_ep); usb_ep_enable (dev->status_ep, dev->status); @@ -1295,6 +1216,8 @@ static void issue_start_status (struct eth_dev *dev) req->length = sizeof *event; req->complete = eth_status_complete; + req->context = dev; + value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC); if (value < 0) DEBUG (dev, "status buf queue --> %d\n", value); @@ -1459,9 +1382,11 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) /* CDC requires the data transfers not be done from * the default interface setting ... also, setting - * the non-default interface clears filters etc. + * the non-default interface resets filters etc. */ if (wValue == 1) { + if (!cdc_active (dev)) + break; usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); dev->cdc_filter = DEFAULT_FILTER; @@ -1691,10 +1616,8 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) */ size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA); size += dev->out_ep->maxpacket - 1; -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) + if (rndis_active(dev)) size += sizeof (struct rndis_packet_msg_type); -#endif size -= size % dev->out_ep->maxpacket; if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) { @@ -1862,8 +1785,6 @@ static void rx_fill (struct eth_dev *dev, int gfp_flags) struct usb_request *req; unsigned long flags; - clear_bit (WORK_RX_MEMORY, &dev->todo); - /* fill unused rxq slots with some skb */ spin_lock_irqsave (&dev->lock, flags); while (!list_empty (&dev->rx_reqs)) { @@ -1886,11 +1807,9 @@ static void eth_work (void *_dev) { struct eth_dev *dev = _dev; - if (test_bit (WORK_RX_MEMORY, &dev->todo)) { + if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) { if (netif_running (dev->net)) rx_fill (dev, GFP_KERNEL); - else - clear_bit (WORK_RX_MEMORY, &dev->todo); } if (dev->todo) @@ -2039,27 +1958,31 @@ drop: #ifdef CONFIG_USB_ETH_RNDIS -static void rndis_send_media_state (struct eth_dev *dev, int connect) -{ - if (!dev) - return; - - if (connect) { - if (rndis_signal_connect (dev->rndis_config)) - return; - } else { - if (rndis_signal_disconnect (dev->rndis_config)) - return; - } -} +/* The interrupt endpoint is used in RNDIS to notify the host when messages + * other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT + * messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even + * REMOTE_NDIS_KEEPALIVE_MSG. + * + * The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and + * normally just one notification will be queued. + */ + +static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, unsigned); +static void eth_req_free (struct usb_ep *ep, struct usb_request *req); static void rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req) { + struct eth_dev *dev = ep->driver_data; + if (req->status || req->actual != req->length) - DEBUG ((struct eth_dev *) ep->driver_data, + DEBUG (dev, "rndis control ack complete --> %d, %d/%d\n", req->status, req->actual, req->length); + req->context = NULL; + + if (req != dev->stat_req) + eth_req_free(ep, req); } static int rndis_control_ack (struct net_device *net) @@ -2074,11 +1997,19 @@ static int rndis_control_ack (struct net_device *net) return -ENODEV; } + /* in case queue length > 1 */ + if (resp->context) { + resp = eth_req_alloc (dev->status_ep, 8, GFP_ATOMIC); + if (!resp) + return -ENOMEM; + } + /* Send RNDIS RESPONSE_AVAILABLE notification; * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too */ resp->length = 8; resp->complete = rndis_control_ack_complete; + resp->context = dev; *((__le32 *) resp->buf) = __constant_cpu_to_le32 (1); *((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0); @@ -2109,7 +2040,7 @@ static void eth_start (struct eth_dev *dev, int gfp_flags) rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, BITRATE(dev->gadget)/100); - rndis_send_media_state (dev, 1); + (void) rndis_signal_connect (dev->rndis_config); } #endif } @@ -2156,7 +2087,7 @@ static int eth_stop (struct net_device *net) if (dev->rndis) { rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, 0); - rndis_send_media_state (dev, 0); + (void) rndis_signal_disconnect (dev->rndis_config); } #endif @@ -2165,15 +2096,16 @@ static int eth_stop (struct net_device *net) /*-------------------------------------------------------------------------*/ -static struct usb_request *eth_req_alloc (struct usb_ep *ep, unsigned size) +static struct usb_request * +eth_req_alloc (struct usb_ep *ep, unsigned size, unsigned gfp_flags) { struct usb_request *req; - req = usb_ep_alloc_request (ep, GFP_KERNEL); + req = usb_ep_alloc_request (ep, gfp_flags); if (!req) return NULL; - req->buf = kmalloc (size, GFP_KERNEL); + req->buf = kmalloc (size, gfp_flags); if (!req->buf) { usb_ep_free_request (ep, req); req = NULL; @@ -2371,13 +2303,11 @@ autoconf_fail: gadget->name); return -ENODEV; } - EP_IN_NAME = in_ep->name; in_ep->driver_data = in_ep; /* claim */ out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc); if (!out_ep) goto autoconf_fail; - EP_OUT_NAME = out_ep->name; out_ep->driver_data = out_ep; /* claim */ #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) @@ -2387,7 +2317,6 @@ autoconf_fail: if (cdc || rndis) { status_ep = usb_ep_autoconfig (gadget, &fs_status_desc); if (status_ep) { - EP_STATUS_NAME = status_ep->name; status_ep->driver_data = status_ep; /* claim */ } else if (rndis) { dev_err (&gadget->dev, @@ -2429,7 +2358,7 @@ autoconf_fail: hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (EP_STATUS_NAME) + if (status_ep) hs_status_desc.bEndpointAddress = fs_status_desc.bEndpointAddress; #endif @@ -2502,7 +2431,7 @@ autoconf_fail: SET_ETHTOOL_OPS(net, &ops); /* preallocate control message data and buffer */ - dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ); + dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ, GFP_KERNEL); if (!dev->req) goto fail; dev->req->complete = eth_setup_complete; @@ -2510,11 +2439,12 @@ autoconf_fail: /* ... and maybe likewise for status transfer */ if (dev->status_ep) { dev->stat_req = eth_req_alloc (dev->status_ep, - STATUS_BYTECOUNT); + STATUS_BYTECOUNT, GFP_KERNEL); if (!dev->stat_req) { eth_req_free (gadget->ep0, dev->req); goto fail; } + dev->stat_req->context = NULL; } /* finish hookup to lower layer ... */ @@ -2529,16 +2459,16 @@ autoconf_fail: netif_stop_queue (dev->net); netif_carrier_off (dev->net); - // SET_NETDEV_DEV (dev->net, &gadget->dev); + SET_NETDEV_DEV (dev->net, &gadget->dev); status = register_netdev (dev->net); if (status < 0) goto fail1; INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name, - EP_OUT_NAME, EP_IN_NAME, - EP_STATUS_NAME ? " STATUS " : "", - EP_STATUS_NAME ? EP_STATUS_NAME : "" + out_ep->name, in_ep->name, + status_ep ? " STATUS " : "", + status_ep ? status_ep->name : "" ); INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", net->dev_addr [0], net->dev_addr [1], @@ -2613,11 +2543,8 @@ eth_resume (struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver eth_driver = { -#ifdef CONFIG_USB_GADGET_DUALSPEED - .speed = USB_SPEED_HIGH, -#else - .speed = USB_SPEED_FULL, -#endif + .speed = DEVSPEED, + .function = (char *) driver_desc, .bind = eth_bind, .unbind = eth_unbind, -- cgit v1.2.3 From 65111084c63d7674dc37833e8eb59cfdaa4d0bda Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 28 Apr 2005 13:52:31 -0700 Subject: [PATCH] USB: more omap_udc updates (dma and omap1710) More omap_udc updates: * OMAP 1710 updates - new UDC bit for clearing endpoint toggle, affecting CLEAR_HALT - new OTG bits affecting wakeup * Fix the bug Vladimir noted, that IN-DMA transfer code path kicks in for under 1024 bytes (not "up to 1024 bytes") * Handle transceiver setup more intelligently - use transceiver whenever one's available; this can be handy for GPIO based, loopback, or transceiverless configs - cleanup correctly after the "unrecognized HMC" case * DMA performance tweaks - allow burst/pack for memory access - use 16 bit DMA access most of the time on TIPB * Add workarounds for some DMA errata (not observed "in the wild"): - DMA CSAC/CDAC reads returning zero - RX/TX DMA config registers bit 12 always reads as zero (TI patch) * More "sparse" warnings removed, notably "changing" the SETUP packet to return data in USB byteorder (an API change, null effect on OMAP except for these warnings). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/omap_udc.c | 153 +++++++++++++++++++++++++++++----------- drivers/usb/gadget/omap_udc.h | 4 +- include/asm-arm/arch-omap/usb.h | 9 +++ 3 files changed, 125 insertions(+), 41 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 4ec91a68f96c..a2b812af6e66 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -166,7 +166,7 @@ static int omap_ep_enable(struct usb_ep *_ep, maxp = le16_to_cpu (desc->wMaxPacketSize); if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK && maxp != ep->maxpacket) - || desc->wMaxPacketSize > ep->maxpacket + || le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket || !desc->wMaxPacketSize) { DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); return -ERANGE; @@ -213,7 +213,7 @@ static int omap_ep_enable(struct usb_ep *_ep, ep->has_dma = 0; ep->lch = -1; use_ep(ep, UDC_EP_SEL); - UDC_CTRL_REG = UDC_RESET_EP; + UDC_CTRL_REG = udc->clr_halt; ep->ackwait = 0; deselect_ep(); @@ -537,6 +537,32 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req) /*-------------------------------------------------------------------------*/ +static inline dma_addr_t dma_csac(unsigned lch) +{ + dma_addr_t csac; + + /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is + * read before the DMA controller finished disabling the channel. + */ + csac = omap_readw(OMAP_DMA_CSAC(lch)); + if (csac == 0) + csac = omap_readw(OMAP_DMA_CSAC(lch)); + return csac; +} + +static inline dma_addr_t dma_cdac(unsigned lch) +{ + dma_addr_t cdac; + + /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is + * read before the DMA controller finished disabling the channel. + */ + cdac = omap_readw(OMAP_DMA_CDAC(lch)); + if (cdac == 0) + cdac = omap_readw(OMAP_DMA_CDAC(lch)); + return cdac; +} + static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) { dma_addr_t end; @@ -547,7 +573,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) if (cpu_is_omap15xx()) return 0; - end = omap_readw(OMAP_DMA_CSAC(ep->lch)); + end = dma_csac(ep->lch); if (end == ep->dma_counter) return 0; @@ -558,14 +584,14 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) } #define DMA_DEST_LAST(x) (cpu_is_omap15xx() \ - ? OMAP_DMA_CSAC(x) /* really: CPC */ \ - : OMAP_DMA_CDAC(x)) + ? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \ + : dma_cdac(x)) static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start) { dma_addr_t end; - end = omap_readw(DMA_DEST_LAST(ep->lch)); + end = DMA_DEST_LAST(ep->lch); if (end == ep->dma_counter) return 0; @@ -592,7 +618,7 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) : OMAP_DMA_SYNC_ELEMENT; /* measure length in either bytes or packets */ - if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1)) + if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC) || (cpu_is_omap15xx() && length < ep->maxpacket)) { txdma_ctrl = UDC_TXN_EOT | length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, @@ -601,15 +627,15 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) length = min(length / ep->maxpacket, (unsigned) UDC_TXN_TSC + 1); txdma_ctrl = length; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - ep->ep.maxpacket, length, sync_mode); + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, + ep->ep.maxpacket >> 1, length, sync_mode); length *= ep->maxpacket; } omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); omap_start_dma(ep->lch); - ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch)); + ep->dma_counter = dma_csac(ep->lch); UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel); UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl; req->dma_bytes = length; @@ -649,12 +675,12 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req) packets = (req->req.length - req->req.actual) / ep->ep.maxpacket; packets = min(packets, (unsigned)UDC_RXN_TC + 1); req->dma_bytes = packets * ep->ep.maxpacket; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - ep->ep.maxpacket, packets, + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, + ep->ep.maxpacket >> 1, packets, OMAP_DMA_SYNC_ELEMENT); omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); - ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch)); + ep->dma_counter = DMA_DEST_LAST(ep->lch); UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1); UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel); @@ -762,7 +788,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) reg = UDC_TXDMA_CFG_REG; else reg = UDC_RXDMA_CFG_REG; - reg |= 1 << 12; /* "pulse" activated */ + reg |= UDC_DMA_REQ; /* "pulse" activated */ ep->dma_channel = 0; ep->lch = -1; @@ -786,6 +812,11 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) ep->ep.name, dma_error, ep, &ep->lch); if (status == 0) { UDC_TXDMA_CFG_REG = reg; + /* EMIFF */ + omap_set_dma_src_burst_mode(ep->lch, + OMAP_DMA_DATA_BURST_4); + omap_set_dma_src_data_pack(ep->lch, 1); + /* TIPB */ omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, @@ -796,10 +827,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) ep->ep.name, dma_error, ep, &ep->lch); if (status == 0) { UDC_RXDMA_CFG_REG = reg; + /* TIPB */ omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + /* EMIFF */ + omap_set_dma_dest_burst_mode(ep->lch, + OMAP_DMA_DATA_BURST_4); + omap_set_dma_dest_data_pack(ep->lch, 1); } } if (status) @@ -864,9 +900,13 @@ static void dma_channel_release(struct omap_ep *ep) (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r', ep->dma_channel - 1, req); + /* NOTE: re-setting RX_REQ/TX_REQ because of a chip bug (before + * OMAP 1710 ES2.0) where reading the DMA_CFG can clear them. + */ + /* wait till current packet DMA finishes, and fifo empties */ if (ep->bEndpointAddress & USB_DIR_IN) { - UDC_TXDMA_CFG_REG &= ~mask; + UDC_TXDMA_CFG_REG = (UDC_TXDMA_CFG_REG & ~mask) | UDC_DMA_REQ; if (req) { finish_in_dma(ep, req, -ECONNRESET); @@ -879,7 +919,7 @@ static void dma_channel_release(struct omap_ep *ep) while (UDC_TXDMA_CFG_REG & mask) udelay(10); } else { - UDC_RXDMA_CFG_REG &= ~mask; + UDC_RXDMA_CFG_REG = (UDC_RXDMA_CFG_REG & ~mask) | UDC_DMA_REQ; /* dma empties the fifo */ while (UDC_RXDMA_CFG_REG & mask) @@ -1140,7 +1180,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value) dma_channel_claim(ep, channel); } else { use_ep(ep, 0); - UDC_CTRL_REG = UDC_RESET_EP; + UDC_CTRL_REG = ep->udc->clr_halt; ep->ackwait = 0; if (!(ep->bEndpointAddress & USB_DIR_IN)) { UDC_CTRL_REG = UDC_SET_FIFO_EN; @@ -1514,6 +1554,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) UDC_EP_NUM_REG = 0; } while (UDC_IRQ_SRC_REG & UDC_SETUP); +#define w_value le16_to_cpup (&u.r.wValue) +#define w_index le16_to_cpup (&u.r.wIndex) +#define w_length le16_to_cpup (&u.r.wLength) + /* Delegate almost all control requests to the gadget driver, * except for a handful of ch9 status/feature requests that * hardware doesn't autodecode _and_ the gadget API hides. @@ -1528,11 +1572,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) /* udc needs to know when ep != 0 is valid */ if (u.r.bRequestType != USB_RECIP_DEVICE) goto delegate; - if (u.r.wLength != 0) + if (w_length != 0) goto do_stall; udc->ep0_set_config = 1; - udc->ep0_reset_config = (u.r.wValue == 0); - VDBG("set config %d\n", u.r.wValue); + udc->ep0_reset_config = (w_value == 0); + VDBG("set config %d\n", w_value); /* update udc NOW since gadget driver may start * queueing requests immediately; clear config @@ -1548,18 +1592,18 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) /* clear endpoint halt */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - ep = &udc->ep[u.r.wIndex & 0xf]; + ep = &udc->ep[w_index & 0xf]; if (ep != ep0) { - if (u.r.wIndex & USB_DIR_IN) + if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || !ep->desc) goto do_stall; use_ep(ep, 0); - UDC_CTRL_REG = UDC_RESET_EP; + UDC_CTRL_REG = udc->clr_halt; ep->ackwait = 0; if (!(ep->bEndpointAddress & USB_DIR_IN)) { UDC_CTRL_REG = UDC_SET_FIFO_EN; @@ -1577,11 +1621,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) /* set endpoint halt */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - ep = &udc->ep[u.r.wIndex & 0xf]; - if (u.r.wIndex & USB_DIR_IN) + ep = &udc->ep[w_index & 0xf]; + if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || ep == ep0 || !ep->desc) @@ -1619,13 +1663,13 @@ ep0out_status_stage: UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_EP_NUM_REG = UDC_EP_DIR; status = 0; - VDBG("GET_STATUS, interface %d\n", u.r.wIndex); + VDBG("GET_STATUS, interface %d\n", w_index); /* next, status stage */ break; default: delegate: /* activate the ep0out fifo right away */ - if (!udc->ep0_in && u.r.wLength) { + if (!udc->ep0_in && w_length) { UDC_EP_NUM_REG = 0; UDC_CTRL_REG = UDC_SET_FIFO_EN; } @@ -1636,7 +1680,11 @@ delegate: */ VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, u.r.wLength); + w_value, w_index, w_length); + +#undef w_value +#undef w_index +#undef w_length /* The gadget driver may return an error here, * causing an immediate protocol stall. @@ -2181,14 +2229,14 @@ static int proc_otg_show(struct seq_file *s) tmp = OTG_REV_REG; trans = USB_TRANSCEIVER_CTRL_REG; - seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %03x\n", + seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\n", tmp >> 4, tmp & 0xf, trans); tmp = OTG_SYSCON_1_REG; seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," FOURBITS "\n", tmp, trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R), trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R), - (USB0_TRX_MODE(tmp) == 0) + (USB0_TRX_MODE(tmp) == 0 && !cpu_is_omap1710()) ? "internal" : trx_mode(USB0_TRX_MODE(tmp), 1), (tmp & OTG_IDLE_EN) ? " !otg" : "", @@ -2418,6 +2466,10 @@ static inline void remove_proc_file(void) {} /* Before this controller can enumerate, we need to pick an endpoint * configuration, or "fifo_mode" That involves allocating 2KB of packet * buffer space among the endpoints we'll be operating. + * + * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when + * UDC_SYSCON_1_REG.CFG_LOCK is set can now work. We won't use that + * capability yet though. */ static unsigned __init omap_ep_setup(char *name, u8 addr, u8 type, @@ -2690,6 +2742,19 @@ static int __init omap_udc_probe(struct device *dev) FUNC_MUX_CTRL_0_REG = tmp; } } else { + /* The transceiver may package some GPIO logic or handle + * loopback and/or transceiverless setup; if we find one, + * use it. Except for OTG, we don't _need_ to talk to one; + * but not having one probably means no VBUS detection. + */ + xceiv = otg_get_transceiver(); + if (xceiv) + type = xceiv->label; + else if (config->otg) { + DBG("OTG requires external transceiver!\n"); + goto cleanup0; + } + hmc = HMC_1610; switch (hmc) { case 0: /* POWERUP DEFAULT == 0 */ @@ -2706,25 +2771,27 @@ static int __init omap_udc_probe(struct device *dev) case 16: case 19: case 25: - xceiv = otg_get_transceiver(); if (!xceiv) { DBG("external transceiver not registered!\n"); - if (config->otg) - goto cleanup0; type = "unknown"; - } else - type = xceiv->label; + } break; case 21: /* internal loopback */ type = "loopback"; break; case 14: /* transceiverless */ + if (cpu_is_omap1710()) + goto bad_on_1710; + /* FALL THROUGH */ + case 13: + case 15: type = "no"; break; default: +bad_on_1710: ERR("unrecognized UDC HMC mode %d\n", hmc); - return -ENODEV; + goto cleanup0; } } INFO("hmc mode %d, %s transceiver\n", hmc, type); @@ -2741,6 +2808,12 @@ static int __init omap_udc_probe(struct device *dev) udc->gadget.is_otg = (config->otg != 0); #endif + /* starting with omap1710 es2.0, clear toggle is a separate bit */ + if (UDC_REV_REG >= 0x61) + udc->clr_halt = UDC_RESET_EP | UDC_CLRDATA_TOGGLE; + else + udc->clr_halt = UDC_RESET_EP; + /* USB general purpose IRQ: ep0, state changes, dma, etc */ status = request_irq(odev->resource[1].start, omap_udc_irq, SA_SAMPLE_RANDOM, driver_name, udc); diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h index c9e68541622c..652ee4627344 100644 --- a/drivers/usb/gadget/omap_udc.h +++ b/drivers/usb/gadget/omap_udc.h @@ -20,6 +20,7 @@ #define UDC_CTRL_REG UDC_REG(0x0C) /* Endpoint control */ # define UDC_CLR_HALT (1 << 7) # define UDC_SET_HALT (1 << 6) +# define UDC_CLRDATA_TOGGLE (1 << 3) # define UDC_SET_FIFO_EN (1 << 2) # define UDC_CLR_EP (1 << 1) # define UDC_RESET_EP (1 << 0) @@ -99,6 +100,7 @@ /* DMA configuration registers: up to three channels in each direction. */ #define UDC_RXDMA_CFG_REG UDC_REG(0x40) /* 3 eps for RX DMA */ +# define UDC_DMA_REQ (1 << 12) #define UDC_TXDMA_CFG_REG UDC_REG(0x44) /* 3 eps for TX DMA */ #define UDC_DATA_DMA_REG UDC_REG(0x48) /* rx/tx fifo addr */ @@ -162,6 +164,7 @@ struct omap_udc { spinlock_t lock; struct omap_ep ep[32]; u16 devstat; + u16 clr_halt; struct otg_transceiver *transceiver; struct list_head iso; unsigned softconnect:1; @@ -171,7 +174,6 @@ struct omap_udc { unsigned ep0_set_config:1; unsigned ep0_reset_config:1; unsigned ep0_setup:1; - struct completion *done; }; diff --git a/include/asm-arm/arch-omap/usb.h b/include/asm-arm/arch-omap/usb.h index 1438c6cef0ca..054fb9a8e0c6 100644 --- a/include/asm-arm/arch-omap/usb.h +++ b/include/asm-arm/arch-omap/usb.h @@ -47,6 +47,15 @@ # define HMC_TLLATTACH (1 << 6) # define OTG_HMC(w) (((w)>>0)&0x3f) #define OTG_CTRL_REG OTG_REG32(0x0c) +# define OTG_USB2_EN (1 << 29) +# define OTG_USB2_DP (1 << 28) +# define OTG_USB2_DM (1 << 27) +# define OTG_USB1_EN (1 << 26) +# define OTG_USB1_DP (1 << 25) +# define OTG_USB1_DM (1 << 24) +# define OTG_USB0_EN (1 << 23) +# define OTG_USB0_DP (1 << 22) +# define OTG_USB0_DM (1 << 21) # define OTG_ASESSVLD (1 << 20) # define OTG_BSESSEND (1 << 19) # define OTG_BSESSVLD (1 << 18) -- cgit v1.2.3 From 5742b0c95026c817d9c266174ca39a909e8d38ca Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 2 May 2005 11:25:17 -0400 Subject: [PATCH] USB dummy_hcd: Partial OTG emulation Partial OTG support for dummy_hcd, mostly as a framework for further work. It emulates the new OTG flags in the host and peripheral frameworks, if that option is configured. But it's incomplete: - Resetting the peripheral needs to clear the OTG state bits; a second enumeration won't work correctly. - This stops modeling HNP right when roles should switch the first time. It should probably disconnect, then set the usb_bus.is_b_host and usb_gadget.is_a_peripheral flags; then it'd enumerate almost normally, except for the role reversal. Roles could then switch a second time, back to "normal" (with those flags cleared). - SRP should be modeled as "resume from port-unpowered", which is a state that usbcore doesn't yet use. HNP can be triggered by enabling the OTG whitelist and configuring a gadget driver that's not in that list; or by configuring Gadget Zero to identify itself as the HNP test device. Sent-by: David Brownell Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 1918d10f7569..e9b95df5b23d 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -601,8 +601,10 @@ static int dummy_wakeup (struct usb_gadget *_gadget) struct dummy *dum; dum = gadget_to_dummy (_gadget); - if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0 - || !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND))) + if (!(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) + || !(dum->devstatus & + ( (1 << USB_DEVICE_B_HNP_ENABLE) + | (1 << USB_DEVICE_REMOTE_WAKEUP)))) return -EINVAL; /* hub notices our request, issues downstream resume, etc */ @@ -713,6 +715,9 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) dum->gadget.ops = &dummy_ops; dum->gadget.is_dualspeed = 1; + /* maybe claim OTG support, though we won't complete HNP */ + dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); + dum->devstatus = 0; dum->resuming = 0; @@ -1215,6 +1220,16 @@ restart: switch (setup.wValue) { case USB_DEVICE_REMOTE_WAKEUP: break; + case USB_DEVICE_B_HNP_ENABLE: + dum->gadget.b_hnp_enable = 1; + break; + case USB_DEVICE_A_HNP_SUPPORT: + dum->gadget.a_hnp_support = 1; + break; + case USB_DEVICE_A_ALT_HNP_SUPPORT: + dum->gadget.a_alt_hnp_support + = 1; + break; default: value = -EOPNOTSUPP; } @@ -1533,6 +1548,13 @@ static int dummy_hub_control ( spin_unlock (&dum->lock); dum->driver->suspend (&dum->gadget); spin_lock (&dum->lock); + /* HNP would happen here; for now we + * assume b_bus_req is always true. + */ + if (((1 << USB_DEVICE_B_HNP_ENABLE) + & dum->devstatus) != 0) + dev_dbg (dummy_dev(dum), + "no HNP yet!\n"); } } break; @@ -1648,6 +1670,10 @@ static int dummy_start (struct usb_hcd *hcd) hcd->power_budget = 8; hcd->state = HC_STATE_RUNNING; +#ifdef CONFIG_USB_OTG + hcd->self.otg_port = 1; +#endif + /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ device_create_file (dummy_dev(dum), &dev_attr_urbs); return 0; -- cgit v1.2.3 From c2db8b5e5692a6f35913a829607ee6efde3c7cbd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 29 Apr 2005 16:30:48 -0400 Subject: [PATCH] USB: dummy_hcd: USB_PORT_FEAT changed to USB_PORT_STAT This patch makes some cosmetic changes to dummy_hcd: Minor alterations of comments and whitespace. Replace USB_PORT_FEAT_xxx with USB_PORT_STAT_xxx. This is appropriate as the values are stored in a status variable and they aren't feature indices. Also it allows the elimination of a bunch of awkward bit shift operations. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 50 +++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 27 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index e9b95df5b23d..ffedf4d1b747 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -601,7 +601,7 @@ static int dummy_wakeup (struct usb_gadget *_gadget) struct dummy *dum; dum = gadget_to_dummy (_gadget); - if (!(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) + if (!(dum->port_status & USB_PORT_STAT_SUSPEND) || !(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE) | (1 << USB_DEVICE_REMOTE_WAKEUP)))) @@ -609,7 +609,7 @@ static int dummy_wakeup (struct usb_gadget *_gadget) /* hub notices our request, issues downstream resume, etc */ dum->resuming = 1; - dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); + dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); return 0; } @@ -661,15 +661,15 @@ DEVICE_ATTR (function, S_IRUGO, show_function, NULL); * for each driver that registers: just add to a big root hub. */ +/* This doesn't need to do anything because the udc device structure is + * stored inside the hcd and will be deallocated along with it. */ static void -dummy_udc_release (struct device *dev) -{ -} +dummy_udc_release (struct device *dev) {} +/* This doesn't need to do anything because the pdev structure is + * statically allocated. */ static void -dummy_pdev_release (struct device *dev) -{ -} +dummy_pdev_release (struct device *dev) {} static int dummy_register_udc (struct dummy *dum) @@ -753,15 +753,13 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) return retval; } - // FIXME: Check these calls for errors and re-order driver->driver.bus = dum->gadget.dev.parent->bus; driver_register (&driver->driver); - device_bind_driver (&dum->gadget.dev); /* khubd will enumerate this in a while */ dum->port_status |= USB_PORT_STAT_CONNECTION - | (1 << USB_PORT_FEAT_C_CONNECTION); + | (USB_PORT_STAT_C_CONNECTION << 16); return 0; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -807,14 +805,13 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) stop_activity (dum, driver); dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); - dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); + dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); spin_unlock_irqrestore (&dum->lock, flags); driver->unbind (&dum->gadget); dum->driver = NULL; device_release_driver (&dum->gadget.dev); - driver_unregister (&driver->driver); return 0; @@ -1406,11 +1403,11 @@ return_urb: /*-------------------------------------------------------------------------*/ #define PORT_C_MASK \ - ((1 << USB_PORT_FEAT_C_CONNECTION) \ - | (1 << USB_PORT_FEAT_C_ENABLE) \ - | (1 << USB_PORT_FEAT_C_SUSPEND) \ - | (1 << USB_PORT_FEAT_C_OVER_CURRENT) \ - | (1 << USB_PORT_FEAT_C_RESET)) + ((USB_PORT_STAT_C_CONNECTION \ + | USB_PORT_STAT_C_ENABLE \ + | USB_PORT_STAT_C_SUSPEND \ + | USB_PORT_STAT_C_OVERCURRENT \ + | USB_PORT_STAT_C_RESET) << 16) static int dummy_hub_status (struct usb_hcd *hcd, char *buf) { @@ -1465,7 +1462,7 @@ static int dummy_hub_control ( case ClearPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) { + if (dum->port_status & USB_PORT_STAT_SUSPEND) { /* 20msec resume signaling */ dum->resuming = 1; dum->re_timeout = jiffies + @@ -1495,8 +1492,8 @@ static int dummy_hub_control ( * complete it!! */ if (dum->resuming && time_after (jiffies, dum->re_timeout)) { - dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); - dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND); + dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); + dum->port_status &= ~USB_PORT_STAT_SUSPEND; dum->resuming = 0; dum->re_timeout = 0; if (dum->driver && dum->driver->resume) { @@ -1505,10 +1502,10 @@ static int dummy_hub_control ( spin_lock (&dum->lock); } } - if ((dum->port_status & (1 << USB_PORT_FEAT_RESET)) != 0 + if ((dum->port_status & USB_PORT_STAT_RESET) != 0 && time_after (jiffies, dum->re_timeout)) { - dum->port_status |= (1 << USB_PORT_FEAT_C_RESET); - dum->port_status &= ~(1 << USB_PORT_FEAT_RESET); + dum->port_status |= (USB_PORT_STAT_C_RESET << 16); + dum->port_status &= ~USB_PORT_STAT_RESET; dum->re_timeout = 0; if (dum->driver) { dum->port_status |= USB_PORT_STAT_ENABLE; @@ -1540,10 +1537,9 @@ static int dummy_hub_control ( case SetPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) + if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0) { - dum->port_status |= - (1 << USB_PORT_FEAT_SUSPEND); + dum->port_status |= USB_PORT_STAT_SUSPEND; if (dum->driver && dum->driver->suspend) { spin_unlock (&dum->lock); dum->driver->suspend (&dum->gadget); -- cgit v1.2.3 From d9b762510c186584a6be0d3ece03e8a4b2ac13a8 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 May 2005 16:15:43 -0400 Subject: [PATCH] USB dummy_hcd: Use separate pdevs for HC and UDC This patch makes the dummy_hcd driver create separate platform devices for the emulated host controller and emulated device controller. This gives a more accurate simulation and will permit testing of situations where only one of the two devices is suspended. This also changes the name of the host controller platform device to match the name of the driver. That way the normal platform bus probe mechanism will handle binding the driver to the device. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 231 ++++++++++++++++++++++++----------------- 1 file changed, 133 insertions(+), 98 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index ffedf4d1b747..dc0e3233b0e9 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -141,6 +141,8 @@ static const char *const ep_name [] = { }; #define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *)) +/*-------------------------------------------------------------------------*/ + #define FIFO_SIZE 64 struct urbp { @@ -189,6 +191,11 @@ static inline struct device *dummy_dev (struct dummy *dum) return dummy_to_hcd(dum)->self.controller; } +static inline struct device *udc_dev (struct dummy *dum) +{ + return dum->gadget.dev.parent; +} + static inline struct dummy *ep_to_dummy (struct dummy_ep *ep) { return container_of (ep->gadget, struct dummy, gadget); @@ -208,19 +215,6 @@ static struct dummy *the_controller; /*-------------------------------------------------------------------------*/ -/* - * This "hardware" may look a bit odd in diagnostics since it's got both - * host and device sides; and it binds different drivers to each side. - */ -static struct platform_device the_pdev; - -static struct device_driver dummy_driver = { - .name = (char *) driver_name, - .bus = &platform_bus_type, -}; - -/*-------------------------------------------------------------------------*/ - /* SLAVE/GADGET SIDE DRIVER * * This only tracks gadget state. All the work is done when the host @@ -324,7 +318,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) _ep->maxpacket = max; ep->desc = desc; - dev_dbg (dummy_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n", + dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n", _ep->name, desc->bEndpointAddress & 0x0f, (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", @@ -379,7 +373,7 @@ static int dummy_disable (struct usb_ep *_ep) nuke (dum, ep); spin_unlock_irqrestore (&dum->lock, flags); - dev_dbg (dummy_dev(dum), "disabled %s\n", _ep->name); + dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name); return retval; } @@ -474,7 +468,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags) return -ESHUTDOWN; #if 0 - dev_dbg (dummy_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", + dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", ep, _req, _ep->name, _req->length, _req->buf); #endif @@ -537,7 +531,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) spin_unlock_irqrestore (&dum->lock, flags); if (retval == 0) { - dev_dbg (dummy_dev(dum), + dev_dbg (udc_dev(dum), "dequeued req %p from %s, len %d buf %p\n", req, _ep->name, _req->length, _req->buf); _req->complete (_ep, _req); @@ -661,38 +655,6 @@ DEVICE_ATTR (function, S_IRUGO, show_function, NULL); * for each driver that registers: just add to a big root hub. */ -/* This doesn't need to do anything because the udc device structure is - * stored inside the hcd and will be deallocated along with it. */ -static void -dummy_udc_release (struct device *dev) {} - -/* This doesn't need to do anything because the pdev structure is - * statically allocated. */ -static void -dummy_pdev_release (struct device *dev) {} - -static int -dummy_register_udc (struct dummy *dum) -{ - int rc; - - strcpy (dum->gadget.dev.bus_id, "udc"); - dum->gadget.dev.parent = dummy_dev(dum); - dum->gadget.dev.release = dummy_udc_release; - - rc = device_register (&dum->gadget.dev); - if (rc == 0) - device_create_file (&dum->gadget.dev, &dev_attr_function); - return rc; -} - -static void -dummy_unregister_udc (struct dummy *dum) -{ - device_remove_file (&dum->gadget.dev, &dev_attr_function); - device_unregister (&dum->gadget.dev); -} - int usb_gadget_register_driver (struct usb_gadget_driver *driver) { @@ -711,12 +673,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) * SLAVE side init ... the layer above hardware, which * can't enumerate without help from the driver we're binding. */ - dum->gadget.name = gadget_name; - dum->gadget.ops = &dummy_ops; - dum->gadget.is_dualspeed = 1; - - /* maybe claim OTG support, though we won't complete HNP */ - dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); dum->devstatus = 0; dum->resuming = 0; @@ -745,7 +701,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) dum->driver = driver; dum->gadget.dev.driver = &driver->driver; - dev_dbg (dummy_dev(dum), "binding gadget driver '%s'\n", + dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", driver->driver.name); if ((retval = driver->bind (&dum->gadget)) != 0) { dum->driver = NULL; @@ -798,7 +754,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) if (!driver || driver != dum->driver) return -EINVAL; - dev_dbg (dummy_dev(dum), "unregister gadget driver '%s'\n", + dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n", driver->driver.name); spin_lock_irqsave (&dum->lock, flags); @@ -826,6 +782,64 @@ int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) } EXPORT_SYMBOL (net2280_set_fifo_mode); + +/* The gadget structure is stored inside the hcd structure and will be + * released along with it. */ +static void +dummy_gadget_release (struct device *dev) +{ +#if 0 /* usb_bus_put isn't EXPORTed! */ + struct dummy *dum = gadget_dev_to_dummy (dev); + + usb_bus_put (&dummy_to_hcd (dum)->self); +#endif +} + +static int dummy_udc_probe (struct device *dev) +{ + struct dummy *dum = the_controller; + int rc; + + dum->gadget.name = gadget_name; + dum->gadget.ops = &dummy_ops; + dum->gadget.is_dualspeed = 1; + + /* maybe claim OTG support, though we won't complete HNP */ + dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); + + strcpy (dum->gadget.dev.bus_id, "gadget"); + dum->gadget.dev.parent = dev; + dum->gadget.dev.release = dummy_gadget_release; + rc = device_register (&dum->gadget.dev); + if (rc < 0) + return rc; + +#if 0 /* usb_bus_get isn't EXPORTed! */ + usb_bus_get (&dummy_to_hcd (dum)->self); +#endif + + dev_set_drvdata (dev, dum); + device_create_file (&dum->gadget.dev, &dev_attr_function); + return rc; +} + +static int dummy_udc_remove (struct device *dev) +{ + struct dummy *dum = dev_get_drvdata (dev); + + dev_set_drvdata (dev, NULL); + device_remove_file (&dum->gadget.dev, &dev_attr_function); + device_unregister (&dum->gadget.dev); + return 0; +} + +static struct device_driver dummy_udc_driver = { + .name = (char *) gadget_name, + .bus = &platform_bus_type, + .probe = dummy_udc_probe, + .remove = dummy_udc_remove, +}; + /*-------------------------------------------------------------------------*/ /* MASTER/HOST SIDE DRIVER @@ -1184,7 +1198,7 @@ restart: list_for_each_entry (req, &ep->queue, queue) { list_del_init (&req->queue); req->req.status = -EOVERFLOW; - dev_dbg (dummy_dev(dum), "stale req = %p\n", + dev_dbg (udc_dev(dum), "stale req = %p\n", req); spin_unlock (&dum->lock); @@ -1207,7 +1221,7 @@ restart: break; dum->address = setup.wValue; maybe_set_status (urb, 0); - dev_dbg (dummy_dev(dum), "set_address = %d\n", + dev_dbg (udc_dev(dum), "set_address = %d\n", setup.wValue); value = 0; break; @@ -1333,7 +1347,7 @@ restart: if (value < 0) { if (value != -EOPNOTSUPP) - dev_dbg (dummy_dev(dum), + dev_dbg (udc_dev(dum), "setup --> %d\n", value); maybe_set_status (urb, -EPIPE); @@ -1561,7 +1575,7 @@ static int dummy_hub_control ( | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); if (dum->driver) { - dev_dbg (dummy_dev(dum), + dev_dbg (udc_dev(dum), "disconnect\n"); stop_activity (dum, dum->driver); } @@ -1643,7 +1657,6 @@ static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); static int dummy_start (struct usb_hcd *hcd) { struct dummy *dum; - int retval; dum = hcd_to_dummy (hcd); @@ -1659,9 +1672,6 @@ static int dummy_start (struct usb_hcd *hcd) INIT_LIST_HEAD (&dum->urbp_list); - if ((retval = dummy_register_udc (dum)) != 0) - return retval; - /* only show a low-power port: just 8mA */ hcd->power_budget = 8; hcd->state = HC_STATE_RUNNING; @@ -1682,10 +1692,7 @@ static void dummy_stop (struct usb_hcd *hcd) dum = hcd_to_dummy (hcd); device_remove_file (dummy_dev(dum), &dev_attr_urbs); - usb_gadget_unregister_driver (dum->driver); - dummy_unregister_udc (dum); - dev_info (dummy_dev(dum), "stopped\n"); } @@ -1715,7 +1722,7 @@ static const struct hc_driver dummy_hcd = { .hub_control = dummy_hub_control, }; -static int dummy_probe (struct device *dev) +static int dummy_hcd_probe (struct device *dev) { struct usb_hcd *hcd; int retval; @@ -1735,7 +1742,7 @@ static int dummy_probe (struct device *dev) return retval; } -static void dummy_remove (struct device *dev) +static int dummy_hcd_remove (struct device *dev) { struct usb_hcd *hcd; @@ -1743,35 +1750,41 @@ static void dummy_remove (struct device *dev) usb_remove_hcd (hcd); usb_put_hcd (hcd); the_controller = NULL; + return 0; } -/*-------------------------------------------------------------------------*/ - -static int dummy_pdev_detect (void) -{ - int retval; - - retval = driver_register (&dummy_driver); - if (retval < 0) - return retval; +static struct device_driver dummy_hcd_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, + .probe = dummy_hcd_probe, + .remove = dummy_hcd_remove, +}; - the_pdev.name = "hc"; - the_pdev.dev.driver = &dummy_driver; - the_pdev.dev.release = dummy_pdev_release; +/*-------------------------------------------------------------------------*/ - retval = platform_device_register (&the_pdev); - if (retval < 0) - driver_unregister (&dummy_driver); - return retval; -} +/* These don't need to do anything because the pdev structures are + * statically allocated. */ +static void +dummy_udc_release (struct device *dev) {} -static void dummy_pdev_remove (void) -{ - platform_device_unregister (&the_pdev); - driver_unregister (&dummy_driver); -} +static void +dummy_hcd_release (struct device *dev) {} + +static struct platform_device the_udc_pdev = { + .name = (char *) gadget_name, + .id = -1, + .dev = { + .release = dummy_udc_release, + }, +}; -/*-------------------------------------------------------------------------*/ +static struct platform_device the_hcd_pdev = { + .name = (char *) driver_name, + .id = -1, + .dev = { + .release = dummy_hcd_release, + }, +}; static int __init init (void) { @@ -1779,17 +1792,39 @@ static int __init init (void) if (usb_disabled ()) return -ENODEV; - if ((retval = dummy_pdev_detect ()) != 0) + + retval = driver_register (&dummy_hcd_driver); + if (retval < 0) return retval; - if ((retval = dummy_probe (&the_pdev.dev)) != 0) - dummy_pdev_remove (); + + retval = driver_register (&dummy_udc_driver); + if (retval < 0) + goto err_register_udc_driver; + + retval = platform_device_register (&the_hcd_pdev); + if (retval < 0) + goto err_register_hcd; + + retval = platform_device_register (&the_udc_pdev); + if (retval < 0) + goto err_register_udc; + return retval; + +err_register_udc: + platform_device_unregister (&the_hcd_pdev); +err_register_hcd: + driver_unregister (&dummy_udc_driver); +err_register_udc_driver: + driver_unregister (&dummy_hcd_driver); return retval; } module_init (init); static void __exit cleanup (void) { - dummy_remove (&the_pdev.dev); - dummy_pdev_remove (); + platform_device_unregister (&the_udc_pdev); + platform_device_unregister (&the_hcd_pdev); + driver_unregister (&dummy_udc_driver); + driver_unregister (&dummy_hcd_driver); } module_exit (cleanup); -- cgit v1.2.3 From f1c39fad7d1bbea31744138cd3a532ff346cd4ab Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 May 2005 16:24:04 -0400 Subject: [PATCH] USB dummy_hcd: Centralize link state computations This patch adds to the dummy_hcd driver a new routine for keeping track of all changes in the state of the emulated USB link. The logic is now kept in one spot instead of spread around, and it's easier to verify and update the code. The behavior of the port features has been corrected in a few respects as well (for instance, if the POWER feature is clear then none of the other features can be set). Also added is support for the (relatively new) _connect() and _disconnect() calls of the Gadget API. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 254 ++++++++++++++++++++++++++--------------- 1 file changed, 162 insertions(+), 92 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index dc0e3233b0e9..2d6d22951326 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -163,12 +163,16 @@ struct dummy { struct dummy_request fifo_req; u8 fifo_buf [FIFO_SIZE]; u16 devstatus; + unsigned pullup:1; + unsigned active:1; + unsigned old_active:1; /* * MASTER/HOST side support */ struct timer_list timer; u32 port_status; + u32 old_status; unsigned resuming:1; unsigned long re_timeout; @@ -215,6 +219,98 @@ static struct dummy *the_controller; /*-------------------------------------------------------------------------*/ +/* SLAVE/GADGET SIDE UTILITY ROUTINES */ + +/* called with spinlock held */ +static void nuke (struct dummy *dum, struct dummy_ep *ep) +{ + while (!list_empty (&ep->queue)) { + struct dummy_request *req; + + req = list_entry (ep->queue.next, struct dummy_request, queue); + list_del_init (&req->queue); + req->req.status = -ESHUTDOWN; + + spin_unlock (&dum->lock); + req->req.complete (&ep->ep, &req->req); + spin_lock (&dum->lock); + } +} + +/* caller must hold lock */ +static void +stop_activity (struct dummy *dum) +{ + struct dummy_ep *ep; + + /* prevent any more requests */ + dum->address = 0; + + /* The timer is left running so that outstanding URBs can fail */ + + /* nuke any pending requests first, so driver i/o is quiesced */ + list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) + nuke (dum, ep); + + /* driver now does any non-usb quiescing necessary */ +} + +/* caller must hold lock */ +static void +set_link_state (struct dummy *dum) +{ + dum->active = 0; + if ((dum->port_status & USB_PORT_STAT_POWER) == 0) + dum->port_status = 0; + else if (!dum->pullup) { + dum->port_status &= ~(USB_PORT_STAT_CONNECTION | + USB_PORT_STAT_ENABLE | + USB_PORT_STAT_LOW_SPEED | + USB_PORT_STAT_HIGH_SPEED | + USB_PORT_STAT_SUSPEND); + if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0) + dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); + } else { + dum->port_status |= USB_PORT_STAT_CONNECTION; + if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0) + dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); + if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0) + dum->port_status &= ~USB_PORT_STAT_SUSPEND; + else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0) + dum->active = 1; + } + + if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active) + dum->resuming = 0; + + if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 || + (dum->port_status & USB_PORT_STAT_RESET) != 0) { + if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 && + (dum->old_status & USB_PORT_STAT_RESET) == 0 && + dum->driver) { + stop_activity (dum); + spin_unlock (&dum->lock); + dum->driver->disconnect (&dum->gadget); + spin_lock (&dum->lock); + } + } else if (dum->active != dum->old_active) { + if (dum->old_active && dum->driver->suspend) { + spin_unlock (&dum->lock); + dum->driver->suspend (&dum->gadget); + spin_lock (&dum->lock); + } else if (!dum->old_active && dum->driver->resume) { + spin_unlock (&dum->lock); + dum->driver->resume (&dum->gadget); + spin_lock (&dum->lock); + } + } + + dum->old_status = dum->port_status; + dum->old_active = dum->active; +} + +/*-------------------------------------------------------------------------*/ + /* SLAVE/GADGET SIDE DRIVER * * This only tracks gadget state. All the work is done when the host @@ -339,22 +435,6 @@ done: return retval; } -/* called with spinlock held */ -static void nuke (struct dummy *dum, struct dummy_ep *ep) -{ - while (!list_empty (&ep->queue)) { - struct dummy_request *req; - - req = list_entry (ep->queue.next, struct dummy_request, queue); - list_del_init (&req->queue); - req->req.status = -ESHUTDOWN; - - spin_unlock (&dum->lock); - req->req.complete (&ep->ep, &req->req); - spin_lock (&dum->lock); - } -} - static int dummy_disable (struct usb_ep *_ep) { struct dummy_ep *ep; @@ -603,7 +683,7 @@ static int dummy_wakeup (struct usb_gadget *_gadget) /* hub notices our request, issues downstream resume, etc */ dum->resuming = 1; - dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); + dum->re_timeout = jiffies + msecs_to_jiffies(20); return 0; } @@ -619,10 +699,24 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) return 0; } +static int dummy_pullup (struct usb_gadget *_gadget, int value) +{ + struct dummy *dum; + unsigned long flags; + + dum = gadget_to_dummy (_gadget); + spin_lock_irqsave (&dum->lock, flags); + dum->pullup = (value != 0); + set_link_state (dum); + spin_unlock_irqrestore (&dum->lock, flags); + return 0; +} + static const struct usb_gadget_ops dummy_ops = { .get_frame = dummy_g_get_frame, .wakeup = dummy_wakeup, .set_selfpowered = dummy_set_selfpowered, + .pullup = dummy_pullup, }; /*-------------------------------------------------------------------------*/ @@ -675,7 +769,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) */ dum->devstatus = 0; - dum->resuming = 0; INIT_LIST_HEAD (&dum->gadget.ep_list); for (i = 0; i < DUMMY_ENDPOINTS; i++) { @@ -714,35 +807,14 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) device_bind_driver (&dum->gadget.dev); /* khubd will enumerate this in a while */ - dum->port_status |= USB_PORT_STAT_CONNECTION - | (USB_PORT_STAT_C_CONNECTION << 16); + spin_lock_irq (&dum->lock); + dum->pullup = 1; + set_link_state (dum); + spin_unlock_irq (&dum->lock); return 0; } EXPORT_SYMBOL (usb_gadget_register_driver); -/* caller must hold lock */ -static void -stop_activity (struct dummy *dum, struct usb_gadget_driver *driver) -{ - struct dummy_ep *ep; - - /* prevent any more requests */ - dum->address = 0; - - /* The timer is left running so that outstanding URBs can fail */ - - /* nuke any pending requests first, so driver i/o is quiesced */ - list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) - nuke (dum, ep); - - /* driver now does any non-usb quiescing necessary */ - if (driver) { - spin_unlock (&dum->lock); - driver->disconnect (&dum->gadget); - spin_lock (&dum->lock); - } -} - int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) { @@ -758,10 +830,8 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) driver->driver.name); spin_lock_irqsave (&dum->lock, flags); - stop_activity (dum, driver); - dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | - USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); - dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); + dum->pullup = 0; + set_link_state (dum); spin_unlock_irqrestore (&dum->lock, flags); driver->unbind (&dum->gadget); @@ -770,6 +840,11 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) device_release_driver (&dum->gadget.dev); driver_unregister (&driver->driver); + spin_lock_irqsave (&dum->lock, flags); + dum->pullup = 0; + set_link_state (dum); + spin_unlock_irqrestore (&dum->lock, flags); + return 0; } EXPORT_SYMBOL (usb_gadget_unregister_driver); @@ -1432,6 +1507,13 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf) dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); + + if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { + dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); + dum->port_status &= ~USB_PORT_STAT_SUSPEND; + set_link_state (dum); + } + if (!(dum->port_status & PORT_C_MASK)) retval = 0; else { @@ -1480,16 +1562,16 @@ static int dummy_hub_control ( /* 20msec resume signaling */ dum->resuming = 1; dum->re_timeout = jiffies + - msecs_to_jiffies(20); + msecs_to_jiffies(20); } break; case USB_PORT_FEAT_POWER: - dum->port_status = 0; - dum->resuming = 0; - stop_activity(dum, dum->driver); - break; + if (dum->port_status & USB_PORT_STAT_POWER) + dev_dbg (dummy_dev(dum), "power-off\n"); + /* FALLS THROUGH */ default: dum->port_status &= ~(1 << wValue); + set_link_state (dum); } break; case GetHubDescriptor: @@ -1505,23 +1587,16 @@ static int dummy_hub_control ( /* whoever resets or resumes must GetPortStatus to * complete it!! */ - if (dum->resuming && time_after (jiffies, dum->re_timeout)) { + if (dum->resuming && + time_after_eq (jiffies, dum->re_timeout)) { dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); dum->port_status &= ~USB_PORT_STAT_SUSPEND; - dum->resuming = 0; - dum->re_timeout = 0; - if (dum->driver && dum->driver->resume) { - spin_unlock (&dum->lock); - dum->driver->resume (&dum->gadget); - spin_lock (&dum->lock); - } } - if ((dum->port_status & USB_PORT_STAT_RESET) != 0 - && time_after (jiffies, dum->re_timeout)) { + if ((dum->port_status & USB_PORT_STAT_RESET) != 0 && + time_after_eq (jiffies, dum->re_timeout)) { dum->port_status |= (USB_PORT_STAT_C_RESET << 16); dum->port_status &= ~USB_PORT_STAT_RESET; - dum->re_timeout = 0; - if (dum->driver) { + if (dum->pullup) { dum->port_status |= USB_PORT_STAT_ENABLE; /* give it the best speed we agree on */ dum->gadget.speed = dum->driver->speed; @@ -1542,6 +1617,7 @@ static int dummy_hub_control ( } } } + set_link_state (dum); ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status); ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); break; @@ -1551,42 +1627,36 @@ static int dummy_hub_control ( case SetPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - if ((dum->port_status & USB_PORT_STAT_SUSPEND) - == 0) { + if (dum->active) { dum->port_status |= USB_PORT_STAT_SUSPEND; - if (dum->driver && dum->driver->suspend) { - spin_unlock (&dum->lock); - dum->driver->suspend (&dum->gadget); - spin_lock (&dum->lock); - /* HNP would happen here; for now we - * assume b_bus_req is always true. - */ - if (((1 << USB_DEVICE_B_HNP_ENABLE) - & dum->devstatus) != 0) - dev_dbg (dummy_dev(dum), + + /* HNP would happen here; for now we + * assume b_bus_req is always true. + */ + set_link_state (dum); + if (((1 << USB_DEVICE_B_HNP_ENABLE) + & dum->devstatus) != 0) + dev_dbg (dummy_dev(dum), "no HNP yet!\n"); - } } break; + case USB_PORT_FEAT_POWER: + dum->port_status |= USB_PORT_STAT_POWER; + set_link_state (dum); + break; case USB_PORT_FEAT_RESET: - /* if it's already running, disconnect first */ - if (dum->port_status & USB_PORT_STAT_ENABLE) { - dum->port_status &= ~(USB_PORT_STAT_ENABLE - | USB_PORT_STAT_LOW_SPEED - | USB_PORT_STAT_HIGH_SPEED); - if (dum->driver) { - dev_dbg (udc_dev(dum), - "disconnect\n"); - stop_activity (dum, dum->driver); - } - - /* FIXME test that code path! */ - } + /* if it's already enabled, disable */ + dum->port_status &= ~(USB_PORT_STAT_ENABLE + | USB_PORT_STAT_LOW_SPEED + | USB_PORT_STAT_HIGH_SPEED); /* 50msec reset signaling */ dum->re_timeout = jiffies + msecs_to_jiffies(50); - /* FALLTHROUGH */ + /* FALLS THROUGH */ default: - dum->port_status |= (1 << wValue); + if ((dum->port_status & USB_PORT_STAT_POWER) != 0) { + dum->port_status |= (1 << wValue); + set_link_state (dum); + } } break; -- cgit v1.2.3 From 685eb93f086eb15d9fb1e82c7400fd750f564640 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 May 2005 16:27:26 -0400 Subject: [PATCH] USB dummy_hcd: Use root-hub interrupts instead of polling This patch makes the dummy_hcd driver use emulated root-hub interrupts instead of polling. It's in the spirit of similar changes being made to the other HCDs. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 2d6d22951326..73d2f24050ab 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -684,6 +684,7 @@ static int dummy_wakeup (struct usb_gadget *_gadget) /* hub notices our request, issues downstream resume, etc */ dum->resuming = 1; dum->re_timeout = jiffies + msecs_to_jiffies(20); + mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout); return 0; } @@ -709,6 +710,8 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value) dum->pullup = (value != 0); set_link_state (dum); spin_unlock_irqrestore (&dum->lock, flags); + + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } @@ -811,6 +814,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) dum->pullup = 1; set_link_state (dum); spin_unlock_irq (&dum->lock); + + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -845,6 +850,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) set_link_state (dum); spin_unlock_irqrestore (&dum->lock, flags); + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } EXPORT_SYMBOL (usb_gadget_unregister_driver); @@ -1669,6 +1675,9 @@ static int dummy_hub_control ( retval = -EPIPE; } spin_unlock_irqrestore (&dum->lock, flags); + + if ((dum->port_status & PORT_C_MASK) != 0) + usb_hcd_poll_rh_status (hcd); return retval; } @@ -1745,6 +1754,7 @@ static int dummy_start (struct usb_hcd *hcd) /* only show a low-power port: just 8mA */ hcd->power_budget = 8; hcd->state = HC_STATE_RUNNING; + hcd->uses_new_polling = 1; #ifdef CONFIG_USB_OTG hcd->self.otg_port = 1; -- cgit v1.2.3 From 028b271b687714f9fc7a1e89bb79f1fbeef154ee Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 6 May 2005 07:02:01 -0700 Subject: [PATCH] USB: Kconfig fixes for usb/gadget This prevents gadget drivers from being selected when no controller has been selected, by adding an additional boolean and depending on it. It's mostly to help "allmodconfig". Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3b24f9f2c234..ff075a53c8d6 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -53,6 +53,9 @@ config USB_GADGET_DEBUG_FILES driver on a new board. Enable these files by choosing "Y" here. If in doubt, or to conserve kernel memory, say "N". +config USB_GADGET_SELECTED + boolean + # # USB Peripheral Controller Support # @@ -85,6 +88,7 @@ config USB_NET2280 tristate depends on USB_GADGET_NET2280 default USB_GADGET + select USB_GADGET_SELECTED config USB_GADGET_PXA2XX boolean "PXA 25x or IXP 4xx" @@ -105,6 +109,7 @@ config USB_PXA2XX tristate depends on USB_GADGET_PXA2XX default USB_GADGET + select USB_GADGET_SELECTED # if there's only one gadget driver, using only two bulk endpoints, # don't waste memory for the other endpoints @@ -134,6 +139,7 @@ config USB_GOKU tristate depends on USB_GADGET_GOKU default USB_GADGET + select USB_GADGET_SELECTED config USB_GADGET_LH7A40X @@ -146,6 +152,7 @@ config USB_LH7A40X tristate depends on USB_GADGET_LH7A40X default USB_GADGET + select USB_GADGET_SELECTED config USB_GADGET_OMAP @@ -167,6 +174,7 @@ config USB_OMAP tristate depends on USB_GADGET_OMAP default USB_GADGET + select USB_GADGET_SELECTED config USB_OTG boolean "OTG Support" @@ -207,6 +215,7 @@ config USB_DUMMY_HCD tristate depends on USB_GADGET_DUMMY_HCD default USB_GADGET + select USB_GADGET_SELECTED # NOTE: Please keep dummy_hcd LAST so that "real hardware" appears # first and will be selected by default. @@ -226,7 +235,7 @@ config USB_GADGET_DUALSPEED # choice tristate "USB Gadget Drivers" - depends on USB_GADGET + depends on USB_GADGET && USB_GADGET_SELECTED default USB_ETH help A Linux "Gadget Driver" talks to the USB Peripheral Controller -- cgit v1.2.3 From 1bbc169621cbe502b9143a27eb12802a0f1d43a0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 May 2005 13:05:13 -0700 Subject: [PATCH] USB: gadget driver updates (SETUP api change) This updates most of the gadget framework to expect SETUP packets use USB byteorder (matching the annotation in and usage in the host side stack): - definition in - gadget drivers: Ethernet/RNDIS, serial/ACM, file_storage, gadgetfs. - dummy_hcd It also includes some other similar changes as suggested by "sparse", which was used to detect byteorder bugs. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 3 --- drivers/usb/gadget/ether.c | 6 +++--- drivers/usb/gadget/file_storage.c | 19 +++++++++---------- drivers/usb/gadget/inode.c | 12 ++++++------ drivers/usb/gadget/serial.c | 36 +++++++++++++++++++----------------- drivers/usb/gadget/zero.c | 6 +++--- include/linux/usb_gadget.h | 2 +- 7 files changed, 41 insertions(+), 43 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 73d2f24050ab..f9540adf2a4f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1267,9 +1267,6 @@ restart: struct dummy_ep *ep2; setup = *(struct usb_ctrlrequest*) urb->setup_packet; - le16_to_cpus (&setup.wIndex); - le16_to_cpus (&setup.wValue); - le16_to_cpus (&setup.wLength); if (setup.wLength != urb->transfer_buffer_length) { maybe_set_status (urb, -EOVERFLOW); goto return_urb; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 3830a0a0fd50..9f8413e3c10a 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1277,9 +1277,9 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct eth_dev *dev = get_gadget_data (gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; - u16 wIndex = (__force u16) ctrl->wIndex; - u16 wValue = (__force u16) ctrl->wValue; - u16 wLength = (__force u16) ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); /* descriptors just go into the pre-allocated ep0 buffer, * while config change events may enable network traffic. diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index f5ce45c4b2a3..4f57085619b4 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -819,7 +819,7 @@ static void inline put_be32(u8 *buf, u32 val) buf[0] = val >> 24; buf[1] = val >> 16; buf[2] = val >> 8; - buf[3] = val; + buf[3] = val & 0xff; } @@ -1277,8 +1277,8 @@ static int class_setup_req(struct fsg_dev *fsg, { struct usb_request *req = fsg->ep0req; int value = -EOPNOTSUPP; - u16 w_index = ctrl->wIndex; - u16 w_length = ctrl->wLength; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_length = le16_to_cpu(ctrl->wLength); if (!fsg->config) return value; @@ -1345,7 +1345,7 @@ static int class_setup_req(struct fsg_dev *fsg, "unknown class-specific control req " "%02x.%02x v%04x i%04x l%u\n", ctrl->bRequestType, ctrl->bRequest, - ctrl->wValue, w_index, w_length); + le16_to_cpu(ctrl->wValue), w_index, w_length); return value; } @@ -1359,8 +1359,8 @@ static int standard_setup_req(struct fsg_dev *fsg, { struct usb_request *req = fsg->ep0req; int value = -EOPNOTSUPP; - u16 w_index = ctrl->wIndex; - u16 w_value = ctrl->wValue; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); /* Usually this just stores reply data in the pre-allocated ep0 buffer, * but config change events will also reconfigure hardware. */ @@ -1469,7 +1469,7 @@ static int standard_setup_req(struct fsg_dev *fsg, VDBG(fsg, "unknown control req %02x.%02x v%04x i%04x l%u\n", ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, ctrl->wLength); + w_value, w_index, le16_to_cpu(ctrl->wLength)); } return value; @@ -1481,7 +1481,7 @@ static int fsg_setup(struct usb_gadget *gadget, { struct fsg_dev *fsg = get_gadget_data(gadget); int rc; - int w_length = ctrl->wLength; + int w_length = le16_to_cpu(ctrl->wLength); ++fsg->ep0_req_tag; // Record arrival of a new request fsg->ep0req->context = NULL; @@ -1497,8 +1497,7 @@ static int fsg_setup(struct usb_gadget *gadget, if (rc >= 0 && rc != DELAYED_STATUS) { rc = min(rc, w_length); fsg->ep0req->length = rc; - fsg->ep0req->zero = (rc < w_length && - (rc % gadget->ep0->maxpacket) == 0); + fsg->ep0req->zero = rc < w_length; fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); rc = ep0_queue(fsg); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 1e5e6ddef787..020815397a49 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -417,8 +417,8 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) goto free1; value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s read %d OUT, status %d\n", - data->name, len, value); + VDEBUG (data->dev, "%s read %zu OUT, status %d\n", + data->name, len, (int) value); if (value >= 0 && copy_to_user (buf, kbuf, value)) value = -EFAULT; @@ -465,8 +465,8 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) } value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s write %d IN, status %d\n", - data->name, len, value); + VDEBUG (data->dev, "%s write %zu IN, status %d\n", + data->name, len, (int) value); free1: up (&data->lock); kfree (kbuf); @@ -1318,8 +1318,8 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct usb_request *req = dev->req; int value = -EOPNOTSUPP; struct usb_gadgetfs_event *event; - u16 w_value = ctrl->wValue; - u16 w_length = ctrl->wLength; + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); spin_lock (&dev->lock); dev->setup_abort = 0; diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 4d591c764e38..9e4f1c6935a5 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -300,18 +300,18 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, - int kmalloc_flags); + unsigned kmalloc_flags); static void gs_free_req(struct usb_ep *ep, struct usb_request *req); static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, - int kmalloc_flags); + unsigned kmalloc_flags); static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req); -static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags); +static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags); static void gs_free_ports(struct gs_dev *dev); /* circular buffer */ -static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags); +static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags); static void gs_buf_free(struct gs_buf *gb); static void gs_buf_clear(struct gs_buf *gb); static unsigned int gs_buf_data_avail(struct gs_buf *gb); @@ -1607,9 +1607,9 @@ static int gs_setup(struct usb_gadget *gadget, int ret = -EOPNOTSUPP; struct gs_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->dev_ctrl_req; - u16 wIndex = ctrl->wIndex; - u16 wValue = ctrl->wValue; - u16 wLength = ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); switch (ctrl->bRequestType & USB_TYPE_MASK) { case USB_TYPE_STANDARD: @@ -1651,9 +1651,9 @@ static int gs_setup_standard(struct usb_gadget *gadget, int ret = -EOPNOTSUPP; struct gs_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->dev_ctrl_req; - u16 wIndex = ctrl->wIndex; - u16 wValue = ctrl->wValue; - u16 wLength = ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: @@ -1782,9 +1782,9 @@ static int gs_setup_class(struct usb_gadget *gadget, struct gs_dev *dev = get_gadget_data(gadget); struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */ struct usb_request *req = dev->dev_ctrl_req; - u16 wIndex = ctrl->wIndex; - u16 wValue = ctrl->wValue; - u16 wLength = ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); switch (ctrl->bRequest) { case USB_CDC_REQ_SET_LINE_CODING: @@ -2119,7 +2119,8 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, * Allocate a usb_request and its buffer. Returns a pointer to the * usb_request or NULL if there is an error. */ -static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int kmalloc_flags) +static struct usb_request * +gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags) { struct usb_request *req; @@ -2159,7 +2160,8 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req) * Allocates a request and its buffer, using the given * endpoint, buffer len, and kmalloc flags. */ -static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, int kmalloc_flags) +static struct gs_req_entry * +gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags) { struct gs_req_entry *req; @@ -2200,7 +2202,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req) * * The device lock is normally held when calling this function. */ -static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags) +static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags) { int i; struct gs_port *port; @@ -2282,7 +2284,7 @@ static void gs_free_ports(struct gs_dev *dev) * * Allocate a circular buffer and all associated memory. */ -static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags) +static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags) { struct gs_buf *gb; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 6e49432071a1..a6e035e24479 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -919,9 +919,9 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct zero_dev *dev = get_gadget_data (gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; - u16 w_index = ctrl->wIndex; - u16 w_value = ctrl->wValue; - u16 w_length = ctrl->wLength; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); /* usually this stores reply data in the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index 9bba9997947b..b00f127cb447 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -711,7 +711,7 @@ usb_gadget_disconnect (struct usb_gadget *gadget) * the hardware level driver. Most calls must be handled by * the gadget driver, including descriptor and configuration * management. The 16 bit members of the setup data are in - * cpu order. Called in_interrupt; this may not sleep. Driver + * USB byte order. Called in_interrupt; this may not sleep. Driver * queues a response to ep0, or returns negative to stall. * @disconnect: Invoked after all transfers have been stopped, * when the host is disconnected. May be called in_interrupt; this -- cgit v1.2.3 From 320f34595c3cf37d180a087a935c050e4ac0e4d5 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 May 2005 13:05:18 -0700 Subject: [PATCH] USB: net2280 updates (sparse, SETUP api change) This is mostly "sparse" related updates, one of which was a missing le32_to_cpu() should have affected big-endian hardware. Notable is the API change: setup packets are now provided in USB byte order. This affects only big-endian hardware, and the gadget drivers have been updated in a separate patch. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/net2280.c | 51 +++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 22 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index e47e398daeb5..13a3dbc9949b 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -448,7 +448,7 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req) #elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) #define USE_KMALLOC -#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO) +#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT) #define USE_KMALLOC /* FIXME there are other cases, including an x86-64 one ... */ @@ -1113,7 +1113,7 @@ static void restart_dma (struct net2280_ep *ep) if (ep->in_fifo_validate) dmactl |= (1 << DMA_FIFO_VALIDATE); list_for_each_entry (entry, &ep->queue, queue) { - u32 dmacount; + __le32 dmacount; if (entry == req) continue; @@ -1238,7 +1238,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) &ep->dma->dmadesc); if (req->td->dmacount & dma_done_ie) writel (readl (&ep->dma->dmacount) - | dma_done_ie, + | le32_to_cpu(dma_done_ie), &ep->dma->dmacount); } else { struct net2280_request *prev; @@ -1779,6 +1779,9 @@ static void set_fifo_mode (struct net2280 *dev, int mode) list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list); } +/* just declare this in any driver that really need it */ +extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); + /** * net2280_set_fifo_mode - change allocation of fifo buffers * @gadget: access to the net2280 device that will be updated @@ -2382,9 +2385,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) cpu_to_le32s (&u.raw [0]); cpu_to_le32s (&u.raw [1]); - le16_to_cpus (&u.r.wValue); - le16_to_cpus (&u.r.wIndex); - le16_to_cpus (&u.r.wLength); +#define w_value le16_to_cpup (&u.r.wValue) +#define w_index le16_to_cpup (&u.r.wIndex) +#define w_length le16_to_cpup (&u.r.wLength) /* ack the irq */ writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0); @@ -2413,25 +2416,25 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) switch (u.r.bRequest) { case USB_REQ_GET_STATUS: { struct net2280_ep *e; - u16 status; + __le32 status; /* hw handles device and interface status */ if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) goto delegate; - if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0 - || u.r.wLength > 2) + if ((e = get_ep_by_addr (dev, w_index)) == 0 + || w_length > 2) goto do_stall; if (readl (&e->regs->ep_rsp) & (1 << SET_ENDPOINT_HALT)) - status = __constant_cpu_to_le16 (1); + status = __constant_cpu_to_le32 (1); else - status = __constant_cpu_to_le16 (0); + status = __constant_cpu_to_le32 (0); /* don't bother with a request object! */ writel (0, &dev->epregs [0].ep_irqenb); - set_fifo_bytecount (ep, u.r.wLength); - writel (status, &dev->epregs [0].ep_data); + set_fifo_bytecount (ep, w_length); + writel ((__force u32)status, &dev->epregs [0].ep_data); allow_status (ep); VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status); goto next_endpoints; @@ -2443,10 +2446,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) + if ((e = get_ep_by_addr (dev, w_index)) == 0) goto do_stall; clear_halt (e); allow_status (ep); @@ -2460,10 +2463,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) + if ((e = get_ep_by_addr (dev, w_index)) == 0) goto do_stall; set_halt (e); allow_status (ep); @@ -2473,10 +2476,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) break; default: delegate: - VDEBUG (dev, "setup %02x.%02x v%04x i%04x " + VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x" "ep_cfg %08x\n", u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, + w_value, w_index, w_length, readl (&ep->regs->ep_cfg)); spin_unlock (&dev->lock); tmp = dev->driver->setup (&dev->gadget, &u.r); @@ -2497,6 +2500,10 @@ do_stall: */ } +#undef w_value +#undef w_index +#undef w_length + next_endpoints: /* endpoint data irq ? */ scratch = stat & 0x7f; @@ -2653,7 +2660,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) restart_dma (ep); else if (ep->is_in && use_dma_chaining) { struct net2280_request *req; - u32 dmacount; + __le32 dmacount; /* the descriptor at the head of the chain * may still have VALID_BIT clear; that's -- cgit v1.2.3 From 988199fe34411b413d5a388fc751c91eb4686f36 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 May 2005 13:05:52 -0700 Subject: [PATCH] USB: goku_udc updates (sparse, SETUP api change) Sparse updates; and the API change for SETUP packets being in USB byteorder. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/goku_udc.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 005db7cca292..ed773a9111de 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -70,7 +70,7 @@ MODULE_LICENSE("GPL"); * seem to behave quite as expected. Used by default. * * OUT dma documents design problems handling the common "short packet" - * transfer termination policy; it couldn't enabled by default, even + * transfer termination policy; it couldn't be enabled by default, even * if the OUT-dma abort problems had a resolution. */ static unsigned use_dma = 1; @@ -313,7 +313,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req) #if defined(CONFIG_X86) #define USE_KMALLOC -#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO) +#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT) #define USE_KMALLOC #elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) @@ -1524,9 +1524,12 @@ static void ep0_setup(struct goku_udc *dev) /* read SETUP packet and enter DATA stage */ ctrl.bRequestType = readl(®s->bRequestType); ctrl.bRequest = readl(®s->bRequest); - ctrl.wValue = (readl(®s->wValueH) << 8) | readl(®s->wValueL); - ctrl.wIndex = (readl(®s->wIndexH) << 8) | readl(®s->wIndexL); - ctrl.wLength = (readl(®s->wLengthH) << 8) | readl(®s->wLengthL); + ctrl.wValue = cpu_to_le16((readl(®s->wValueH) << 8) + | readl(®s->wValueL)); + ctrl.wIndex = cpu_to_le16((readl(®s->wIndexH) << 8) + | readl(®s->wIndexL)); + ctrl.wLength = cpu_to_le16((readl(®s->wLengthH) << 8) + | readl(®s->wLengthL)); writel(0, ®s->SetupRecv); nuke(&dev->ep[0], 0); @@ -1548,18 +1551,20 @@ static void ep0_setup(struct goku_udc *dev) case USB_REQ_CLEAR_FEATURE: switch (ctrl.bRequestType) { case USB_RECIP_ENDPOINT: - tmp = ctrl.wIndex & 0x0f; + tmp = le16_to_cpu(ctrl.wIndex) & 0x0f; /* active endpoint */ if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0)) goto stall; - if (ctrl.wIndex & USB_DIR_IN) { + if (ctrl.wIndex & __constant_cpu_to_le16( + USB_DIR_IN)) { if (!dev->ep[tmp].is_in) goto stall; } else { if (dev->ep[tmp].is_in) goto stall; } - if (ctrl.wValue != USB_ENDPOINT_HALT) + if (ctrl.wValue != __constant_cpu_to_le16( + USB_ENDPOINT_HALT)) goto stall; if (tmp) goku_clear_halt(&dev->ep[tmp]); @@ -1571,7 +1576,7 @@ succeed: return; case USB_RECIP_DEVICE: /* device remote wakeup: always clear */ - if (ctrl.wValue != 1) + if (ctrl.wValue != __constant_cpu_to_le16(1)) goto stall; VDBG(dev, "clear dev remote wakeup\n"); goto succeed; @@ -1589,14 +1594,15 @@ succeed: #ifdef USB_TRACE VDBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", ctrl.bRequestType, ctrl.bRequest, - ctrl.wValue, ctrl.wIndex, ctrl.wLength); + le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex), + le16_to_cpu(ctrl.wLength)); #endif /* hw wants to know when we're configured (or not) */ dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION && ctrl.bRequestType == USB_RECIP_DEVICE); if (unlikely(dev->req_config)) - dev->configured = (ctrl.wValue != 0); + dev->configured = (ctrl.wValue != __constant_cpu_to_le16(0)); /* delegate everything to the gadget driver. * it may respond after this irq handler returns. -- cgit v1.2.3 From 9198769363d4dc1d63d49ecb2e2b189aceb42d94 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 May 2005 13:20:19 -0700 Subject: [PATCH] USB: pxa2xx_udc updates This has several small updates to the px2xx UDC driver: * small fixes from Eugeny S. Mints - local_irq_save() around potential endpoint disable race - fix handling of enqueue to OUT endpoints (potential oops) * add shutdown() method to disable any D+ pullup * rename methods accessing raw signals, referencing the signals * describes itself as for "pxa25x", since pxa27x is different Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pxa2xx_udc.c | 43 ++++++++++++++++++++++++++--------------- drivers/usb/gadget/pxa2xx_udc.h | 10 +++++----- 2 files changed, 32 insertions(+), 21 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index b8b4524ed746..6a0b957af335 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -1,6 +1,6 @@ /* * linux/drivers/usb/gadget/pxa2xx_udc.c - * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers + * Intel PXA25x and IXP4xx on-chip full speed USB device controllers * * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) * Copyright (C) 2003 Robert Schwebel, Pengutronix @@ -63,7 +63,7 @@ /* - * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx + * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x * series processors. The UDC for the IXP 4xx series is very similar. * There are fifteen endpoints, in addition to ep0. * @@ -79,8 +79,8 @@ * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. */ -#define DRIVER_VERSION "14-Dec-2003" -#define DRIVER_DESC "PXA 2xx USB Device Controller driver" +#define DRIVER_VERSION "4-May-2005" +#define DRIVER_DESC "PXA 25x USB Device Controller driver" static const char driver_name [] = "pxa2xx_udc"; @@ -290,6 +290,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, static int pxa2xx_ep_disable (struct usb_ep *_ep) { struct pxa2xx_ep *ep; + unsigned long flags; ep = container_of (_ep, struct pxa2xx_ep, ep); if (!_ep || !ep->desc) { @@ -297,6 +298,8 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) _ep ? ep->ep.name : NULL); return -EINVAL; } + local_irq_save(flags); + nuke (ep, -ESHUTDOWN); #ifdef USE_DMA @@ -313,6 +316,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) ep->desc = NULL; ep->stopped = 1; + local_irq_restore(flags); DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); return 0; } @@ -971,10 +975,10 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) kick_dma(ep, req); #endif /* can the FIFO can satisfy the request immediately? */ - } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0 - && (*ep->reg_udccs & UDCCS_BI_TFS) != 0 - && write_fifo(ep, req)) { - req = NULL; + } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { + if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0 + && write_fifo(ep, req)) + req = NULL; } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0 && read_fifo(ep, req)) { req = NULL; @@ -1290,7 +1294,7 @@ udc_proc_read(char *page, char **start, off_t off, int count, "%s version: %s\nGadget driver: %s\nHost %s\n\n", driver_name, DRIVER_VERSION SIZE_STR DMASTR, dev->driver ? dev->driver->driver.name : "(none)", - is_usb_connected() ? "full speed" : "disconnected"); + is_vbus_present() ? "full speed" : "disconnected"); size -= t; next += t; @@ -1339,7 +1343,7 @@ udc_proc_read(char *page, char **start, off_t off, int count, next += t; } - if (!is_usb_connected() || !dev->driver) + if (!is_vbus_present() || !dev->driver) goto done; t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", @@ -1454,7 +1458,7 @@ static void udc_disable(struct pxa2xx_udc *dev) UFNRH = UFNRH_SIM; /* if hardware supports it, disconnect from usb */ - make_usb_disappear(); + pullup_off(); udc_clear_mask_UDCCR(UDCCR_UDE); @@ -1567,7 +1571,7 @@ static void udc_enable (struct pxa2xx_udc *dev) UICR0 &= ~UICR0_IM0; /* if hardware supports it, pullup D+ and wait for reset */ - let_usb_appear(); + pullup_on(); } @@ -2052,10 +2056,10 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r) if (unlikely(udccr & UDCCR_SUSIR)) { udc_ack_int_UDCCR(UDCCR_SUSIR); handled = 1; - DBG(DBG_VERBOSE, "USB suspend%s\n", is_usb_connected() + DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present() ? "" : "+disconnect"); - if (!is_usb_connected()) + if (!is_vbus_present()) stop_activity(dev, dev->driver); else if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver @@ -2073,7 +2077,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r) if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->resume - && is_usb_connected()) + && is_vbus_present()) dev->driver->resume(&dev->gadget); } @@ -2509,7 +2513,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev) udc_disable(dev); udc_reinit(dev); - dev->vbus = is_usb_connected(); + dev->vbus = is_vbus_present(); /* irq setup after old hardware state is cleaned up */ retval = request_irq(IRQ_USB, pxa2xx_udc_irq, @@ -2555,6 +2559,12 @@ lubbock_fail0: return 0; } + +static void pxa2xx_udc_shutdown(struct device *_dev) +{ + pullup_off(); +} + static int __exit pxa2xx_udc_remove(struct device *_dev) { struct pxa2xx_udc *dev = dev_get_drvdata(_dev); @@ -2624,6 +2634,7 @@ static struct device_driver udc_driver = { .name = "pxa2xx-udc", .bus = &platform_bus_type, .probe = pxa2xx_udc_probe, + .shutdown = pxa2xx_udc_shutdown, .remove = __exit_p(pxa2xx_udc_remove), .suspend = pxa2xx_udc_suspend, .resume = pxa2xx_udc_resume, diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index 1f3a7d999da7..d0bc396a85d5 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -177,23 +177,23 @@ struct pxa2xx_udc { static struct pxa2xx_udc *the_controller; -/* one GPIO should be used to detect host disconnect */ -static inline int is_usb_connected(void) +/* one GPIO should be used to detect VBUS from the host */ +static inline int is_vbus_present(void) { if (!the_controller->mach->udc_is_connected) return 1; return the_controller->mach->udc_is_connected(); } -/* one GPIO should force the host to see this device (or not) */ -static inline void make_usb_disappear(void) +/* one GPIO should control a D+ pullup, so host sees this device (or not) */ +static inline void pullup_off(void) { if (!the_controller->mach->udc_command) return; the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); } -static inline void let_usb_appear(void) +static inline void pullup_on(void) { if (!the_controller->mach->udc_command) return; -- cgit v1.2.3 From cc095b0b5b653dca3e106710a72ba28b5bb7456b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 10 May 2005 15:28:38 -0400 Subject: [PATCH] USB: dummy_hcd: sparse cleanups This patch fixes the byte-ordering issue for setup packets in the dummy_hcd driver and cleans up a few things that sparse -Wbitwise dislikes. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index f9540adf2a4f..c78c64ae87af 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -734,7 +734,7 @@ show_function (struct device *dev, struct device_attribute *attr, char *buf) return 0; return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); } -DEVICE_ATTR (function, S_IRUGO, show_function, NULL); +static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); /*-------------------------------------------------------------------------*/ @@ -857,6 +857,9 @@ EXPORT_SYMBOL (usb_gadget_unregister_driver); #undef is_enabled +/* just declare this in any driver that really need it */ +extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); + int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) { return -ENOSYS; @@ -1122,7 +1125,6 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) /* high bandwidth mode */ tmp = le16_to_cpu(ep->desc->wMaxPacketSize); - tmp = le16_to_cpu (tmp); tmp = (tmp >> 11) & 0x03; tmp *= 8 /* applies to entire frame */; limit += limit * tmp; @@ -1265,9 +1267,14 @@ restart: struct usb_ctrlrequest setup; int value = 1; struct dummy_ep *ep2; + unsigned w_index; + unsigned w_value; setup = *(struct usb_ctrlrequest*) urb->setup_packet; - if (setup.wLength != urb->transfer_buffer_length) { + w_index = le16_to_cpu(setup.wIndex); + w_value = le16_to_cpu(setup.wValue); + if (le16_to_cpu(setup.wLength) != + urb->transfer_buffer_length) { maybe_set_status (urb, -EOVERFLOW); goto return_urb; } @@ -1297,16 +1304,16 @@ restart: case USB_REQ_SET_ADDRESS: if (setup.bRequestType != Dev_Request) break; - dum->address = setup.wValue; + dum->address = w_value; maybe_set_status (urb, 0); dev_dbg (udc_dev(dum), "set_address = %d\n", - setup.wValue); + w_value); value = 0; break; case USB_REQ_SET_FEATURE: if (setup.bRequestType == Dev_Request) { value = 0; - switch (setup.wValue) { + switch (w_value) { case USB_DEVICE_REMOTE_WAKEUP: break; case USB_DEVICE_B_HNP_ENABLE: @@ -1324,14 +1331,13 @@ restart: } if (value == 0) { dum->devstatus |= - (1 << setup.wValue); + (1 << w_value); maybe_set_status (urb, 0); } } else if (setup.bRequestType == Ep_Request) { // endpoint halt - ep2 = find_endpoint (dum, - setup.wIndex); + ep2 = find_endpoint (dum, w_index); if (!ep2) { value = -EOPNOTSUPP; break; @@ -1343,7 +1349,7 @@ restart: break; case USB_REQ_CLEAR_FEATURE: if (setup.bRequestType == Dev_Request) { - switch (setup.wValue) { + switch (w_value) { case USB_DEVICE_REMOTE_WAKEUP: dum->devstatus &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); @@ -1356,8 +1362,7 @@ restart: } } else if (setup.bRequestType == Ep_Request) { // endpoint halt - ep2 = find_endpoint (dum, - setup.wIndex); + ep2 = find_endpoint (dum, w_index); if (!ep2) { value = -EOPNOTSUPP; break; @@ -1383,7 +1388,7 @@ restart: if (urb->transfer_buffer_length > 0) { if (setup.bRequestType == Ep_InRequest) { - ep2 = find_endpoint (dum, setup.wIndex); + ep2 = find_endpoint (dum, w_index); if (!ep2) { value = -EOPNOTSUPP; break; @@ -1535,7 +1540,8 @@ hub_descriptor (struct usb_hub_descriptor *desc) memset (desc, 0, sizeof *desc); desc->bDescriptorType = 0x29; desc->bDescLength = 9; - desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001); + desc->wHubCharacteristics = (__force __u16) + (__constant_cpu_to_le16 (0x0001)); desc->bNbrPorts = 1; desc->bitmap [0] = 0xff; desc->bitmap [1] = 0xff; @@ -1581,7 +1587,7 @@ static int dummy_hub_control ( hub_descriptor ((struct usb_hub_descriptor *) buf); break; case GetHubStatus: - *(u32 *) buf = __constant_cpu_to_le32 (0); + *(__le32 *) buf = __constant_cpu_to_le32 (0); break; case GetPortStatus: if (wIndex != 1) @@ -1621,8 +1627,8 @@ static int dummy_hub_control ( } } set_link_state (dum); - ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status); - ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); + ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status); + ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); break; case SetHubFeature: retval = -EPIPE; -- cgit v1.2.3 From 391eca9d8892a940ff8dbfee2ca78942e05c2d37 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 10 May 2005 15:34:16 -0400 Subject: [PATCH] USB: dummy_hcd: add suspend/resume support This patch adds support to dummy_hcd for suspending and resuming the root hub and the emulated platform devices. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 179 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 162 insertions(+), 17 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c78c64ae87af..4d692670f288 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -65,7 +65,7 @@ #define DRIVER_DESC "USB Host+Gadget Emulator" -#define DRIVER_VERSION "17 Dec 2004" +#define DRIVER_VERSION "02 May 2005" static const char driver_name [] = "dummy_hcd"; static const char driver_desc [] = "USB Host+Gadget Emulator"; @@ -150,6 +150,13 @@ struct urbp { struct list_head urbp_list; }; + +enum dummy_rh_state { + DUMMY_RH_RESET, + DUMMY_RH_SUSPENDED, + DUMMY_RH_RUNNING +}; + struct dummy { spinlock_t lock; @@ -163,6 +170,7 @@ struct dummy { struct dummy_request fifo_req; u8 fifo_buf [FIFO_SIZE]; u16 devstatus; + unsigned udc_suspended:1; unsigned pullup:1; unsigned active:1; unsigned old_active:1; @@ -170,6 +178,7 @@ struct dummy { /* * MASTER/HOST side support */ + enum dummy_rh_state rh_state; struct timer_list timer; u32 port_status; u32 old_status; @@ -262,7 +271,9 @@ set_link_state (struct dummy *dum) dum->active = 0; if ((dum->port_status & USB_PORT_STAT_POWER) == 0) dum->port_status = 0; - else if (!dum->pullup) { + + /* UDC suspend must cause a disconnect */ + else if (!dum->pullup || dum->udc_suspended) { dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | @@ -276,7 +287,8 @@ set_link_state (struct dummy *dum) dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0) dum->port_status &= ~USB_PORT_STAT_SUSPEND; - else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0) + else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && + dum->rh_state != DUMMY_RH_SUSPENDED) dum->active = 1; } @@ -675,11 +687,16 @@ static int dummy_wakeup (struct usb_gadget *_gadget) struct dummy *dum; dum = gadget_to_dummy (_gadget); - if (!(dum->port_status & USB_PORT_STAT_SUSPEND) - || !(dum->devstatus & - ( (1 << USB_DEVICE_B_HNP_ENABLE) + if (!(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE) | (1 << USB_DEVICE_REMOTE_WAKEUP)))) return -EINVAL; + if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0) + return -ENOLINK; + if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && + dum->rh_state != DUMMY_RH_SUSPENDED) + return -EIO; + + /* FIXME: What if the root hub is suspended but the port isn't? */ /* hub notices our request, issues downstream resume, etc */ dum->resuming = 1; @@ -917,11 +934,50 @@ static int dummy_udc_remove (struct device *dev) return 0; } +static int dummy_udc_suspend (struct device *dev, pm_message_t state, + u32 level) +{ + struct dummy *dum = dev_get_drvdata(dev); + + if (level != SUSPEND_DISABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + spin_lock_irq (&dum->lock); + dum->udc_suspended = 1; + set_link_state (dum); + spin_unlock_irq (&dum->lock); + + dev->power.power_state = state; + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + return 0; +} + +static int dummy_udc_resume (struct device *dev, u32 level) +{ + struct dummy *dum = dev_get_drvdata(dev); + + if (level != RESUME_ENABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + spin_lock_irq (&dum->lock); + dum->udc_suspended = 0; + set_link_state (dum); + spin_unlock_irq (&dum->lock); + + dev->power.power_state = PMSG_ON; + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + return 0; +} + static struct device_driver dummy_udc_driver = { .name = (char *) gadget_name, .bus = &platform_bus_type, .probe = dummy_udc_probe, .remove = dummy_udc_remove, + .suspend = dummy_udc_suspend, + .resume = dummy_udc_resume, }; /*-------------------------------------------------------------------------*/ @@ -980,7 +1036,16 @@ static int dummy_urb_enqueue ( static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { - /* giveback happens automatically in timer callback */ + struct dummy *dum; + unsigned long flags; + + /* giveback happens automatically in timer callback, + * so make sure the callback happens */ + dum = hcd_to_dummy (hcd); + spin_lock_irqsave (&dum->lock, flags); + if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list)) + mod_timer (&dum->timer, jiffies); + spin_unlock_irqrestore (&dum->lock, flags); return 0; } @@ -1222,7 +1287,8 @@ restart: if (urb->status != -EINPROGRESS) { /* likely it was just unlinked */ goto return_urb; - } + } else if (dum->rh_state != DUMMY_RH_RUNNING) + continue; type = usb_pipetype (urb->pipe); /* used up this frame's non-periodic bandwidth? @@ -1486,12 +1552,12 @@ return_urb: goto restart; } - /* want a 1 msec delay here */ - if (!list_empty (&dum->urbp_list)) - mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); - else { + if (list_empty (&dum->urbp_list)) { usb_put_dev (dum->udev); dum->udev = NULL; + } else if (dum->rh_state == DUMMY_RH_RUNNING) { + /* want a 1 msec delay here */ + mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); } spin_unlock_irqrestore (&dum->lock, flags); @@ -1510,11 +1576,13 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf) { struct dummy *dum; unsigned long flags; - int retval; + int retval = 0; dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); + if (hcd->state != HC_STATE_RUNNING) + goto done; if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); @@ -1522,14 +1590,15 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf) set_link_state (dum); } - if (!(dum->port_status & PORT_C_MASK)) - retval = 0; - else { + if ((dum->port_status & PORT_C_MASK) != 0) { *buf = (1 << 1); dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n", - dum->port_status); + dum->port_status); retval = 1; + if (dum->rh_state == DUMMY_RH_SUSPENDED) + usb_hcd_resume_root_hub (hcd); } +done: spin_unlock_irqrestore (&dum->lock, flags); return retval; } @@ -1559,6 +1628,9 @@ static int dummy_hub_control ( int retval = 0; unsigned long flags; + if (hcd->state != HC_STATE_RUNNING) + return -ETIMEDOUT; + dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); switch (typeReq) { @@ -1658,6 +1730,7 @@ static int dummy_hub_control ( dum->port_status &= ~(USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); + dum->devstatus = 0; /* 50msec reset signaling */ dum->re_timeout = jiffies + msecs_to_jiffies(50); /* FALLS THROUGH */ @@ -1684,6 +1757,29 @@ static int dummy_hub_control ( return retval; } +static int dummy_hub_suspend (struct usb_hcd *hcd) +{ + struct dummy *dum = hcd_to_dummy (hcd); + + spin_lock_irq (&dum->lock); + dum->rh_state = DUMMY_RH_SUSPENDED; + set_link_state (dum); + spin_unlock_irq (&dum->lock); + return 0; +} + +static int dummy_hub_resume (struct usb_hcd *hcd) +{ + struct dummy *dum = hcd_to_dummy (hcd); + + spin_lock_irq (&dum->lock); + dum->rh_state = DUMMY_RH_RUNNING; + set_link_state (dum); + if (!list_empty(&dum->urbp_list)) + mod_timer (&dum->timer, jiffies); + spin_unlock_irq (&dum->lock); + return 0; +} /*-------------------------------------------------------------------------*/ @@ -1751,6 +1847,7 @@ static int dummy_start (struct usb_hcd *hcd) init_timer (&dum->timer); dum->timer.function = dummy_timer; dum->timer.data = (unsigned long) dum; + dum->rh_state = DUMMY_RH_RUNNING; INIT_LIST_HEAD (&dum->urbp_list); @@ -1803,6 +1900,8 @@ static const struct hc_driver dummy_hcd = { .hub_status_data = dummy_hub_status, .hub_control = dummy_hub_control, + .hub_suspend = dummy_hub_suspend, + .hub_resume = dummy_hub_resume, }; static int dummy_hcd_probe (struct device *dev) @@ -1836,11 +1935,57 @@ static int dummy_hcd_remove (struct device *dev) return 0; } +static int dummy_hcd_suspend (struct device *dev, pm_message_t state, + u32 level) +{ + struct usb_hcd *hcd; + + if (level != SUSPEND_DISABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + hcd = dev_get_drvdata (dev); + +#ifndef CONFIG_USB_SUSPEND + /* Otherwise this would never happen */ + usb_lock_device (hcd->self.root_hub); + dummy_hub_suspend (hcd); + usb_unlock_device (hcd->self.root_hub); +#endif + + hcd->state = HC_STATE_SUSPENDED; + return 0; +} + +static int dummy_hcd_resume (struct device *dev, u32 level) +{ + struct usb_hcd *hcd; + + if (level != RESUME_ENABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + hcd = dev_get_drvdata (dev); + hcd->state = HC_STATE_RUNNING; + +#ifndef CONFIG_USB_SUSPEND + /* Otherwise this would never happen */ + usb_lock_device (hcd->self.root_hub); + dummy_hub_resume (hcd); + usb_unlock_device (hcd->self.root_hub); +#endif + + usb_hcd_poll_rh_status (hcd); + return 0; +} + static struct device_driver dummy_hcd_driver = { .name = (char *) driver_name, .bus = &platform_bus_type, .probe = dummy_hcd_probe, .remove = dummy_hcd_remove, + .suspend = dummy_hcd_suspend, + .resume = dummy_hcd_resume, }; /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From 45e45ab45c266642276d01e56d9fb5dccbfad960 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 16 May 2005 08:26:38 -0700 Subject: [PATCH] USB: fix drivers/usb/gadget/ether.c compile error This fixes a compile glitch with CONFIG_USB_ETH_RNDIS disabled, and replaces some inline #ifdeffery (and other code) with inline functions which can evaluate to constants. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 53 ++++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9f8413e3c10a..86affef226e5 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -91,12 +91,12 @@ static const char driver_desc [] = DRIVER_DESC; #define RX_EXTRA 20 /* guard against rx overflows */ -#ifdef CONFIG_USB_ETH_RNDIS #include "rndis.h" -#else -#define rndis_init() 0 -#define rndis_uninit(x) do{}while(0) -#define rndis_exit() do{}while(0) + +#ifndef CONFIG_USB_ETH_RNDIS +#define rndis_uninit(x) do{}while(0) +#define rndis_deregister(c) do{}while(0) +#define rndis_exit() do{}while(0) #endif /* CDC and RNDIS support the same host-chosen outgoing packet filters. */ @@ -1133,9 +1133,9 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) dev->config = number; INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n", speed, number, power, driver_desc, - dev->rndis + rndis_active(dev) ? "RNDIS" - : (dev->cdc + : (cdc_active(dev) ? "CDC Ethernet" : "CDC Ethernet Subset")); } @@ -1350,7 +1350,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) || !dev->config || wIndex > 1) break; - if (!dev->cdc && wIndex != 0) + if (!cdc_active(dev) && wIndex != 0) break; spin_lock (&dev->lock); @@ -1420,11 +1420,11 @@ done_set_intf: || !dev->config || wIndex > 1) break; - if (!(dev->cdc || dev->rndis) && wIndex != 0) + if (!(cdc_active(dev) || rndis_active(dev)) && wIndex != 0) break; /* for CDC, iff carrier is on, data interface is active. */ - if (dev->rndis || wIndex != 1) + if (rndis_active(dev) || wIndex != 1) *(u8 *)req->buf = 0; else *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; @@ -1437,8 +1437,7 @@ done_set_intf: * wValue = packet filter bitmap */ if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) - || !dev->cdc - || dev->rndis + || !cdc_active(dev) || wLength != 0 || wIndex > 1) break; @@ -1462,7 +1461,7 @@ done_set_intf: */ case USB_CDC_SEND_ENCAPSULATED_COMMAND: if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) - || !dev->rndis + || !rndis_active(dev) || wLength > USB_BUFSIZ || wValue || rndis_control_intf.bInterfaceNumber @@ -1477,7 +1476,7 @@ done_set_intf: case USB_CDC_GET_ENCAPSULATED_RESPONSE: if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE) == ctrl->bRequestType - && dev->rndis + && rndis_active(dev) // && wLength >= 0x0400 && !wValue && rndis_control_intf.bInterfaceNumber @@ -1661,11 +1660,9 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) /* normal completion */ case 0: skb_put (skb, req->actual); -#ifdef CONFIG_USB_ETH_RNDIS /* we know MaxPacketsPerTransfer == 1 here */ - if (dev->rndis) + if (rndis_active(dev)) status = rndis_rm_hdr (skb); -#endif if (status < 0 || ETH_HLEN > skb->len || skb->len > ETH_FRAME_LEN) { @@ -1893,8 +1890,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) * or the hardware can't use skb buffers. * or there's not enough space for any RNDIS headers we need */ -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) { + if (rndis_active(dev)) { struct sk_buff *skb_rndis; skb_rndis = skb_realloc_headroom (skb, @@ -1907,7 +1903,6 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) rndis_add_hdr (skb); length = skb->len; } -#endif req->buf = skb->data; req->context = skb; req->complete = tx_complete; @@ -1940,9 +1935,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) } if (retval) { -#ifdef CONFIG_USB_ETH_RNDIS drop: -#endif dev->stats.tx_dropped++; dev_kfree_skb_any (skb); spin_lock_irqsave (&dev->lock, flags); @@ -2023,6 +2016,10 @@ static int rndis_control_ack (struct net_device *net) return 0; } +#else + +#define rndis_control_ack NULL + #endif /* RNDIS */ static void eth_start (struct eth_dev *dev, int gfp_flags) @@ -2035,14 +2032,12 @@ static void eth_start (struct eth_dev *dev, int gfp_flags) /* and open the tx floodgates */ atomic_set (&dev->tx_qlen, 0); netif_wake_queue (dev->net); -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) { + if (rndis_active(dev)) { rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, BITRATE(dev->gadget)/100); (void) rndis_signal_connect (dev->rndis_config); } -#endif } static int eth_open (struct net_device *net) @@ -2083,13 +2078,11 @@ static int eth_stop (struct net_device *net) } } -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) { + if (rndis_active(dev)) { rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, 0); (void) rndis_signal_disconnect (dev->rndis_config); } -#endif return 0; } @@ -2127,10 +2120,8 @@ eth_unbind (struct usb_gadget *gadget) struct eth_dev *dev = get_gadget_data (gadget); DEBUG (dev, "unbind\n"); -#ifdef CONFIG_USB_ETH_RNDIS rndis_deregister (dev->rndis_config); rndis_exit (); -#endif /* we've already been disconnected ... no i/o is active */ if (dev->req) { @@ -2481,7 +2472,6 @@ autoconf_fail: dev->host_mac [2], dev->host_mac [3], dev->host_mac [4], dev->host_mac [5]); -#ifdef CONFIG_USB_ETH_RNDIS if (rndis) { u32 vendorID = 0; @@ -2509,7 +2499,6 @@ fail0: goto fail0; INFO (dev, "RNDIS ready\n"); } -#endif return status; -- cgit v1.2.3 From 486e2df6ce213d0c776befdf3fe5ffc61dd61688 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 24 May 2005 17:51:52 -0700 Subject: [PATCH] USB gadget: drain rndis response queue on disconnect Drain the rndis response queue on disconnect. This fixes a problem in which an rndis response left in the queue from a previous session could cause a subsequent session to fail. Signed-off-by: Andy Lowe Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/rndis.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index c9a0af29ecb6..06b6eba925b5 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -1025,11 +1025,17 @@ int rndis_signal_disconnect (int configNr) void rndis_uninit (int configNr) { + u8 *buf; + u32 length; + if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params [configNr].used = 0; rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED; - return; + + /* drain the response queue */ + while ((buf = rndis_get_next_response(configNr, &length))) + rndis_free_response(configNr, buf); } void rndis_set_host_mac (int configNr, const u8 *addr) -- cgit v1.2.3 From 822e14ac222d1dad3f5393b75603f0455aebbefc Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 13 Jun 2005 06:55:03 -0700 Subject: [PATCH] USB: resolve ethernet gadget build glitch on pxa This fixes a build error on pxa25x processes with pxa2xx_udc and CONFIG_USB_ETH=m # CONFIG_USB_ETH_RNDIS is not set The error is because on that CPU there's no status transfer support except with RNDIS. Workaround, enable the RNDIS support too. Signed-off-by: Ian Campbell Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 86affef226e5..5bb53ae88969 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2428,6 +2428,7 @@ autoconf_fail: dev->req->complete = eth_setup_complete; /* ... and maybe likewise for status transfer */ +#ifdef DEV_CONFIG_CDC if (dev->status_ep) { dev->stat_req = eth_req_alloc (dev->status_ep, STATUS_BYTECOUNT, GFP_KERNEL); @@ -2437,6 +2438,7 @@ autoconf_fail: } dev->stat_req->context = NULL; } +#endif /* finish hookup to lower layer ... */ dev->gadget = gadget; -- cgit v1.2.3