diff options
Diffstat (limited to 'drivers')
50 files changed, 3614 insertions, 846 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 84c1897188d2..5da546c4fd79 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3629,7 +3629,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) } if (!parent_hdev) { - /* this requires hcd-specific logic; see OHCI hc_restart() */ + /* this requires hcd-specific logic; see ohci_restart() */ dev_dbg(&udev->dev, "%s for root hub!\n", __func__); return -EISDIR; } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 419e6b34e2fe..c14fc082864f 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -401,8 +401,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) }; /* Check that the pipe's type matches the endpoint's type */ - if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) + if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) { + dev_err(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", + usb_pipetype(urb->pipe), pipetypes[xfertype]); return -EPIPE; /* The most suitable error code :-) */ + } /* enforce simple/standard policy */ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK | diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 731150d4b1d9..2b361500af1e 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -203,7 +203,7 @@ static void print_regs(struct udc *dev) DBG(dev, "DMA mode = PPBNDU (packet per buffer " "WITHOUT desc. update)\n"); dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU"); - } else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) { + } else if (use_dma && use_dma_ppb && use_dma_ppb_du) { DBG(dev, "DMA mode = PPBDU (packet per buffer " "WITH desc. update)\n"); dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU"); @@ -1954,13 +1954,14 @@ static int setup_ep0(struct udc *dev) } /* Called by gadget driver to register itself */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct udc *dev = udc; int retval; u32 tmp; - if (!driver || !driver->bind || !driver->setup + if (!driver || !bind || !driver->setup || driver->speed != USB_SPEED_HIGH) return -EINVAL; if (!dev) @@ -1972,7 +1973,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) dev->driver = driver; dev->gadget.dev.driver = &driver->driver; - retval = driver->bind(&dev->gadget); + retval = bind(&dev->gadget); /* Some gadget drivers use both ep0 directions. * NOTE: to gadget driver, ep0 is just one endpoint... @@ -2000,7 +2001,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); /* shutdown requests and disconnect from gadget */ static void diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index d90c9e89688e..bdec36acd0fa 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1627,7 +1627,8 @@ static void at91_vbus_timer(unsigned long data) schedule_work(&udc->vbus_timer_work); } -int usb_gadget_register_driver (struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct at91_udc *udc = &controller; int retval; @@ -1635,7 +1636,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (!driver || driver->speed < USB_SPEED_FULL - || !driver->bind + || !bind || !driver->setup) { DBG("bad parameter.\n"); return -EINVAL; @@ -1652,9 +1653,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) udc->enabled = 1; udc->selfpowered = 1; - retval = driver->bind(&udc->gadget); + retval = bind(&udc->gadget); if (retval) { - DBG("driver->bind() returned %d\n", retval); + DBG("bind() returned %d\n", retval); udc->driver = NULL; udc->gadget.dev.driver = NULL; dev_set_drvdata(&udc->gadget.dev, NULL); @@ -1670,7 +1671,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) DBG("bound to %s\n", driver->driver.name); return 0; } -EXPORT_SYMBOL (usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) { diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index d623c7bda1f6..e4810c6a0b1f 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1789,7 +1789,8 @@ out: return IRQ_HANDLED; } -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct usba_udc *udc = &the_udc; unsigned long flags; @@ -1812,7 +1813,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) clk_enable(udc->pclk); clk_enable(udc->hclk); - ret = driver->bind(&udc->gadget); + ret = bind(&udc->gadget); if (ret) { DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", driver->driver.name, ret); @@ -1841,7 +1842,7 @@ err_driver_bind: udc->gadget.dev.driver = NULL; return ret; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c index b744ccd0f34d..93b999e49ef3 100644 --- a/drivers/usb/gadget/audio.c +++ b/drivers/usb/gadget/audio.c @@ -89,7 +89,7 @@ static const struct usb_descriptor_header *otg_desc[] = { /*-------------------------------------------------------------------------*/ -static int __ref audio_do_config(struct usb_configuration *c) +static int __init audio_do_config(struct usb_configuration *c) { /* FIXME alloc iConfiguration string, set it in c->strings */ @@ -105,7 +105,6 @@ static int __ref audio_do_config(struct usb_configuration *c) static struct usb_configuration audio_config_driver = { .label = DRIVER_DESC, - .bind = audio_do_config, .bConfigurationValue = 1, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_SELFPOWER, @@ -113,7 +112,7 @@ static struct usb_configuration audio_config_driver = { /*-------------------------------------------------------------------------*/ -static int __ref audio_bind(struct usb_composite_dev *cdev) +static int __init audio_bind(struct usb_composite_dev *cdev) { int gcnum; int status; @@ -145,7 +144,7 @@ static int __ref audio_bind(struct usb_composite_dev *cdev) strings_dev[STRING_PRODUCT_IDX].id = status; device_desc.iProduct = status; - status = usb_add_config(cdev, &audio_config_driver); + status = usb_add_config(cdev, &audio_config_driver, audio_do_config); if (status < 0) goto fail; @@ -166,13 +165,12 @@ static struct usb_composite_driver audio_driver = { .name = "g_audio", .dev = &device_desc, .strings = audio_strings, - .bind = audio_bind, .unbind = __exit_p(audio_unbind), }; static int __init init(void) { - return usb_composite_register(&audio_driver); + return usb_composite_probe(&audio_driver, audio_bind); } module_init(init); diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 1f5ba2fd4c1f..2720ab07ef1a 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -129,7 +129,7 @@ static u8 hostaddr[ETH_ALEN]; /* * We _always_ have both CDC ECM and CDC ACM functions. */ -static int __ref cdc_do_config(struct usb_configuration *c) +static int __init cdc_do_config(struct usb_configuration *c) { int status; @@ -151,7 +151,6 @@ static int __ref cdc_do_config(struct usb_configuration *c) static struct usb_configuration cdc_config_driver = { .label = "CDC Composite (ECM + ACM)", - .bind = cdc_do_config, .bConfigurationValue = 1, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_SELFPOWER, @@ -159,7 +158,7 @@ static struct usb_configuration cdc_config_driver = { /*-------------------------------------------------------------------------*/ -static int __ref cdc_bind(struct usb_composite_dev *cdev) +static int __init cdc_bind(struct usb_composite_dev *cdev) { int gcnum; struct usb_gadget *gadget = cdev->gadget; @@ -218,7 +217,7 @@ static int __ref cdc_bind(struct usb_composite_dev *cdev) device_desc.iProduct = status; /* register our configuration */ - status = usb_add_config(cdev, &cdc_config_driver); + status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config); if (status < 0) goto fail1; @@ -245,7 +244,6 @@ static struct usb_composite_driver cdc_driver = { .name = "g_cdc", .dev = &device_desc, .strings = dev_strings, - .bind = cdc_bind, .unbind = __exit_p(cdc_unbind), }; @@ -255,7 +253,7 @@ MODULE_LICENSE("GPL"); static int __init init(void) { - return usb_composite_register(&cdc_driver); + return usb_composite_probe(&cdc_driver, cdc_bind); } module_init(init); diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 699695128e33..98b36fc88c77 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -2340,12 +2340,15 @@ static const struct usb_ep_ops usb_ep_ops = { static const struct usb_gadget_ops usb_gadget_ops; /** - * usb_gadget_register_driver: register a gadget driver + * usb_gadget_probe_driver: register a gadget driver + * @driver: the driver being registered + * @bind: the driver's bind callback * - * Check usb_gadget_register_driver() at "usb_gadget.h" for details - * Interrupts are enabled here + * Check usb_gadget_probe_driver() at <linux/usb/gadget.h> for details. + * Interrupts are enabled here. */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct ci13xxx *udc = _udc; unsigned long i, k, flags; @@ -2354,7 +2357,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) trace("%p", driver); if (driver == NULL || - driver->bind == NULL || + bind == NULL || driver->unbind == NULL || driver->setup == NULL || driver->disconnect == NULL || @@ -2430,7 +2433,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(udc->lock, flags); - retval = driver->bind(&udc->gadget); /* MAY SLEEP */ + retval = bind(&udc->gadget); /* MAY SLEEP */ spin_lock_irqsave(udc->lock, flags); if (retval) { @@ -2447,7 +2450,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) usb_gadget_unregister_driver(driver); return retval; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); /** * usb_gadget_unregister_driver: unregister a gadget driver @@ -2462,7 +2465,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) trace("%p", driver); if (driver == NULL || - driver->bind == NULL || driver->unbind == NULL || driver->setup == NULL || driver->disconnect == NULL || diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 1160c55de7f2..5e2bd7428424 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/device.h> +#include <linux/utsname.h> #include <linux/usb/composite.h> @@ -39,6 +40,7 @@ #define USB_BUFSIZ 1024 static struct usb_composite_driver *composite; +static int (*composite_gadget_bind)(struct usb_composite_dev *cdev); /* Some systems will need runtime overrides for the product identifers * published in the device descriptor, either numbers or strings or both. @@ -69,6 +71,8 @@ static char *iSerialNumber; module_param(iSerialNumber, charp, 0); MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); +static char composite_manufacturer[50]; + /*-------------------------------------------------------------------------*/ /** @@ -470,18 +474,20 @@ done: * usb_add_config() - add a configuration to a device. * @cdev: wraps the USB gadget * @config: the configuration, with bConfigurationValue assigned + * @bind: the configuration's bind function * Context: single threaded during gadget setup * - * One of the main tasks of a composite driver's bind() routine is to + * One of the main tasks of a composite @bind() routine is to * add each of the configurations it supports, using this routine. * - * This function returns the value of the configuration's bind(), which + * This function returns the value of the configuration's @bind(), which * is zero for success else a negative errno value. Binding configurations * assigns global resources including string IDs, and per-configuration * resources such as interface IDs and endpoints. */ int usb_add_config(struct usb_composite_dev *cdev, - struct usb_configuration *config) + struct usb_configuration *config, + int (*bind)(struct usb_configuration *)) { int status = -EINVAL; struct usb_configuration *c; @@ -490,7 +496,7 @@ int usb_add_config(struct usb_composite_dev *cdev, config->bConfigurationValue, config->label, config); - if (!config->bConfigurationValue || !config->bind) + if (!config->bConfigurationValue || !bind) goto done; /* Prevent duplicate configuration identifiers */ @@ -507,7 +513,7 @@ int usb_add_config(struct usb_composite_dev *cdev, INIT_LIST_HEAD(&config->functions); config->next_interface_id = 0; - status = config->bind(config); + status = bind(config); if (status < 0) { list_del(&config->list); config->cdev = NULL; @@ -533,7 +539,7 @@ int usb_add_config(struct usb_composite_dev *cdev, } } - /* set_alt(), or next config->bind(), sets up + /* set_alt(), or next bind(), sets up * ep->driver_data as needed. */ usb_ep_autoconfig_reset(cdev->gadget); @@ -599,6 +605,7 @@ static int get_string(struct usb_composite_dev *cdev, struct usb_configuration *c; struct usb_function *f; int len; + const char *str; /* Yes, not only is USB's I18N support probably more than most * folk will ever care about ... also, it's all supported here. @@ -638,9 +645,29 @@ static int get_string(struct usb_composite_dev *cdev, return s->bLength; } - /* Otherwise, look up and return a specified string. String IDs - * are device-scoped, so we look up each string table we're told - * about. These lookups are infrequent; simpler-is-better here. + /* Otherwise, look up and return a specified string. First + * check if the string has not been overridden. + */ + if (cdev->manufacturer_override == id) + str = iManufacturer ?: composite->iManufacturer ?: + composite_manufacturer; + else if (cdev->product_override == id) + str = iProduct ?: composite->iProduct; + else if (cdev->serial_override == id) + str = iSerialNumber; + else + str = NULL; + if (str) { + struct usb_gadget_strings strings = { + .language = language, + .strings = &(struct usb_string) { 0xff, str } + }; + return usb_gadget_get_string(&strings, 0xff, buf); + } + + /* String IDs are device-scoped, so we look up each string + * table we're told about. These lookups are infrequent; + * simpler-is-better here. */ if (composite->strings) { len = lookup_string(composite->strings, buf, language, id); @@ -1025,26 +1052,17 @@ composite_unbind(struct usb_gadget *gadget) composite = NULL; } -static void -string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s) +static u8 override_id(struct usb_composite_dev *cdev, u8 *desc) { - struct usb_string *str = tab->strings; - - for (str = tab->strings; str->s; str++) { - if (str->id == id) { - str->s = s; - return; - } + if (!*desc) { + int ret = usb_string_id(cdev); + if (unlikely(ret < 0)) + WARNING(cdev, "failed to override string ID\n"); + else + *desc = ret; } -} -static void -string_override(struct usb_gadget_strings **tab, u8 id, const char *s) -{ - while (*tab) { - string_override_one(*tab, id, s); - tab++; - } + return *desc; } static int composite_bind(struct usb_gadget *gadget) @@ -1074,7 +1092,13 @@ static int composite_bind(struct usb_gadget *gadget) cdev->bufsiz = USB_BUFSIZ; cdev->driver = composite; - usb_gadget_set_selfpowered(gadget); + /* + * As per USB compliance update, a device that is actively drawing + * more than 100mA from USB must report itself as bus-powered in + * the GetStatus(DEVICE) call. + */ + if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW) + usb_gadget_set_selfpowered(gadget); /* interface and string IDs start at zero via kzalloc. * we force endpoints to start unassigned; few controller @@ -1094,26 +1118,41 @@ static int composite_bind(struct usb_gadget *gadget) * serial number), register function drivers, potentially update * power state and consumption, etc */ - status = composite->bind(cdev); + status = composite_gadget_bind(cdev); if (status < 0) goto fail; cdev->desc = *composite->dev; cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - /* strings can't be assigned before bind() allocates the - * releavnt identifiers - */ - if (cdev->desc.iManufacturer && iManufacturer) - string_override(composite->strings, - cdev->desc.iManufacturer, iManufacturer); - if (cdev->desc.iProduct && iProduct) - string_override(composite->strings, - cdev->desc.iProduct, iProduct); - if (cdev->desc.iSerialNumber && iSerialNumber) - string_override(composite->strings, - cdev->desc.iSerialNumber, iSerialNumber); + /* stirng overrides */ + if (iManufacturer || !cdev->desc.iManufacturer) { + if (!iManufacturer && !composite->iManufacturer && + !*composite_manufacturer) + snprintf(composite_manufacturer, + sizeof composite_manufacturer, + "%s %s with %s", + init_utsname()->sysname, + init_utsname()->release, + gadget->name); + + cdev->manufacturer_override = + override_id(cdev, &cdev->desc.iManufacturer); + } + + if (iProduct || (!cdev->desc.iProduct && composite->iProduct)) + cdev->product_override = + override_id(cdev, &cdev->desc.iProduct); + + if (iSerialNumber) + cdev->serial_override = + override_id(cdev, &cdev->desc.iSerialNumber); + + /* has userspace failed to provide a serial number? */ + if (composite->needs_serial && !cdev->desc.iSerialNumber) + WARNING(cdev, "userspace failed to provide iSerialNumber\n"); + /* finish up */ status = device_create_file(&gadget->dev, &dev_attr_suspended); if (status) goto fail; @@ -1177,7 +1216,6 @@ composite_resume(struct usb_gadget *gadget) static struct usb_gadget_driver composite_driver = { .speed = USB_SPEED_HIGH, - .bind = composite_bind, .unbind = composite_unbind, .setup = composite_setup, @@ -1192,8 +1230,12 @@ static struct usb_gadget_driver composite_driver = { }; /** - * usb_composite_register() - register a composite driver + * usb_composite_probe() - register a composite driver * @driver: the driver to register + * @bind: the callback used to allocate resources that are shared across the + * whole device, such as string IDs, and add its configurations using + * @usb_add_config(). This may fail by returning a negative errno + * value; it should return zero on successful initialization. * Context: single threaded during gadget setup * * This function is used to register drivers using the composite driver @@ -1206,18 +1248,22 @@ static struct usb_gadget_driver composite_driver = { * while it was binding. That would usually be done in order to wait for * some userspace participation. */ -int usb_composite_register(struct usb_composite_driver *driver) +extern int usb_composite_probe(struct usb_composite_driver *driver, + int (*bind)(struct usb_composite_dev *cdev)) { - if (!driver || !driver->dev || !driver->bind || composite) + if (!driver || !driver->dev || !bind || composite) return -EINVAL; + if (!driver->iProduct) + driver->iProduct = driver->name; if (!driver->name) driver->name = "composite"; composite_driver.function = (char *) driver->name; composite_driver.driver.name = driver->name; composite = driver; + composite_gadget_bind = bind; - return usb_gadget_register_driver(&composite_driver); + return usb_gadget_probe_driver(&composite_driver, composite_bind); } /** diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index 0ed50a2c0a36..e5ac8a316fec 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -386,15 +386,13 @@ static int dbgp_setup(struct usb_gadget *gadget, } else goto fail; - if (len >= 0) { - req->length = min(length, len); - req->zero = len < req->length; - if (data && req->length) - memcpy(req->buf, data, req->length); - - req->complete = dbgp_setup_complete; - return usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); - } + req->length = min(length, len); + req->zero = len < req->length; + if (data && req->length) + memcpy(req->buf, data, req->length); + + req->complete = dbgp_setup_complete; + return usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); fail: dev_dbg(&dbgp.gadget->dev, @@ -405,7 +403,6 @@ fail: static struct usb_gadget_driver dbgp_driver = { .function = "dbgp", .speed = USB_SPEED_HIGH, - .bind = dbgp_bind, .unbind = dbgp_unbind, .setup = dbgp_setup, .disconnect = dbgp_disconnect, @@ -417,7 +414,7 @@ static struct usb_gadget_driver dbgp_driver = { static int __init dbgp_init(void) { - return usb_gadget_register_driver(&dbgp_driver); + return usb_gadget_probe_driver(&dbgp_driver, dbgp_bind); } static void __exit dbgp_exit(void) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index dc6546248ed9..7bb9d78aac27 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -748,7 +748,8 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); */ int -usb_gadget_register_driver (struct usb_gadget_driver *driver) +usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct dummy *dum = the_controller; int retval, i; @@ -757,8 +758,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) return -EINVAL; if (dum->driver) return -EBUSY; - if (!driver->bind || !driver->setup - || driver->speed == USB_SPEED_UNKNOWN) + if (!bind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN) return -EINVAL; /* @@ -796,7 +796,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) dum->gadget.dev.driver = &driver->driver; dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", driver->driver.name); - retval = driver->bind(&dum->gadget); + retval = bind(&dum->gadget); if (retval) { dum->driver = NULL; dum->gadget.dev.driver = NULL; @@ -812,7 +812,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } -EXPORT_SYMBOL (usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 114fa024c22c..1690c9d68256 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -237,7 +237,7 @@ static u8 hostaddr[ETH_ALEN]; * the first one present. That's to make Microsoft's drivers happy, * and to follow DOCSIS 1.0 (cable modem standard). */ -static int __ref rndis_do_config(struct usb_configuration *c) +static int __init rndis_do_config(struct usb_configuration *c) { /* FIXME alloc iConfiguration string, set it in c->strings */ @@ -251,7 +251,6 @@ static int __ref rndis_do_config(struct usb_configuration *c) static struct usb_configuration rndis_config_driver = { .label = "RNDIS", - .bind = rndis_do_config, .bConfigurationValue = 2, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_SELFPOWER, @@ -270,7 +269,7 @@ MODULE_PARM_DESC(use_eem, "use CDC EEM mode"); /* * We _always_ have an ECM, CDC Subset, or EEM configuration. */ -static int __ref eth_do_config(struct usb_configuration *c) +static int __init eth_do_config(struct usb_configuration *c) { /* FIXME alloc iConfiguration string, set it in c->strings */ @@ -289,7 +288,6 @@ static int __ref eth_do_config(struct usb_configuration *c) static struct usb_configuration eth_config_driver = { /* .label = f(hardware) */ - .bind = eth_do_config, .bConfigurationValue = 1, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_SELFPOWER, @@ -297,7 +295,7 @@ static struct usb_configuration eth_config_driver = { /*-------------------------------------------------------------------------*/ -static int __ref eth_bind(struct usb_composite_dev *cdev) +static int __init eth_bind(struct usb_composite_dev *cdev) { int gcnum; struct usb_gadget *gadget = cdev->gadget; @@ -373,12 +371,13 @@ static int __ref eth_bind(struct usb_composite_dev *cdev) /* register our configuration(s); RNDIS first, if it's used */ if (has_rndis()) { - status = usb_add_config(cdev, &rndis_config_driver); + status = usb_add_config(cdev, &rndis_config_driver, + rndis_do_config); if (status < 0) goto fail; } - status = usb_add_config(cdev, ð_config_driver); + status = usb_add_config(cdev, ð_config_driver, eth_do_config); if (status < 0) goto fail; @@ -402,7 +401,6 @@ static struct usb_composite_driver eth_driver = { .name = "g_ether", .dev = &device_desc, .strings = dev_strings, - .bind = eth_bind, .unbind = __exit_p(eth_unbind), }; @@ -412,7 +410,7 @@ MODULE_LICENSE("GPL"); static int __init init(void) { - return usb_composite_register(ð_driver); + return usb_composite_probe(ð_driver, eth_bind); } module_init(init); diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 43225879c3cd..b37960f9e753 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -324,7 +324,7 @@ static void loopback_disable(struct usb_function *f) /*-------------------------------------------------------------------------*/ -static int __ref loopback_bind_config(struct usb_configuration *c) +static int __init loopback_bind_config(struct usb_configuration *c) { struct f_loopback *loop; int status; @@ -346,10 +346,9 @@ static int __ref loopback_bind_config(struct usb_configuration *c) return status; } -static struct usb_configuration loopback_driver = { +static struct usb_configuration loopback_driver = { .label = "loopback", .strings = loopback_strings, - .bind = loopback_bind_config, .bConfigurationValue = 2, .bmAttributes = USB_CONFIG_ATT_SELFPOWER, /* .iConfiguration = DYNAMIC */ @@ -382,5 +381,5 @@ int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume) loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - return usb_add_config(cdev, &loopback_driver); + return usb_add_config(cdev, &loopback_driver, loopback_bind_config); } diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 32cce029f65c..44e5ffed5c08 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -73,6 +73,8 @@ * being removable. * ->cdrom Flag specifying that LUN shall be reported as * being a CD-ROM. + * ->nofua Flag specifying that FUA flag in SCSI WRITE(10,12) + * commands for this LUN shall be ignored. * * lun_name_format A printf-like format for names of the LUN * devices. This determines how the @@ -127,6 +129,8 @@ * Default true, boolean for removable media. * cdrom=b[,b...] Default false, boolean for whether to emulate * a CD-ROM drive. + * nofua=b[,b...] Default false, booleans for ignore FUA flag + * in SCSI WRITE(10,12) commands * luns=N Default N = number of filenames, number of * LUNs to support. * stall Default determined according to the type of @@ -409,6 +413,7 @@ struct fsg_config { char ro; char removable; char cdrom; + char nofua; } luns[FSG_MAX_LUNS]; const char *lun_name_format; @@ -887,7 +892,7 @@ static int do_write(struct fsg_common *common) curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } - if (common->cmnd[1] & 0x08) { /* FUA */ + if (!curlun->nofua && (common->cmnd[1] & 0x08)) { /* FUA */ spin_lock(&curlun->filp->f_lock); curlun->filp->f_flags |= O_SYNC; spin_unlock(&curlun->filp->f_lock); @@ -2662,6 +2667,7 @@ static int fsg_main_thread(void *common_) /* Write permission is checked per LUN in store_*() functions. */ static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro); +static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua); static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file); @@ -2768,6 +2774,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, rc = device_create_file(&curlun->dev, &dev_attr_file); if (rc) goto error_luns; + rc = device_create_file(&curlun->dev, &dev_attr_nofua); + if (rc) + goto error_luns; if (lcfg->filename) { rc = fsg_lun_open(curlun, lcfg->filename); @@ -2911,6 +2920,7 @@ static void fsg_common_release(struct kref *ref) /* In error recovery common->nluns may be zero. */ for (; i; --i, ++lun) { + device_remove_file(&lun->dev, &dev_attr_nofua); device_remove_file(&lun->dev, &dev_attr_ro); device_remove_file(&lun->dev, &dev_attr_file); fsg_lun_close(lun); @@ -3069,8 +3079,10 @@ struct fsg_module_parameters { int ro[FSG_MAX_LUNS]; int removable[FSG_MAX_LUNS]; int cdrom[FSG_MAX_LUNS]; + int nofua[FSG_MAX_LUNS]; unsigned int file_count, ro_count, removable_count, cdrom_count; + unsigned int nofua_count; unsigned int luns; /* nluns */ int stall; /* can_stall */ }; @@ -3096,6 +3108,8 @@ struct fsg_module_parameters { "true to simulate removable media"); \ _FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \ "true to simulate CD-ROM instead of disk"); \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool, \ + "true to ignore SCSI WRITE(10,12) FUA bit"); \ _FSG_MODULE_PARAM(prefix, params, luns, uint, \ "number of LUNs"); \ _FSG_MODULE_PARAM(prefix, params, stall, bool, \ diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 685d768f336e..e403a534dd55 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -404,7 +404,7 @@ static void sourcesink_disable(struct usb_function *f) /*-------------------------------------------------------------------------*/ -static int __ref sourcesink_bind_config(struct usb_configuration *c) +static int __init sourcesink_bind_config(struct usb_configuration *c) { struct f_sourcesink *ss; int status; @@ -498,7 +498,6 @@ unknown: static struct usb_configuration sourcesink_driver = { .label = "source/sink", .strings = sourcesink_strings, - .bind = sourcesink_bind_config, .setup = sourcesink_setup, .bConfigurationValue = 3, .bmAttributes = USB_CONFIG_ATT_SELFPOWER, @@ -532,5 +531,5 @@ int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume) sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - return usb_add_config(cdev, &sourcesink_driver); + return usb_add_config(cdev, &sourcesink_driver, sourcesink_bind_config); } diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index a857b7ac238c..ce437f5dd674 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -89,6 +89,7 @@ * Required if "removable" is not set, names of * the files or block devices used for * backing storage + * serial=HHHH... Required serial number (string of hex chars) * ro=b[,b...] Default false, booleans for read-only access * removable Default false, boolean for removable media * luns=N Default N = number of filenames, number of @@ -108,12 +109,11 @@ * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID * release=0xRRRR Override the USB release number (bcdDevice) - * serial=HHHH... Override serial number (string of hex chars) * buflen=N Default N=16384, buffer size used (will be * rounded down to a multiple of * PAGE_CACHE_SIZE) * - * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro", * "removable", "luns", "nofua", "stall", and "cdrom" options are available; * default values are used for everything else. * @@ -273,13 +273,10 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -/* DRIVER_VERSION must be at least 6 characters long, as it is used - * to generate a fallback serial number. */ -#define DRIVER_VERSION "20 November 2008" +#define DRIVER_VERSION "1 September 2010" static char fsg_string_manufacturer[64]; static const char fsg_string_product[] = DRIVER_DESC; -static char fsg_string_serial[13]; static const char fsg_string_config[] = "Self-powered"; static const char fsg_string_interface[] = "Mass Storage"; @@ -305,6 +302,7 @@ MODULE_LICENSE("Dual BSD/GPL"); static struct { char *file[FSG_MAX_LUNS]; + char *serial; int ro[FSG_MAX_LUNS]; int nofua[FSG_MAX_LUNS]; unsigned int num_filenames; @@ -321,7 +319,6 @@ static struct { unsigned short vendor; unsigned short product; unsigned short release; - char *serial; unsigned int buflen; int transport_type; @@ -346,6 +343,9 @@ module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames, S_IRUGO); MODULE_PARM_DESC(file, "names of backing files or devices"); +module_param_named(serial, mod_data.serial, charp, S_IRUGO); +MODULE_PARM_DESC(serial, "USB serial number"); + module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); MODULE_PARM_DESC(ro, "true to force read-only"); @@ -365,9 +365,6 @@ MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO); MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); -module_param_named(serial, mod_data.serial, charp, S_IRUGO); -MODULE_PARM_DESC(serial, "USB serial number"); - /* In the non-TEST version, only the module parameters listed above * are available. */ #ifdef CONFIG_USB_FILE_STORAGE_TEST @@ -3178,6 +3175,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) for (i = 0; i < fsg->nluns; ++i) { curlun = &fsg->luns[i]; if (curlun->registered) { + device_remove_file(&curlun->dev, &dev_attr_nofua); device_remove_file(&curlun->dev, &dev_attr_ro); device_remove_file(&curlun->dev, &dev_attr_file); fsg_lun_close(curlun); @@ -3213,7 +3211,6 @@ static int __init check_parameters(struct fsg_dev *fsg) { int prot; int gcnum; - int i; /* Store the default values */ mod_data.transport_type = USB_PR_BULK; @@ -3309,45 +3306,29 @@ static int __init check_parameters(struct fsg_dev *fsg) if ((*ch < '0' || *ch > '9') && (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */ WARNING(fsg, - "Invalid serial string character: %c; " - "Failing back to default\n", + "Invalid serial string character: %c\n", *ch); - goto fill_serial; + goto no_serial; } } if (len > 126 || (mod_data.transport_type == USB_PR_BULK && len < 12) || (mod_data.transport_type != USB_PR_BULK && len > 12)) { - WARNING(fsg, - "Invalid serial string length; " - "Failing back to default\n"); - goto fill_serial; + WARNING(fsg, "Invalid serial string length!\n"); + goto no_serial; } fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial; } else { - WARNING(fsg, - "Userspace failed to provide serial number; " - "Failing back to default\n"); -fill_serial: - /* Serial number not specified or invalid, make our own. - * We just encode it from the driver version string, - * 12 characters to comply with both CB[I] and BBB spec. - * Warning : Two devices running the same kernel will have - * the same fallback serial number. */ - for (i = 0; i < 12; i += 2) { - unsigned char c = DRIVER_VERSION[i / 2]; - - if (!c) - break; - sprintf(&fsg_string_serial[i], "%02X", c); - } + WARNING(fsg, "No serial-number string provided!\n"); + no_serial: + device_desc.iSerialNumber = 0; } return 0; } -static int __ref fsg_bind(struct usb_gadget *gadget) +static int __init fsg_bind(struct usb_gadget *gadget) { struct fsg_dev *fsg = the_fsg; int rc; @@ -3607,7 +3588,6 @@ static struct usb_gadget_driver fsg_driver = { .speed = USB_SPEED_FULL, #endif .function = (char *) fsg_string_product, - .bind = fsg_bind, .unbind = fsg_unbind, .disconnect = fsg_disconnect, .setup = fsg_setup, @@ -3649,7 +3629,7 @@ static int __init fsg_init(void) if ((rc = fsg_alloc()) != 0) return rc; fsg = the_fsg; - if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) + if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0) kref_put(&fsg->ref, fsg_release); return rc; } diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index a5ea2c1d8c93..792d5ef40137 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2302,9 +2302,10 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc) } /*------------------------------------------------------------------------- - Gadget driver register and unregister. + Gadget driver probe and unregister. --------------------------------------------------------------------------*/ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { int retval; unsigned long flags = 0; @@ -2315,8 +2316,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!driver || (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH) - || !driver->bind || !driver->disconnect - || !driver->setup) + || !bind || !driver->disconnect || !driver->setup) return -EINVAL; if (udc_controller->driver) @@ -2332,7 +2332,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed); spin_unlock_irqrestore(&udc_controller->lock, flags); - retval = driver->bind(&udc_controller->gadget); + retval = bind(&udc_controller->gadget); if (retval) { dev_err(udc_controller->dev, "bind to %s --> %d", driver->driver.name, retval); @@ -2353,7 +2353,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) udc_controller->gadget.name, driver->driver.name); return 0; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index d933e6398412..4c55eda4bd20 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1759,7 +1759,8 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) * Hook to gadget drivers * Called by initialization code of gadget drivers *----------------------------------------------------------------*/ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { int retval = -ENODEV; unsigned long flags = 0; @@ -1769,8 +1770,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!driver || (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH) - || !driver->bind || !driver->disconnect - || !driver->setup) + || !bind || !driver->disconnect || !driver->setup) return -EINVAL; if (udc_controller->driver) @@ -1786,7 +1786,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&udc_controller->lock, flags); /* bind udc driver to gadget driver */ - retval = driver->bind(&udc_controller->gadget); + retval = bind(&udc_controller->gadget); if (retval) { VDBG("bind to %s --> %d", driver->driver.name, retval); udc_controller->gadget.dev.driver = NULL; @@ -1808,7 +1808,7 @@ out: retval); return retval; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); /* Disconnect from gadget driver */ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index a9474f8d5325..af75e3620849 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -52,9 +52,8 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Michal Nazarewicz"); MODULE_LICENSE("GPL"); - -static unsigned short gfs_vendor_id = 0x0525; /* XXX NetChip */ -static unsigned short gfs_product_id = 0xa4ac; /* XXX */ +#define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */ +#define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */ static struct usb_device_descriptor gfs_dev_desc = { .bLength = sizeof gfs_dev_desc, @@ -63,29 +62,16 @@ static struct usb_device_descriptor gfs_dev_desc = { .bcdUSB = cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_PER_INTERFACE, - /* Vendor and product id can be overridden by module parameters. */ - /* .idVendor = cpu_to_le16(gfs_vendor_id), */ - /* .idProduct = cpu_to_le16(gfs_product_id), */ - /* .bcdDevice = f(hardware) */ - /* .iManufacturer = DYNAMIC */ - /* .iProduct = DYNAMIC */ - /* NO SERIAL NUMBER */ - .bNumConfigurations = 1, + .idVendor = cpu_to_le16(GFS_VENDOR_ID), + .idProduct = cpu_to_le16(GFS_PRODUCT_ID), }; -#define GFS_MODULE_PARAM_DESC(name, field) \ - MODULE_PARM_DESC(name, "Value of the " #field " field of the device descriptor sent to the host. Takes effect only prior to the user-space driver registering to the FunctionFS.") - -module_param_named(usb_class, gfs_dev_desc.bDeviceClass, byte, 0644); -GFS_MODULE_PARAM_DESC(usb_class, bDeviceClass); -module_param_named(usb_subclass, gfs_dev_desc.bDeviceSubClass, byte, 0644); -GFS_MODULE_PARAM_DESC(usb_subclass, bDeviceSubClass); -module_param_named(usb_protocol, gfs_dev_desc.bDeviceProtocol, byte, 0644); -GFS_MODULE_PARAM_DESC(usb_protocol, bDeviceProtocol); -module_param_named(usb_vendor, gfs_vendor_id, ushort, 0644); -GFS_MODULE_PARAM_DESC(usb_vendor, idVendor); -module_param_named(usb_product, gfs_product_id, ushort, 0644); -GFS_MODULE_PARAM_DESC(usb_product, idProduct); +module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644); +MODULE_PARM_DESC(bDeviceClass, "USB Device class"); +module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644); +MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass"); +module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644); +MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol"); @@ -95,8 +81,10 @@ static const struct usb_descriptor_header *gfs_otg_desc[] = { .bLength = sizeof(struct usb_otg_descriptor), .bDescriptorType = USB_DT_OTG, - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... */ + /* + * REVISIT SRP-only hardware is possible, although + * it would not be called "OTG" ... + */ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, }, @@ -105,19 +93,7 @@ static const struct usb_descriptor_header *gfs_otg_desc[] = { /* string IDs are assigned dynamically */ -enum { - GFS_STRING_MANUFACTURER_IDX, - GFS_STRING_PRODUCT_IDX, - GFS_STRING_FIRST_CONFIG_IDX, -}; - -static char gfs_manufacturer[50]; -static const char gfs_driver_desc[] = DRIVER_DESC; -static const char gfs_short_name[] = DRIVER_NAME; - static struct usb_string gfs_strings[] = { - [GFS_STRING_MANUFACTURER_IDX].s = gfs_manufacturer, - [GFS_STRING_PRODUCT_IDX].s = gfs_driver_desc, #ifdef CONFIG_USB_FUNCTIONFS_RNDIS { .s = "FunctionFS + RNDIS" }, #endif @@ -168,11 +144,11 @@ static int gfs_unbind(struct usb_composite_dev *cdev); static int gfs_do_config(struct usb_configuration *c); static struct usb_composite_driver gfs_driver = { - .name = gfs_short_name, + .name = DRIVER_NAME, .dev = &gfs_dev_desc, .strings = gfs_dev_strings, - .bind = gfs_bind, .unbind = gfs_unbind, + .iProduct = DRIVER_DESC, }; @@ -210,7 +186,7 @@ static int functionfs_ready_callback(struct ffs_data *ffs) return -EBUSY; gfs_ffs_data = ffs; - ret = usb_composite_register(&gfs_driver); + ret = usb_composite_probe(&gfs_driver, gfs_bind); if (unlikely(ret < 0)) clear_bit(0, &gfs_registered); return ret; @@ -245,20 +221,10 @@ static int gfs_bind(struct usb_composite_dev *cdev) if (unlikely(ret < 0)) goto error_quick; - gfs_dev_desc.idVendor = cpu_to_le16(gfs_vendor_id); - gfs_dev_desc.idProduct = cpu_to_le16(gfs_product_id); - - snprintf(gfs_manufacturer, sizeof gfs_manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - cdev->gadget->name); - ret = usb_string_ids_tab(cdev, gfs_strings); if (unlikely(ret < 0)) goto error; - gfs_dev_desc.iManufacturer = gfs_strings[GFS_STRING_MANUFACTURER_IDX].id; - gfs_dev_desc.iProduct = gfs_strings[GFS_STRING_PRODUCT_IDX].id; - ret = functionfs_bind(gfs_ffs_data, cdev); if (unlikely(ret < 0)) goto error; @@ -266,14 +232,12 @@ static int gfs_bind(struct usb_composite_dev *cdev) for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { struct gfs_configuration *c = gfs_configurations + i; - ret = GFS_STRING_FIRST_CONFIG_IDX + i; - c->c.label = gfs_strings[ret].s; - c->c.iConfiguration = gfs_strings[ret].id; - c->c.bind = gfs_do_config; + c->c.label = gfs_strings[i].s; + c->c.iConfiguration = gfs_strings[i].id; c->c.bConfigurationValue = 1 + i; c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER; - ret = usb_add_config(cdev, &c->c); + ret = usb_add_config(cdev, &c->c, gfs_do_config); if (unlikely(ret < 0)) goto error_unbind; } @@ -293,13 +257,14 @@ static int gfs_unbind(struct usb_composite_dev *cdev) { ENTER(); - /* We may have been called in an error recovery frem + /* + * We may have been called in an error recovery from * composite_bind() after gfs_unbind() failure so we need to * check if gfs_ffs_data is not NULL since gfs_bind() handles * all error recovery itself. I'd rather we werent called * from composite on orror recovery, but what you're gonna - * do...? */ - + * do...? + */ if (gfs_ffs_data) { gether_cleanup(); functionfs_unbind(gfs_ffs_data); @@ -334,14 +299,16 @@ static int gfs_do_config(struct usb_configuration *c) if (unlikely(ret < 0)) return ret; - /* After previous do_configs there may be some invalid + /* + * After previous do_configs there may be some invalid * pointers in c->interface array. This happens every time * a user space function with fewer interfaces than a user * space function that was run before the new one is run. The * compasit's set_config() assumes that if there is no more * then MAX_CONFIG_INTERFACES interfaces in a configuration * then there is a NULL pointer after the last interface in - * c->interface array. We need to make sure this is true. */ + * c->interface array. We need to make sure this is true. + */ if (c->next_interface_id < ARRAY_SIZE(c->interface)) c->interface[c->next_interface_id] = NULL; @@ -350,10 +317,12 @@ static int gfs_do_config(struct usb_configuration *c) #ifdef CONFIG_USB_FUNCTIONFS_ETH + static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) { return can_support_ecm(c->cdev->gadget) ? ecm_bind_config(c, ethaddr) : geth_bind_config(c, ethaddr); } + #endif diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 1b413a5cc3f6..0ab7e141d494 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -1157,7 +1157,7 @@ fail: /* * Creates an output endpoint, and initializes output ports. */ -static int __ref gmidi_bind(struct usb_gadget *gadget) +static int __init gmidi_bind(struct usb_gadget *gadget) { struct gmidi_device *dev; struct usb_ep *in_ep, *out_ep; @@ -1292,7 +1292,6 @@ static void gmidi_resume(struct usb_gadget *gadget) static struct usb_gadget_driver gmidi_driver = { .speed = USB_SPEED_FULL, .function = (char *)longname, - .bind = gmidi_bind, .unbind = gmidi_unbind, .setup = gmidi_setup, @@ -1309,7 +1308,7 @@ static struct usb_gadget_driver gmidi_driver = { static int __init gmidi_init(void) { - return usb_gadget_register_driver(&gmidi_driver); + return usb_gadget_probe_driver(&gmidi_driver, gmidi_bind); } module_init(gmidi_init); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 1088d08c7ed8..49fbd4dbeb94 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1343,14 +1343,15 @@ static struct goku_udc *the_controller; * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct goku_udc *dev = the_controller; int retval; if (!driver || driver->speed < USB_SPEED_FULL - || !driver->bind + || !bind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -1363,7 +1364,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; - retval = driver->bind(&dev->gadget); + retval = bind(&dev->gadget); if (retval) { DBG(dev, "bind to driver %s --> error %d\n", driver->driver.name, retval); @@ -1380,7 +1381,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) DBG(dev, "registered gadget driver '%s'\n", driver->driver.name); return 0; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver) diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c index 735495bf8411..2523e54097bd 100644 --- a/drivers/usb/gadget/hid.c +++ b/drivers/usb/gadget/hid.c @@ -127,7 +127,7 @@ static struct usb_gadget_strings *dev_strings[] = { /****************************** Configurations ******************************/ -static int __ref do_config(struct usb_configuration *c) +static int __init do_config(struct usb_configuration *c) { struct hidg_func_node *e; int func = 0, status = 0; @@ -148,7 +148,6 @@ static int __ref do_config(struct usb_configuration *c) static struct usb_configuration config_driver = { .label = "HID Gadget", - .bind = do_config, .bConfigurationValue = 1, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_SELFPOWER, @@ -156,7 +155,7 @@ static struct usb_configuration config_driver = { /****************************** Gadget Bind ******************************/ -static int __ref hid_bind(struct usb_composite_dev *cdev) +static int __init hid_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; struct list_head *tmp; @@ -201,7 +200,7 @@ static int __ref hid_bind(struct usb_composite_dev *cdev) device_desc.iProduct = status; /* register our configuration */ - status = usb_add_config(cdev, &config_driver); + status = usb_add_config(cdev, &config_driver, do_config); if (status < 0) return status; @@ -256,7 +255,6 @@ static struct usb_composite_driver hidg_driver = { .name = "g_hid", .dev = &device_desc, .strings = dev_strings, - .bind = hid_bind, .unbind = __exit_p(hid_unbind), }; @@ -282,7 +280,7 @@ static int __init hidg_init(void) if (status < 0) return status; - status = usb_composite_register(&hidg_driver); + status = usb_composite_probe(&hidg_driver, hid_bind); if (status < 0) platform_driver_unregister(&hidg_plat_driver); diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index e743122fcd93..ed0266462c57 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1319,14 +1319,15 @@ static struct imx_udc_struct controller = { * USB gadged driver functions ******************************************************************************* */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct imx_udc_struct *imx_usb = &controller; int retval; if (!driver || driver->speed < USB_SPEED_FULL - || !driver->bind + || !bind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -1342,7 +1343,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) retval = device_add(&imx_usb->gadget.dev); if (retval) goto fail; - retval = driver->bind(&imx_usb->gadget); + retval = bind(&imx_usb->gadget); if (retval) { D_ERR(imx_usb->dev, "<%s> bind to driver %s --> error %d\n", __func__, driver->driver.name, retval); @@ -1362,7 +1363,7 @@ fail: imx_usb->gadget.dev.driver = NULL; return retval; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index fc35406fc80c..e2e8eda83f0d 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1775,7 +1775,6 @@ static struct usb_gadget_driver gadgetfs_driver = { .speed = USB_SPEED_FULL, #endif .function = (char *) driver_desc, - .bind = gadgetfs_bind, .unbind = gadgetfs_unbind, .setup = gadgetfs_setup, .disconnect = gadgetfs_disconnect, @@ -1798,7 +1797,6 @@ static int gadgetfs_probe (struct usb_gadget *gadget) static struct usb_gadget_driver probe_driver = { .speed = USB_SPEED_HIGH, - .bind = gadgetfs_probe, .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, @@ -1908,7 +1906,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* triggers gadgetfs_bind(); then we can enumerate. */ spin_unlock_irq (&dev->lock); - value = usb_gadget_register_driver (&gadgetfs_driver); + value = usb_gadget_probe_driver(&gadgetfs_driver, gadgetfs_bind); if (value != 0) { kfree (dev->buf); dev->buf = NULL; @@ -2047,7 +2045,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) return -ESRCH; /* fake probe to determine $CHIP */ - (void) usb_gadget_register_driver (&probe_driver); + (void) usb_gadget_probe_driver(&probe_driver, gadgetfs_probe); if (!CHIP) return -ENODEV; diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index c2d2a201f84b..d297f9eb92e4 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -19,7 +19,7 @@ /* #undef DEBUG */ -/* #undef VERBOSE */ +/* #undef VERBOSE_DEBUG */ #if defined(CONFIG_USB_LANGWELL_OTG) #define OTG_TRANSCEIVER @@ -77,141 +77,110 @@ langwell_ep0_desc = { /*-------------------------------------------------------------------------*/ /* debugging */ -#ifdef DEBUG -#define DBG(dev, fmt, args...) \ - pr_debug("%s %s: " fmt , driver_name, \ - pci_name(dev->pdev), ## args) -#else -#define DBG(dev, fmt, args...) \ - do { } while (0) -#endif /* DEBUG */ - - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev, fmt, args...) \ - do { } while (0) -#endif /* VERBOSE */ - - -#define ERROR(dev, fmt, args...) \ - pr_err("%s %s: " fmt , driver_name, \ - pci_name(dev->pdev), ## args) - -#define WARNING(dev, fmt, args...) \ - pr_warning("%s %s: " fmt , driver_name, \ - pci_name(dev->pdev), ## args) - -#define INFO(dev, fmt, args...) \ - pr_info("%s %s: " fmt , driver_name, \ - pci_name(dev->pdev), ## args) - - -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG static inline void print_all_registers(struct langwell_udc *dev) { int i; /* Capability Registers */ - printk(KERN_DEBUG "Capability Registers (offset: " - "0x%04x, length: 0x%08x)\n", - CAP_REG_OFFSET, - (u32)sizeof(struct langwell_cap_regs)); - printk(KERN_DEBUG "caplength=0x%02x\n", + dev_dbg(&dev->pdev->dev, + "Capability Registers (offset: 0x%04x, length: 0x%08x)\n", + CAP_REG_OFFSET, (u32)sizeof(struct langwell_cap_regs)); + dev_dbg(&dev->pdev->dev, "caplength=0x%02x\n", readb(&dev->cap_regs->caplength)); - printk(KERN_DEBUG "hciversion=0x%04x\n", + dev_dbg(&dev->pdev->dev, "hciversion=0x%04x\n", readw(&dev->cap_regs->hciversion)); - printk(KERN_DEBUG "hcsparams=0x%08x\n", + dev_dbg(&dev->pdev->dev, "hcsparams=0x%08x\n", readl(&dev->cap_regs->hcsparams)); - printk(KERN_DEBUG "hccparams=0x%08x\n", + dev_dbg(&dev->pdev->dev, "hccparams=0x%08x\n", readl(&dev->cap_regs->hccparams)); - printk(KERN_DEBUG "dciversion=0x%04x\n", + dev_dbg(&dev->pdev->dev, "dciversion=0x%04x\n", readw(&dev->cap_regs->dciversion)); - printk(KERN_DEBUG "dccparams=0x%08x\n", + dev_dbg(&dev->pdev->dev, "dccparams=0x%08x\n", readl(&dev->cap_regs->dccparams)); /* Operational Registers */ - printk(KERN_DEBUG "Operational Registers (offset: " - "0x%04x, length: 0x%08x)\n", - OP_REG_OFFSET, - (u32)sizeof(struct langwell_op_regs)); - printk(KERN_DEBUG "extsts=0x%08x\n", + dev_dbg(&dev->pdev->dev, + "Operational Registers (offset: 0x%04x, length: 0x%08x)\n", + OP_REG_OFFSET, (u32)sizeof(struct langwell_op_regs)); + dev_dbg(&dev->pdev->dev, "extsts=0x%08x\n", readl(&dev->op_regs->extsts)); - printk(KERN_DEBUG "extintr=0x%08x\n", + dev_dbg(&dev->pdev->dev, "extintr=0x%08x\n", readl(&dev->op_regs->extintr)); - printk(KERN_DEBUG "usbcmd=0x%08x\n", + dev_dbg(&dev->pdev->dev, "usbcmd=0x%08x\n", readl(&dev->op_regs->usbcmd)); - printk(KERN_DEBUG "usbsts=0x%08x\n", + dev_dbg(&dev->pdev->dev, "usbsts=0x%08x\n", readl(&dev->op_regs->usbsts)); - printk(KERN_DEBUG "usbintr=0x%08x\n", + dev_dbg(&dev->pdev->dev, "usbintr=0x%08x\n", readl(&dev->op_regs->usbintr)); - printk(KERN_DEBUG "frindex=0x%08x\n", + dev_dbg(&dev->pdev->dev, "frindex=0x%08x\n", readl(&dev->op_regs->frindex)); - printk(KERN_DEBUG "ctrldssegment=0x%08x\n", + dev_dbg(&dev->pdev->dev, "ctrldssegment=0x%08x\n", readl(&dev->op_regs->ctrldssegment)); - printk(KERN_DEBUG "deviceaddr=0x%08x\n", + dev_dbg(&dev->pdev->dev, "deviceaddr=0x%08x\n", readl(&dev->op_regs->deviceaddr)); - printk(KERN_DEBUG "endpointlistaddr=0x%08x\n", + dev_dbg(&dev->pdev->dev, "endpointlistaddr=0x%08x\n", readl(&dev->op_regs->endpointlistaddr)); - printk(KERN_DEBUG "ttctrl=0x%08x\n", + dev_dbg(&dev->pdev->dev, "ttctrl=0x%08x\n", readl(&dev->op_regs->ttctrl)); - printk(KERN_DEBUG "burstsize=0x%08x\n", + dev_dbg(&dev->pdev->dev, "burstsize=0x%08x\n", readl(&dev->op_regs->burstsize)); - printk(KERN_DEBUG "txfilltuning=0x%08x\n", + dev_dbg(&dev->pdev->dev, "txfilltuning=0x%08x\n", readl(&dev->op_regs->txfilltuning)); - printk(KERN_DEBUG "txttfilltuning=0x%08x\n", + dev_dbg(&dev->pdev->dev, "txttfilltuning=0x%08x\n", readl(&dev->op_regs->txttfilltuning)); - printk(KERN_DEBUG "ic_usb=0x%08x\n", + dev_dbg(&dev->pdev->dev, "ic_usb=0x%08x\n", readl(&dev->op_regs->ic_usb)); - printk(KERN_DEBUG "ulpi_viewport=0x%08x\n", + dev_dbg(&dev->pdev->dev, "ulpi_viewport=0x%08x\n", readl(&dev->op_regs->ulpi_viewport)); - printk(KERN_DEBUG "configflag=0x%08x\n", + dev_dbg(&dev->pdev->dev, "configflag=0x%08x\n", readl(&dev->op_regs->configflag)); - printk(KERN_DEBUG "portsc1=0x%08x\n", + dev_dbg(&dev->pdev->dev, "portsc1=0x%08x\n", readl(&dev->op_regs->portsc1)); - printk(KERN_DEBUG "devlc=0x%08x\n", + dev_dbg(&dev->pdev->dev, "devlc=0x%08x\n", readl(&dev->op_regs->devlc)); - printk(KERN_DEBUG "otgsc=0x%08x\n", + dev_dbg(&dev->pdev->dev, "otgsc=0x%08x\n", readl(&dev->op_regs->otgsc)); - printk(KERN_DEBUG "usbmode=0x%08x\n", + dev_dbg(&dev->pdev->dev, "usbmode=0x%08x\n", readl(&dev->op_regs->usbmode)); - printk(KERN_DEBUG "endptnak=0x%08x\n", + dev_dbg(&dev->pdev->dev, "endptnak=0x%08x\n", readl(&dev->op_regs->endptnak)); - printk(KERN_DEBUG "endptnaken=0x%08x\n", + dev_dbg(&dev->pdev->dev, "endptnaken=0x%08x\n", readl(&dev->op_regs->endptnaken)); - printk(KERN_DEBUG "endptsetupstat=0x%08x\n", + dev_dbg(&dev->pdev->dev, "endptsetupstat=0x%08x\n", readl(&dev->op_regs->endptsetupstat)); - printk(KERN_DEBUG "endptprime=0x%08x\n", + dev_dbg(&dev->pdev->dev, "endptprime=0x%08x\n", readl(&dev->op_regs->endptprime)); - printk(KERN_DEBUG "endptflush=0x%08x\n", + dev_dbg(&dev->pdev->dev, "endptflush=0x%08x\n", readl(&dev->op_regs->endptflush)); - printk(KERN_DEBUG "endptstat=0x%08x\n", + dev_dbg(&dev->pdev->dev, "endptstat=0x%08x\n", readl(&dev->op_regs->endptstat)); - printk(KERN_DEBUG "endptcomplete=0x%08x\n", + dev_dbg(&dev->pdev->dev, "endptcomplete=0x%08x\n", readl(&dev->op_regs->endptcomplete)); for (i = 0; i < dev->ep_max / 2; i++) { - printk(KERN_DEBUG "endptctrl[%d]=0x%08x\n", + dev_dbg(&dev->pdev->dev, "endptctrl[%d]=0x%08x\n", i, readl(&dev->op_regs->endptctrl[i])); } } -#endif /* VERBOSE */ +#else + +#define print_all_registers(dev) do { } while (0) + +#endif /* VERBOSE_DEBUG */ /*-------------------------------------------------------------------------*/ -#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") +#define is_in(ep) (((ep)->ep_num == 0) ? ((ep)->dev->ep0_dir == \ + USB_DIR_IN) : (usb_endpoint_dir_in((ep)->desc))) -#define is_in(ep) (((ep)->ep_num == 0) ? ((ep)->dev->ep0_dir == \ - USB_DIR_IN) : ((ep)->desc->bEndpointAddress \ - & USB_DIR_IN) == USB_DIR_IN) +#define DIR_STRING(ep) (is_in(ep) ? "in" : "out") -#ifdef DEBUG -static char *type_string(u8 bmAttributes) +static char *type_string(const struct usb_endpoint_descriptor *desc) { - switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_BULK: return "bulk"; case USB_ENDPOINT_XFER_ISOC: @@ -222,7 +191,6 @@ static char *type_string(u8 bmAttributes) return "control"; } -#endif /* configure endpoint control registers */ @@ -233,7 +201,7 @@ static void ep_reset(struct langwell_ep *ep, unsigned char ep_num, u32 endptctrl; dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); if (is_in) { /* TX */ @@ -250,7 +218,7 @@ static void ep_reset(struct langwell_ep *ep, unsigned char ep_num, writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -260,7 +228,7 @@ static void ep0_reset(struct langwell_udc *dev) struct langwell_ep *ep; int i; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); /* ep0 in and out */ for (i = 0; i < 2; i++) { @@ -274,17 +242,18 @@ static void ep0_reset(struct langwell_udc *dev) ep->dqh->dqh_ios = 1; ep->dqh->dqh_mpl = EP0_MAX_PKT_SIZE; - /* FIXME: enable ep0-in HW zero length termination select */ + /* enable ep0-in HW zero length termination select */ if (is_in(ep)) ep->dqh->dqh_zlt = 0; ep->dqh->dqh_mult = 0; + ep->dqh->dtd_next = DTD_TERM; + /* configure ep0 control registers */ ep_reset(&dev->ep[0], 0, i, USB_ENDPOINT_XFER_CONTROL); } - VDBG(dev, "<--- %s()\n", __func__); - return; + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -300,12 +269,12 @@ static int langwell_ep_enable(struct usb_ep *_ep, struct langwell_ep *ep; u16 max = 0; unsigned long flags; - int retval = 0; + int i, retval = 0; unsigned char zlt, ios = 0, mult = 0; ep = container_of(_ep, struct langwell_ep, ep); dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (!_ep || !desc || ep->desc || desc->bDescriptorType != USB_DT_ENDPOINT) @@ -326,7 +295,7 @@ static int langwell_ep_enable(struct usb_ep *_ep, * sanity check type, direction, address, and then * initialize the endpoint capabilities fields in dQH */ - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: ios = 1; break; @@ -386,33 +355,36 @@ static int langwell_ep_enable(struct usb_ep *_ep, spin_lock_irqsave(&dev->lock, flags); - /* configure endpoint capabilities in dQH */ - ep->dqh->dqh_ios = ios; - ep->dqh->dqh_mpl = cpu_to_le16(max); - ep->dqh->dqh_zlt = zlt; - ep->dqh->dqh_mult = mult; - ep->ep.maxpacket = max; ep->desc = desc; ep->stopped = 0; - ep->ep_num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep->ep_num = usb_endpoint_num(desc); /* ep_type */ - ep->ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + ep->ep_type = usb_endpoint_type(desc); /* configure endpoint control registers */ ep_reset(ep, ep->ep_num, is_in(ep), ep->ep_type); - DBG(dev, "enabled %s (ep%d%s-%s), max %04x\n", + /* configure endpoint capabilities in dQH */ + i = ep->ep_num * 2 + is_in(ep); + ep->dqh = &dev->ep_dqh[i]; + ep->dqh->dqh_ios = ios; + ep->dqh->dqh_mpl = cpu_to_le16(max); + ep->dqh->dqh_zlt = zlt; + ep->dqh->dqh_mult = mult; + ep->dqh->dtd_next = DTD_TERM; + + dev_dbg(&dev->pdev->dev, "enabled %s (ep%d%s-%s), max %04x\n", _ep->name, ep->ep_num, - DIR_STRING(desc->bEndpointAddress), - type_string(desc->bmAttributes), + DIR_STRING(ep), + type_string(desc), max); spin_unlock_irqrestore(&dev->lock, flags); done: - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return retval; } @@ -428,7 +400,7 @@ static void done(struct langwell_ep *ep, struct langwell_request *req, struct langwell_dtd *curr_dtd, *next_dtd; int i; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); /* remove the req from ep->queue */ list_del_init(&req->queue); @@ -448,7 +420,8 @@ static void done(struct langwell_ep *ep, struct langwell_request *req, } if (req->mapped) { - dma_unmap_single(&dev->pdev->dev, req->req.dma, req->req.length, + dma_unmap_single(&dev->pdev->dev, + req->req.dma, req->req.length, is_in(ep) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); req->req.dma = DMA_ADDR_INVALID; req->mapped = 0; @@ -458,9 +431,10 @@ static void done(struct langwell_ep *ep, struct langwell_request *req, is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (status != -ESHUTDOWN) - DBG(dev, "complete %s, req %p, stat %d, len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); + dev_dbg(&dev->pdev->dev, + "complete %s, req %p, stat %d, len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); /* don't modify queue heads during completion callback */ ep->stopped = 1; @@ -473,7 +447,7 @@ static void done(struct langwell_ep *ep, struct langwell_request *req, spin_lock(&dev->lock); ep->stopped = stopped; - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -511,7 +485,7 @@ static int langwell_ep_disable(struct usb_ep *_ep) ep = container_of(_ep, struct langwell_ep, ep); dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (!_ep || !ep->desc) return -EINVAL; @@ -535,8 +509,8 @@ static int langwell_ep_disable(struct usb_ep *_ep) spin_unlock_irqrestore(&dev->lock, flags); - DBG(dev, "disabled %s\n", _ep->name); - VDBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "disabled %s\n", _ep->name); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -555,7 +529,7 @@ static struct usb_request *langwell_alloc_request(struct usb_ep *_ep, ep = container_of(_ep, struct langwell_ep, ep); dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); req = kzalloc(sizeof(*req), gfp_flags); if (!req) @@ -564,8 +538,8 @@ static struct usb_request *langwell_alloc_request(struct usb_ep *_ep, req->req.dma = DMA_ADDR_INVALID; INIT_LIST_HEAD(&req->queue); - VDBG(dev, "alloc request for %s\n", _ep->name); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "alloc request for %s\n", _ep->name); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return &req->req; } @@ -580,7 +554,7 @@ static void langwell_free_request(struct usb_ep *_ep, ep = container_of(_ep, struct langwell_ep, ep); dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (!_ep || !_req) return; @@ -591,8 +565,8 @@ static void langwell_free_request(struct usb_ep *_ep, if (_req) kfree(req); - VDBG(dev, "free request for %s\n", _ep->name); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "free request for %s\n", _ep->name); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -608,23 +582,24 @@ static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req) struct langwell_udc *dev; dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); i = ep->ep_num * 2 + is_in(ep); dqh = &dev->ep_dqh[i]; if (ep->ep_num) - VDBG(dev, "%s\n", ep->name); + dev_vdbg(&dev->pdev->dev, "%s\n", ep->name); else /* ep0 */ - VDBG(dev, "%s-%s\n", ep->name, is_in(ep) ? "in" : "out"); + dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep)); - VDBG(dev, "ep_dqh[%d] addr: 0x%08x\n", i, (u32)&(dev->ep_dqh[i])); + dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%08x\n", + i, (u32)&(dev->ep_dqh[i])); bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << (ep->ep_num)); - VDBG(dev, "bit_mask = 0x%08x\n", bit_mask); + dev_vdbg(&dev->pdev->dev, "bit_mask = 0x%08x\n", bit_mask); /* check if the pipe is empty */ if (!(list_empty(&ep->queue))) { @@ -665,14 +640,17 @@ static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req) /* clear active and halt bit */ dtd_status = (u8) ~(DTD_STS_ACTIVE | DTD_STS_HALTED); dqh->dtd_status &= dtd_status; - VDBG(dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status); + dev_vdbg(&dev->pdev->dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status); + + /* ensure that updates to the dQH will occure before priming */ + wmb(); /* write 1 to endptprime register to PRIME endpoint */ bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << ep->ep_num); - VDBG(dev, "endprime bit_mask = 0x%08x\n", bit_mask); + dev_vdbg(&dev->pdev->dev, "endprime bit_mask = 0x%08x\n", bit_mask); writel(bit_mask, &dev->op_regs->endptprime); out: - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -687,7 +665,7 @@ static struct langwell_dtd *build_dtd(struct langwell_request *req, int i; dev = req->ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); /* the maximum transfer length, up to 16k bytes */ *length = min(req->req.length - req->req.actual, @@ -708,7 +686,7 @@ static struct langwell_dtd *build_dtd(struct langwell_request *req, /* fill in total bytes with transfer size */ dtd->dtd_total = cpu_to_le16(*length); - VDBG(dev, "dtd->dtd_total = %d\n", dtd->dtd_total); + dev_vdbg(&dev->pdev->dev, "dtd->dtd_total = %d\n", dtd->dtd_total); /* set is_last flag if req->req.zero is set or not */ if (req->req.zero) { @@ -722,7 +700,7 @@ static struct langwell_dtd *build_dtd(struct langwell_request *req, *is_last = 0; if (*is_last == 0) - VDBG(dev, "multi-dtd request!\n"); + dev_vdbg(&dev->pdev->dev, "multi-dtd request!\n"); /* set interrupt on complete bit for the last dTD */ if (*is_last && !req->req.no_interrupt) @@ -733,10 +711,12 @@ static struct langwell_dtd *build_dtd(struct langwell_request *req, /* set the active bit of status field to 1 */ dtd->dtd_status = DTD_STS_ACTIVE; - VDBG(dev, "dtd->dtd_status = 0x%02x\n", dtd->dtd_status); + dev_vdbg(&dev->pdev->dev, "dtd->dtd_status = 0x%02x\n", + dtd->dtd_status); - VDBG(dev, "length = %d, dma addr= 0x%08x\n", *length, (int)*dma); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "length = %d, dma addr= 0x%08x\n", + *length, (int)*dma); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return dtd; } @@ -751,7 +731,7 @@ static int req_to_dtd(struct langwell_request *req) dma_addr_t dma; dev = req->ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); do { dtd = build_dtd(req, &count, &dma, &is_last); if (dtd == NULL) @@ -773,7 +753,7 @@ static int req_to_dtd(struct langwell_request *req) req->tail = dtd; - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -803,9 +783,9 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req, dev = ep->dev; req->ep = ep; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (usb_endpoint_xfer_isoc(ep->desc)) { if (req->req.length > ep->ep.maxpacket) return -EMSGSIZE; is_iso = 1; @@ -818,7 +798,7 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req, if (_req->dma == DMA_ADDR_INVALID) { /* WORKAROUND: WARN_ON(size == 0) */ if (_req->length == 0) { - VDBG(dev, "req->length: 0->1\n"); + dev_vdbg(&dev->pdev->dev, "req->length: 0->1\n"); zlflag = 1; _req->length++; } @@ -827,24 +807,25 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req, _req->buf, _req->length, is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (zlflag && (_req->length == 1)) { - VDBG(dev, "req->length: 1->0\n"); + dev_vdbg(&dev->pdev->dev, "req->length: 1->0\n"); zlflag = 0; _req->length = 0; } req->mapped = 1; - VDBG(dev, "req->mapped = 1\n"); + dev_vdbg(&dev->pdev->dev, "req->mapped = 1\n"); } else { dma_sync_single_for_device(&dev->pdev->dev, _req->dma, _req->length, is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->mapped = 0; - VDBG(dev, "req->mapped = 0\n"); + dev_vdbg(&dev->pdev->dev, "req->mapped = 0\n"); } - DBG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08llx\n", - _ep->name, - _req, _req->length, _req->buf, (unsigned long long)_req->dma); + dev_dbg(&dev->pdev->dev, + "%s queue req %p, len %u, buf %p, dma 0x%08x\n", + _ep->name, + _req, _req->length, _req->buf, (int)_req->dma); _req->status = -EINPROGRESS; _req->actual = 0; @@ -866,12 +847,12 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req, if (likely(req != NULL)) { list_add_tail(&req->queue, &ep->queue); - VDBG(dev, "list_add_tail() \n"); + dev_vdbg(&dev->pdev->dev, "list_add_tail()\n"); } spin_unlock_irqrestore(&dev->lock, flags); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -888,7 +869,7 @@ static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) ep = container_of(_ep, struct langwell_ep, ep); dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (!_ep || !ep->desc || !_req) return -EINVAL; @@ -924,7 +905,7 @@ static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* queue head may be partially complete. */ if (ep->queue.next == &req->queue) { - DBG(dev, "unlink (%s) dma\n", _ep->name); + dev_dbg(&dev->pdev->dev, "unlink (%s) dma\n", _ep->name); _req->status = -ECONNRESET; langwell_ep_fifo_flush(&ep->ep); @@ -963,7 +944,7 @@ done: ep->stopped = stopped; spin_unlock_irqrestore(&dev->lock, flags); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return retval; } @@ -976,7 +957,7 @@ static void ep_set_halt(struct langwell_ep *ep, int value) u32 endptctrl = 0; int ep_num; struct langwell_udc *dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); ep_num = ep->ep_num; endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); @@ -1001,7 +982,7 @@ static void ep_set_halt(struct langwell_ep *ep, int value) writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -1016,7 +997,7 @@ static int langwell_ep_set_halt(struct usb_ep *_ep, int value) ep = container_of(_ep, struct langwell_ep, ep); dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (!_ep || !ep->desc) return -EINVAL; @@ -1024,8 +1005,7 @@ static int langwell_ep_set_halt(struct usb_ep *_ep, int value) if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; - if (ep->desc && (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_ISOC) + if (usb_endpoint_xfer_isoc(ep->desc)) return -EOPNOTSUPP; spin_lock_irqsave(&dev->lock, flags); @@ -1036,7 +1016,7 @@ static int langwell_ep_set_halt(struct usb_ep *_ep, int value) */ if (!list_empty(&ep->queue) && is_in(ep) && value) { /* IN endpoint FIFO holds bytes */ - DBG(dev, "%s FIFO holds bytes\n", _ep->name); + dev_dbg(&dev->pdev->dev, "%s FIFO holds bytes\n", _ep->name); retval = -EAGAIN; goto done; } @@ -1050,8 +1030,9 @@ static int langwell_ep_set_halt(struct usb_ep *_ep, int value) } done: spin_unlock_irqrestore(&dev->lock, flags); - DBG(dev, "%s %s halt\n", _ep->name, value ? "set" : "clear"); - VDBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "%s %s halt\n", + _ep->name, value ? "set" : "clear"); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return retval; } @@ -1065,12 +1046,12 @@ static int langwell_ep_set_wedge(struct usb_ep *_ep) ep = container_of(_ep, struct langwell_ep, ep); dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (!_ep || !ep->desc) return -EINVAL; - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return usb_ep_set_halt(_ep); } @@ -1086,15 +1067,16 @@ static void langwell_ep_fifo_flush(struct usb_ep *_ep) ep = container_of(_ep, struct langwell_ep, ep); dev = ep->dev; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (!_ep || !ep->desc) { - VDBG(dev, "ep or ep->desc is NULL\n"); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "ep or ep->desc is NULL\n"); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return; } - VDBG(dev, "%s-%s fifo flush\n", _ep->name, is_in(ep) ? "in" : "out"); + dev_vdbg(&dev->pdev->dev, "%s-%s fifo flush\n", + _ep->name, DIR_STRING(ep)); /* flush endpoint buffer */ if (ep->ep_num == 0) @@ -1110,14 +1092,14 @@ static void langwell_ep_fifo_flush(struct usb_ep *_ep) writel(flush_bit, &dev->op_regs->endptflush); while (readl(&dev->op_regs->endptflush)) { if (time_after(jiffies, timeout)) { - ERROR(dev, "ep flush timeout\n"); + dev_err(&dev->pdev->dev, "ep flush timeout\n"); goto done; } cpu_relax(); } } while (readl(&dev->op_regs->endptstat) & flush_bit); done: - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -1167,31 +1149,59 @@ static int langwell_get_frame(struct usb_gadget *_gadget) return -ENODEV; dev = container_of(_gadget, struct langwell_udc, gadget); - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); retval = readl(&dev->op_regs->frindex) & FRINDEX_MASK; - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return retval; } +/* enter or exit PHY low power state */ +static void langwell_phy_low_power(struct langwell_udc *dev, bool flag) +{ + u32 devlc; + u8 devlc_byte2; + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); + + devlc = readl(&dev->op_regs->devlc); + dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc); + + if (flag) + devlc |= LPM_PHCD; + else + devlc &= ~LPM_PHCD; + + /* FIXME: workaround for Langwell A1/A2/A3 sighting */ + devlc_byte2 = (devlc >> 16) & 0xff; + writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2); + + devlc = readl(&dev->op_regs->devlc); + dev_vdbg(&dev->pdev->dev, + "%s PHY low power suspend, devlc = 0x%08x\n", + flag ? "enter" : "exit", devlc); +} + + /* tries to wake up the host connected to this gadget */ static int langwell_wakeup(struct usb_gadget *_gadget) { struct langwell_udc *dev; - u32 portsc1, devlc; - unsigned long flags; + u32 portsc1; + unsigned long flags; if (!_gadget) return 0; dev = container_of(_gadget, struct langwell_udc, gadget); - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - /* Remote Wakeup feature not enabled by host */ - if (!dev->remote_wakeup) + /* remote wakeup feature not enabled by host */ + if (!dev->remote_wakeup) { + dev_info(&dev->pdev->dev, "remote wakeup is disabled\n"); return -ENOTSUPP; + } spin_lock_irqsave(&dev->lock, flags); @@ -1201,27 +1211,23 @@ static int langwell_wakeup(struct usb_gadget *_gadget) return 0; } - /* LPM L1 to L0, remote wakeup */ - if (dev->lpm && dev->lpm_state == LPM_L1) { - portsc1 |= PORTS_SLP; - writel(portsc1, &dev->op_regs->portsc1); - } - - /* force port resume */ - if (dev->usb_state == USB_STATE_SUSPENDED) { - portsc1 |= PORTS_FPR; - writel(portsc1, &dev->op_regs->portsc1); - } + /* LPM L1 to L0 or legacy remote wakeup */ + if (dev->lpm && dev->lpm_state == LPM_L1) + dev_info(&dev->pdev->dev, "LPM L1 to L0 remote wakeup\n"); + else + dev_info(&dev->pdev->dev, "device remote wakeup\n"); /* exit PHY low power suspend */ - devlc = readl(&dev->op_regs->devlc); - VDBG(dev, "devlc = 0x%08x\n", devlc); - devlc &= ~LPM_PHCD; - writel(devlc, &dev->op_regs->devlc); + if (dev->pdev->device != 0x0829) + langwell_phy_low_power(dev, 0); + + /* force port resume */ + portsc1 |= PORTS_FPR; + writel(portsc1, &dev->op_regs->portsc1); spin_unlock_irqrestore(&dev->lock, flags); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -1231,16 +1237,17 @@ static int langwell_vbus_session(struct usb_gadget *_gadget, int is_active) { struct langwell_udc *dev; unsigned long flags; - u32 usbcmd; + u32 usbcmd; if (!_gadget) return -ENODEV; dev = container_of(_gadget, struct langwell_udc, gadget); - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); spin_lock_irqsave(&dev->lock, flags); - VDBG(dev, "VBUS status: %s\n", is_active ? "on" : "off"); + dev_vdbg(&dev->pdev->dev, "VBUS status: %s\n", + is_active ? "on" : "off"); dev->vbus_active = (is_active != 0); if (dev->driver && dev->softconnected && dev->vbus_active) { @@ -1255,7 +1262,7 @@ static int langwell_vbus_session(struct usb_gadget *_gadget, int is_active) spin_unlock_irqrestore(&dev->lock, flags); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -1269,15 +1276,15 @@ static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA) return -ENODEV; dev = container_of(_gadget, struct langwell_udc, gadget); - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (dev->transceiver) { - VDBG(dev, "otg_set_power\n"); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "otg_set_power\n"); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return otg_set_power(dev->transceiver, mA); } - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return -ENOTSUPP; } @@ -1286,15 +1293,15 @@ static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA) static int langwell_pullup(struct usb_gadget *_gadget, int is_on) { struct langwell_udc *dev; - u32 usbcmd; - unsigned long flags; + u32 usbcmd; + unsigned long flags; if (!_gadget) return -ENODEV; dev = container_of(_gadget, struct langwell_udc, gadget); - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); spin_lock_irqsave(&dev->lock, flags); dev->softconnected = (is_on != 0); @@ -1310,7 +1317,7 @@ static int langwell_pullup(struct usb_gadget *_gadget, int is_on) } spin_unlock_irqrestore(&dev->lock, flags); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -1346,12 +1353,13 @@ static const struct usb_gadget_ops langwell_ops = { static int langwell_udc_reset(struct langwell_udc *dev) { u32 usbcmd, usbmode, devlc, endpointlistaddr; + u8 devlc_byte0, devlc_byte2; unsigned long timeout; if (!dev) return -EINVAL; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); /* set controller to stop state */ usbcmd = readl(&dev->op_regs->usbcmd); @@ -1367,7 +1375,7 @@ static int langwell_udc_reset(struct langwell_udc *dev) timeout = jiffies + RESET_TIMEOUT; while (readl(&dev->op_regs->usbcmd) & CMD_RST) { if (time_after(jiffies, timeout)) { - ERROR(dev, "device reset timeout\n"); + dev_err(&dev->pdev->dev, "device reset timeout\n"); return -ETIMEDOUT; } cpu_relax(); @@ -1382,7 +1390,7 @@ static int langwell_udc_reset(struct langwell_udc *dev) writel(usbmode, &dev->op_regs->usbmode); usbmode = readl(&dev->op_regs->usbmode); - VDBG(dev, "usbmode=0x%08x\n", usbmode); + dev_vdbg(&dev->pdev->dev, "usbmode=0x%08x\n", usbmode); /* Write-Clear setup status */ writel(0, &dev->op_regs->usbsts); @@ -1390,9 +1398,17 @@ static int langwell_udc_reset(struct langwell_udc *dev) /* if support USB LPM, ACK all LPM token */ if (dev->lpm) { devlc = readl(&dev->op_regs->devlc); + dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc); + /* FIXME: workaround for Langwell A1/A2/A3 sighting */ devlc &= ~LPM_STL; /* don't STALL LPM token */ devlc &= ~LPM_NYT_ACK; /* ACK LPM token */ - writel(devlc, &dev->op_regs->devlc); + devlc_byte0 = devlc & 0xff; + devlc_byte2 = (devlc >> 16) & 0xff; + writeb(devlc_byte0, (u8 *)&dev->op_regs->devlc); + writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2); + devlc = readl(&dev->op_regs->devlc); + dev_vdbg(&dev->pdev->dev, + "ACK LPM token, devlc = 0x%08x\n", devlc); } /* fill endpointlistaddr register */ @@ -1400,10 +1416,11 @@ static int langwell_udc_reset(struct langwell_udc *dev) endpointlistaddr &= ENDPOINTLISTADDR_MASK; writel(endpointlistaddr, &dev->op_regs->endpointlistaddr); - VDBG(dev, "dQH base (vir: %p, phy: 0x%08x), endpointlistaddr=0x%08x\n", - dev->ep_dqh, endpointlistaddr, - readl(&dev->op_regs->endpointlistaddr)); - DBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, + "dQH base (vir: %p, phy: 0x%08x), endpointlistaddr=0x%08x\n", + dev->ep_dqh, endpointlistaddr, + readl(&dev->op_regs->endpointlistaddr)); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -1415,7 +1432,7 @@ static int eps_reinit(struct langwell_udc *dev) char name[14]; int i; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); /* initialize ep0 */ ep = &dev->ep[0]; @@ -1449,11 +1466,9 @@ static int eps_reinit(struct langwell_udc *dev) INIT_LIST_HEAD(&ep->queue); list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); - - ep->dqh = &dev->ep_dqh[i]; } - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -1462,7 +1477,7 @@ static int eps_reinit(struct langwell_udc *dev) static void langwell_udc_start(struct langwell_udc *dev) { u32 usbintr, usbcmd; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); /* enable interrupts */ usbintr = INTR_ULPIE /* ULPI */ @@ -1485,8 +1500,7 @@ static void langwell_udc_start(struct langwell_udc *dev) usbcmd |= CMD_RUNSTOP; writel(usbcmd, &dev->op_regs->usbcmd); - DBG(dev, "<--- %s()\n", __func__); - return; + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -1495,7 +1509,7 @@ static void langwell_udc_stop(struct langwell_udc *dev) { u32 usbcmd; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); /* disable all interrupts */ writel(0, &dev->op_regs->usbintr); @@ -1508,8 +1522,7 @@ static void langwell_udc_stop(struct langwell_udc *dev) usbcmd &= ~CMD_RUNSTOP; writel(usbcmd, &dev->op_regs->usbcmd); - DBG(dev, "<--- %s()\n", __func__); - return; + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -1518,7 +1531,7 @@ static void stop_activity(struct langwell_udc *dev, struct usb_gadget_driver *driver) { struct langwell_ep *ep; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); nuke(&dev->ep[0], -ESHUTDOWN); @@ -1533,7 +1546,7 @@ static void stop_activity(struct langwell_udc *dev, spin_lock(&dev->lock); } - DBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -1659,13 +1672,15 @@ static ssize_t show_langwell_udc(struct device *_dev, "Over-current Change: %s\n" "Port Enable/Disable Change: %s\n" "Port Enabled/Disabled: %s\n" - "Current Connect Status: %s\n\n", + "Current Connect Status: %s\n" + "LPM Suspend Status: %s\n\n", (tmp_reg & PORTS_PR) ? "Reset" : "Not Reset", (tmp_reg & PORTS_SUSP) ? "Suspend " : "Not Suspend", (tmp_reg & PORTS_OCC) ? "Detected" : "No", (tmp_reg & PORTS_PEC) ? "Changed" : "Not Changed", (tmp_reg & PORTS_PE) ? "Enable" : "Not Correct", - (tmp_reg & PORTS_CCS) ? "Attached" : "Not Attached"); + (tmp_reg & PORTS_CCS) ? "Attached" : "Not Attached", + (tmp_reg & PORTS_SLP) ? "LPM L1" : "LPM L0"); size -= t; next += t; @@ -1676,7 +1691,7 @@ static ssize_t show_langwell_udc(struct device *_dev, "Serial Transceiver : %d\n" "Port Speed: %s\n" "Port Force Full Speed Connenct: %s\n" - "PHY Low Power Suspend Clock Disable: %s\n" + "PHY Low Power Suspend Clock: %s\n" "BmAttributes: %d\n\n", LPM_PTS(tmp_reg), (tmp_reg & LPM_STS) ? 1 : 0, @@ -1797,6 +1812,36 @@ static ssize_t show_langwell_udc(struct device *_dev, static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL); +/* device "remote_wakeup" sysfs attribute file */ +static ssize_t store_remote_wakeup(struct device *_dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct langwell_udc *dev = the_controller; + unsigned long flags; + ssize_t rc = count; + + if (count > 2) + return -EINVAL; + + if (count > 0 && buf[count-1] == '\n') + ((char *) buf)[count-1] = 0; + + if (buf[0] != '1') + return -EINVAL; + + /* force remote wakeup enabled in case gadget driver doesn't support */ + spin_lock_irqsave(&dev->lock, flags); + dev->remote_wakeup = 1; + dev->dev_status |= (1 << USB_DEVICE_REMOTE_WAKEUP); + spin_unlock_irqrestore(&dev->lock, flags); + + langwell_wakeup(&dev->gadget); + + return rc; +} +static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup); + + /*-------------------------------------------------------------------------*/ /* @@ -1807,7 +1852,8 @@ static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL); * the driver might get unbound. */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct langwell_udc *dev = the_controller; unsigned long flags; @@ -1816,7 +1862,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!dev) return -ENODEV; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); if (dev->driver) return -EBUSY; @@ -1830,9 +1876,9 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&dev->lock, flags); - retval = driver->bind(&dev->gadget); + retval = bind(&dev->gadget); if (retval) { - DBG(dev, "bind to driver %s --> %d\n", + dev_dbg(&dev->pdev->dev, "bind to driver %s --> %d\n", driver->driver.name, retval); dev->driver = NULL; dev->gadget.dev.driver = NULL; @@ -1851,13 +1897,13 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (dev->got_irq) langwell_udc_start(dev); - VDBG(dev, "After langwell_udc_start(), print all registers:\n"); -#ifdef VERBOSE + dev_vdbg(&dev->pdev->dev, + "After langwell_udc_start(), print all registers:\n"); print_all_registers(dev); -#endif - INFO(dev, "register driver: %s\n", driver->driver.name); - VDBG(dev, "<--- %s()\n", __func__); + dev_info(&dev->pdev->dev, "register driver: %s\n", + driver->driver.name); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; err_unbind: @@ -1865,10 +1911,10 @@ err_unbind: dev->gadget.dev.driver = NULL; dev->driver = NULL; - DBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); return retval; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); /* unregister gadget driver */ @@ -1880,11 +1926,15 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!dev) return -ENODEV; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - if (unlikely(!driver || !driver->bind || !driver->unbind)) + if (unlikely(!driver || !driver->unbind)) return -EINVAL; + /* exit PHY low power suspend */ + if (dev->pdev->device != 0x0829) + langwell_phy_low_power(dev, 0); + /* unbind OTG transceiver */ if (dev->transceiver) (void)otg_set_peripheral(dev->transceiver, 0); @@ -1910,8 +1960,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) device_remove_file(&dev->pdev->dev, &dev_attr_function); - INFO(dev, "unregistered driver '%s'\n", driver->driver.name); - DBG(dev, "<--- %s()\n", __func__); + dev_info(&dev->pdev->dev, "unregistered driver '%s'\n", + driver->driver.name); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } EXPORT_SYMBOL(usb_gadget_unregister_driver); @@ -1930,7 +1981,7 @@ static void setup_tripwire(struct langwell_udc *dev) unsigned long timeout; struct langwell_dqh *dqh; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); /* ep0 OUT dQH */ dqh = &dev->ep_dqh[EP_DIR_OUT]; @@ -1943,7 +1994,7 @@ static void setup_tripwire(struct langwell_udc *dev) timeout = jiffies + SETUPSTAT_TIMEOUT; while (readl(&dev->op_regs->endptsetupstat)) { if (time_after(jiffies, timeout)) { - ERROR(dev, "setup_tripwire timeout\n"); + dev_err(&dev->pdev->dev, "setup_tripwire timeout\n"); break; } cpu_relax(); @@ -1963,7 +2014,7 @@ static void setup_tripwire(struct langwell_udc *dev) usbcmd = readl(&dev->op_regs->usbcmd); writel(usbcmd & ~CMD_SUTW, &dev->op_regs->usbcmd); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -1972,7 +2023,7 @@ static void ep0_stall(struct langwell_udc *dev) { u32 endptctrl; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); /* set TX and RX to stall */ endptctrl = readl(&dev->op_regs->endptctrl[0]); @@ -1983,7 +2034,7 @@ static void ep0_stall(struct langwell_udc *dev) dev->ep0_state = WAIT_FOR_SETUP; dev->ep0_dir = USB_DIR_OUT; - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -1994,7 +2045,7 @@ static int prime_status_phase(struct langwell_udc *dev, int dir) struct langwell_ep *ep; int status = 0; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (dir == EP_DIR_IN) dev->ep0_dir = USB_DIR_IN; @@ -2019,11 +2070,11 @@ static int prime_status_phase(struct langwell_udc *dev, int dir) return -ENOMEM; if (status) - ERROR(dev, "can't queue ep0 status request\n"); + dev_err(&dev->pdev->dev, "can't queue ep0 status request\n"); list_add_tail(&req->queue, &ep->queue); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return status; } @@ -2032,11 +2083,11 @@ static int prime_status_phase(struct langwell_udc *dev, int dir) static void set_address(struct langwell_udc *dev, u16 value, u16 index, u16 length) { - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); /* save the new address to device struct */ dev->dev_addr = (u8) value; - VDBG(dev, "dev->dev_addr = %d\n", dev->dev_addr); + dev_vdbg(&dev->pdev->dev, "dev->dev_addr = %d\n", dev->dev_addr); /* update usb state */ dev->usb_state = USB_STATE_ADDRESS; @@ -2045,7 +2096,7 @@ static void set_address(struct langwell_udc *dev, u16 value, if (prime_status_phase(dev, EP_DIR_IN)) ep0_stall(dev); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -2054,7 +2105,7 @@ static struct langwell_ep *get_ep_by_windex(struct langwell_udc *dev, u16 wIndex) { struct langwell_ep *ep; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) return &dev->ep[0]; @@ -2073,7 +2124,7 @@ static struct langwell_ep *get_ep_by_windex(struct langwell_udc *dev, return ep; } - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return NULL; } @@ -2085,7 +2136,7 @@ static int ep_is_stall(struct langwell_ep *ep) u32 endptctrl; int retval; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); endptctrl = readl(&dev->op_regs->endptctrl[ep->ep_num]); if (is_in(ep)) @@ -2093,7 +2144,7 @@ static int ep_is_stall(struct langwell_ep *ep) else retval = endptctrl & EPCTRL_RXS ? 1 : 0; - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return retval; } @@ -2107,14 +2158,13 @@ static void get_status(struct langwell_udc *dev, u8 request_type, u16 value, u16 status_data = 0; /* 16 bits cpu view status data */ int status = 0; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); ep = &dev->ep[0]; if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { /* get device status */ - status_data = 1 << USB_DEVICE_SELF_POWERED; - status_data |= dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP; + status_data = dev->dev_status; } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { /* get interface status */ status_data = 0; @@ -2129,6 +2179,8 @@ static void get_status(struct langwell_udc *dev, u8 request_type, u16 value, status_data = ep_is_stall(epn) << USB_ENDPOINT_HALT; } + dev_dbg(&dev->pdev->dev, "get status data: 0x%04x\n", status_data); + dev->ep0_dir = USB_DIR_IN; /* borrow the per device status_req */ @@ -2150,18 +2202,19 @@ static void get_status(struct langwell_udc *dev, u8 request_type, u16 value, goto stall; if (status) { - ERROR(dev, "response error on GET_STATUS request\n"); + dev_err(&dev->pdev->dev, + "response error on GET_STATUS request\n"); goto stall; } list_add_tail(&req->queue, &ep->queue); dev->ep0_state = DATA_STATE_XMIT; - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return; stall: ep0_stall(dev); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -2173,12 +2226,12 @@ static void handle_setup_packet(struct langwell_udc *dev, u16 wIndex = le16_to_cpu(setup->wIndex); u16 wLength = le16_to_cpu(setup->wLength); - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); /* ep0 fifo flush */ nuke(&dev->ep[0], -ESHUTDOWN); - DBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", + dev_dbg(&dev->pdev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", setup->bRequestType, setup->bRequest, wValue, wIndex, wLength); @@ -2197,7 +2250,7 @@ static void handle_setup_packet(struct langwell_udc *dev, /* We process some stardard setup requests here */ switch (setup->bRequest) { case USB_REQ_GET_STATUS: - DBG(dev, "SETUP: USB_REQ_GET_STATUS\n"); + dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_GET_STATUS\n"); /* get status, DATA and STATUS phase */ if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) != (USB_DIR_IN | USB_TYPE_STANDARD)) @@ -2206,7 +2259,7 @@ static void handle_setup_packet(struct langwell_udc *dev, goto end; case USB_REQ_SET_ADDRESS: - DBG(dev, "SETUP: USB_REQ_SET_ADDRESS\n"); + dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_SET_ADDRESS\n"); /* STATUS phase */ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) @@ -2220,9 +2273,11 @@ static void handle_setup_packet(struct langwell_udc *dev, { int rc = -EOPNOTSUPP; if (setup->bRequest == USB_REQ_SET_FEATURE) - DBG(dev, "SETUP: USB_REQ_SET_FEATURE\n"); + dev_dbg(&dev->pdev->dev, + "SETUP: USB_REQ_SET_FEATURE\n"); else if (setup->bRequest == USB_REQ_CLEAR_FEATURE) - DBG(dev, "SETUP: USB_REQ_CLEAR_FEATURE\n"); + dev_dbg(&dev->pdev->dev, + "SETUP: USB_REQ_CLEAR_FEATURE\n"); if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) { @@ -2240,13 +2295,29 @@ static void handle_setup_packet(struct langwell_udc *dev, spin_unlock(&dev->lock); rc = langwell_ep_set_halt(&epn->ep, - (setup->bRequest == USB_REQ_SET_FEATURE) - ? 1 : 0); + (setup->bRequest == USB_REQ_SET_FEATURE) + ? 1 : 0); spin_lock(&dev->lock); } else if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == (USB_RECIP_DEVICE | USB_TYPE_STANDARD)) { + rc = 0; + switch (wValue) { + case USB_DEVICE_REMOTE_WAKEUP: + if (setup->bRequest == USB_REQ_SET_FEATURE) { + dev->remote_wakeup = 1; + dev->dev_status |= (1 << wValue); + } else { + dev->remote_wakeup = 0; + dev->dev_status &= ~(1 << wValue); + } + break; + default: + rc = -EOPNOTSUPP; + break; + } + if (!gadget_is_otg(&dev->gadget)) break; else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) { @@ -2262,7 +2333,6 @@ static void handle_setup_packet(struct langwell_udc *dev, dev->gadget.a_alt_hnp_support = 1; else break; - rc = 0; } else break; @@ -2274,31 +2344,38 @@ static void handle_setup_packet(struct langwell_udc *dev, } case USB_REQ_GET_DESCRIPTOR: - DBG(dev, "SETUP: USB_REQ_GET_DESCRIPTOR\n"); + dev_dbg(&dev->pdev->dev, + "SETUP: USB_REQ_GET_DESCRIPTOR\n"); goto delegate; case USB_REQ_SET_DESCRIPTOR: - DBG(dev, "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n"); + dev_dbg(&dev->pdev->dev, + "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n"); goto delegate; case USB_REQ_GET_CONFIGURATION: - DBG(dev, "SETUP: USB_REQ_GET_CONFIGURATION\n"); + dev_dbg(&dev->pdev->dev, + "SETUP: USB_REQ_GET_CONFIGURATION\n"); goto delegate; case USB_REQ_SET_CONFIGURATION: - DBG(dev, "SETUP: USB_REQ_SET_CONFIGURATION\n"); + dev_dbg(&dev->pdev->dev, + "SETUP: USB_REQ_SET_CONFIGURATION\n"); goto delegate; case USB_REQ_GET_INTERFACE: - DBG(dev, "SETUP: USB_REQ_GET_INTERFACE\n"); + dev_dbg(&dev->pdev->dev, + "SETUP: USB_REQ_GET_INTERFACE\n"); goto delegate; case USB_REQ_SET_INTERFACE: - DBG(dev, "SETUP: USB_REQ_SET_INTERFACE\n"); + dev_dbg(&dev->pdev->dev, + "SETUP: USB_REQ_SET_INTERFACE\n"); goto delegate; case USB_REQ_SYNCH_FRAME: - DBG(dev, "SETUP: USB_REQ_SYNCH_FRAME unsupported\n"); + dev_dbg(&dev->pdev->dev, + "SETUP: USB_REQ_SYNCH_FRAME unsupported\n"); goto delegate; default: @@ -2310,7 +2387,8 @@ delegate: /* DATA phase from gadget, STATUS phase from udc */ dev->ep0_dir = (setup->bRequestType & USB_DIR_IN) ? USB_DIR_IN : USB_DIR_OUT; - VDBG(dev, "dev->ep0_dir = 0x%x, wLength = %d\n", + dev_vdbg(&dev->pdev->dev, + "dev->ep0_dir = 0x%x, wLength = %d\n", dev->ep0_dir, wLength); spin_unlock(&dev->lock); if (dev->driver->setup(&dev->gadget, @@ -2322,7 +2400,8 @@ delegate: } else { /* no DATA phase, IN STATUS phase from gadget */ dev->ep0_dir = USB_DIR_IN; - VDBG(dev, "dev->ep0_dir = 0x%x, wLength = %d\n", + dev_vdbg(&dev->pdev->dev, + "dev->ep0_dir = 0x%x, wLength = %d\n", dev->ep0_dir, wLength); spin_unlock(&dev->lock); if (dev->driver->setup(&dev->gadget, @@ -2334,8 +2413,7 @@ delegate: break; } end: - VDBG(dev, "<--- %s()\n", __func__); - return; + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -2359,7 +2437,7 @@ static int process_ep_req(struct langwell_udc *dev, int index, td_complete = 0; actual = curr_req->req.length; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); for (i = 0; i < curr_req->dtd_count; i++) { remaining_length = le16_to_cpu(curr_dtd->dtd_total); @@ -2372,10 +2450,12 @@ static int process_ep_req(struct langwell_udc *dev, int index, /* transfers completed successfully */ if (!remaining_length) { td_complete++; - VDBG(dev, "dTD transmitted successfully\n"); + dev_vdbg(&dev->pdev->dev, + "dTD transmitted successfully\n"); } else { if (dir) { - VDBG(dev, "TX dTD remains data\n"); + dev_vdbg(&dev->pdev->dev, + "TX dTD remains data\n"); retval = -EPROTO; break; @@ -2387,27 +2467,32 @@ static int process_ep_req(struct langwell_udc *dev, int index, } else { /* transfers completed with errors */ if (dtd_status & DTD_STS_ACTIVE) { - DBG(dev, "request not completed\n"); + dev_dbg(&dev->pdev->dev, + "dTD status ACTIVE dQH[%d]\n", index); retval = 1; return retval; } else if (dtd_status & DTD_STS_HALTED) { - ERROR(dev, "dTD error %08x dQH[%d]\n", - dtd_status, index); + dev_err(&dev->pdev->dev, + "dTD error %08x dQH[%d]\n", + dtd_status, index); /* clear the errors and halt condition */ curr_dqh->dtd_status = 0; retval = -EPIPE; break; } else if (dtd_status & DTD_STS_DBE) { - DBG(dev, "data buffer (overflow) error\n"); + dev_dbg(&dev->pdev->dev, + "data buffer (overflow) error\n"); retval = -EPROTO; break; } else if (dtd_status & DTD_STS_TRE) { - DBG(dev, "transaction(ISO) error\n"); + dev_dbg(&dev->pdev->dev, + "transaction(ISO) error\n"); retval = -EILSEQ; break; } else - ERROR(dev, "unknown error (0x%x)!\n", - dtd_status); + dev_err(&dev->pdev->dev, + "unknown error (0x%x)!\n", + dtd_status); } if (i != curr_req->dtd_count - 1) @@ -2420,7 +2505,7 @@ static int process_ep_req(struct langwell_udc *dev, int index, curr_req->req.actual = actual; - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -2430,7 +2515,7 @@ static void ep0_req_complete(struct langwell_udc *dev, struct langwell_ep *ep0, struct langwell_request *req) { u32 new_addr; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (dev->usb_state == USB_STATE_ADDRESS) { /* set the new address */ @@ -2438,7 +2523,7 @@ static void ep0_req_complete(struct langwell_udc *dev, writel(new_addr << USBADR_SHIFT, &dev->op_regs->deviceaddr); new_addr = USBADR(readl(&dev->op_regs->deviceaddr)); - VDBG(dev, "new_addr = %d\n", new_addr); + dev_vdbg(&dev->pdev->dev, "new_addr = %d\n", new_addr); } done(ep0, req, 0); @@ -2458,14 +2543,14 @@ static void ep0_req_complete(struct langwell_udc *dev, dev->ep0_state = WAIT_FOR_SETUP; break; case WAIT_FOR_SETUP: - ERROR(dev, "unexpect ep0 packets\n"); + dev_err(&dev->pdev->dev, "unexpect ep0 packets\n"); break; default: ep0_stall(dev); break; } - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -2477,16 +2562,17 @@ static void handle_trans_complete(struct langwell_udc *dev) struct langwell_ep *epn; struct langwell_request *curr_req, *temp_req; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); complete_bits = readl(&dev->op_regs->endptcomplete); - VDBG(dev, "endptcomplete register: 0x%08x\n", complete_bits); + dev_vdbg(&dev->pdev->dev, "endptcomplete register: 0x%08x\n", + complete_bits); /* Write-Clear the bits in endptcomplete register */ writel(complete_bits, &dev->op_regs->endptcomplete); if (!complete_bits) { - DBG(dev, "complete_bits = 0\n"); + dev_dbg(&dev->pdev->dev, "complete_bits = 0\n"); goto done; } @@ -2506,23 +2592,25 @@ static void handle_trans_complete(struct langwell_udc *dev) epn = &dev->ep[i]; if (epn->name == NULL) { - WARNING(dev, "invalid endpoint\n"); + dev_warn(&dev->pdev->dev, "invalid endpoint\n"); continue; } if (i < 2) /* ep0 in and out */ - DBG(dev, "%s-%s transfer completed\n", + dev_dbg(&dev->pdev->dev, "%s-%s transfer completed\n", epn->name, is_in(epn) ? "in" : "out"); else - DBG(dev, "%s transfer completed\n", epn->name); + dev_dbg(&dev->pdev->dev, "%s transfer completed\n", + epn->name); /* process the req queue until an uncomplete request */ list_for_each_entry_safe(curr_req, temp_req, &epn->queue, queue) { status = process_ep_req(dev, i, curr_req); - VDBG(dev, "%s req status: %d\n", epn->name, status); + dev_vdbg(&dev->pdev->dev, "%s req status: %d\n", + epn->name, status); if (status) break; @@ -2540,8 +2628,7 @@ static void handle_trans_complete(struct langwell_udc *dev) } } done: - VDBG(dev, "<--- %s()\n", __func__); - return; + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -2551,14 +2638,14 @@ static void handle_port_change(struct langwell_udc *dev) u32 portsc1, devlc; u32 speed; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (dev->bus_reset) dev->bus_reset = 0; portsc1 = readl(&dev->op_regs->portsc1); devlc = readl(&dev->op_regs->devlc); - VDBG(dev, "portsc1 = 0x%08x, devlc = 0x%08x\n", + dev_vdbg(&dev->pdev->dev, "portsc1 = 0x%08x, devlc = 0x%08x\n", portsc1, devlc); /* bus reset is finished */ @@ -2579,25 +2666,22 @@ static void handle_port_change(struct langwell_udc *dev) dev->gadget.speed = USB_SPEED_UNKNOWN; break; } - VDBG(dev, "speed = %d, dev->gadget.speed = %d\n", + dev_vdbg(&dev->pdev->dev, + "speed = %d, dev->gadget.speed = %d\n", speed, dev->gadget.speed); } /* LPM L0 to L1 */ if (dev->lpm && dev->lpm_state == LPM_L0) if (portsc1 & PORTS_SUSP && portsc1 & PORTS_SLP) { - INFO(dev, "LPM L0 to L1\n"); - dev->lpm_state = LPM_L1; + dev_info(&dev->pdev->dev, "LPM L0 to L1\n"); + dev->lpm_state = LPM_L1; } /* LPM L1 to L0, force resume or remote wakeup finished */ if (dev->lpm && dev->lpm_state == LPM_L1) if (!(portsc1 & PORTS_SUSP)) { - if (portsc1 & PORTS_SLP) - INFO(dev, "LPM L1 to L0, force resume\n"); - else - INFO(dev, "LPM L1 to L0, remote wakeup\n"); - + dev_info(&dev->pdev->dev, "LPM L1 to L0\n"); dev->lpm_state = LPM_L0; } @@ -2605,7 +2689,7 @@ static void handle_port_change(struct langwell_udc *dev) if (!dev->resume_state) dev->usb_state = USB_STATE_DEFAULT; - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -2617,7 +2701,7 @@ static void handle_usb_reset(struct langwell_udc *dev) endptcomplete; unsigned long timeout; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); /* Write-Clear the device address */ deviceaddr = readl(&dev->op_regs->deviceaddr); @@ -2634,7 +2718,10 @@ static void handle_usb_reset(struct langwell_udc *dev) dev->ep0_dir = USB_DIR_OUT; dev->ep0_state = WAIT_FOR_SETUP; - dev->remote_wakeup = 0; /* default to 0 on reset */ + + /* remote wakeup reset to 0 when the device is reset */ + dev->remote_wakeup = 0; + dev->dev_status = 1 << USB_DEVICE_SELF_POWERED; dev->gadget.b_hnp_enable = 0; dev->gadget.a_hnp_support = 0; dev->gadget.a_alt_hnp_support = 0; @@ -2651,7 +2738,7 @@ static void handle_usb_reset(struct langwell_udc *dev) timeout = jiffies + PRIME_TIMEOUT; while (readl(&dev->op_regs->endptprime)) { if (time_after(jiffies, timeout)) { - ERROR(dev, "USB reset timeout\n"); + dev_err(&dev->pdev->dev, "USB reset timeout\n"); break; } cpu_relax(); @@ -2661,7 +2748,7 @@ static void handle_usb_reset(struct langwell_udc *dev) writel((u32) ~0, &dev->op_regs->endptflush); if (readl(&dev->op_regs->portsc1) & PORTS_PR) { - VDBG(dev, "USB bus reset\n"); + dev_vdbg(&dev->pdev->dev, "USB bus reset\n"); /* bus is reseting */ dev->bus_reset = 1; @@ -2669,7 +2756,7 @@ static void handle_usb_reset(struct langwell_udc *dev) stop_activity(dev, dev->driver); dev->usb_state = USB_STATE_DEFAULT; } else { - VDBG(dev, "device controller reset\n"); + dev_vdbg(&dev->pdev->dev, "device controller reset\n"); /* controller reset */ langwell_udc_reset(dev); @@ -2691,15 +2778,14 @@ static void handle_usb_reset(struct langwell_udc *dev) dev->lotg->hsm.b_hnp_enable = 0; #endif - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } /* USB bus suspend/resume interrupt */ static void handle_bus_suspend(struct langwell_udc *dev) { - u32 devlc; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); dev->resume_state = dev->usb_state; dev->usb_state = USB_STATE_SUSPENDED; @@ -2733,33 +2819,29 @@ static void handle_bus_suspend(struct langwell_udc *dev) spin_unlock(&dev->lock); dev->driver->suspend(&dev->gadget); spin_lock(&dev->lock); - DBG(dev, "suspend %s\n", dev->driver->driver.name); + dev_dbg(&dev->pdev->dev, "suspend %s\n", + dev->driver->driver.name); } } /* enter PHY low power suspend */ - devlc = readl(&dev->op_regs->devlc); - VDBG(dev, "devlc = 0x%08x\n", devlc); - devlc |= LPM_PHCD; - writel(devlc, &dev->op_regs->devlc); + if (dev->pdev->device != 0x0829) + langwell_phy_low_power(dev, 0); - DBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); } static void handle_bus_resume(struct langwell_udc *dev) { - u32 devlc; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); dev->usb_state = dev->resume_state; dev->resume_state = 0; /* exit PHY low power suspend */ - devlc = readl(&dev->op_regs->devlc); - VDBG(dev, "devlc = 0x%08x\n", devlc); - devlc &= ~LPM_PHCD; - writel(devlc, &dev->op_regs->devlc); + if (dev->pdev->device != 0x0829) + langwell_phy_low_power(dev, 0); #ifdef OTG_TRANSCEIVER if (dev->lotg->otg.default_a == 0) @@ -2772,11 +2854,12 @@ static void handle_bus_resume(struct langwell_udc *dev) spin_unlock(&dev->lock); dev->driver->resume(&dev->gadget); spin_lock(&dev->lock); - DBG(dev, "resume %s\n", dev->driver->driver.name); + dev_dbg(&dev->pdev->dev, "resume %s\n", + dev->driver->driver.name); } } - DBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -2789,11 +2872,11 @@ static irqreturn_t langwell_irq(int irq, void *_dev) irq_sts, portsc1; - VDBG(dev, "---> %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); if (dev->stopped) { - VDBG(dev, "handle IRQ_NONE\n"); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n"); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return IRQ_NONE; } @@ -2806,12 +2889,13 @@ static irqreturn_t langwell_irq(int irq, void *_dev) usbintr = readl(&dev->op_regs->usbintr); irq_sts = usbsts & usbintr; - VDBG(dev, "usbsts = 0x%08x, usbintr = 0x%08x, irq_sts = 0x%08x\n", + dev_vdbg(&dev->pdev->dev, + "usbsts = 0x%08x, usbintr = 0x%08x, irq_sts = 0x%08x\n", usbsts, usbintr, irq_sts); if (!irq_sts) { - VDBG(dev, "handle IRQ_NONE\n"); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n"); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); spin_unlock(&dev->lock); return IRQ_NONE; } @@ -2827,12 +2911,13 @@ static irqreturn_t langwell_irq(int irq, void *_dev) /* USB interrupt */ if (irq_sts & STS_UI) { - VDBG(dev, "USB interrupt\n"); + dev_vdbg(&dev->pdev->dev, "USB interrupt\n"); /* setup packet received from ep0 */ if (readl(&dev->op_regs->endptsetupstat) & EP0SETUPSTAT_MASK) { - VDBG(dev, "USB SETUP packet received interrupt\n"); + dev_vdbg(&dev->pdev->dev, + "USB SETUP packet received interrupt\n"); /* setup tripwire semaphone */ setup_tripwire(dev); handle_setup_packet(dev, &dev->local_setup_buff); @@ -2840,7 +2925,8 @@ static irqreturn_t langwell_irq(int irq, void *_dev) /* USB transfer completion */ if (readl(&dev->op_regs->endptcomplete)) { - VDBG(dev, "USB transfer completion interrupt\n"); + dev_vdbg(&dev->pdev->dev, + "USB transfer completion interrupt\n"); handle_trans_complete(dev); } } @@ -2848,36 +2934,36 @@ static irqreturn_t langwell_irq(int irq, void *_dev) /* SOF received interrupt (for ISO transfer) */ if (irq_sts & STS_SRI) { /* FIXME */ - /* VDBG(dev, "SOF received interrupt\n"); */ + /* dev_vdbg(&dev->pdev->dev, "SOF received interrupt\n"); */ } /* port change detect interrupt */ if (irq_sts & STS_PCI) { - VDBG(dev, "port change detect interrupt\n"); + dev_vdbg(&dev->pdev->dev, "port change detect interrupt\n"); handle_port_change(dev); } /* suspend interrrupt */ if (irq_sts & STS_SLI) { - VDBG(dev, "suspend interrupt\n"); + dev_vdbg(&dev->pdev->dev, "suspend interrupt\n"); handle_bus_suspend(dev); } /* USB reset interrupt */ if (irq_sts & STS_URI) { - VDBG(dev, "USB reset interrupt\n"); + dev_vdbg(&dev->pdev->dev, "USB reset interrupt\n"); handle_usb_reset(dev); } /* USB error or system error interrupt */ if (irq_sts & (STS_UEI | STS_SEI)) { /* FIXME */ - WARNING(dev, "error IRQ, irq_sts: %x\n", irq_sts); + dev_warn(&dev->pdev->dev, "error IRQ, irq_sts: %x\n", irq_sts); } spin_unlock(&dev->lock); - VDBG(dev, "<--- %s()\n", __func__); + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return IRQ_HANDLED; } @@ -2889,15 +2975,59 @@ static void gadget_release(struct device *_dev) { struct langwell_udc *dev = the_controller; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); complete(dev->done); - DBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); kfree(dev); } +/* enable SRAM caching if SRAM detected */ +static void sram_init(struct langwell_udc *dev) +{ + struct pci_dev *pdev = dev->pdev; + + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); + + dev->sram_addr = pci_resource_start(pdev, 1); + dev->sram_size = pci_resource_len(pdev, 1); + dev_info(&dev->pdev->dev, "Found private SRAM at %x size:%x\n", + dev->sram_addr, dev->sram_size); + dev->got_sram = 1; + + if (pci_request_region(pdev, 1, kobject_name(&pdev->dev.kobj))) { + dev_warn(&dev->pdev->dev, "SRAM request failed\n"); + dev->got_sram = 0; + } else if (!dma_declare_coherent_memory(&pdev->dev, dev->sram_addr, + dev->sram_addr, dev->sram_size, DMA_MEMORY_MAP)) { + dev_warn(&dev->pdev->dev, "SRAM DMA declare failed\n"); + pci_release_region(pdev, 1); + dev->got_sram = 0; + } + + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); +} + + +/* release SRAM caching */ +static void sram_deinit(struct langwell_udc *dev) +{ + struct pci_dev *pdev = dev->pdev; + + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); + + dma_release_declared_memory(&pdev->dev); + pci_release_region(pdev, 1); + + dev->got_sram = 0; + + dev_info(&dev->pdev->dev, "release SRAM caching\n"); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); +} + + /* tear down the binding between this driver and the pci device */ static void langwell_udc_remove(struct pci_dev *pdev) { @@ -2906,23 +3036,29 @@ static void langwell_udc_remove(struct pci_dev *pdev) DECLARE_COMPLETION(done); BUG_ON(dev->driver); - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); dev->done = &done; - /* free memory allocated in probe */ +#ifndef OTG_TRANSCEIVER + /* free dTD dma_pool and dQH */ if (dev->dtd_pool) dma_pool_destroy(dev->dtd_pool); + if (dev->ep_dqh) + dma_free_coherent(&pdev->dev, dev->ep_dqh_size, + dev->ep_dqh, dev->ep_dqh_dma); + + /* release SRAM caching */ + if (dev->has_sram && dev->got_sram) + sram_deinit(dev); +#endif + if (dev->status_req) { kfree(dev->status_req->req.buf); kfree(dev->status_req); } - if (dev->ep_dqh) - dma_free_coherent(&pdev->dev, dev->ep_dqh_size, - dev->ep_dqh, dev->ep_dqh_dma); - kfree(dev->ep); /* diable IRQ handler */ @@ -2949,11 +3085,12 @@ static void langwell_udc_remove(struct pci_dev *pdev) dev->cap_regs = NULL; - INFO(dev, "unbind\n"); - DBG(dev, "<--- %s()\n", __func__); + dev_info(&dev->pdev->dev, "unbind\n"); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); device_unregister(&dev->gadget.dev); device_remove_file(&pdev->dev, &dev_attr_langwell_udc); + device_remove_file(&pdev->dev, &dev_attr_remote_wakeup); #ifndef OTG_TRANSCEIVER pci_set_drvdata(pdev, NULL); @@ -2997,7 +3134,7 @@ static int langwell_udc_probe(struct pci_dev *pdev, spin_lock_init(&dev->lock); dev->pdev = pdev; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); #ifdef OTG_TRANSCEIVER /* PCI device is already enabled by otg_transceiver driver */ @@ -3022,7 +3159,7 @@ static int langwell_udc_probe(struct pci_dev *pdev, resource = pci_resource_start(pdev, 0); len = pci_resource_len(pdev, 0); if (!request_mem_region(resource, len, driver_name)) { - ERROR(dev, "controller already in use\n"); + dev_err(&dev->pdev->dev, "controller already in use\n"); retval = -EBUSY; goto error; } @@ -3031,33 +3168,43 @@ static int langwell_udc_probe(struct pci_dev *pdev, base = ioremap_nocache(resource, len); #endif if (base == NULL) { - ERROR(dev, "can't map memory\n"); + dev_err(&dev->pdev->dev, "can't map memory\n"); retval = -EFAULT; goto error; } dev->cap_regs = (struct langwell_cap_regs __iomem *) base; - VDBG(dev, "dev->cap_regs: %p\n", dev->cap_regs); + dev_vdbg(&dev->pdev->dev, "dev->cap_regs: %p\n", dev->cap_regs); dev->op_regs = (struct langwell_op_regs __iomem *) (base + OP_REG_OFFSET); - VDBG(dev, "dev->op_regs: %p\n", dev->op_regs); + dev_vdbg(&dev->pdev->dev, "dev->op_regs: %p\n", dev->op_regs); /* irq setup after old hardware is cleaned up */ if (!pdev->irq) { - ERROR(dev, "No IRQ. Check PCI setup!\n"); + dev_err(&dev->pdev->dev, "No IRQ. Check PCI setup!\n"); retval = -ENODEV; goto error; } + dev->has_sram = 1; + dev->got_sram = 0; + dev_vdbg(&dev->pdev->dev, "dev->has_sram: %d\n", dev->has_sram); + #ifndef OTG_TRANSCEIVER - INFO(dev, "irq %d, io mem: 0x%08lx, len: 0x%08lx, pci mem 0x%p\n", + /* enable SRAM caching if detected */ + if (dev->has_sram && !dev->got_sram) + sram_init(dev); + + dev_info(&dev->pdev->dev, + "irq %d, io mem: 0x%08lx, len: 0x%08lx, pci mem 0x%p\n", pdev->irq, resource, len, base); /* enables bus-mastering for device dev */ pci_set_master(pdev); if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, driver_name, dev) != 0) { - ERROR(dev, "request interrupt %d failed\n", pdev->irq); + dev_err(&dev->pdev->dev, + "request interrupt %d failed\n", pdev->irq); retval = -EBUSY; goto error; } @@ -3071,32 +3218,34 @@ static int langwell_udc_probe(struct pci_dev *pdev, dev->lpm = (readl(&dev->cap_regs->hccparams) & HCC_LEN) ? 1 : 0; dev->dciversion = readw(&dev->cap_regs->dciversion); dev->devcap = (readl(&dev->cap_regs->dccparams) & DEVCAP) ? 1 : 0; - VDBG(dev, "dev->lpm: %d\n", dev->lpm); - VDBG(dev, "dev->dciversion: 0x%04x\n", dev->dciversion); - VDBG(dev, "dccparams: 0x%08x\n", readl(&dev->cap_regs->dccparams)); - VDBG(dev, "dev->devcap: %d\n", dev->devcap); + dev_vdbg(&dev->pdev->dev, "dev->lpm: %d\n", dev->lpm); + dev_vdbg(&dev->pdev->dev, "dev->dciversion: 0x%04x\n", + dev->dciversion); + dev_vdbg(&dev->pdev->dev, "dccparams: 0x%08x\n", + readl(&dev->cap_regs->dccparams)); + dev_vdbg(&dev->pdev->dev, "dev->devcap: %d\n", dev->devcap); if (!dev->devcap) { - ERROR(dev, "can't support device mode\n"); + dev_err(&dev->pdev->dev, "can't support device mode\n"); retval = -ENODEV; goto error; } /* a pair of endpoints (out/in) for each address */ dev->ep_max = DEN(readl(&dev->cap_regs->dccparams)) * 2; - VDBG(dev, "dev->ep_max: %d\n", dev->ep_max); + dev_vdbg(&dev->pdev->dev, "dev->ep_max: %d\n", dev->ep_max); /* allocate endpoints memory */ dev->ep = kzalloc(sizeof(struct langwell_ep) * dev->ep_max, GFP_KERNEL); if (!dev->ep) { - ERROR(dev, "allocate endpoints memory failed\n"); + dev_err(&dev->pdev->dev, "allocate endpoints memory failed\n"); retval = -ENOMEM; goto error; } /* allocate device dQH memory */ size = dev->ep_max * sizeof(struct langwell_dqh); - VDBG(dev, "orig size = %d\n", size); + dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size); if (size < DQH_ALIGNMENT) size = DQH_ALIGNMENT; else if ((size % DQH_ALIGNMENT) != 0) { @@ -3106,17 +3255,18 @@ static int langwell_udc_probe(struct pci_dev *pdev, dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size, &dev->ep_dqh_dma, GFP_KERNEL); if (!dev->ep_dqh) { - ERROR(dev, "allocate dQH memory failed\n"); + dev_err(&dev->pdev->dev, "allocate dQH memory failed\n"); retval = -ENOMEM; goto error; } dev->ep_dqh_size = size; - VDBG(dev, "ep_dqh_size = %d\n", dev->ep_dqh_size); + dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size); /* initialize ep0 status request structure */ dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL); if (!dev->status_req) { - ERROR(dev, "allocate status_req memory failed\n"); + dev_err(&dev->pdev->dev, + "allocate status_req memory failed\n"); retval = -ENOMEM; goto error; } @@ -3129,7 +3279,10 @@ static int langwell_udc_probe(struct pci_dev *pdev, dev->resume_state = USB_STATE_NOTATTACHED; dev->usb_state = USB_STATE_POWERED; dev->ep0_dir = USB_DIR_OUT; - dev->remote_wakeup = 0; /* default to 0 on reset */ + + /* remote wakeup reset to 0 when the device is reset */ + dev->remote_wakeup = 0; + dev->dev_status = 1 << USB_DEVICE_SELF_POWERED; #ifndef OTG_TRANSCEIVER /* reset device controller */ @@ -3174,18 +3327,20 @@ static int langwell_udc_probe(struct pci_dev *pdev, } /* done */ - INFO(dev, "%s\n", driver_desc); - INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base); - INFO(dev, "Driver version: " DRIVER_VERSION "\n"); - INFO(dev, "Support (max) %d endpoints\n", dev->ep_max); - INFO(dev, "Device interface version: 0x%04x\n", dev->dciversion); - INFO(dev, "Controller mode: %s\n", dev->devcap ? "Device" : "Host"); - INFO(dev, "Support USB LPM: %s\n", dev->lpm ? "Yes" : "No"); - - VDBG(dev, "After langwell_udc_probe(), print all registers:\n"); -#ifdef VERBOSE + dev_info(&dev->pdev->dev, "%s\n", driver_desc); + dev_info(&dev->pdev->dev, "irq %d, pci mem %p\n", pdev->irq, base); + dev_info(&dev->pdev->dev, "Driver version: " DRIVER_VERSION "\n"); + dev_info(&dev->pdev->dev, "Support (max) %d endpoints\n", dev->ep_max); + dev_info(&dev->pdev->dev, "Device interface version: 0x%04x\n", + dev->dciversion); + dev_info(&dev->pdev->dev, "Controller mode: %s\n", + dev->devcap ? "Device" : "Host"); + dev_info(&dev->pdev->dev, "Support USB LPM: %s\n", + dev->lpm ? "Yes" : "No"); + + dev_vdbg(&dev->pdev->dev, + "After langwell_udc_probe(), print all registers:\n"); print_all_registers(dev); -#endif the_controller = dev; @@ -3197,12 +3352,18 @@ static int langwell_udc_probe(struct pci_dev *pdev, if (retval) goto error; - VDBG(dev, "<--- %s()\n", __func__); + retval = device_create_file(&pdev->dev, &dev_attr_remote_wakeup); + if (retval) + goto error_attr1; + + dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; +error_attr1: + device_remove_file(&pdev->dev, &dev_attr_langwell_udc); error: if (dev) { - DBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); langwell_udc_remove(pdev); } @@ -3214,9 +3375,8 @@ error: static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) { struct langwell_udc *dev = the_controller; - u32 devlc; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); /* disable interrupt and set controller to stop state */ langwell_udc_stop(dev); @@ -3226,20 +3386,29 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) free_irq(pdev->irq, dev); dev->got_irq = 0; - /* save PCI state */ pci_save_state(pdev); + /* free dTD dma_pool and dQH */ + if (dev->dtd_pool) + dma_pool_destroy(dev->dtd_pool); + + if (dev->ep_dqh) + dma_free_coherent(&pdev->dev, dev->ep_dqh_size, + dev->ep_dqh, dev->ep_dqh_dma); + + /* release SRAM caching */ + if (dev->has_sram && dev->got_sram) + sram_deinit(dev); + /* set device power state */ pci_set_power_state(pdev, PCI_D3hot); /* enter PHY low power suspend */ - devlc = readl(&dev->op_regs->devlc); - VDBG(dev, "devlc = 0x%08x\n", devlc); - devlc |= LPM_PHCD; - writel(devlc, &dev->op_regs->devlc); + if (dev->pdev->device != 0x0829) + langwell_phy_low_power(dev, 1); - DBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -3248,27 +3417,58 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) static int langwell_udc_resume(struct pci_dev *pdev) { struct langwell_udc *dev = the_controller; - u32 devlc; + size_t size; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); /* exit PHY low power suspend */ - devlc = readl(&dev->op_regs->devlc); - VDBG(dev, "devlc = 0x%08x\n", devlc); - devlc &= ~LPM_PHCD; - writel(devlc, &dev->op_regs->devlc); + if (dev->pdev->device != 0x0829) + langwell_phy_low_power(dev, 0); /* set device D0 power state */ pci_set_power_state(pdev, PCI_D0); + /* enable SRAM caching if detected */ + if (dev->has_sram && !dev->got_sram) + sram_init(dev); + + /* allocate device dQH memory */ + size = dev->ep_max * sizeof(struct langwell_dqh); + dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size); + if (size < DQH_ALIGNMENT) + size = DQH_ALIGNMENT; + else if ((size % DQH_ALIGNMENT) != 0) { + size += DQH_ALIGNMENT + 1; + size &= ~(DQH_ALIGNMENT - 1); + } + dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size, + &dev->ep_dqh_dma, GFP_KERNEL); + if (!dev->ep_dqh) { + dev_err(&dev->pdev->dev, "allocate dQH memory failed\n"); + return -ENOMEM; + } + dev->ep_dqh_size = size; + dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size); + + /* create dTD dma_pool resource */ + dev->dtd_pool = dma_pool_create("langwell_dtd", + &dev->pdev->dev, + sizeof(struct langwell_dtd), + DTD_ALIGNMENT, + DMA_BOUNDARY); + + if (!dev->dtd_pool) + return -ENOMEM; + /* restore PCI state */ pci_restore_state(pdev); /* enable IRQ handler */ - if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, driver_name, dev) - != 0) { - ERROR(dev, "request interrupt %d failed\n", pdev->irq); - return -1; + if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, + driver_name, dev) != 0) { + dev_err(&dev->pdev->dev, "request interrupt %d failed\n", + pdev->irq); + return -EBUSY; } dev->got_irq = 1; @@ -3290,7 +3490,7 @@ static int langwell_udc_resume(struct pci_dev *pdev) dev->ep0_state = WAIT_FOR_SETUP; dev->ep0_dir = USB_DIR_OUT; - DBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } @@ -3301,15 +3501,15 @@ static void langwell_udc_shutdown(struct pci_dev *pdev) struct langwell_udc *dev = the_controller; u32 usbmode; - DBG(dev, "---> %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); /* reset controller mode to IDLE */ usbmode = readl(&dev->op_regs->usbmode); - DBG(dev, "usbmode = 0x%08x\n", usbmode); + dev_dbg(&dev->pdev->dev, "usbmode = 0x%08x\n", usbmode); usbmode &= (~3 | MODE_IDLE); writel(usbmode, &dev->op_regs->usbmode); - DBG(dev, "<--- %s()\n", __func__); + dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); } /*-------------------------------------------------------------------------*/ @@ -3324,7 +3524,6 @@ static const struct pci_device_id pci_ids[] = { { }, { /* end: all zeroes */ } }; - MODULE_DEVICE_TABLE(pci, pci_ids); @@ -3343,12 +3542,6 @@ static struct pci_driver langwell_pci_driver = { }; -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Xiaochen Shen <xiaochen.shen@intel.com>"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - - static int __init init(void) { #ifdef OTG_TRANSCEIVER @@ -3370,3 +3563,9 @@ static void __exit cleanup(void) } module_exit(cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Xiaochen Shen <xiaochen.shen@intel.com>"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h index 9719934e1c08..f1d9c1bb04f3 100644 --- a/drivers/usb/gadget/langwell_udc.h +++ b/drivers/usb/gadget/langwell_udc.h @@ -18,11 +18,7 @@ */ #include <linux/usb/langwell_udc.h> - -#if defined(CONFIG_USB_LANGWELL_OTG) #include <linux/usb/langwell_otg.h> -#endif - /*-------------------------------------------------------------------------*/ @@ -199,7 +195,9 @@ struct langwell_udc { vbus_active:1, suspended:1, stopped:1, - lpm:1; /* LPM capability */ + lpm:1, /* LPM capability */ + has_sram:1, /* SRAM caching */ + got_sram:1; /* pci state used to access those endpoints */ struct pci_dev *pdev; @@ -224,5 +222,12 @@ struct langwell_udc { /* make sure release() is done */ struct completion *done; + + /* for private SRAM caching */ + unsigned int sram_addr; + unsigned int sram_size; + + /* device status data for get_status request */ + u16 dev_status; }; diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index fded3fca793b..6b58bd8ce623 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -408,7 +408,8 @@ static void udc_enable(struct lh7a40x_udc *dev) /* Register entry point for the peripheral controller driver. */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct lh7a40x_udc *dev = the_controller; int retval; @@ -417,7 +418,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!driver || driver->speed != USB_SPEED_FULL - || !driver->bind + || !bind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -431,7 +432,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) dev->gadget.dev.driver = &driver->driver; device_add(&dev->gadget.dev); - retval = driver->bind(&dev->gadget); + retval = bind(&dev->gadget); if (retval) { printk(KERN_WARNING "%s: bind to driver %s --> error %d\n", dev->gadget.name, driver->driver.name, retval); @@ -453,8 +454,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) return 0; } - -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); /* Unregister entry point for the peripheral controller driver. diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index e03058fe23cb..51b19f3027e7 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1454,14 +1454,15 @@ static struct usb_ep_ops m66592_ep_ops = { /*-------------------------------------------------------------------------*/ static struct m66592 *the_controller; -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct m66592 *m66592 = the_controller; int retval; if (!driver || driver->speed != USB_SPEED_HIGH - || !driver->bind + || !bind || !driver->setup) return -EINVAL; if (!m66592) @@ -1480,7 +1481,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) goto error; } - retval = driver->bind (&m66592->gadget); + retval = bind(&m66592->gadget); if (retval) { pr_err("bind to driver error (%d)\n", retval); device_del(&m66592->gadget.dev); @@ -1505,7 +1506,7 @@ error: return retval; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index 585f2559484d..0769179dbdb0 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -75,10 +75,6 @@ static struct usb_device_descriptor msg_device_desc = { /* Vendor and product id can be overridden by module parameters. */ .idVendor = cpu_to_le16(FSG_VENDOR_ID), .idProduct = cpu_to_le16(FSG_PRODUCT_ID), - /* .bcdDevice = f(hardware) */ - /* .iManufacturer = DYNAMIC */ - /* .iProduct = DYNAMIC */ - /* NO SERIAL NUMBER */ .bNumConfigurations = 1, }; @@ -86,7 +82,8 @@ static struct usb_otg_descriptor otg_descriptor = { .bLength = sizeof otg_descriptor, .bDescriptorType = USB_DT_OTG, - /* REVISIT SRP-only hardware is possible, although + /* + * REVISIT SRP-only hardware is possible, although * it would not be called "OTG" ... */ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, @@ -98,33 +95,6 @@ static const struct usb_descriptor_header *otg_desc[] = { }; -/* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_CONFIGURATION_IDX 2 - -static char manufacturer[50]; - -static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = DRIVER_DESC, - [STRING_CONFIGURATION_IDX].s = "Self Powered", - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab_dev = { - .language = 0x0409, /* en-us */ - .strings = strings_dev, -}; - -static struct usb_gadget_strings *dev_strings[] = { - &stringtab_dev, - NULL, -}; - - - /****************************** Configurations ******************************/ static struct fsg_module_parameters mod_data = { @@ -141,7 +111,7 @@ static int msg_thread_exits(struct fsg_common *common) return 0; } -static int __ref msg_do_config(struct usb_configuration *c) +static int __init msg_do_config(struct usb_configuration *c) { static const struct fsg_operations ops = { .thread_exits = msg_thread_exits, @@ -171,54 +141,23 @@ static int __ref msg_do_config(struct usb_configuration *c) static struct usb_configuration msg_config_driver = { .label = "Linux File-Backed Storage", - .bind = msg_do_config, .bConfigurationValue = 1, - /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_SELFPOWER, }; - /****************************** Gadget Bind ******************************/ - -static int __ref msg_bind(struct usb_composite_dev *cdev) +static int __init msg_bind(struct usb_composite_dev *cdev) { - struct usb_gadget *gadget = cdev->gadget; int status; - /* Allocate string descriptor numbers ... note that string - * contents can be overridden by the composite_dev glue. - */ - - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - status = usb_string_id(cdev); + status = usb_add_config(cdev, &msg_config_driver, msg_do_config); if (status < 0) return status; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - msg_device_desc.iManufacturer = status; - status = usb_string_id(cdev); - if (status < 0) - return status; - strings_dev[STRING_PRODUCT_IDX].id = status; - msg_device_desc.iProduct = status; - - status = usb_string_id(cdev); - if (status < 0) - return status; - strings_dev[STRING_CONFIGURATION_IDX].id = status; - msg_config_driver.iConfiguration = status; - - /* register our second configuration */ - status = usb_add_config(cdev, &msg_config_driver); - if (status < 0) - return status; - - dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); + dev_info(&cdev->gadget->dev, + DRIVER_DESC ", version: " DRIVER_VERSION "\n"); set_bit(0, &msg_registered); return 0; } @@ -226,12 +165,11 @@ static int __ref msg_bind(struct usb_composite_dev *cdev) /****************************** Some noise ******************************/ - static struct usb_composite_driver msg_driver = { .name = "g_mass_storage", .dev = &msg_device_desc, - .strings = dev_strings, - .bind = msg_bind, + .iProduct = DRIVER_DESC, + .needs_serial = 1, }; MODULE_DESCRIPTION(DRIVER_DESC); @@ -240,7 +178,7 @@ MODULE_LICENSE("GPL"); static int __init msg_init(void) { - return usb_composite_register(&msg_driver); + return usb_composite_probe(&msg_driver, msg_bind); } module_init(msg_init); diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 795d76232167..d9feced348e3 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -74,8 +74,8 @@ MODULE_LICENSE("GPL"); /***************************** Device Descriptor ****************************/ -#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */ -#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */ +#define MULTI_VENDOR_NUM 0x1d6b /* Linux Foundation */ +#define MULTI_PRODUCT_NUM 0x0104 /* Multifunction Composite Gadget */ enum { @@ -121,8 +121,6 @@ static const struct usb_descriptor_header *otg_desc[] = { enum { - MULTI_STRING_MANUFACTURER_IDX, - MULTI_STRING_PRODUCT_IDX, #ifdef CONFIG_USB_G_MULTI_RNDIS MULTI_STRING_RNDIS_CONFIG_IDX, #endif @@ -131,11 +129,7 @@ enum { #endif }; -static char manufacturer[50]; - static struct usb_string strings_dev[] = { - [MULTI_STRING_MANUFACTURER_IDX].s = manufacturer, - [MULTI_STRING_PRODUCT_IDX].s = DRIVER_DESC, #ifdef CONFIG_USB_G_MULTI_RNDIS [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS", #endif @@ -170,7 +164,7 @@ static u8 hostaddr[ETH_ALEN]; #ifdef USB_ETH_RNDIS -static __ref int rndis_do_config(struct usb_configuration *c) +static __init int rndis_do_config(struct usb_configuration *c) { int ret; @@ -197,7 +191,6 @@ static __ref int rndis_do_config(struct usb_configuration *c) static int rndis_config_register(struct usb_composite_dev *cdev) { static struct usb_configuration config = { - .bind = rndis_do_config, .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM, .bmAttributes = USB_CONFIG_ATT_SELFPOWER, }; @@ -205,7 +198,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev) config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s; config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id; - return usb_add_config(cdev, &config); + return usb_add_config(cdev, &config, rndis_do_config); } #else @@ -222,7 +215,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev) #ifdef CONFIG_USB_G_MULTI_CDC -static __ref int cdc_do_config(struct usb_configuration *c) +static __init int cdc_do_config(struct usb_configuration *c) { int ret; @@ -249,7 +242,6 @@ static __ref int cdc_do_config(struct usb_configuration *c) static int cdc_config_register(struct usb_composite_dev *cdev) { static struct usb_configuration config = { - .bind = cdc_do_config, .bConfigurationValue = MULTI_CDC_CONFIG_NUM, .bmAttributes = USB_CONFIG_ATT_SELFPOWER, }; @@ -257,7 +249,7 @@ static int cdc_config_register(struct usb_composite_dev *cdev) config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s; config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id; - return usb_add_config(cdev, &config); + return usb_add_config(cdev, &config, cdc_do_config); } #else @@ -314,20 +306,11 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099); } - /* allocate string descriptor numbers */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - + /* allocate string IDs */ status = usb_string_ids_tab(cdev, strings_dev); if (unlikely(status < 0)) goto fail2; - device_desc.iManufacturer = - strings_dev[MULTI_STRING_MANUFACTURER_IDX].id; - device_desc.iProduct = - strings_dev[MULTI_STRING_PRODUCT_IDX].id; - /* register configurations */ status = rndis_config_register(cdev); if (unlikely(status < 0)) @@ -368,14 +351,15 @@ static struct usb_composite_driver multi_driver = { .name = "g_multi", .dev = &device_desc, .strings = dev_strings, - .bind = multi_bind, .unbind = __exit_p(multi_unbind), + .iProduct = DRIVER_DESC, + .needs_serial = 1, }; static int __init multi_init(void) { - return usb_composite_register(&multi_driver); + return usb_composite_probe(&multi_driver, multi_bind); } module_init(multi_init); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 9498be87a724..d09155b25d73 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1929,7 +1929,8 @@ static void ep0_start (struct net2280 *dev) * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -int usb_gadget_register_driver (struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct net2280 *dev = the_controller; int retval; @@ -1941,8 +1942,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) */ if (!driver || driver->speed != USB_SPEED_HIGH - || !driver->bind - || !driver->setup) + || !bind || !driver->setup) return -EINVAL; if (!dev) return -ENODEV; @@ -1957,7 +1957,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; - retval = driver->bind (&dev->gadget); + retval = bind(&dev->gadget); if (retval) { DEBUG (dev, "bind to driver %s --> %d\n", driver->driver.name, retval); @@ -1993,7 +1993,7 @@ err_unbind: dev->driver = NULL; return retval; } -EXPORT_SYMBOL (usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 7d6b66a85724..b5364f9d7cd2 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -135,7 +135,6 @@ static int __init nokia_bind_config(struct usb_configuration *c) static struct usb_configuration nokia_config_500ma_driver = { .label = "Bus Powered", - .bind = nokia_bind_config, .bConfigurationValue = 1, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_ONE, @@ -144,7 +143,6 @@ static struct usb_configuration nokia_config_500ma_driver = { static struct usb_configuration nokia_config_100ma_driver = { .label = "Self Powered", - .bind = nokia_bind_config, .bConfigurationValue = 2, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, @@ -206,11 +204,13 @@ static int __init nokia_bind(struct usb_composite_dev *cdev) } /* finaly register the configuration */ - status = usb_add_config(cdev, &nokia_config_500ma_driver); + status = usb_add_config(cdev, &nokia_config_500ma_driver, + nokia_bind_config); if (status < 0) goto err_usb; - status = usb_add_config(cdev, &nokia_config_100ma_driver); + status = usb_add_config(cdev, &nokia_config_100ma_driver, + nokia_bind_config); if (status < 0) goto err_usb; @@ -241,13 +241,12 @@ static struct usb_composite_driver nokia_driver = { .name = "g_nokia", .dev = &device_desc, .strings = dev_strings, - .bind = nokia_bind, .unbind = __exit_p(nokia_unbind), }; static int __init nokia_init(void) { - return usb_composite_register(&nokia_driver); + return usb_composite_probe(&nokia_driver, nokia_bind); } module_init(nokia_init); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index f81e4f025f23..61d3ca6619bb 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2102,7 +2102,8 @@ static inline int machine_without_vbus_sense(void) ); } -int usb_gadget_register_driver (struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { int status = -ENODEV; struct omap_ep *ep; @@ -2114,8 +2115,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (!driver // FIXME if otg, check: driver->is_otg || driver->speed < USB_SPEED_FULL - || !driver->bind - || !driver->setup) + || !bind || !driver->setup) return -EINVAL; spin_lock_irqsave(&udc->lock, flags); @@ -2145,7 +2145,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (udc->dc_clk != NULL) omap_udc_enable_clock(1); - status = driver->bind (&udc->gadget); + status = bind(&udc->gadget); if (status) { DBG("bind to %s --> %d\n", driver->driver.name, status); udc->gadget.dev.driver = NULL; @@ -2186,7 +2186,7 @@ done: omap_udc_enable_clock(0); return status; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) { diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index cf241c371a71..ded080a1c8ce 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1347,7 +1347,7 @@ printer_unbind(struct usb_gadget *gadget) set_gadget_data(gadget, NULL); } -static int __ref +static int __init printer_bind(struct usb_gadget *gadget) { struct printer_dev *dev; @@ -1543,7 +1543,6 @@ static struct usb_gadget_driver printer_driver = { .speed = DEVSPEED, .function = (char *) driver_desc, - .bind = printer_bind, .unbind = printer_unbind, .setup = printer_setup, @@ -1579,11 +1578,11 @@ init(void) return status; } - status = usb_gadget_register_driver(&printer_driver); + status = usb_gadget_probe_driver(&printer_driver, printer_bind); if (status) { class_destroy(usb_gadget_class); unregister_chrdev_region(g_printer_devno, 1); - DBG(dev, "usb_gadget_register_driver %x\n", status); + DBG(dev, "usb_gadget_probe_driver %x\n", status); } return status; diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index be5fb34d9602..b37f92cb71bc 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -1280,14 +1280,15 @@ static void udc_enable (struct pxa25x_udc *dev) * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct pxa25x_udc *dev = the_controller; int retval; if (!driver || driver->speed < USB_SPEED_FULL - || !driver->bind + || !bind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -1308,7 +1309,7 @@ fail: dev->gadget.dev.driver = NULL; return retval; } - retval = driver->bind(&dev->gadget); + retval = bind(&dev->gadget); if (retval) { DMSG("bind to driver %s --> error %d\n", driver->driver.name, retval); @@ -1338,7 +1339,7 @@ fail: bind_fail: return retval; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 98dfa181449f..2efd6732d130 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1790,8 +1790,9 @@ static void udc_enable(struct pxa_udc *udc) } /** - * usb_gadget_register_driver - Register gadget driver + * usb_gadget_probe_driver - Register gadget driver * @driver: gadget driver + * @bind: bind function * * When a driver is successfully registered, it will receive control requests * including set_configuration(), which enables non-control requests. Then @@ -1803,12 +1804,13 @@ static void udc_enable(struct pxa_udc *udc) * * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct pxa_udc *udc = the_controller; int retval; - if (!driver || driver->speed < USB_SPEED_FULL || !driver->bind + if (!driver || driver->speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; if (!udc) @@ -1826,7 +1828,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) dev_err(udc->dev, "device_add error %d\n", retval); goto add_fail; } - retval = driver->bind(&udc->gadget); + retval = bind(&udc->gadget); if (retval) { dev_err(udc->dev, "bind to driver %s --> error %d\n", driver->driver.name, retval); @@ -1857,7 +1859,7 @@ add_fail: udc->gadget.dev.driver = NULL; return retval; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); /** diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 2456ccd9965e..95092151f901 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1405,14 +1405,15 @@ static struct usb_ep_ops r8a66597_ep_ops = { /*-------------------------------------------------------------------------*/ static struct r8a66597 *the_controller; -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct r8a66597 *r8a66597 = the_controller; int retval; if (!driver || driver->speed != USB_SPEED_HIGH - || !driver->bind + || !bind || !driver->setup) return -EINVAL; if (!r8a66597) @@ -1431,7 +1432,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) goto error; } - retval = driver->bind(&r8a66597->gadget); + retval = bind(&r8a66597->gadget); if (retval) { printk(KERN_ERR "bind to driver error (%d)\n", retval); device_del(&r8a66597->gadget.dev); @@ -1456,7 +1457,7 @@ error: return retval; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index a229744a8c7d..ef825c3baed9 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2523,7 +2523,8 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) return 0; } -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct s3c_hsotg *hsotg = our_hsotg; int ret; @@ -2543,7 +2544,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) dev_err(hsotg->dev, "%s: bad speed\n", __func__); } - if (!driver->bind || !driver->setup) { + if (!bind || !driver->setup) { dev_err(hsotg->dev, "%s: missing entry points\n", __func__); return -EINVAL; } @@ -2562,7 +2563,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) goto err; } - ret = driver->bind(&hsotg->gadget); + ret = bind(&hsotg->gadget); if (ret) { dev_err(hsotg->dev, "failed bind %s\n", driver->driver.name); @@ -2687,7 +2688,7 @@ err: hsotg->gadget.dev.driver = NULL; return ret; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index ea2b3c7ebee5..c2448950a8d8 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1632,15 +1632,15 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev) } /* - * usb_gadget_register_driver + * usb_gadget_probe_driver */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { struct s3c2410_udc *udc = the_controller; int retval; - dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n", - driver->driver.name); + dprintk(DEBUG_NORMAL, "%s() '%s'\n", __func__, driver->driver.name); /* Sanity checks */ if (!udc) @@ -1649,10 +1649,9 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (udc->driver) return -EBUSY; - if (!driver->bind || !driver->setup - || driver->speed < USB_SPEED_FULL) { + if (!bind || !driver->setup || driver->speed < USB_SPEED_FULL) { printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", - driver->bind, driver->setup, driver->speed); + bind, driver->setup, driver->speed); return -EINVAL; } #if defined(MODULE) @@ -1675,7 +1674,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n", driver->driver.name); - if ((retval = driver->bind (&udc->gadget)) != 0) { + if ((retval = bind(&udc->gadget)) != 0) { device_del(&udc->gadget.dev); goto register_error; } @@ -1690,6 +1689,7 @@ register_error: udc->gadget.dev.driver = NULL; return retval; } +EXPORT_SYMBOL(usb_gadget_probe_driver); /* * usb_gadget_unregister_driver @@ -2049,7 +2049,6 @@ static void __exit udc_exit(void) } EXPORT_SYMBOL(usb_gadget_unregister_driver); -EXPORT_SYMBOL(usb_gadget_register_driver); module_init(udc_init); module_exit(udc_exit); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index b22eedbc7dc5..1ac57a973aa9 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -137,7 +137,7 @@ MODULE_PARM_DESC(n_ports, "number of ports to create, default=1"); /*-------------------------------------------------------------------------*/ -static int __ref serial_bind_config(struct usb_configuration *c) +static int __init serial_bind_config(struct usb_configuration *c) { unsigned i; int status = 0; @@ -155,13 +155,12 @@ static int __ref serial_bind_config(struct usb_configuration *c) static struct usb_configuration serial_config_driver = { /* .label = f(use_acm) */ - .bind = serial_bind_config, /* .bConfigurationValue = f(use_acm) */ /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_SELFPOWER, }; -static int __ref gs_bind(struct usb_composite_dev *cdev) +static int __init gs_bind(struct usb_composite_dev *cdev) { int gcnum; struct usb_gadget *gadget = cdev->gadget; @@ -225,7 +224,8 @@ static int __ref gs_bind(struct usb_composite_dev *cdev) } /* register our configuration */ - status = usb_add_config(cdev, &serial_config_driver); + status = usb_add_config(cdev, &serial_config_driver, + serial_bind_config); if (status < 0) goto fail; @@ -242,7 +242,6 @@ static struct usb_composite_driver gserial_driver = { .name = "g_serial", .dev = &device_desc, .strings = dev_strings, - .bind = gs_bind, }; static int __init init(void) @@ -271,7 +270,7 @@ static int __init init(void) } strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label; - return usb_composite_register(&gserial_driver); + return usb_composite_probe(&gserial_driver, gs_bind); } module_init(init); diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 484acfb1a7c5..d7856c599d5a 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -26,7 +26,6 @@ * be defined (each of type pointer to char): * - fsg_string_manufacturer -- name of the manufacturer * - fsg_string_product -- name of the product - * - fsg_string_serial -- product's serial * - fsg_string_config -- name of the configuration * - fsg_string_interface -- name of the interface * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS @@ -552,7 +551,7 @@ static struct usb_string fsg_strings[] = { #ifndef FSG_NO_DEVICE_STRINGS {FSG_STRING_MANUFACTURER, fsg_string_manufacturer}, {FSG_STRING_PRODUCT, fsg_string_product}, - {FSG_STRING_SERIAL, fsg_string_serial}, + {FSG_STRING_SERIAL, ""}, {FSG_STRING_CONFIG, fsg_string_config}, #endif {FSG_STRING_INTERFACE, fsg_string_interface}, diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c index de1deb7a3c63..a5a0fdb808c7 100644 --- a/drivers/usb/gadget/webcam.c +++ b/drivers/usb/gadget/webcam.c @@ -308,7 +308,7 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = { * USB configuration */ -static int __ref +static int __init webcam_config_bind(struct usb_configuration *c) { return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls, @@ -317,7 +317,6 @@ webcam_config_bind(struct usb_configuration *c) static struct usb_configuration webcam_config_driver = { .label = webcam_config_label, - .bind = webcam_config_bind, .bConfigurationValue = 1, .iConfiguration = 0, /* dynamic */ .bmAttributes = USB_CONFIG_ATT_SELFPOWER, @@ -330,7 +329,7 @@ webcam_unbind(struct usb_composite_dev *cdev) return 0; } -static int __ref +static int __init webcam_bind(struct usb_composite_dev *cdev) { int ret; @@ -354,7 +353,8 @@ webcam_bind(struct usb_composite_dev *cdev) webcam_config_driver.iConfiguration = ret; /* Register our configuration. */ - if ((ret = usb_add_config(cdev, &webcam_config_driver)) < 0) + if ((ret = usb_add_config(cdev, &webcam_config_driver, + webcam_config_bind)) < 0) goto error; INFO(cdev, "Webcam Video Gadget\n"); @@ -373,14 +373,13 @@ static struct usb_composite_driver webcam_driver = { .name = "g_webcam", .dev = &webcam_device_descriptor, .strings = webcam_device_strings, - .bind = webcam_bind, .unbind = webcam_unbind, }; static int __init webcam_init(void) { - return usb_composite_register(&webcam_driver); + return usb_composite_probe(&webcam_driver, webcam_bind); } static void __exit diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index cf353920bb1c..6d16db9d9d2d 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -264,7 +264,7 @@ static void zero_resume(struct usb_composite_dev *cdev) /*-------------------------------------------------------------------------*/ -static int __ref zero_bind(struct usb_composite_dev *cdev) +static int __init zero_bind(struct usb_composite_dev *cdev) { int gcnum; struct usb_gadget *gadget = cdev->gadget; @@ -340,7 +340,6 @@ static struct usb_composite_driver zero_driver = { .name = "zero", .dev = &device_desc, .strings = dev_strings, - .bind = zero_bind, .unbind = zero_unbind, .suspend = zero_suspend, .resume = zero_resume, @@ -351,7 +350,7 @@ MODULE_LICENSE("GPL"); static int __init init(void) { - return usb_composite_register(&zero_driver); + return usb_composite_probe(&zero_driver, zero_bind); } module_init(init); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index a83a139da5bc..7cc713f187bc 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1695,9 +1695,11 @@ void musb_gadget_cleanup(struct musb *musb) * -ENOMEM no memeory to perform the operation * * @param driver the gadget driver + * @param bind the driver's bind function * @return <0 if error, 0 if everything is fine */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { int retval; unsigned long flags; @@ -1705,8 +1707,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!driver || driver->speed != USB_SPEED_HIGH - || !driver->bind - || !driver->setup) + || !bind || !driver->setup) return -EINVAL; /* driver must be initialized to support peripheral mode */ @@ -1734,7 +1735,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&musb->lock, flags); if (retval == 0) { - retval = driver->bind(&musb->g); + retval = bind(&musb->g); if (retval != 0) { DBG(3, "bind to driver %s failed --> %d\n", driver->driver.name, retval); diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 3b1289572d72..299dfd2510cb 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -67,4 +67,18 @@ config NOP_USB_XCEIV built-in with usb ip or which are autonomous and doesn't require any phy programming such as ISP1x04 etc. +config USB_LANGWELL_OTG + tristate "Intel Langwell USB OTG dual-role support" + depends on USB && X86_MRST + select USB_OTG + select USB_OTG_UTILS + help + Say Y here if you want to build Intel Langwell USB OTG + transciever driver in kernel. This driver implements role + switch between EHCI host driver and Langwell USB OTG + client driver. + + To compile this driver as a module, choose M here: the + module will be called langwell_otg. + endif # USB || OTG diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index aeb49a8ec412..b6609db3a849 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg.o obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o +obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o obj-$(CONFIG_USB_ULPI) += ulpi.o diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c new file mode 100644 index 000000000000..879188086daf --- /dev/null +++ b/drivers/usb/otg/langwell_otg.c @@ -0,0 +1,2408 @@ +/* + * Intel Langwell USB OTG transceiver driver + * Copyright (C) 2008 - 2009, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +/* This driver helps to switch Langwell OTG controller function between host + * and peripheral. It works with EHCI driver and Langwell client controller + * driver together. + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/moduleparam.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb.h> +#include <linux/usb/otg.h> +#include <linux/usb/hcd.h> +#include <linux/notifier.h> +#include <linux/delay.h> +#include <asm/intel_scu_ipc.h> + +#include <linux/usb/langwell_otg.h> + +#define DRIVER_DESC "Intel Langwell USB OTG transceiver driver" +#define DRIVER_VERSION "3.0.0.32L.0003" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Henry Yuan <hang.yuan@intel.com>, Hao Wu <hao.wu@intel.com>"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + +static const char driver_name[] = "langwell_otg"; + +static int langwell_otg_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +static void langwell_otg_remove(struct pci_dev *pdev); +static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message); +static int langwell_otg_resume(struct pci_dev *pdev); + +static int langwell_otg_set_host(struct otg_transceiver *otg, + struct usb_bus *host); +static int langwell_otg_set_peripheral(struct otg_transceiver *otg, + struct usb_gadget *gadget); +static int langwell_otg_start_srp(struct otg_transceiver *otg); + +static const struct pci_device_id pci_ids[] = {{ + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = 0x8086, + .device = 0x0811, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, +}, { /* end: all zeroes */ } +}; + +static struct pci_driver otg_pci_driver = { + .name = (char *) driver_name, + .id_table = pci_ids, + + .probe = langwell_otg_probe, + .remove = langwell_otg_remove, + + .suspend = langwell_otg_suspend, + .resume = langwell_otg_resume, +}; + +static const char *state_string(enum usb_otg_state state) +{ + switch (state) { + case OTG_STATE_A_IDLE: + return "a_idle"; + case OTG_STATE_A_WAIT_VRISE: + return "a_wait_vrise"; + case OTG_STATE_A_WAIT_BCON: + return "a_wait_bcon"; + case OTG_STATE_A_HOST: + return "a_host"; + case OTG_STATE_A_SUSPEND: + return "a_suspend"; + case OTG_STATE_A_PERIPHERAL: + return "a_peripheral"; + case OTG_STATE_A_WAIT_VFALL: + return "a_wait_vfall"; + case OTG_STATE_A_VBUS_ERR: + return "a_vbus_err"; + case OTG_STATE_B_IDLE: + return "b_idle"; + case OTG_STATE_B_SRP_INIT: + return "b_srp_init"; + case OTG_STATE_B_PERIPHERAL: + return "b_peripheral"; + case OTG_STATE_B_WAIT_ACON: + return "b_wait_acon"; + case OTG_STATE_B_HOST: + return "b_host"; + default: + return "UNDEFINED"; + } +} + +/* HSM timers */ +static inline struct langwell_otg_timer *otg_timer_initializer +(void (*function)(unsigned long), unsigned long expires, unsigned long data) +{ + struct langwell_otg_timer *timer; + timer = kmalloc(sizeof(struct langwell_otg_timer), GFP_KERNEL); + if (timer == NULL) + return timer; + + timer->function = function; + timer->expires = expires; + timer->data = data; + return timer; +} + +static struct langwell_otg_timer *a_wait_vrise_tmr, *a_aidl_bdis_tmr, + *b_se0_srp_tmr, *b_srp_init_tmr; + +static struct list_head active_timers; + +static struct langwell_otg *the_transceiver; + +/* host/client notify transceiver when event affects HNP state */ +void langwell_update_transceiver(void) +{ + struct langwell_otg *lnw = the_transceiver; + + dev_dbg(lnw->dev, "transceiver is updated\n"); + + if (!lnw->qwork) + return ; + + queue_work(lnw->qwork, &lnw->work); +} +EXPORT_SYMBOL(langwell_update_transceiver); + +static int langwell_otg_set_host(struct otg_transceiver *otg, + struct usb_bus *host) +{ + otg->host = host; + + return 0; +} + +static int langwell_otg_set_peripheral(struct otg_transceiver *otg, + struct usb_gadget *gadget) +{ + otg->gadget = gadget; + + return 0; +} + +static int langwell_otg_set_power(struct otg_transceiver *otg, + unsigned mA) +{ + return 0; +} + +/* A-device drives vbus, controlled through PMIC CHRGCNTL register*/ +static int langwell_otg_set_vbus(struct otg_transceiver *otg, bool enabled) +{ + struct langwell_otg *lnw = the_transceiver; + u8 r; + + dev_dbg(lnw->dev, "%s <--- %s\n", __func__, enabled ? "on" : "off"); + + /* FIXME: surely we should cache this on the first read. If not use + readv to avoid two transactions */ + if (intel_scu_ipc_ioread8(0x00, &r) < 0) { + dev_dbg(lnw->dev, "Failed to read PMIC register 0xD2"); + return -EBUSY; + } + if ((r & 0x03) != 0x02) { + dev_dbg(lnw->dev, "not NEC PMIC attached\n"); + return -EBUSY; + } + + if (intel_scu_ipc_ioread8(0x20, &r) < 0) { + dev_dbg(lnw->dev, "Failed to read PMIC register 0xD2"); + return -EBUSY; + } + + if ((r & 0x20) == 0) { + dev_dbg(lnw->dev, "no battery attached\n"); + return -EBUSY; + } + + /* Workaround for battery attachment issue */ + if (r == 0x34) { + dev_dbg(lnw->dev, "no battery attached on SH\n"); + return -EBUSY; + } + + dev_dbg(lnw->dev, "battery attached. 2 reg = %x\n", r); + + /* workaround: FW detect writing 0x20/0xc0 to d4 event. + * this is only for NEC PMIC. + */ + + if (intel_scu_ipc_iowrite8(0xD4, enabled ? 0x20 : 0xC0)) + dev_dbg(lnw->dev, "Failed to write PMIC.\n"); + + dev_dbg(lnw->dev, "%s --->\n", __func__); + + return 0; +} + +/* charge vbus or discharge vbus through a resistor to ground */ +static void langwell_otg_chrg_vbus(int on) +{ + struct langwell_otg *lnw = the_transceiver; + u32 val; + + val = readl(lnw->iotg.base + CI_OTGSC); + + if (on) + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VC, + lnw->iotg.base + CI_OTGSC); + else + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VD, + lnw->iotg.base + CI_OTGSC); +} + +/* Start SRP */ +static int langwell_otg_start_srp(struct otg_transceiver *otg) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + u32 val; + + dev_dbg(lnw->dev, "%s --->\n", __func__); + + val = readl(iotg->base + CI_OTGSC); + + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, + iotg->base + CI_OTGSC); + + /* Check if the data plus is finished or not */ + msleep(8); + val = readl(iotg->base + CI_OTGSC); + if (val & (OTGSC_HADP | OTGSC_DP)) + dev_dbg(lnw->dev, "DataLine SRP Error\n"); + + /* Disable interrupt - b_sess_vld */ + val = readl(iotg->base + CI_OTGSC); + val &= (~(OTGSC_BSVIE | OTGSC_BSEIE)); + writel(val, iotg->base + CI_OTGSC); + + /* Start VBus SRP, drive vbus to generate VBus pulse */ + iotg->otg.set_vbus(&iotg->otg, true); + msleep(15); + iotg->otg.set_vbus(&iotg->otg, false); + + /* Enable interrupt - b_sess_vld*/ + val = readl(iotg->base + CI_OTGSC); + dev_dbg(lnw->dev, "after VBUS pulse otgsc = %x\n", val); + + val |= (OTGSC_BSVIE | OTGSC_BSEIE); + writel(val, iotg->base + CI_OTGSC); + + /* If Vbus is valid, then update the hsm */ + if (val & OTGSC_BSV) { + dev_dbg(lnw->dev, "no b_sess_vld interrupt\n"); + + lnw->iotg.hsm.b_sess_vld = 1; + langwell_update_transceiver(); + } + + dev_dbg(lnw->dev, "%s <---\n", __func__); + return 0; +} + +/* stop SOF via bus_suspend */ +static void langwell_otg_loc_sof(int on) +{ + struct langwell_otg *lnw = the_transceiver; + struct usb_hcd *hcd; + int err; + + dev_dbg(lnw->dev, "%s ---> %s\n", __func__, on ? "suspend" : "resume"); + + hcd = bus_to_hcd(lnw->iotg.otg.host); + if (on) + err = hcd->driver->bus_resume(hcd); + else + err = hcd->driver->bus_suspend(hcd); + + if (err) + dev_dbg(lnw->dev, "Fail to resume/suspend USB bus - %d\n", err); + + dev_dbg(lnw->dev, "%s <---\n", __func__); +} + +static int langwell_otg_check_otgsc(void) +{ + struct langwell_otg *lnw = the_transceiver; + u32 otgsc, usbcfg; + + dev_dbg(lnw->dev, "check sync OTGSC and USBCFG registers\n"); + + otgsc = readl(lnw->iotg.base + CI_OTGSC); + usbcfg = readl(lnw->usbcfg); + + dev_dbg(lnw->dev, "OTGSC = %08x, USBCFG = %08x\n", + otgsc, usbcfg); + dev_dbg(lnw->dev, "OTGSC_AVV = %d\n", !!(otgsc & OTGSC_AVV)); + dev_dbg(lnw->dev, "USBCFG.VBUSVAL = %d\n", + !!(usbcfg & USBCFG_VBUSVAL)); + dev_dbg(lnw->dev, "OTGSC_ASV = %d\n", !!(otgsc & OTGSC_ASV)); + dev_dbg(lnw->dev, "USBCFG.AVALID = %d\n", + !!(usbcfg & USBCFG_AVALID)); + dev_dbg(lnw->dev, "OTGSC_BSV = %d\n", !!(otgsc & OTGSC_BSV)); + dev_dbg(lnw->dev, "USBCFG.BVALID = %d\n", + !!(usbcfg & USBCFG_BVALID)); + dev_dbg(lnw->dev, "OTGSC_BSE = %d\n", !!(otgsc & OTGSC_BSE)); + dev_dbg(lnw->dev, "USBCFG.SESEND = %d\n", + !!(usbcfg & USBCFG_SESEND)); + + /* Check USBCFG VBusValid/AValid/BValid/SessEnd */ + if (!!(otgsc & OTGSC_AVV) ^ !!(usbcfg & USBCFG_VBUSVAL)) { + dev_dbg(lnw->dev, "OTGSC.AVV != USBCFG.VBUSVAL\n"); + goto err; + } + if (!!(otgsc & OTGSC_ASV) ^ !!(usbcfg & USBCFG_AVALID)) { + dev_dbg(lnw->dev, "OTGSC.ASV != USBCFG.AVALID\n"); + goto err; + } + if (!!(otgsc & OTGSC_BSV) ^ !!(usbcfg & USBCFG_BVALID)) { + dev_dbg(lnw->dev, "OTGSC.BSV != USBCFG.BVALID\n"); + goto err; + } + if (!!(otgsc & OTGSC_BSE) ^ !!(usbcfg & USBCFG_SESEND)) { + dev_dbg(lnw->dev, "OTGSC.BSE != USBCFG.SESSEN\n"); + goto err; + } + + dev_dbg(lnw->dev, "OTGSC and USBCFG are synced\n"); + + return 0; + +err: + dev_warn(lnw->dev, "OTGSC isn't equal to USBCFG\n"); + return -EPIPE; +} + + +static void langwell_otg_phy_low_power(int on) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + u8 val, phcd; + int retval; + + dev_dbg(lnw->dev, "%s ---> %s mode\n", + __func__, on ? "Low power" : "Normal"); + + phcd = 0x40; + + val = readb(iotg->base + CI_HOSTPC1 + 2); + + if (on) { + /* Due to hardware issue, after set PHCD, sync will failed + * between USBCFG and OTGSC, so before set PHCD, check if + * sync is in process now. If the answer is "yes", then do + * not touch PHCD bit */ + retval = langwell_otg_check_otgsc(); + if (retval) { + dev_dbg(lnw->dev, "Skip PHCD programming..\n"); + return ; + } + + writeb(val | phcd, iotg->base + CI_HOSTPC1 + 2); + } else + writeb(val & ~phcd, iotg->base + CI_HOSTPC1 + 2); + + dev_dbg(lnw->dev, "%s <--- done\n", __func__); +} + +/* After drv vbus, add 2 ms delay to set PHCD */ +static void langwell_otg_phy_low_power_wait(int on) +{ + struct langwell_otg *lnw = the_transceiver; + + dev_dbg(lnw->dev, "add 2ms delay before programing PHCD\n"); + + mdelay(2); + langwell_otg_phy_low_power(on); +} + +/* Enable/Disable OTG interrupt */ +static void langwell_otg_intr(int on) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + u32 val; + + dev_dbg(lnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off"); + + val = readl(iotg->base + CI_OTGSC); + + /* OTGSC_INT_MASK doesn't contains 1msInt */ + if (on) { + val = val | (OTGSC_INT_MASK); + writel(val, iotg->base + CI_OTGSC); + } else { + val = val & ~(OTGSC_INT_MASK); + writel(val, iotg->base + CI_OTGSC); + } + + dev_dbg(lnw->dev, "%s <---\n", __func__); +} + +/* set HAAR: Hardware Assist Auto-Reset */ +static void langwell_otg_HAAR(int on) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + u32 val; + + dev_dbg(lnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off"); + + val = readl(iotg->base + CI_OTGSC); + if (on) + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HAAR, + iotg->base + CI_OTGSC); + else + writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HAAR, + iotg->base + CI_OTGSC); + + dev_dbg(lnw->dev, "%s <---\n", __func__); +} + +/* set HABA: Hardware Assist B-Disconnect to A-Connect */ +static void langwell_otg_HABA(int on) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + u32 val; + + dev_dbg(lnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off"); + + val = readl(iotg->base + CI_OTGSC); + if (on) + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA, + iotg->base + CI_OTGSC); + else + writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA, + iotg->base + CI_OTGSC); + + dev_dbg(lnw->dev, "%s <---\n", __func__); +} + +static int langwell_otg_check_se0_srp(int on) +{ + struct langwell_otg *lnw = the_transceiver; + int delay_time = TB_SE0_SRP * 10; + u32 val; + + dev_dbg(lnw->dev, "%s --->\n", __func__); + + do { + udelay(100); + if (!delay_time--) + break; + val = readl(lnw->iotg.base + CI_PORTSC1); + val &= PORTSC_LS; + } while (!val); + + dev_dbg(lnw->dev, "%s <---\n", __func__); + return val; +} + +/* The timeout callback function to set time out bit */ +static void set_tmout(unsigned long indicator) +{ + *(int *)indicator = 1; +} + +void langwell_otg_nsf_msg(unsigned long indicator) +{ + struct langwell_otg *lnw = the_transceiver; + + switch (indicator) { + case 2: + case 4: + case 6: + case 7: + dev_warn(lnw->dev, + "OTG:NSF-%lu - deivce not responding\n", indicator); + break; + case 3: + dev_warn(lnw->dev, + "OTG:NSF-%lu - deivce not supported\n", indicator); + break; + default: + dev_warn(lnw->dev, "Do not have this kind of NSF\n"); + break; + } +} + +/* Initialize timers */ +static int langwell_otg_init_timers(struct otg_hsm *hsm) +{ + /* HSM used timers */ + a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE, + (unsigned long)&hsm->a_wait_vrise_tmout); + if (a_wait_vrise_tmr == NULL) + return -ENOMEM; + a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS, + (unsigned long)&hsm->a_aidl_bdis_tmout); + if (a_aidl_bdis_tmr == NULL) + return -ENOMEM; + b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP, + (unsigned long)&hsm->b_se0_srp); + if (b_se0_srp_tmr == NULL) + return -ENOMEM; + b_srp_init_tmr = otg_timer_initializer(&set_tmout, TB_SRP_INIT, + (unsigned long)&hsm->b_srp_init_tmout); + if (b_srp_init_tmr == NULL) + return -ENOMEM; + + return 0; +} + +/* Free timers */ +static void langwell_otg_free_timers(void) +{ + kfree(a_wait_vrise_tmr); + kfree(a_aidl_bdis_tmr); + kfree(b_se0_srp_tmr); + kfree(b_srp_init_tmr); +} + +/* The timeout callback function to set time out bit */ +static void langwell_otg_timer_fn(unsigned long indicator) +{ + struct langwell_otg *lnw = the_transceiver; + + *(int *)indicator = 1; + + dev_dbg(lnw->dev, "kernel timer - timeout\n"); + + langwell_update_transceiver(); +} + +/* kernel timer used instead of HW based interrupt */ +static void langwell_otg_add_ktimer(enum langwell_otg_timer_type timers) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + unsigned long j = jiffies; + unsigned long data, time; + + switch (timers) { + case TA_WAIT_VRISE_TMR: + iotg->hsm.a_wait_vrise_tmout = 0; + data = (unsigned long)&iotg->hsm.a_wait_vrise_tmout; + time = TA_WAIT_VRISE; + break; + case TA_WAIT_BCON_TMR: + iotg->hsm.a_wait_bcon_tmout = 0; + data = (unsigned long)&iotg->hsm.a_wait_bcon_tmout; + time = TA_WAIT_BCON; + break; + case TA_AIDL_BDIS_TMR: + iotg->hsm.a_aidl_bdis_tmout = 0; + data = (unsigned long)&iotg->hsm.a_aidl_bdis_tmout; + time = TA_AIDL_BDIS; + break; + case TB_ASE0_BRST_TMR: + iotg->hsm.b_ase0_brst_tmout = 0; + data = (unsigned long)&iotg->hsm.b_ase0_brst_tmout; + time = TB_ASE0_BRST; + break; + case TB_SRP_INIT_TMR: + iotg->hsm.b_srp_init_tmout = 0; + data = (unsigned long)&iotg->hsm.b_srp_init_tmout; + time = TB_SRP_INIT; + break; + case TB_SRP_FAIL_TMR: + iotg->hsm.b_srp_fail_tmout = 0; + data = (unsigned long)&iotg->hsm.b_srp_fail_tmout; + time = TB_SRP_FAIL; + break; + case TB_BUS_SUSPEND_TMR: + iotg->hsm.b_bus_suspend_tmout = 0; + data = (unsigned long)&iotg->hsm.b_bus_suspend_tmout; + time = TB_BUS_SUSPEND; + break; + default: + dev_dbg(lnw->dev, "unkown timer, cannot enable it\n"); + return; + } + + lnw->hsm_timer.data = data; + lnw->hsm_timer.function = langwell_otg_timer_fn; + lnw->hsm_timer.expires = j + time * HZ / 1000; /* milliseconds */ + + add_timer(&lnw->hsm_timer); + + dev_dbg(lnw->dev, "add timer successfully\n"); +} + +/* Add timer to timer list */ +static void langwell_otg_add_timer(void *gtimer) +{ + struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer; + struct langwell_otg_timer *tmp_timer; + struct intel_mid_otg_xceiv *iotg = &the_transceiver->iotg; + u32 val32; + + /* Check if the timer is already in the active list, + * if so update timer count + */ + list_for_each_entry(tmp_timer, &active_timers, list) + if (tmp_timer == timer) { + timer->count = timer->expires; + return; + } + timer->count = timer->expires; + + if (list_empty(&active_timers)) { + val32 = readl(iotg->base + CI_OTGSC); + writel(val32 | OTGSC_1MSE, iotg->base + CI_OTGSC); + } + + list_add_tail(&timer->list, &active_timers); +} + +/* Remove timer from the timer list; clear timeout status */ +static void langwell_otg_del_timer(void *gtimer) +{ + struct langwell_otg *lnw = the_transceiver; + struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer; + struct langwell_otg_timer *tmp_timer, *del_tmp; + u32 val32; + + list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) + if (tmp_timer == timer) + list_del(&timer->list); + + if (list_empty(&active_timers)) { + val32 = readl(lnw->iotg.base + CI_OTGSC); + writel(val32 & ~OTGSC_1MSE, lnw->iotg.base + CI_OTGSC); + } +} + +/* Reduce timer count by 1, and find timeout conditions.*/ +static int langwell_otg_tick_timer(u32 *int_sts) +{ + struct langwell_otg *lnw = the_transceiver; + struct langwell_otg_timer *tmp_timer, *del_tmp; + int expired = 0; + + list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) { + tmp_timer->count--; + /* check if timer expires */ + if (!tmp_timer->count) { + list_del(&tmp_timer->list); + tmp_timer->function(tmp_timer->data); + expired = 1; + } + } + + if (list_empty(&active_timers)) { + dev_dbg(lnw->dev, "tick timer: disable 1ms int\n"); + *int_sts = *int_sts & ~OTGSC_1MSE; + } + return expired; +} + +static void reset_otg(void) +{ + struct langwell_otg *lnw = the_transceiver; + int delay_time = 1000; + u32 val; + + dev_dbg(lnw->dev, "reseting OTG controller ...\n"); + val = readl(lnw->iotg.base + CI_USBCMD); + writel(val | USBCMD_RST, lnw->iotg.base + CI_USBCMD); + do { + udelay(100); + if (!delay_time--) + dev_dbg(lnw->dev, "reset timeout\n"); + val = readl(lnw->iotg.base + CI_USBCMD); + val &= USBCMD_RST; + } while (val != 0); + dev_dbg(lnw->dev, "reset done.\n"); +} + +static void set_host_mode(void) +{ + struct langwell_otg *lnw = the_transceiver; + u32 val; + + reset_otg(); + val = readl(lnw->iotg.base + CI_USBMODE); + val = (val & (~USBMODE_CM)) | USBMODE_HOST; + writel(val, lnw->iotg.base + CI_USBMODE); +} + +static void set_client_mode(void) +{ + struct langwell_otg *lnw = the_transceiver; + u32 val; + + reset_otg(); + val = readl(lnw->iotg.base + CI_USBMODE); + val = (val & (~USBMODE_CM)) | USBMODE_DEVICE; + writel(val, lnw->iotg.base + CI_USBMODE); +} + +static void init_hsm(void) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + u32 val32; + + /* read OTGSC after reset */ + val32 = readl(lnw->iotg.base + CI_OTGSC); + dev_dbg(lnw->dev, "%s: OTGSC init value = 0x%x\n", __func__, val32); + + /* set init state */ + if (val32 & OTGSC_ID) { + iotg->hsm.id = 1; + iotg->otg.default_a = 0; + set_client_mode(); + iotg->otg.state = OTG_STATE_B_IDLE; + } else { + iotg->hsm.id = 0; + iotg->otg.default_a = 1; + set_host_mode(); + iotg->otg.state = OTG_STATE_A_IDLE; + } + + /* set session indicator */ + if (val32 & OTGSC_BSE) + iotg->hsm.b_sess_end = 1; + if (val32 & OTGSC_BSV) + iotg->hsm.b_sess_vld = 1; + if (val32 & OTGSC_ASV) + iotg->hsm.a_sess_vld = 1; + if (val32 & OTGSC_AVV) + iotg->hsm.a_vbus_vld = 1; + + /* defautly power the bus */ + iotg->hsm.a_bus_req = 1; + iotg->hsm.a_bus_drop = 0; + /* defautly don't request bus as B device */ + iotg->hsm.b_bus_req = 0; + /* no system error */ + iotg->hsm.a_clr_err = 0; + + langwell_otg_phy_low_power_wait(1); +} + +static void update_hsm(void) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + u32 val32; + + /* read OTGSC */ + val32 = readl(lnw->iotg.base + CI_OTGSC); + dev_dbg(lnw->dev, "%s: OTGSC value = 0x%x\n", __func__, val32); + + iotg->hsm.id = !!(val32 & OTGSC_ID); + iotg->hsm.b_sess_end = !!(val32 & OTGSC_BSE); + iotg->hsm.b_sess_vld = !!(val32 & OTGSC_BSV); + iotg->hsm.a_sess_vld = !!(val32 & OTGSC_ASV); + iotg->hsm.a_vbus_vld = !!(val32 & OTGSC_AVV); +} + +static irqreturn_t otg_dummy_irq(int irq, void *_dev) +{ + struct langwell_otg *lnw = the_transceiver; + void __iomem *reg_base = _dev; + u32 val; + u32 int_mask = 0; + + val = readl(reg_base + CI_USBMODE); + if ((val & USBMODE_CM) != USBMODE_DEVICE) + return IRQ_NONE; + + val = readl(reg_base + CI_USBSTS); + int_mask = val & INTR_DUMMY_MASK; + + if (int_mask == 0) + return IRQ_NONE; + + /* clear hsm.b_conn here since host driver can't detect it + * otg_dummy_irq called means B-disconnect happened. + */ + if (lnw->iotg.hsm.b_conn) { + lnw->iotg.hsm.b_conn = 0; + if (spin_trylock(&lnw->wq_lock)) { + langwell_update_transceiver(); + spin_unlock(&lnw->wq_lock); + } + } + + /* Clear interrupts */ + writel(int_mask, reg_base + CI_USBSTS); + return IRQ_HANDLED; +} + +static irqreturn_t otg_irq(int irq, void *_dev) +{ + struct langwell_otg *lnw = _dev; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + u32 int_sts, int_en; + u32 int_mask = 0; + int flag = 0; + + int_sts = readl(lnw->iotg.base + CI_OTGSC); + int_en = (int_sts & OTGSC_INTEN_MASK) >> 8; + int_mask = int_sts & int_en; + if (int_mask == 0) + return IRQ_NONE; + + if (int_mask & OTGSC_IDIS) { + dev_dbg(lnw->dev, "%s: id change int\n", __func__); + iotg->hsm.id = (int_sts & OTGSC_ID) ? 1 : 0; + dev_dbg(lnw->dev, "id = %d\n", iotg->hsm.id); + flag = 1; + } + if (int_mask & OTGSC_DPIS) { + dev_dbg(lnw->dev, "%s: data pulse int\n", __func__); + iotg->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0; + dev_dbg(lnw->dev, "data pulse = %d\n", iotg->hsm.a_srp_det); + flag = 1; + } + if (int_mask & OTGSC_BSEIS) { + dev_dbg(lnw->dev, "%s: b session end int\n", __func__); + iotg->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0; + dev_dbg(lnw->dev, "b_sess_end = %d\n", iotg->hsm.b_sess_end); + flag = 1; + } + if (int_mask & OTGSC_BSVIS) { + dev_dbg(lnw->dev, "%s: b session valid int\n", __func__); + iotg->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0; + dev_dbg(lnw->dev, "b_sess_vld = %d\n", iotg->hsm.b_sess_end); + flag = 1; + } + if (int_mask & OTGSC_ASVIS) { + dev_dbg(lnw->dev, "%s: a session valid int\n", __func__); + iotg->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0; + dev_dbg(lnw->dev, "a_sess_vld = %d\n", iotg->hsm.a_sess_vld); + flag = 1; + } + if (int_mask & OTGSC_AVVIS) { + dev_dbg(lnw->dev, "%s: a vbus valid int\n", __func__); + iotg->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0; + dev_dbg(lnw->dev, "a_vbus_vld = %d\n", iotg->hsm.a_vbus_vld); + flag = 1; + } + + if (int_mask & OTGSC_1MSS) { + /* need to schedule otg_work if any timer is expired */ + if (langwell_otg_tick_timer(&int_sts)) + flag = 1; + } + + writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask, + lnw->iotg.base + CI_OTGSC); + if (flag) + langwell_update_transceiver(); + + return IRQ_HANDLED; +} + +static int langwell_otg_iotg_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = data; + int flag = 0; + + if (iotg == NULL) + return NOTIFY_BAD; + + if (lnw == NULL) + return NOTIFY_BAD; + + switch (action) { + case MID_OTG_NOTIFY_CONNECT: + dev_dbg(lnw->dev, "Lnw OTG Notify Connect Event\n"); + if (iotg->otg.default_a == 1) + iotg->hsm.b_conn = 1; + else + iotg->hsm.a_conn = 1; + flag = 1; + break; + case MID_OTG_NOTIFY_DISCONN: + dev_dbg(lnw->dev, "Lnw OTG Notify Disconnect Event\n"); + if (iotg->otg.default_a == 1) + iotg->hsm.b_conn = 0; + else + iotg->hsm.a_conn = 0; + flag = 1; + break; + case MID_OTG_NOTIFY_HSUSPEND: + dev_dbg(lnw->dev, "Lnw OTG Notify Host Bus suspend Event\n"); + if (iotg->otg.default_a == 1) + iotg->hsm.a_suspend_req = 1; + else + iotg->hsm.b_bus_req = 0; + flag = 1; + break; + case MID_OTG_NOTIFY_HRESUME: + dev_dbg(lnw->dev, "Lnw OTG Notify Host Bus resume Event\n"); + if (iotg->otg.default_a == 1) + iotg->hsm.b_bus_resume = 1; + flag = 1; + break; + case MID_OTG_NOTIFY_CSUSPEND: + dev_dbg(lnw->dev, "Lnw OTG Notify Client Bus suspend Event\n"); + if (iotg->otg.default_a == 1) { + if (iotg->hsm.b_bus_suspend_vld == 2) { + iotg->hsm.b_bus_suspend = 1; + iotg->hsm.b_bus_suspend_vld = 0; + flag = 1; + } else { + iotg->hsm.b_bus_suspend_vld++; + flag = 0; + } + } else { + if (iotg->hsm.a_bus_suspend == 0) { + iotg->hsm.a_bus_suspend = 1; + flag = 1; + } + } + break; + case MID_OTG_NOTIFY_CRESUME: + dev_dbg(lnw->dev, "Lnw OTG Notify Client Bus resume Event\n"); + if (iotg->otg.default_a == 0) + iotg->hsm.a_bus_suspend = 0; + flag = 0; + break; + case MID_OTG_NOTIFY_HOSTADD: + dev_dbg(lnw->dev, "Lnw OTG Nofity Host Driver Add\n"); + flag = 1; + break; + case MID_OTG_NOTIFY_HOSTREMOVE: + dev_dbg(lnw->dev, "Lnw OTG Nofity Host Driver remove\n"); + flag = 1; + break; + case MID_OTG_NOTIFY_CLIENTADD: + dev_dbg(lnw->dev, "Lnw OTG Nofity Client Driver Add\n"); + flag = 1; + break; + case MID_OTG_NOTIFY_CLIENTREMOVE: + dev_dbg(lnw->dev, "Lnw OTG Nofity Client Driver remove\n"); + flag = 1; + break; + default: + dev_dbg(lnw->dev, "Lnw OTG Nofity unknown notify message\n"); + return NOTIFY_DONE; + } + + if (flag) + langwell_update_transceiver(); + + return NOTIFY_OK; +} + +static void langwell_otg_work(struct work_struct *work) +{ + struct langwell_otg *lnw; + struct intel_mid_otg_xceiv *iotg; + int retval; + struct pci_dev *pdev; + + lnw = container_of(work, struct langwell_otg, work); + iotg = &lnw->iotg; + pdev = to_pci_dev(lnw->dev); + + dev_dbg(lnw->dev, "%s: old state = %s\n", __func__, + state_string(iotg->otg.state)); + + switch (iotg->otg.state) { + case OTG_STATE_UNDEFINED: + case OTG_STATE_B_IDLE: + if (!iotg->hsm.id) { + langwell_otg_del_timer(b_srp_init_tmr); + del_timer_sync(&lnw->hsm_timer); + + iotg->otg.default_a = 1; + iotg->hsm.a_srp_det = 0; + + langwell_otg_chrg_vbus(0); + set_host_mode(); + langwell_otg_phy_low_power(1); + + iotg->otg.state = OTG_STATE_A_IDLE; + langwell_update_transceiver(); + } else if (iotg->hsm.b_sess_vld) { + langwell_otg_del_timer(b_srp_init_tmr); + del_timer_sync(&lnw->hsm_timer); + iotg->hsm.b_sess_end = 0; + iotg->hsm.a_bus_suspend = 0; + langwell_otg_chrg_vbus(0); + + if (lnw->iotg.start_peripheral) { + lnw->iotg.start_peripheral(&lnw->iotg); + iotg->otg.state = OTG_STATE_B_PERIPHERAL; + } else + dev_dbg(lnw->dev, "client driver not loaded\n"); + + } else if (iotg->hsm.b_srp_init_tmout) { + iotg->hsm.b_srp_init_tmout = 0; + dev_warn(lnw->dev, "SRP init timeout\n"); + } else if (iotg->hsm.b_srp_fail_tmout) { + iotg->hsm.b_srp_fail_tmout = 0; + iotg->hsm.b_bus_req = 0; + + /* No silence failure */ + langwell_otg_nsf_msg(6); + } else if (iotg->hsm.b_bus_req && iotg->hsm.b_sess_end) { + del_timer_sync(&lnw->hsm_timer); + /* workaround for b_se0_srp detection */ + retval = langwell_otg_check_se0_srp(0); + if (retval) { + iotg->hsm.b_bus_req = 0; + dev_dbg(lnw->dev, "LS isn't SE0, try later\n"); + } else { + /* clear the PHCD before start srp */ + langwell_otg_phy_low_power(0); + + /* Start SRP */ + langwell_otg_add_timer(b_srp_init_tmr); + iotg->otg.start_srp(&iotg->otg); + langwell_otg_del_timer(b_srp_init_tmr); + langwell_otg_add_ktimer(TB_SRP_FAIL_TMR); + + /* reset PHY low power mode here */ + langwell_otg_phy_low_power_wait(1); + } + } + break; + case OTG_STATE_B_SRP_INIT: + if (!iotg->hsm.id) { + iotg->otg.default_a = 1; + iotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + langwell_otg_chrg_vbus(0); + set_host_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_A_IDLE; + langwell_update_transceiver(); + } else if (iotg->hsm.b_sess_vld) { + langwell_otg_chrg_vbus(0); + if (lnw->iotg.start_peripheral) { + lnw->iotg.start_peripheral(&lnw->iotg); + iotg->otg.state = OTG_STATE_B_PERIPHERAL; + } else + dev_dbg(lnw->dev, "client driver not loaded\n"); + } + break; + case OTG_STATE_B_PERIPHERAL: + if (!iotg->hsm.id) { + iotg->otg.default_a = 1; + iotg->hsm.a_srp_det = 0; + + langwell_otg_chrg_vbus(0); + + if (lnw->iotg.stop_peripheral) + lnw->iotg.stop_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver has been removed.\n"); + + set_host_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_A_IDLE; + langwell_update_transceiver(); + } else if (!iotg->hsm.b_sess_vld) { + iotg->hsm.b_hnp_enable = 0; + + if (lnw->iotg.stop_peripheral) + lnw->iotg.stop_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver has been removed.\n"); + + iotg->otg.state = OTG_STATE_B_IDLE; + } else if (iotg->hsm.b_bus_req && iotg->otg.gadget && + iotg->otg.gadget->b_hnp_enable && + iotg->hsm.a_bus_suspend) { + + if (lnw->iotg.stop_peripheral) + lnw->iotg.stop_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver has been removed.\n"); + + langwell_otg_HAAR(1); + iotg->hsm.a_conn = 0; + + if (lnw->iotg.start_host) { + lnw->iotg.start_host(&lnw->iotg); + iotg->otg.state = OTG_STATE_B_WAIT_ACON; + } else + dev_dbg(lnw->dev, + "host driver not loaded.\n"); + + iotg->hsm.a_bus_resume = 0; + langwell_otg_add_ktimer(TB_ASE0_BRST_TMR); + } + break; + + case OTG_STATE_B_WAIT_ACON: + if (!iotg->hsm.id) { + /* delete hsm timer for b_ase0_brst_tmr */ + del_timer_sync(&lnw->hsm_timer); + + iotg->otg.default_a = 1; + iotg->hsm.a_srp_det = 0; + + langwell_otg_chrg_vbus(0); + + langwell_otg_HAAR(0); + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + set_host_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_A_IDLE; + langwell_update_transceiver(); + } else if (!iotg->hsm.b_sess_vld) { + /* delete hsm timer for b_ase0_brst_tmr */ + del_timer_sync(&lnw->hsm_timer); + + iotg->hsm.b_hnp_enable = 0; + iotg->hsm.b_bus_req = 0; + + langwell_otg_chrg_vbus(0); + langwell_otg_HAAR(0); + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + set_client_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_B_IDLE; + } else if (iotg->hsm.a_conn) { + /* delete hsm timer for b_ase0_brst_tmr */ + del_timer_sync(&lnw->hsm_timer); + + langwell_otg_HAAR(0); + iotg->otg.state = OTG_STATE_B_HOST; + langwell_update_transceiver(); + } else if (iotg->hsm.a_bus_resume || + iotg->hsm.b_ase0_brst_tmout) { + /* delete hsm timer for b_ase0_brst_tmr */ + del_timer_sync(&lnw->hsm_timer); + + langwell_otg_HAAR(0); + langwell_otg_nsf_msg(7); + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + iotg->hsm.a_bus_suspend = 0; + iotg->hsm.b_bus_req = 0; + + if (lnw->iotg.start_peripheral) + lnw->iotg.start_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver not loaded.\n"); + + iotg->otg.state = OTG_STATE_B_PERIPHERAL; + } + break; + + case OTG_STATE_B_HOST: + if (!iotg->hsm.id) { + iotg->otg.default_a = 1; + iotg->hsm.a_srp_det = 0; + + langwell_otg_chrg_vbus(0); + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + set_host_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_A_IDLE; + langwell_update_transceiver(); + } else if (!iotg->hsm.b_sess_vld) { + iotg->hsm.b_hnp_enable = 0; + iotg->hsm.b_bus_req = 0; + + langwell_otg_chrg_vbus(0); + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + set_client_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_B_IDLE; + } else if ((!iotg->hsm.b_bus_req) || + (!iotg->hsm.a_conn)) { + iotg->hsm.b_bus_req = 0; + langwell_otg_loc_sof(0); + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + iotg->hsm.a_bus_suspend = 0; + + if (lnw->iotg.start_peripheral) + lnw->iotg.start_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver not loaded.\n"); + + iotg->otg.state = OTG_STATE_B_PERIPHERAL; + } + break; + + case OTG_STATE_A_IDLE: + iotg->otg.default_a = 1; + if (iotg->hsm.id) { + iotg->otg.default_a = 0; + iotg->hsm.b_bus_req = 0; + iotg->hsm.vbus_srp_up = 0; + + langwell_otg_chrg_vbus(0); + set_client_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_B_IDLE; + langwell_update_transceiver(); + } else if (!iotg->hsm.a_bus_drop && + (iotg->hsm.a_srp_det || iotg->hsm.a_bus_req)) { + langwell_otg_phy_low_power(0); + + /* Turn on VBus */ + iotg->otg.set_vbus(&iotg->otg, true); + + iotg->hsm.vbus_srp_up = 0; + iotg->hsm.a_wait_vrise_tmout = 0; + langwell_otg_add_timer(a_wait_vrise_tmr); + iotg->otg.state = OTG_STATE_A_WAIT_VRISE; + langwell_update_transceiver(); + } else if (!iotg->hsm.a_bus_drop && iotg->hsm.a_sess_vld) { + iotg->hsm.vbus_srp_up = 1; + } else if (!iotg->hsm.a_sess_vld && iotg->hsm.vbus_srp_up) { + msleep(10); + langwell_otg_phy_low_power(0); + + /* Turn on VBus */ + iotg->otg.set_vbus(&iotg->otg, true); + iotg->hsm.a_srp_det = 1; + iotg->hsm.vbus_srp_up = 0; + iotg->hsm.a_wait_vrise_tmout = 0; + langwell_otg_add_timer(a_wait_vrise_tmr); + iotg->otg.state = OTG_STATE_A_WAIT_VRISE; + langwell_update_transceiver(); + } else if (!iotg->hsm.a_sess_vld && + !iotg->hsm.vbus_srp_up) { + langwell_otg_phy_low_power(1); + } + break; + case OTG_STATE_A_WAIT_VRISE: + if (iotg->hsm.id) { + langwell_otg_del_timer(a_wait_vrise_tmr); + iotg->hsm.b_bus_req = 0; + iotg->otg.default_a = 0; + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + set_client_mode(); + langwell_otg_phy_low_power_wait(1); + iotg->otg.state = OTG_STATE_B_IDLE; + } else if (iotg->hsm.a_vbus_vld) { + langwell_otg_del_timer(a_wait_vrise_tmr); + iotg->hsm.b_conn = 0; + if (lnw->iotg.start_host) + lnw->iotg.start_host(&lnw->iotg); + else { + dev_dbg(lnw->dev, "host driver not loaded.\n"); + break; + } + + langwell_otg_add_ktimer(TA_WAIT_BCON_TMR); + iotg->otg.state = OTG_STATE_A_WAIT_BCON; + } else if (iotg->hsm.a_wait_vrise_tmout) { + iotg->hsm.b_conn = 0; + if (iotg->hsm.a_vbus_vld) { + if (lnw->iotg.start_host) + lnw->iotg.start_host(&lnw->iotg); + else { + dev_dbg(lnw->dev, + "host driver not loaded.\n"); + break; + } + langwell_otg_add_ktimer(TA_WAIT_BCON_TMR); + iotg->otg.state = OTG_STATE_A_WAIT_BCON; + } else { + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + langwell_otg_phy_low_power_wait(1); + iotg->otg.state = OTG_STATE_A_VBUS_ERR; + } + } + break; + case OTG_STATE_A_WAIT_BCON: + if (iotg->hsm.id) { + /* delete hsm timer for a_wait_bcon_tmr */ + del_timer_sync(&lnw->hsm_timer); + + iotg->otg.default_a = 0; + iotg->hsm.b_bus_req = 0; + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + set_client_mode(); + langwell_otg_phy_low_power_wait(1); + iotg->otg.state = OTG_STATE_B_IDLE; + langwell_update_transceiver(); + } else if (!iotg->hsm.a_vbus_vld) { + /* delete hsm timer for a_wait_bcon_tmr */ + del_timer_sync(&lnw->hsm_timer); + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + langwell_otg_phy_low_power_wait(1); + iotg->otg.state = OTG_STATE_A_VBUS_ERR; + } else if (iotg->hsm.a_bus_drop || + (iotg->hsm.a_wait_bcon_tmout && + !iotg->hsm.a_bus_req)) { + /* delete hsm timer for a_wait_bcon_tmr */ + del_timer_sync(&lnw->hsm_timer); + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + iotg->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (iotg->hsm.b_conn) { + /* delete hsm timer for a_wait_bcon_tmr */ + del_timer_sync(&lnw->hsm_timer); + + iotg->hsm.a_suspend_req = 0; + iotg->otg.state = OTG_STATE_A_HOST; + if (iotg->hsm.a_srp_det && iotg->otg.host && + !iotg->otg.host->b_hnp_enable) { + /* SRP capable peripheral-only device */ + iotg->hsm.a_bus_req = 1; + iotg->hsm.a_srp_det = 0; + } else if (!iotg->hsm.a_bus_req && iotg->otg.host && + iotg->otg.host->b_hnp_enable) { + /* It is not safe enough to do a fast + * transistion from A_WAIT_BCON to + * A_SUSPEND */ + msleep(10000); + if (iotg->hsm.a_bus_req) + break; + + if (request_irq(pdev->irq, + otg_dummy_irq, IRQF_SHARED, + driver_name, iotg->base) != 0) { + dev_dbg(lnw->dev, + "request interrupt %d fail\n", + pdev->irq); + } + + langwell_otg_HABA(1); + iotg->hsm.b_bus_resume = 0; + iotg->hsm.a_aidl_bdis_tmout = 0; + + langwell_otg_loc_sof(0); + /* clear PHCD to enable HW timer */ + langwell_otg_phy_low_power(0); + langwell_otg_add_timer(a_aidl_bdis_tmr); + iotg->otg.state = OTG_STATE_A_SUSPEND; + } else if (!iotg->hsm.a_bus_req && iotg->otg.host && + !iotg->otg.host->b_hnp_enable) { + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + iotg->otg.state = OTG_STATE_A_WAIT_VFALL; + } + } + break; + case OTG_STATE_A_HOST: + if (iotg->hsm.id) { + iotg->otg.default_a = 0; + iotg->hsm.b_bus_req = 0; + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + set_client_mode(); + langwell_otg_phy_low_power_wait(1); + iotg->otg.state = OTG_STATE_B_IDLE; + langwell_update_transceiver(); + } else if (iotg->hsm.a_bus_drop || + (iotg->otg.host && + !iotg->otg.host->b_hnp_enable && + !iotg->hsm.a_bus_req)) { + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + iotg->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (!iotg->hsm.a_vbus_vld) { + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + langwell_otg_phy_low_power_wait(1); + iotg->otg.state = OTG_STATE_A_VBUS_ERR; + } else if (iotg->otg.host && + iotg->otg.host->b_hnp_enable && + !iotg->hsm.a_bus_req) { + /* Set HABA to enable hardware assistance to signal + * A-connect after receiver B-disconnect. Hardware + * will then set client mode and enable URE, SLE and + * PCE after the assistance. otg_dummy_irq is used to + * clean these ints when client driver is not resumed. + */ + if (request_irq(pdev->irq, otg_dummy_irq, IRQF_SHARED, + driver_name, iotg->base) != 0) { + dev_dbg(lnw->dev, + "request interrupt %d failed\n", + pdev->irq); + } + + /* set HABA */ + langwell_otg_HABA(1); + iotg->hsm.b_bus_resume = 0; + iotg->hsm.a_aidl_bdis_tmout = 0; + langwell_otg_loc_sof(0); + /* clear PHCD to enable HW timer */ + langwell_otg_phy_low_power(0); + langwell_otg_add_timer(a_aidl_bdis_tmr); + iotg->otg.state = OTG_STATE_A_SUSPEND; + } else if (!iotg->hsm.b_conn || !iotg->hsm.a_bus_req) { + langwell_otg_add_ktimer(TA_WAIT_BCON_TMR); + iotg->otg.state = OTG_STATE_A_WAIT_BCON; + } + break; + case OTG_STATE_A_SUSPEND: + if (iotg->hsm.id) { + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + free_irq(pdev->irq, iotg->base); + iotg->otg.default_a = 0; + iotg->hsm.b_bus_req = 0; + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + set_client_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_B_IDLE; + langwell_update_transceiver(); + } else if (iotg->hsm.a_bus_req || + iotg->hsm.b_bus_resume) { + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + free_irq(pdev->irq, iotg->base); + iotg->hsm.a_suspend_req = 0; + langwell_otg_loc_sof(1); + iotg->otg.state = OTG_STATE_A_HOST; + } else if (iotg->hsm.a_aidl_bdis_tmout || + iotg->hsm.a_bus_drop) { + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + free_irq(pdev->irq, iotg->base); + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + iotg->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (!iotg->hsm.b_conn && iotg->otg.host && + iotg->otg.host->b_hnp_enable) { + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + free_irq(pdev->irq, iotg->base); + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + iotg->hsm.b_bus_suspend = 0; + iotg->hsm.b_bus_suspend_vld = 0; + + /* msleep(200); */ + if (lnw->iotg.start_peripheral) + lnw->iotg.start_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver not loaded.\n"); + + langwell_otg_add_ktimer(TB_BUS_SUSPEND_TMR); + iotg->otg.state = OTG_STATE_A_PERIPHERAL; + break; + } else if (!iotg->hsm.a_vbus_vld) { + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + free_irq(pdev->irq, iotg->base); + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + langwell_otg_phy_low_power_wait(1); + iotg->otg.state = OTG_STATE_A_VBUS_ERR; + } + break; + case OTG_STATE_A_PERIPHERAL: + if (iotg->hsm.id) { + /* delete hsm timer for b_bus_suspend_tmr */ + del_timer_sync(&lnw->hsm_timer); + iotg->otg.default_a = 0; + iotg->hsm.b_bus_req = 0; + if (lnw->iotg.stop_peripheral) + lnw->iotg.stop_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + set_client_mode(); + langwell_otg_phy_low_power_wait(1); + iotg->otg.state = OTG_STATE_B_IDLE; + langwell_update_transceiver(); + } else if (!iotg->hsm.a_vbus_vld) { + /* delete hsm timer for b_bus_suspend_tmr */ + del_timer_sync(&lnw->hsm_timer); + + if (lnw->iotg.stop_peripheral) + lnw->iotg.stop_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + langwell_otg_phy_low_power_wait(1); + iotg->otg.state = OTG_STATE_A_VBUS_ERR; + } else if (iotg->hsm.a_bus_drop) { + /* delete hsm timer for b_bus_suspend_tmr */ + del_timer_sync(&lnw->hsm_timer); + + if (lnw->iotg.stop_peripheral) + lnw->iotg.stop_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver has been removed.\n"); + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + iotg->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (iotg->hsm.b_bus_suspend) { + /* delete hsm timer for b_bus_suspend_tmr */ + del_timer_sync(&lnw->hsm_timer); + + if (lnw->iotg.stop_peripheral) + lnw->iotg.stop_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver has been removed.\n"); + + if (lnw->iotg.start_host) + lnw->iotg.start_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver not loaded.\n"); + langwell_otg_add_ktimer(TA_WAIT_BCON_TMR); + iotg->otg.state = OTG_STATE_A_WAIT_BCON; + } else if (iotg->hsm.b_bus_suspend_tmout) { + u32 val; + val = readl(lnw->iotg.base + CI_PORTSC1); + if (!(val & PORTSC_SUSP)) + break; + + if (lnw->iotg.stop_peripheral) + lnw->iotg.stop_peripheral(&lnw->iotg); + else + dev_dbg(lnw->dev, + "client driver has been removed.\n"); + + if (lnw->iotg.start_host) + lnw->iotg.start_host(&lnw->iotg); + else + dev_dbg(lnw->dev, + "host driver not loaded.\n"); + langwell_otg_add_ktimer(TA_WAIT_BCON_TMR); + iotg->otg.state = OTG_STATE_A_WAIT_BCON; + } + break; + case OTG_STATE_A_VBUS_ERR: + if (iotg->hsm.id) { + iotg->otg.default_a = 0; + iotg->hsm.a_clr_err = 0; + iotg->hsm.a_srp_det = 0; + set_client_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_B_IDLE; + langwell_update_transceiver(); + } else if (iotg->hsm.a_clr_err) { + iotg->hsm.a_clr_err = 0; + iotg->hsm.a_srp_det = 0; + reset_otg(); + init_hsm(); + if (iotg->otg.state == OTG_STATE_A_IDLE) + langwell_update_transceiver(); + } else { + /* FW will clear PHCD bit when any VBus + * event detected. Reset PHCD to 1 again */ + langwell_otg_phy_low_power(1); + } + break; + case OTG_STATE_A_WAIT_VFALL: + if (iotg->hsm.id) { + iotg->otg.default_a = 0; + set_client_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_B_IDLE; + langwell_update_transceiver(); + } else if (iotg->hsm.a_bus_req) { + + /* Turn on VBus */ + iotg->otg.set_vbus(&iotg->otg, true); + iotg->hsm.a_wait_vrise_tmout = 0; + langwell_otg_add_timer(a_wait_vrise_tmr); + iotg->otg.state = OTG_STATE_A_WAIT_VRISE; + } else if (!iotg->hsm.a_sess_vld) { + iotg->hsm.a_srp_det = 0; + set_host_mode(); + langwell_otg_phy_low_power(1); + iotg->otg.state = OTG_STATE_A_IDLE; + } + break; + default: + ; + } + + dev_dbg(lnw->dev, "%s: new state = %s\n", __func__, + state_string(iotg->otg.state)); +} + +static ssize_t +show_registers(struct device *_dev, struct device_attribute *attr, char *buf) +{ + struct langwell_otg *lnw = the_transceiver; + char *next; + unsigned size, t; + + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, + "\n" + "USBCMD = 0x%08x\n" + "USBSTS = 0x%08x\n" + "USBINTR = 0x%08x\n" + "ASYNCLISTADDR = 0x%08x\n" + "PORTSC1 = 0x%08x\n" + "HOSTPC1 = 0x%08x\n" + "OTGSC = 0x%08x\n" + "USBMODE = 0x%08x\n", + readl(lnw->iotg.base + 0x30), + readl(lnw->iotg.base + 0x34), + readl(lnw->iotg.base + 0x38), + readl(lnw->iotg.base + 0x48), + readl(lnw->iotg.base + 0x74), + readl(lnw->iotg.base + 0xb4), + readl(lnw->iotg.base + 0xf4), + readl(lnw->iotg.base + 0xf8) + ); + size -= t; + next += t; + + return PAGE_SIZE - size; +} +static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); + +static ssize_t +show_hsm(struct device *_dev, struct device_attribute *attr, char *buf) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + char *next; + unsigned size, t; + + next = buf; + size = PAGE_SIZE; + + if (iotg->otg.host) + iotg->hsm.a_set_b_hnp_en = iotg->otg.host->b_hnp_enable; + + if (iotg->otg.gadget) + iotg->hsm.b_hnp_enable = iotg->otg.gadget->b_hnp_enable; + + t = scnprintf(next, size, + "\n" + "current state = %s\n" + "a_bus_resume = \t%d\n" + "a_bus_suspend = \t%d\n" + "a_conn = \t%d\n" + "a_sess_vld = \t%d\n" + "a_srp_det = \t%d\n" + "a_vbus_vld = \t%d\n" + "b_bus_resume = \t%d\n" + "b_bus_suspend = \t%d\n" + "b_conn = \t%d\n" + "b_se0_srp = \t%d\n" + "b_sess_end = \t%d\n" + "b_sess_vld = \t%d\n" + "id = \t%d\n" + "a_set_b_hnp_en = \t%d\n" + "b_srp_done = \t%d\n" + "b_hnp_enable = \t%d\n" + "a_wait_vrise_tmout = \t%d\n" + "a_wait_bcon_tmout = \t%d\n" + "a_aidl_bdis_tmout = \t%d\n" + "b_ase0_brst_tmout = \t%d\n" + "a_bus_drop = \t%d\n" + "a_bus_req = \t%d\n" + "a_clr_err = \t%d\n" + "a_suspend_req = \t%d\n" + "b_bus_req = \t%d\n" + "b_bus_suspend_tmout = \t%d\n" + "b_bus_suspend_vld = \t%d\n", + state_string(iotg->otg.state), + iotg->hsm.a_bus_resume, + iotg->hsm.a_bus_suspend, + iotg->hsm.a_conn, + iotg->hsm.a_sess_vld, + iotg->hsm.a_srp_det, + iotg->hsm.a_vbus_vld, + iotg->hsm.b_bus_resume, + iotg->hsm.b_bus_suspend, + iotg->hsm.b_conn, + iotg->hsm.b_se0_srp, + iotg->hsm.b_sess_end, + iotg->hsm.b_sess_vld, + iotg->hsm.id, + iotg->hsm.a_set_b_hnp_en, + iotg->hsm.b_srp_done, + iotg->hsm.b_hnp_enable, + iotg->hsm.a_wait_vrise_tmout, + iotg->hsm.a_wait_bcon_tmout, + iotg->hsm.a_aidl_bdis_tmout, + iotg->hsm.b_ase0_brst_tmout, + iotg->hsm.a_bus_drop, + iotg->hsm.a_bus_req, + iotg->hsm.a_clr_err, + iotg->hsm.a_suspend_req, + iotg->hsm.b_bus_req, + iotg->hsm.b_bus_suspend_tmout, + iotg->hsm.b_bus_suspend_vld + ); + size -= t; + next += t; + + return PAGE_SIZE - size; +} +static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL); + +static ssize_t +get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct langwell_otg *lnw = the_transceiver; + char *next; + unsigned size, t; + + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, "%d", lnw->iotg.hsm.a_bus_req); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + + if (!iotg->otg.default_a) + return -1; + if (count > 2) + return -1; + + if (buf[0] == '0') { + iotg->hsm.a_bus_req = 0; + dev_dbg(lnw->dev, "User request: a_bus_req = 0\n"); + } else if (buf[0] == '1') { + /* If a_bus_drop is TRUE, a_bus_req can't be set */ + if (iotg->hsm.a_bus_drop) + return -1; + iotg->hsm.a_bus_req = 1; + dev_dbg(lnw->dev, "User request: a_bus_req = 1\n"); + } + if (spin_trylock(&lnw->wq_lock)) { + langwell_update_transceiver(); + spin_unlock(&lnw->wq_lock); + } + return count; +} +static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req); + +static ssize_t +get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct langwell_otg *lnw = the_transceiver; + char *next; + unsigned size, t; + + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, "%d", lnw->iotg.hsm.a_bus_drop); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_drop(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + + if (!iotg->otg.default_a) + return -1; + if (count > 2) + return -1; + + if (buf[0] == '0') { + iotg->hsm.a_bus_drop = 0; + dev_dbg(lnw->dev, "User request: a_bus_drop = 0\n"); + } else if (buf[0] == '1') { + iotg->hsm.a_bus_drop = 1; + iotg->hsm.a_bus_req = 0; + dev_dbg(lnw->dev, "User request: a_bus_drop = 1\n"); + dev_dbg(lnw->dev, "User request: and a_bus_req = 0\n"); + } + if (spin_trylock(&lnw->wq_lock)) { + langwell_update_transceiver(); + spin_unlock(&lnw->wq_lock); + } + return count; +} +static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO, + get_a_bus_drop, set_a_bus_drop); + +static ssize_t +get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct langwell_otg *lnw = the_transceiver; + char *next; + unsigned size, t; + + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, "%d", lnw->iotg.hsm.b_bus_req); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_b_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + + if (iotg->otg.default_a) + return -1; + + if (count > 2) + return -1; + + if (buf[0] == '0') { + iotg->hsm.b_bus_req = 0; + dev_dbg(lnw->dev, "User request: b_bus_req = 0\n"); + } else if (buf[0] == '1') { + iotg->hsm.b_bus_req = 1; + dev_dbg(lnw->dev, "User request: b_bus_req = 1\n"); + } + if (spin_trylock(&lnw->wq_lock)) { + langwell_update_transceiver(); + spin_unlock(&lnw->wq_lock); + } + return count; +} +static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req); + +static ssize_t +set_a_clr_err(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + + if (!iotg->otg.default_a) + return -1; + if (count > 2) + return -1; + + if (buf[0] == '1') { + iotg->hsm.a_clr_err = 1; + dev_dbg(lnw->dev, "User request: a_clr_err = 1\n"); + } + if (spin_trylock(&lnw->wq_lock)) { + langwell_update_transceiver(); + spin_unlock(&lnw->wq_lock); + } + return count; +} +static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err); + +static struct attribute *inputs_attrs[] = { + &dev_attr_a_bus_req.attr, + &dev_attr_a_bus_drop.attr, + &dev_attr_b_bus_req.attr, + &dev_attr_a_clr_err.attr, + NULL, +}; + +static struct attribute_group debug_dev_attr_group = { + .name = "inputs", + .attrs = inputs_attrs, +}; + +static int langwell_otg_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + unsigned long resource, len; + void __iomem *base = NULL; + int retval; + u32 val32; + struct langwell_otg *lnw; + char qname[] = "langwell_otg_queue"; + + retval = 0; + dev_dbg(&pdev->dev, "\notg controller is detected.\n"); + if (pci_enable_device(pdev) < 0) { + retval = -ENODEV; + goto done; + } + + lnw = kzalloc(sizeof *lnw, GFP_KERNEL); + if (lnw == NULL) { + retval = -ENOMEM; + goto done; + } + the_transceiver = lnw; + + /* control register: BAR 0 */ + resource = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + if (!request_mem_region(resource, len, driver_name)) { + retval = -EBUSY; + goto err; + } + lnw->region = 1; + + base = ioremap_nocache(resource, len); + if (base == NULL) { + retval = -EFAULT; + goto err; + } + lnw->iotg.base = base; + + if (!request_mem_region(USBCFG_ADDR, USBCFG_LEN, driver_name)) { + retval = -EBUSY; + goto err; + } + lnw->cfg_region = 1; + + /* For the SCCB.USBCFG register */ + base = ioremap_nocache(USBCFG_ADDR, USBCFG_LEN); + if (base == NULL) { + retval = -EFAULT; + goto err; + } + lnw->usbcfg = base; + + if (!pdev->irq) { + dev_dbg(&pdev->dev, "No IRQ.\n"); + retval = -ENODEV; + goto err; + } + + lnw->qwork = create_singlethread_workqueue(qname); + if (!lnw->qwork) { + dev_dbg(&pdev->dev, "cannot create workqueue %s\n", qname); + retval = -ENOMEM; + goto err; + } + INIT_WORK(&lnw->work, langwell_otg_work); + + /* OTG common part */ + lnw->dev = &pdev->dev; + lnw->iotg.otg.dev = lnw->dev; + lnw->iotg.otg.label = driver_name; + lnw->iotg.otg.set_host = langwell_otg_set_host; + lnw->iotg.otg.set_peripheral = langwell_otg_set_peripheral; + lnw->iotg.otg.set_power = langwell_otg_set_power; + lnw->iotg.otg.set_vbus = langwell_otg_set_vbus; + lnw->iotg.otg.start_srp = langwell_otg_start_srp; + lnw->iotg.otg.state = OTG_STATE_UNDEFINED; + + if (otg_set_transceiver(&lnw->iotg.otg)) { + dev_dbg(lnw->dev, "can't set transceiver\n"); + retval = -EBUSY; + goto err; + } + + reset_otg(); + init_hsm(); + + spin_lock_init(&lnw->lock); + spin_lock_init(&lnw->wq_lock); + INIT_LIST_HEAD(&active_timers); + retval = langwell_otg_init_timers(&lnw->iotg.hsm); + if (retval) { + dev_dbg(&pdev->dev, "Failed to init timers\n"); + goto err; + } + + init_timer(&lnw->hsm_timer); + ATOMIC_INIT_NOTIFIER_HEAD(&lnw->iotg.iotg_notifier); + + lnw->iotg_notifier.notifier_call = langwell_otg_iotg_notify; + + retval = intel_mid_otg_register_notifier(&lnw->iotg, + &lnw->iotg_notifier); + if (retval) { + dev_dbg(lnw->dev, "Failed to register notifier\n"); + goto err; + } + + if (request_irq(pdev->irq, otg_irq, IRQF_SHARED, + driver_name, lnw) != 0) { + dev_dbg(lnw->dev, "request interrupt %d failed\n", pdev->irq); + retval = -EBUSY; + goto err; + } + + /* enable OTGSC int */ + val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE | + OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU; + writel(val32, lnw->iotg.base + CI_OTGSC); + + retval = device_create_file(&pdev->dev, &dev_attr_registers); + if (retval < 0) { + dev_dbg(lnw->dev, + "Can't register sysfs attribute: %d\n", retval); + goto err; + } + + retval = device_create_file(&pdev->dev, &dev_attr_hsm); + if (retval < 0) { + dev_dbg(lnw->dev, "Can't hsm sysfs attribute: %d\n", retval); + goto err; + } + + retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group); + if (retval < 0) { + dev_dbg(lnw->dev, + "Can't register sysfs attr group: %d\n", retval); + goto err; + } + + if (lnw->iotg.otg.state == OTG_STATE_A_IDLE) + langwell_update_transceiver(); + + return 0; + +err: + if (the_transceiver) + langwell_otg_remove(pdev); +done: + return retval; +} + +static void langwell_otg_remove(struct pci_dev *pdev) +{ + struct langwell_otg *lnw = the_transceiver; + + if (lnw->qwork) { + flush_workqueue(lnw->qwork); + destroy_workqueue(lnw->qwork); + } + intel_mid_otg_unregister_notifier(&lnw->iotg, &lnw->iotg_notifier); + langwell_otg_free_timers(); + + /* disable OTGSC interrupt as OTGSC doesn't change in reset */ + writel(0, lnw->iotg.base + CI_OTGSC); + + if (pdev->irq) + free_irq(pdev->irq, lnw); + if (lnw->usbcfg) + iounmap(lnw->usbcfg); + if (lnw->cfg_region) + release_mem_region(USBCFG_ADDR, USBCFG_LEN); + if (lnw->iotg.base) + iounmap(lnw->iotg.base); + if (lnw->region) + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + + otg_set_transceiver(NULL); + pci_disable_device(pdev); + sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group); + device_remove_file(&pdev->dev, &dev_attr_hsm); + device_remove_file(&pdev->dev, &dev_attr_registers); + kfree(lnw); + lnw = NULL; +} + +static void transceiver_suspend(struct pci_dev *pdev) +{ + pci_save_state(pdev); + pci_set_power_state(pdev, PCI_D3hot); + langwell_otg_phy_low_power(1); +} + +static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message) +{ + struct langwell_otg *lnw = the_transceiver; + struct intel_mid_otg_xceiv *iotg = &lnw->iotg; + int ret = 0; + + /* Disbale OTG interrupts */ + langwell_otg_intr(0); + + if (pdev->irq) + free_irq(pdev->irq, lnw); + + /* Prevent more otg_work */ + flush_workqueue(lnw->qwork); + destroy_workqueue(lnw->qwork); + lnw->qwork = NULL; + + /* start actions */ + switch (iotg->otg.state) { + case OTG_STATE_A_WAIT_VFALL: + iotg->otg.state = OTG_STATE_A_IDLE; + case OTG_STATE_A_IDLE: + case OTG_STATE_B_IDLE: + case OTG_STATE_A_VBUS_ERR: + transceiver_suspend(pdev); + break; + case OTG_STATE_A_WAIT_VRISE: + langwell_otg_del_timer(a_wait_vrise_tmr); + iotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + iotg->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_A_WAIT_BCON: + del_timer_sync(&lnw->hsm_timer); + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(&pdev->dev, "host driver has been removed.\n"); + + iotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + iotg->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_A_HOST: + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(&pdev->dev, "host driver has been removed.\n"); + + iotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + + iotg->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_A_SUSPEND: + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(lnw->dev, "host driver has been removed.\n"); + iotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + iotg->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_A_PERIPHERAL: + del_timer_sync(&lnw->hsm_timer); + + if (lnw->iotg.stop_peripheral) + lnw->iotg.stop_peripheral(&lnw->iotg); + else + dev_dbg(&pdev->dev, + "client driver has been removed.\n"); + iotg->hsm.a_srp_det = 0; + + /* Turn off VBus */ + iotg->otg.set_vbus(&iotg->otg, false); + iotg->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_B_HOST: + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(&pdev->dev, "host driver has been removed.\n"); + iotg->hsm.b_bus_req = 0; + iotg->otg.state = OTG_STATE_B_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_B_PERIPHERAL: + if (lnw->iotg.stop_peripheral) + lnw->iotg.stop_peripheral(&lnw->iotg); + else + dev_dbg(&pdev->dev, + "client driver has been removed.\n"); + iotg->otg.state = OTG_STATE_B_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_B_WAIT_ACON: + /* delete hsm timer for b_ase0_brst_tmr */ + del_timer_sync(&lnw->hsm_timer); + + langwell_otg_HAAR(0); + + if (lnw->iotg.stop_host) + lnw->iotg.stop_host(&lnw->iotg); + else + dev_dbg(&pdev->dev, "host driver has been removed.\n"); + iotg->hsm.b_bus_req = 0; + iotg->otg.state = OTG_STATE_B_IDLE; + transceiver_suspend(pdev); + break; + default: + dev_dbg(lnw->dev, "error state before suspend\n"); + break; + } + + return ret; +} + +static void transceiver_resume(struct pci_dev *pdev) +{ + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); +} + +static int langwell_otg_resume(struct pci_dev *pdev) +{ + struct langwell_otg *lnw = the_transceiver; + int ret = 0; + + transceiver_resume(pdev); + + lnw->qwork = create_singlethread_workqueue("langwell_otg_queue"); + if (!lnw->qwork) { + dev_dbg(&pdev->dev, "cannot create langwell otg workqueuen"); + ret = -ENOMEM; + goto error; + } + + if (request_irq(pdev->irq, otg_irq, IRQF_SHARED, + driver_name, lnw) != 0) { + dev_dbg(&pdev->dev, "request interrupt %d failed\n", pdev->irq); + ret = -EBUSY; + goto error; + } + + /* enable OTG interrupts */ + langwell_otg_intr(1); + + update_hsm(); + + langwell_update_transceiver(); + + return ret; +error: + langwell_otg_intr(0); + transceiver_suspend(pdev); + return ret; +} + +static int __init langwell_otg_init(void) +{ + return pci_register_driver(&otg_pci_driver); +} +module_init(langwell_otg_init); + +static void __exit langwell_otg_cleanup(void) +{ + pci_unregister_driver(&otg_pci_driver); +} +module_exit(langwell_otg_cleanup); diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 916b2b6d765f..95058109f9fa 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -527,6 +527,15 @@ config USB_SERIAL_SAFE_PADDED bool "USB Secure Encapsulated Driver - Padded" depends on USB_SERIAL_SAFE +config USB_SERIAL_SAMBA + tristate "USB Atmel SAM Boot Assistant (SAM-BA) driver" + help + Say Y here if you want to access the SAM-BA boot application of an + Atmel AT91SAM device. + + To compile this driver as a module, choose M here: the + module will be called sam-ba. + config USB_SERIAL_SIEMENS_MPI tristate "USB Siemens MPI driver" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 40ebe17b6ea8..cf41b6209c74 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o +obj-$(CONFIG_USB_SERIAL_SAMBA) += sam-ba.o obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o diff --git a/drivers/usb/serial/sam-ba.c b/drivers/usb/serial/sam-ba.c new file mode 100644 index 000000000000..e3bba64afc57 --- /dev/null +++ b/drivers/usb/serial/sam-ba.c @@ -0,0 +1,206 @@ +/* + * Atmel SAM Boot Assistant (SAM-BA) driver + * + * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> + + +#define DRIVER_VERSION "v1.0" +#define DRIVER_AUTHOR "Johan Hovold <jhovold@gmail.com>" +#define DRIVER_DESC "Atmel SAM Boot Assistant (SAM-BA) driver" + +#define SAMBA_VENDOR_ID 0x3eb +#define SAMBA_PRODUCT_ID 0x6124 + + +static int debug; + +static const struct usb_device_id id_table[] = { + /* + * NOTE: Only match the CDC Data interface. + */ + { USB_DEVICE_AND_INTERFACE_INFO(SAMBA_VENDOR_ID, SAMBA_PRODUCT_ID, + USB_CLASS_CDC_DATA, 0, 0) }, + { } +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver samba_driver = { + .name = "sam-ba", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + + +/* + * NOTE: The SAM-BA firmware cannot handle merged write requests so we cannot + * use the generic write implementation (which uses the port write fifo). + */ +static int samba_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct urb *urb; + unsigned long flags; + int result; + int i; + + if (!count) + return 0; + + count = min_t(int, count, port->bulk_out_size); + + spin_lock_irqsave(&port->lock, flags); + if (!port->write_urbs_free) { + spin_unlock_irqrestore(&port->lock, flags); + return 0; + } + i = find_first_bit(&port->write_urbs_free, + ARRAY_SIZE(port->write_urbs)); + __clear_bit(i, &port->write_urbs_free); + port->tx_bytes += count; + spin_unlock_irqrestore(&port->lock, flags); + + urb = port->write_urbs[i]; + memcpy(urb->transfer_buffer, buf, count); + urb->transfer_buffer_length = count; + usb_serial_debug_data(debug, &port->dev, __func__, count, + urb->transfer_buffer); + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) { + dev_err(&port->dev, "%s - error submitting urb: %d\n", + __func__, result); + spin_lock_irqsave(&port->lock, flags); + __set_bit(i, &port->write_urbs_free); + port->tx_bytes -= count; + spin_unlock_irqrestore(&port->lock, flags); + + return result; + } + + return count; +} + +static int samba_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + unsigned long flags; + unsigned long free; + int count; + int room; + + spin_lock_irqsave(&port->lock, flags); + free = port->write_urbs_free; + spin_unlock_irqrestore(&port->lock, flags); + + count = hweight_long(free); + room = count * port->bulk_out_size; + + dbg("%s - returns %d", __func__, room); + + return room; +} + +static int samba_chars_in_buffer(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + unsigned long flags; + int chars; + + spin_lock_irqsave(&port->lock, flags); + chars = port->tx_bytes; + spin_unlock_irqrestore(&port->lock, flags); + + dbg("%s - returns %d", __func__, chars); + + return chars; +} + +static void samba_write_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + unsigned long flags; + int i; + + dbg("%s - port %d", __func__, port->number); + + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { + if (port->write_urbs[i] == urb) + break; + } + spin_lock_irqsave(&port->lock, flags); + __set_bit(i, &port->write_urbs_free); + port->tx_bytes -= urb->transfer_buffer_length; + spin_unlock_irqrestore(&port->lock, flags); + + if (urb->status) + dbg("%s - non-zero urb status: %d", __func__, urb->status); + + usb_serial_port_softint(port); +} + +static struct usb_serial_driver samba_device = { + .driver = { + .owner = THIS_MODULE, + .name = "sam-ba", + }, + .usb_driver = &samba_driver, + .id_table = id_table, + .num_ports = 1, + .bulk_in_size = 512, + .bulk_out_size = 2048, + .write = samba_write, + .write_room = samba_write_room, + .chars_in_buffer = samba_chars_in_buffer, + .write_bulk_callback = samba_write_bulk_callback, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, +}; + +static int __init samba_init(void) +{ + int retval; + + retval = usb_serial_register(&samba_device); + if (retval) + return retval; + + retval = usb_register(&samba_driver); + if (retval) { + usb_serial_deregister(&samba_device); + return retval; + } + + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": " + DRIVER_DESC "\n"); + return 0; +} + +static void __exit samba_exit(void) +{ + usb_deregister(&samba_driver); + usb_serial_deregister(&samba_device); +} + +module_init(samba_init); +module_exit(samba_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable verbose debugging messages"); |