diff options
Diffstat (limited to 'drivers/usb/gadget')
42 files changed, 526 insertions, 574 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 23a447373c5..7ecb68a6741 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -15,6 +15,7 @@ menuconfig USB_GADGET tristate "USB Gadget Support" + select NLS help USB is a master/slave protocol, organized with one master host (such as a PC) controlling up to 127 peripheral devices. @@ -124,7 +125,6 @@ config USB_GADGET_STORAGE_NUM_BUFFERS # choice prompt "USB Peripheral Controller" - depends on USB_GADGET help A USB device uses a controller to talk to its host. Systems should have only one such upstream link. @@ -234,7 +234,6 @@ config USB_R8A66597 config USB_RENESAS_USBHS_UDC tristate 'Renesas USBHS controller' - depends on SUPERH || ARCH_SHMOBILE depends on USB_RENESAS_USBHS select USB_GADGET_DUALSPEED help @@ -264,7 +263,6 @@ config USB_PXA27X config USB_S3C_HSOTG tristate "S3C HS/OtG USB Device controller" depends on S3C_DEV_USB_HSOTG - select USB_GADGET_S3C_HSOTG_PIO select USB_GADGET_DUALSPEED help The Samsung S3C64XX USB2.0 high-speed gadget controller @@ -310,25 +308,13 @@ config USB_S3C_HSUDC This driver has been tested on S3C2416 and S3C2450 processors. -config USB_PXA_U2O - tristate "PXA9xx Processor USB2.0 controller" - depends on ARCH_MMP +config USB_MV_UDC + tristate "Marvell USB2.0 Device Controller" select USB_GADGET_DUALSPEED help - PXA9xx Processor series include a high speed USB2.0 device - controller, which support high speed and full speed USB peripheral. - -config USB_GADGET_DWC3 - tristate "DesignWare USB3.0 (DRD) Controller" - depends on USB_DWC3 - select USB_GADGET_DUALSPEED - select USB_GADGET_SUPERSPEED - help - DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller - which can be configured for peripheral-only, host-only, hub-only - and Dual-Role operation. This Controller was first integrated into - the OMAP5 series of processors. More information about the OMAP5 - version of this controller, refer to http://www.ti.com/omap5. + Marvell Socs (including PXA and MMP series) include a high speed + USB2.0 OTG controller, which can be configured as high speed or + full speed USB peripheral. # # Controllers available in both integrated and discrete versions @@ -544,12 +530,10 @@ endchoice # Selected by UDC drivers that support high-speed operation. config USB_GADGET_DUALSPEED bool - depends on USB_GADGET # Selected by UDC drivers that support super-speed opperation config USB_GADGET_SUPERSPEED bool - depends on USB_GADGET depends on USB_GADGET_DUALSPEED # @@ -557,7 +541,6 @@ config USB_GADGET_SUPERSPEED # choice tristate "USB Gadget Drivers" - depends on USB_GADGET default USB_ETH help A Linux "Gadget Driver" talks to the USB Peripheral Controller diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index b54ac619089..b7f6eefc392 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o -obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o +obj-$(CONFIG_USB_MV_UDC) += mv_udc.o mv_udc-y := mv_udc_core.o obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 4730016d7cd..e9a2c5c4445 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1959,7 +1959,7 @@ static int amd5536_start(struct usb_gadget_driver *driver, u32 tmp; if (!driver || !bind || !driver->setup - || driver->speed != USB_SPEED_HIGH) + || driver->max_speed < USB_SPEED_HIGH) return -EINVAL; if (!dev) return -ENODEV; @@ -3349,7 +3349,7 @@ static int udc_probe(struct udc *dev) dev_set_name(&dev->gadget.dev, "gadget"); dev->gadget.dev.release = gadget_release; dev->gadget.name = name; - dev->gadget.is_dualspeed = 1; + dev->gadget.max_speed = USB_SPEED_HIGH; /* init registers, interrupts, ... */ startup_registers(dev); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 8efe0fa9228..143a7256b59 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1633,7 +1633,7 @@ static int at91_start(struct usb_gadget_driver *driver, unsigned long flags; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->setup) { DBG("bad parameter.\n"); @@ -1748,7 +1748,7 @@ static int __init at91udc_probe(struct platform_device *pdev) /* rm9200 needs manual D+ pullup; off by default */ if (cpu_is_at91rm9200()) { - if (udc->board.pullup_pin <= 0) { + if (gpio_is_valid(udc->board.pullup_pin)) { DBG("no D+ pullup?\n"); retval = -ENODEV; goto fail0; @@ -1815,7 +1815,7 @@ static int __init at91udc_probe(struct platform_device *pdev) DBG("request irq %d failed\n", udc->udp_irq); goto fail1; } - if (udc->board.vbus_pin > 0) { + if (gpio_is_valid(udc->board.vbus_pin)) { retval = gpio_request(udc->board.vbus_pin, "udc_vbus"); if (retval < 0) { DBG("request vbus pin failed\n"); @@ -1859,10 +1859,10 @@ static int __init at91udc_probe(struct platform_device *pdev) INFO("%s version %s\n", driver_name, DRIVER_VERSION); return 0; fail4: - if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled) + if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled) free_irq(udc->board.vbus_pin, udc); fail3: - if (udc->board.vbus_pin > 0) + if (gpio_is_valid(udc->board.vbus_pin)) gpio_free(udc->board.vbus_pin); fail2: free_irq(udc->udp_irq, udc); @@ -1897,7 +1897,7 @@ static int __exit at91udc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); remove_debug_file(udc); - if (udc->board.vbus_pin > 0) { + if (gpio_is_valid(udc->board.vbus_pin)) { free_irq(udc->board.vbus_pin, udc); gpio_free(udc->board.vbus_pin); } @@ -1941,7 +1941,7 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) enable_irq_wake(udc->udp_irq); udc->active_suspend = wake; - if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled && wake) + if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled && wake) enable_irq_wake(udc->board.vbus_pin); return 0; } @@ -1951,7 +1951,7 @@ static int at91udc_resume(struct platform_device *pdev) struct at91_udc *udc = platform_get_drvdata(pdev); unsigned long flags; - if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled && + if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled && udc->active_suspend) disable_irq_wake(udc->board.vbus_pin); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 271a9d87360..e2fb6d583bd 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1038,7 +1038,7 @@ static struct usba_udc the_udc = { .gadget = { .ops = &usba_udc_ops, .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), - .is_dualspeed = 1, + .max_speed = USB_SPEED_HIGH, .name = "atmel_usba_udc", .dev = { .init_name = "gadget", diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 9a0c3979ff4..27e31371842 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -182,6 +182,16 @@ static inline int hw_ep_bit(int num, int dir) return num + (dir ? 16 : 0); } +static int ep_to_bit(int n) +{ + int fill = 16 - hw_ep_max / 2; + + if (n >= hw_ep_max / 2) + n += fill; + + return n; +} + /** * hw_aread: reads from register bitfield * @addr: address relative to bus map @@ -440,12 +450,13 @@ static int hw_ep_get_halt(int num, int dir) /** * hw_test_and_clear_setup_status: test & clear setup status (execute without * interruption) - * @n: bit number (endpoint) + * @n: endpoint number * * This function returns setup status */ static int hw_test_and_clear_setup_status(int n) { + n = ep_to_bit(n); return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n)); } @@ -641,12 +652,13 @@ static int hw_register_write(u16 addr, u32 data) /** * hw_test_and_clear_complete: test & clear complete status (execute without * interruption) - * @n: bit number (endpoint) + * @n: endpoint number * * This function returns complete status */ static int hw_test_and_clear_complete(int n) { + n = ep_to_bit(n); return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n)); } @@ -754,8 +766,11 @@ static ssize_t show_device(struct device *dev, struct device_attribute *attr, n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", gadget->speed); + n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", + gadget->max_speed); + /* TODO: Scheduled for removal in 3.8. */ n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", - gadget->is_dualspeed); + gadget_is_dualspeed(gadget)); n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", gadget->is_otg); n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", @@ -798,7 +813,7 @@ static ssize_t show_driver(struct device *dev, struct device_attribute *attr, n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", (driver->function ? driver->function : "")); n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", - driver->speed); + driver->max_speed); return n; } @@ -2563,9 +2578,7 @@ static int ci13xxx_start(struct usb_gadget_driver *driver, if (driver == NULL || bind == NULL || driver->setup == NULL || - driver->disconnect == NULL || - driver->suspend == NULL || - driver->resume == NULL) + driver->disconnect == NULL) return -EINVAL; else if (udc == NULL) return -ENODEV; @@ -2693,8 +2706,6 @@ static int ci13xxx_stop(struct usb_gadget_driver *driver) driver->unbind == NULL || driver->setup == NULL || driver->disconnect == NULL || - driver->suspend == NULL || - driver->resume == NULL || driver != udc->driver) return -EINVAL; @@ -2793,7 +2804,7 @@ static irqreturn_t udc_irq(void) isr_statistics.pci++; udc->gadget.speed = hw_port_is_high_speed() ? USB_SPEED_HIGH : USB_SPEED_FULL; - if (udc->suspended) { + if (udc->suspended && udc->driver->resume) { spin_unlock(udc->lock); udc->driver->resume(&udc->gadget); spin_lock(udc->lock); @@ -2807,7 +2818,8 @@ static irqreturn_t udc_irq(void) isr_tr_complete_handler(udc); } if (USBi_SLI & intr) { - if (udc->gadget.speed != USB_SPEED_UNKNOWN) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN && + udc->driver->suspend) { udc->suspended = 1; spin_unlock(udc->lock); udc->driver->suspend(&udc->gadget); @@ -2871,7 +2883,7 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, udc->gadget.ops = &usb_gadget_ops; udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->gadget.is_dualspeed = 1; + udc->gadget.max_speed = USB_SPEED_HIGH; udc->gadget.is_otg = 0; udc->gadget.name = driver->name; diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h index 23707775cb4..f4871e1fac5 100644 --- a/drivers/usb/gadget/ci13xxx_udc.h +++ b/drivers/usb/gadget/ci13xxx_udc.h @@ -127,7 +127,7 @@ struct ci13xxx { struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */ u32 ep0_dir; /* ep0 direction */ #define ep0out ci13xxx_ep[0] -#define ep0in ci13xxx_ep[16] +#define ep0in ci13xxx_ep[hw_ep_max / 2] u8 remote_wakeup; /* Is remote wakeup feature enabled by the host? */ u8 suspended; /* suspended by the host */ diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index f71b0787983..a95de6a4a13 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1535,9 +1535,9 @@ composite_resume(struct usb_gadget *gadget) static struct usb_gadget_driver composite_driver = { #ifdef CONFIG_USB_GADGET_SUPERSPEED - .speed = USB_SPEED_SUPER, + .max_speed = USB_SPEED_SUPER, #else - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, #endif .unbind = composite_unbind, @@ -1584,8 +1584,8 @@ int usb_composite_probe(struct usb_composite_driver *driver, driver->iProduct = driver->name; composite_driver.function = (char *) driver->name; composite_driver.driver.name = driver->name; - composite_driver.speed = min((u8)composite_driver.speed, - (u8)driver->max_speed); + composite_driver.max_speed = + min_t(u8, composite_driver.max_speed, driver->max_speed); composite = driver; composite_gadget_bind = bind; diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index 6256420089f..19d7bb0df75 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -404,7 +404,7 @@ fail: static struct usb_gadget_driver dbgp_driver = { .function = "dbgp", - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, .unbind = dbgp_unbind, .setup = dbgp_setup, .disconnect = dbgp_disconnect, diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index ab8f1b488d5..db815c2da7e 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -823,19 +823,18 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value) if (value && dum->driver) { if (mod_data.is_super_speed) - dum->gadget.speed = dum->driver->speed; + dum->gadget.speed = dum->driver->max_speed; else if (mod_data.is_high_speed) dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, - dum->driver->speed); + dum->driver->max_speed); else dum->gadget.speed = USB_SPEED_FULL; dummy_udc_udpate_ep0(dum); - if (dum->gadget.speed < dum->driver->speed) + if (dum->gadget.speed < dum->driver->max_speed) dev_dbg(udc_dev(dum), "This device can perform faster" - " if you connect it to a %s port...\n", - (dum->driver->speed == USB_SPEED_SUPER ? - "SuperSpeed" : "HighSpeed")); + " if you connect it to a %s port...\n", + usb_speed_string(dum->driver->max_speed)); } dum_hcd = gadget_to_dummy_hcd(_gadget); @@ -898,7 +897,7 @@ static int dummy_udc_start(struct usb_gadget *g, struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); struct dummy *dum = dum_hcd->dum; - if (driver->speed == USB_SPEED_UNKNOWN) + if (driver->max_speed == USB_SPEED_UNKNOWN) return -EINVAL; /* @@ -977,7 +976,7 @@ static int dummy_udc_probe (struct platform_device *pdev) dum->gadget.name = gadget_name; dum->gadget.ops = &dummy_ops; - dum->gadget.is_dualspeed = 1; + dum->gadget.max_speed = USB_SPEED_SUPER; dev_set_name(&dum->gadget.dev, "gadget"); dum->gadget.dev.parent = &pdev->dev; diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 596a0b464e6..753aa0683ac 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -130,9 +130,6 @@ ep_matches ( num_req_streams = ep_comp->bmAttributes & 0x1f; if (num_req_streams > ep->max_streams) return 0; - /* Update the ep_comp descriptor if needed */ - if (num_req_streams != ep->max_streams) - ep_comp->bmAttributes = ep->max_streams; } } @@ -152,7 +149,7 @@ ep_matches ( switch (type) { case USB_ENDPOINT_XFER_INT: /* INT: limit 64 bytes full speed, 1024 high/super speed */ - if (!gadget->is_dualspeed && max > 64) + if (!gadget_is_dualspeed(gadget) && max > 64) return 0; /* FALLTHROUGH */ @@ -160,12 +157,12 @@ ep_matches ( /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ if (ep->maxpacket < max) return 0; - if (!gadget->is_dualspeed && max > 1023) + if (!gadget_is_dualspeed(gadget) && max > 1023) return 0; /* BOTH: "high bandwidth" works only at high speed */ if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) { - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) return 0; /* configure your hardware with enough buffering!! */ } diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index acb38004eec..f63dc6c150d 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1037,7 +1037,6 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) { struct ffs_sb_fill_data *data = _data; struct inode *inode; - struct dentry *d; struct ffs_data *ffs; ENTER(); @@ -1045,7 +1044,7 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) /* Initialise data */ ffs = ffs_data_new(); if (unlikely(!ffs)) - goto enomem0; + goto Enomem; ffs->sb = sb; ffs->dev_name = data->dev_name; @@ -1065,26 +1064,21 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) &simple_dir_inode_operations, &data->perms); if (unlikely(!inode)) - goto enomem1; - d = d_alloc_root(inode); - if (unlikely(!d)) - goto enomem2; - sb->s_root = d; + goto Enomem; + sb->s_root = d_alloc_root(inode); + if (unlikely(!sb->s_root)) { + iput(inode); + goto Enomem; + } /* EP0 file */ if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations, NULL))) - goto enomem3; + goto Enomem; return 0; -enomem3: - dput(d); -enomem2: - iput(inode); -enomem1: - ffs_data_put(ffs); -enomem0: +Enomem: return -ENOMEM; } @@ -1196,14 +1190,11 @@ ffs_fs_mount(struct file_system_type *t, int flags, static void ffs_fs_kill_sb(struct super_block *sb) { - void *ptr; - ENTER(); kill_litter_super(sb); - ptr = xchg(&sb->s_fs_info, NULL); - if (ptr) - ffs_data_put(ptr); + if (sb->s_fs_info) + ffs_data_put(sb->s_fs_info); } static struct file_system_type ffs_fs_type = { @@ -1408,7 +1399,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs) ENTER(); count = ffs->eps_count; - epfiles = kzalloc(count * sizeof *epfiles, GFP_KERNEL); + epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); if (!epfiles) return -ENOMEM; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index c39d58860fa..6353eca1e85 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -1873,17 +1873,14 @@ static int check_command(struct fsg_common *common, int cmnd_size, common->lun, lun); /* Check the LUN */ - if (common->lun < common->nluns) { - curlun = &common->luns[common->lun]; - common->curlun = curlun; + curlun = common->curlun; + if (curlun) { if (common->cmnd[0] != REQUEST_SENSE) { curlun->sense_data = SS_NO_SENSE; curlun->sense_data_info = 0; curlun->info_valid = 0; } } else { - common->curlun = NULL; - curlun = NULL; common->bad_lun_okay = 0; /* @@ -1929,6 +1926,17 @@ static int check_command(struct fsg_common *common, int cmnd_size, return 0; } +/* wrapper of check_command for data size in blocks handling */ +static int check_command_size_in_blocks(struct fsg_common *common, + int cmnd_size, enum data_direction data_dir, + unsigned int mask, int needs_medium, const char *name) +{ + if (common->curlun) + common->data_size_from_cmnd <<= common->curlun->blkbits; + return check_command(common, cmnd_size, data_dir, + mask, needs_medium, name); +} + static int do_scsi_command(struct fsg_common *common) { struct fsg_buffhd *bh; @@ -2011,9 +2019,9 @@ static int do_scsi_command(struct fsg_common *common) case READ_6: i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0 ? 256 : i) << - common->curlun->blkbits; - reply = check_command(common, 6, DATA_DIR_TO_HOST, + common->data_size_from_cmnd = (i == 0) ? 256 : i; + reply = check_command_size_in_blocks(common, 6, + DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1, "READ(6)"); if (reply == 0) @@ -2022,9 +2030,9 @@ static int do_scsi_command(struct fsg_common *common) case READ_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]) << - common->curlun->blkbits; - reply = check_command(common, 10, DATA_DIR_TO_HOST, + get_unaligned_be16(&common->cmnd[7]); + reply = check_command_size_in_blocks(common, 10, + DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "READ(10)"); if (reply == 0) @@ -2033,9 +2041,9 @@ static int do_scsi_command(struct fsg_common *common) case READ_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]) << - common->curlun->blkbits; - reply = check_command(common, 12, DATA_DIR_TO_HOST, + get_unaligned_be32(&common->cmnd[6]); + reply = check_command_size_in_blocks(common, 12, + DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)"); if (reply == 0) @@ -2134,9 +2142,9 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_6: i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0 ? 256 : i) << - common->curlun->blkbits; - reply = check_command(common, 6, DATA_DIR_FROM_HOST, + common->data_size_from_cmnd = (i == 0) ? 256 : i; + reply = check_command_size_in_blocks(common, 6, + DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1, "WRITE(6)"); if (reply == 0) @@ -2145,9 +2153,9 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]) << - common->curlun->blkbits; - reply = check_command(common, 10, DATA_DIR_FROM_HOST, + get_unaligned_be16(&common->cmnd[7]); + reply = check_command_size_in_blocks(common, 10, + DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "WRITE(10)"); if (reply == 0) @@ -2156,9 +2164,9 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]) << - common->curlun->blkbits; - reply = check_command(common, 12, DATA_DIR_FROM_HOST, + get_unaligned_be32(&common->cmnd[6]); + reply = check_command_size_in_blocks(common, 12, + DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)"); if (reply == 0) @@ -2273,6 +2281,10 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) if (common->data_size == 0) common->data_dir = DATA_DIR_NONE; common->lun = cbw->Lun; + if (common->lun >= 0 && common->lun < common->nluns) + common->curlun = &common->luns[common->lun]; + else + common->curlun = NULL; common->tag = cbw->Tag; return 0; } @@ -2763,7 +2775,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, * Create the LUNs, open their backing files, and register the * LUN devices in sysfs. */ - curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL); + curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); if (unlikely(!curlun)) { rc = -ENOMEM; goto error_release; @@ -2975,6 +2987,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) fsg_common_put(common); usb_free_descriptors(fsg->function.descriptors); usb_free_descriptors(fsg->function.hs_descriptors); + usb_free_descriptors(fsg->function.ss_descriptors); kfree(fsg); } diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 16a509ae517..7cdcb63b21f 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -298,11 +298,10 @@ static void pn_net_setup(struct net_device *dev) static int pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags) { - struct net_device *dev = fp->dev; struct page *page; int err; - page = __netdev_alloc_page(dev, gfp_flags); + page = alloc_page(gfp_flags); if (!page) return -ENOMEM; @@ -312,7 +311,7 @@ pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags) err = usb_ep_queue(fp->out_ep, req, gfp_flags); if (unlikely(err)) - netdev_free_page(dev, page); + put_page(page); return err; } @@ -374,9 +373,9 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) } if (page) - netdev_free_page(dev, page); + put_page(page); if (req) - pn_rx_submit(fp, req, GFP_ATOMIC); + pn_rx_submit(fp, req, GFP_ATOMIC | __GFP_COLD); } /*-------------------------------------------------------------------------*/ @@ -436,7 +435,7 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) netif_carrier_on(dev); for (i = 0; i < phonet_rxq_size; i++) - pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC); + pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC | __GFP_COLD); } spin_unlock(&port->lock); return 0; diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 91fdf790ed2..cf33a8d0fd5 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -131,8 +131,8 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } if (!gser->port.in->desc || !gser->port.out->desc) { DBG(cdev, "activate generic ttyGS%d\n", gser->port_num); - if (!config_ep_by_speed(cdev->gadget, f, gser->port.in) || - !config_ep_by_speed(cdev->gadget, f, gser->port.out)) { + if (config_ep_by_speed(cdev->gadget, f, gser->port.in) || + config_ep_by_speed(cdev->gadget, f, gser->port.out)) { gser->port.in->desc = NULL; gser->port.out->desc = NULL; return -EINVAL; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 11b5196284a..e0f30fc70e4 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -2297,19 +2297,17 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, DBG(fsg, "using LUN %d from CBW, " "not LUN %d from CDB\n", fsg->lun, lun); - } else - fsg->lun = lun; // Use LUN from the command + } /* Check the LUN */ - if (fsg->lun < fsg->nluns) { - fsg->curlun = curlun = &fsg->luns[fsg->lun]; + curlun = fsg->curlun; + if (curlun) { if (fsg->cmnd[0] != REQUEST_SENSE) { curlun->sense_data = SS_NO_SENSE; curlun->sense_data_info = 0; curlun->info_valid = 0; } } else { - fsg->curlun = curlun = NULL; fsg->bad_lun_okay = 0; /* INQUIRY and REQUEST SENSE commands are explicitly allowed @@ -2351,6 +2349,16 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, return 0; } +/* wrapper of check_command for data size in blocks handling */ +static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size, + enum data_direction data_dir, unsigned int mask, + int needs_medium, const char *name) +{ + if (fsg->curlun) + fsg->data_size_from_cmnd <<= fsg->curlun->blkbits; + return check_command(fsg, cmnd_size, data_dir, + mask, needs_medium, name); +} static int do_scsi_command(struct fsg_dev *fsg) { @@ -2425,26 +2433,27 @@ static int do_scsi_command(struct fsg_dev *fsg) case READ_6: i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + fsg->data_size_from_cmnd = (i == 0) ? 256 : i; + if ((reply = check_command_size_in_blocks(fsg, 6, + DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1, "READ(6)")) == 0) reply = do_read(fsg); break; case READ_10: - fsg->data_size_from_cmnd = - get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); + if ((reply = check_command_size_in_blocks(fsg, 10, + DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "READ(10)")) == 0) reply = do_read(fsg); break; case READ_12: - fsg->data_size_from_cmnd = - get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); + if ((reply = check_command_size_in_blocks(fsg, 12, + DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)")) == 0) reply = do_read(fsg); @@ -2529,26 +2538,27 @@ static int do_scsi_command(struct fsg_dev *fsg) case WRITE_6: i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, + fsg->data_size_from_cmnd = (i == 0) ? 256 : i; + if ((reply = check_command_size_in_blocks(fsg, 6, + DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1, "WRITE(6)")) == 0) reply = do_write(fsg); break; case WRITE_10: - fsg->data_size_from_cmnd = - get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); + if ((reply = check_command_size_in_blocks(fsg, 10, + DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "WRITE(10)")) == 0) reply = do_write(fsg); break; case WRITE_12: - fsg->data_size_from_cmnd = - get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); + if ((reply = check_command_size_in_blocks(fsg, 12, + DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)")) == 0) reply = do_write(fsg); @@ -2715,7 +2725,17 @@ static int get_next_command(struct fsg_dev *fsg) memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); fsg->cbbuf_cmnd_size = 0; spin_unlock_irq(&fsg->lock); + + /* Use LUN from the command */ + fsg->lun = fsg->cmnd[1] >> 5; } + + /* Update current lun */ + if (fsg->lun >= 0 && fsg->lun < fsg->nluns) + fsg->curlun = &fsg->luns[fsg->lun]; + else + fsg->curlun = NULL; + return rc; } @@ -3584,7 +3604,7 @@ static void fsg_resume(struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver fsg_driver = { - .speed = USB_SPEED_SUPER, + .max_speed = USB_SPEED_SUPER, .function = (char *) fsg_string_product, .unbind = fsg_unbind, .disconnect = fsg_disconnect, diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c index 43a49ecc1f3..dcbc0a2e48d 100644 --- a/drivers/usb/gadget/fsl_mxc_udc.c +++ b/drivers/usb/gadget/fsl_mxc_udc.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/fsl_devices.h> #include <linux/platform_device.h> +#include <linux/io.h> #include <mach/hardware.h> @@ -88,7 +89,6 @@ eenahb: void fsl_udc_clk_finalize(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; -#if defined(CONFIG_SOC_IMX35) if (cpu_is_mx35()) { unsigned int v; @@ -101,7 +101,6 @@ void fsl_udc_clk_finalize(struct platform_device *pdev) USBPHYCTRL_OTGBASE_OFFSET)); } } -#endif /* ULPI transceivers don't need usbpll */ if (pdata->phy_mode == FSL_USB2_PHY_ULPI) { diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 2a03e4de11c..b95697c03d0 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2336,8 +2336,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver, if (!udc_controller) return -ENODEV; - if (!driver || (driver->speed != USB_SPEED_FULL - && driver->speed != USB_SPEED_HIGH) + if (!driver || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -2351,7 +2350,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver, /* hook up the driver */ udc_controller->driver = driver; udc_controller->gadget.dev.driver = &driver->driver; - udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed); + udc_controller->gadget.speed = driver->max_speed; spin_unlock_irqrestore(&udc_controller->lock, flags); retval = bind(&udc_controller->gadget); @@ -2815,20 +2814,7 @@ static struct platform_driver udc_driver = { #endif }; -static int __init qe_udc_init(void) -{ - printk(KERN_INFO "%s: %s, %s\n", driver_name, driver_desc, - DRIVER_VERSION); - return platform_driver_register(&udc_driver); -} - -static void __exit qe_udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} - -module_init(qe_udc_init); -module_exit(qe_udc_exit); +module_platform_driver(udc_driver); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index b3b3d83b7c3..d7ea6c076ce 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -696,12 +696,31 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req) kfree(req); } -/*-------------------------------------------------------------------------*/ +/* Actually add a dTD chain to an empty dQH and let go */ +static void fsl_prime_ep(struct fsl_ep *ep, struct ep_td_struct *td) +{ + struct ep_queue_head *qh = get_qh_by_ep(ep); + + /* Write dQH next pointer and terminate bit to 0 */ + qh->next_dtd_ptr = cpu_to_hc32(td->td_dma + & EP_QUEUE_HEAD_NEXT_POINTER_MASK); + + /* Clear active and halt bit */ + qh->size_ioc_int_sts &= cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE + | EP_QUEUE_HEAD_STATUS_HALT)); + + /* Ensure that updates to the QH will occur before priming. */ + wmb(); + + /* Prime endpoint by writing correct bit to ENDPTPRIME */ + fsl_writel(ep_is_in(ep) ? (1 << (ep_index(ep) + 16)) + : (1 << (ep_index(ep))), &dr_regs->endpointprime); +} + +/* Add dTD chain to the dQH of an EP */ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) { - int i = ep_index(ep) * 2 + ep_is_in(ep); u32 temp, bitmask, tmp_stat; - struct ep_queue_head *dQH = &ep->udc->ep_qh[i]; /* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr); VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */ @@ -719,7 +738,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK); /* Read prime bit, if 1 goto done */ if (fsl_readl(&dr_regs->endpointprime) & bitmask) - goto out; + return; do { /* Set ATDTW bit in USBCMD */ @@ -736,28 +755,10 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd); if (tmp_stat) - goto out; + return; } - /* Write dQH next pointer and terminate bit to 0 */ - temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - dQH->next_dtd_ptr = cpu_to_hc32(temp); - - /* Clear active and halt bit */ - temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE - | EP_QUEUE_HEAD_STATUS_HALT)); - dQH->size_ioc_int_sts &= temp; - - /* Ensure that updates to the QH will occur before priming. */ - wmb(); - - /* Prime endpoint by writing 1 to ENDPTPRIME */ - temp = ep_is_in(ep) - ? (1 << (ep_index(ep) + 16)) - : (1 << (ep_index(ep))); - fsl_writel(temp, &dr_regs->endpointprime); -out: - return; + fsl_prime_ep(ep, req->head); } /* Fill in the dTD structure @@ -877,7 +878,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) VDBG("%s, bad ep", __func__); return -EINVAL; } - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (usb_endpoint_xfer_isoc(ep->desc)) { if (req->req.length > ep->ep.maxpacket) return -EMSGSIZE; } @@ -973,25 +974,20 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* The request isn't the last request in this ep queue */ if (req->queue.next != &ep->queue) { - struct ep_queue_head *qh; struct fsl_req *next_req; - qh = ep->qh; next_req = list_entry(req->queue.next, struct fsl_req, queue); - /* Point the QH to the first TD of next request */ - fsl_writel((u32) next_req->head, &qh->curr_dtd_ptr); + /* prime with dTD of next request */ + fsl_prime_ep(ep, next_req->head); } - - /* The request hasn't been processed, patch up the TD chain */ + /* The request hasn't been processed, patch up the TD chain */ } else { struct fsl_req *prev_req; prev_req = list_entry(req->queue.prev, struct fsl_req, queue); - fsl_writel(fsl_readl(&req->tail->next_td_ptr), - &prev_req->tail->next_td_ptr); - + prev_req->tail->next_td_ptr = req->tail->next_td_ptr; } done(ep, req, -ECONNRESET); @@ -1032,7 +1028,7 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value) goto out; } - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (usb_endpoint_xfer_isoc(ep->desc)) { status = -EOPNOTSUPP; goto out; } @@ -1068,7 +1064,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep) struct fsl_udc *udc; int size = 0; u32 bitmask; - struct ep_queue_head *d_qh; + struct ep_queue_head *qh; ep = container_of(_ep, struct fsl_ep, ep); if (!_ep || (!ep->desc && ep_index(ep) != 0)) @@ -1079,13 +1075,13 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep) if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; - d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)]; + qh = get_qh_by_ep(ep); bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) : (1 << (ep_index(ep))); if (fsl_readl(&dr_regs->endptstatus) & bitmask) - size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE) + size = (qh->size_ioc_int_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS; pr_debug("%s %u\n", __func__, size); @@ -1938,8 +1934,7 @@ static int fsl_start(struct usb_gadget_driver *driver, if (!udc_controller) return -ENODEV; - if (!driver || (driver->speed != USB_SPEED_FULL - && driver->speed != USB_SPEED_HIGH) + if (!driver || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -2530,7 +2525,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) /* Setup gadget structure */ udc_controller->gadget.ops = &fsl_gadget_ops; - udc_controller->gadget.is_dualspeed = 1; + udc_controller->gadget.max_speed = USB_SPEED_HIGH; udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; INIT_LIST_HEAD(&udc_controller->gadget.ep_list); udc_controller->gadget.speed = USB_SPEED_UNKNOWN; diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index 1d51be83fda..f781f5dec41 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -569,6 +569,16 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length) * 2 + ((windex & USB_DIR_IN) ? 1 : 0)) #define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP)) +static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep) +{ + /* we only have one ep0 structure but two queue heads */ + if (ep_index(ep) != 0) + return ep->qh; + else + return &ep->udc->ep_qh[(ep->udc->ep0_dir == + USB_DIR_IN) ? 1 : 0]; +} + struct platform_device; #ifdef CONFIG_ARCH_MXC int fsl_udc_clk_init(struct platform_device *pdev); diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 74da206c840..5831cb4a0b3 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1317,7 +1317,7 @@ static int fusb300_udc_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->setup) return -EINVAL; @@ -1463,7 +1463,7 @@ static int __init fusb300_probe(struct platform_device *pdev) dev_set_name(&fusb300->gadget.dev, "gadget"); - fusb300->gadget.is_dualspeed = 1; + fusb300->gadget.max_speed = USB_SPEED_HIGH; fusb300->gadget.dev.parent = &pdev->dev; fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask; fusb300->gadget.dev.release = pdev->dev.release; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 7f87805cddc..5af70fcce13 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1357,7 +1357,7 @@ static int goku_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) @@ -1796,6 +1796,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init(&dev->lock); dev->pdev = pdev; dev->gadget.ops = &goku_ops; + dev->gadget.max_speed = USB_SPEED_FULL; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&dev->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index 2d978c0e7ce..8d1c75abd73 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1336,7 +1336,7 @@ static int imx_udc_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 6ccae2707e5..ae04266dba1 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1766,9 +1766,9 @@ gadgetfs_suspend (struct usb_gadget *gadget) static struct usb_gadget_driver gadgetfs_driver = { #ifdef CONFIG_USB_GADGET_DUALSPEED - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, #else - .speed = USB_SPEED_FULL, + .max_speed = USB_SPEED_FULL, #endif .function = (char *) driver_desc, .unbind = gadgetfs_unbind, @@ -1792,7 +1792,7 @@ static int gadgetfs_probe (struct usb_gadget *gadget) } static struct usb_gadget_driver probe_driver = { - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, @@ -2035,7 +2035,6 @@ static int gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) { struct inode *inode; - struct dentry *d; struct dev_data *dev; if (the_device) @@ -2058,24 +2057,27 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) NULL, &simple_dir_operations, S_IFDIR | S_IRUGO | S_IXUGO); if (!inode) - goto enomem0; + goto Enomem; inode->i_op = &simple_dir_inode_operations; - if (!(d = d_alloc_root (inode))) - goto enomem1; - sb->s_root = d; + if (!(sb->s_root = d_alloc_root (inode))) { + iput(inode); + goto Enomem; + } /* the ep0 file is named after the controller we expect; * user mode code can use it for sanity checks, like we do. */ dev = dev_new (); if (!dev) - goto enomem2; + goto Enomem; dev->sb = sb; if (!gadgetfs_create_file (sb, CHIP, dev, &dev_init_operations, - &dev->dentry)) - goto enomem3; + &dev->dentry)) { + put_dev(dev); + goto Enomem; + } /* other endpoint files are available after hardware setup, * from binding to a controller. @@ -2083,13 +2085,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) the_device = dev; return 0; -enomem3: - put_dev (dev); -enomem2: - dput (d); -enomem1: - iput (inode); -enomem0: +Enomem: return -ENOMEM; } diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index c9fa3bf5b37..fa0fcc11263 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -3267,7 +3267,7 @@ static int langwell_udc_probe(struct pci_dev *pdev, dev->gadget.ep0 = &dev->ep[0].ep; /* gadget ep0 */ INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */ dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - dev->gadget.is_dualspeed = 1; /* support dual speed */ + dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ #ifdef OTG_TRANSCEIVER dev->gadget.is_otg = 1; /* support otg mode */ #endif diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 91d0af2a24a..3608b3bd573 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1472,7 +1472,7 @@ static int m66592_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed != USB_SPEED_HIGH + || driver->max_speed < USB_SPEED_HIGH || !bind || !driver->setup) return -EINVAL; @@ -1653,7 +1653,7 @@ static int __init m66592_probe(struct platform_device *pdev) m66592->gadget.ops = &m66592_gadget_ops; device_initialize(&m66592->gadget.dev); dev_set_name(&m66592->gadget.dev, "gadget"); - m66592->gadget.is_dualspeed = 1; + m66592->gadget.max_speed = USB_SPEED_HIGH; m66592->gadget.dev.parent = &pdev->dev; m66592->gadget.dev.dma_mask = pdev->dev.dma_mask; m66592->gadget.dev.release = pdev->dev.release; diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h index daa75c12f33..34aadfae723 100644 --- a/drivers/usb/gadget/mv_udc.h +++ b/drivers/usb/gadget/mv_udc.h @@ -180,7 +180,7 @@ struct mv_udc { struct mv_cap_regs __iomem *cap_regs; struct mv_op_regs __iomem *op_regs; - unsigned int phy_regs; + void __iomem *phy_regs; unsigned int max_eps; struct mv_dqh *ep_dqh; size_t ep_dqh_size; @@ -211,11 +211,14 @@ struct mv_udc { softconnected:1, force_fs:1, clock_gating:1, - active:1; + active:1, + stopped:1; /* stop bit is setted */ struct work_struct vbus_work; struct workqueue_struct *qwork; + struct otg_transceiver *transceiver; + struct mv_usb_platform_data *pdata; /* some SOC has mutiple clock sources for USB*/ diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 892412103dd..f97e737d26f 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -276,11 +276,12 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status) static int queue_dtd(struct mv_ep *ep, struct mv_req *req) { - u32 tmp, epstatus, bit_pos, direction; struct mv_udc *udc; struct mv_dqh *dqh; + u32 bit_pos, direction; + u32 usbcmd, epstatus; unsigned int loops; - int readsafe, retval = 0; + int retval = 0; udc = ep->udc; direction = ep_dir(ep); @@ -293,30 +294,18 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req) lastreq = list_entry(ep->queue.prev, struct mv_req, queue); lastreq->tail->dtd_next = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - if (readl(&udc->op_regs->epprime) & bit_pos) { - loops = LOOPS(PRIME_TIMEOUT); - while (readl(&udc->op_regs->epprime) & bit_pos) { - if (loops == 0) { - retval = -ETIME; - goto done; - } - udelay(LOOPS_USEC); - loops--; - } - if (readl(&udc->op_regs->epstatus) & bit_pos) - goto done; - } - readsafe = 0; + + wmb(); + + if (readl(&udc->op_regs->epprime) & bit_pos) + goto done; + loops = LOOPS(READSAFE_TIMEOUT); - while (readsafe == 0) { - if (loops == 0) { - retval = -ETIME; - goto done; - } + while (1) { /* start with setting the semaphores */ - tmp = readl(&udc->op_regs->usbcmd); - tmp |= USBCMD_ATDTW_TRIPWIRE_SET; - writel(tmp, &udc->op_regs->usbcmd); + usbcmd = readl(&udc->op_regs->usbcmd); + usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET; + writel(usbcmd, &udc->op_regs->usbcmd); /* read the endpoint status */ epstatus = readl(&udc->op_regs->epstatus) & bit_pos; @@ -329,98 +318,46 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req) * primed. */ if (readl(&udc->op_regs->usbcmd) - & USBCMD_ATDTW_TRIPWIRE_SET) { - readsafe = 1; - } + & USBCMD_ATDTW_TRIPWIRE_SET) + break; + loops--; + if (loops == 0) { + dev_err(&udc->dev->dev, + "Timeout for ATDTW_TRIPWIRE...\n"); + retval = -ETIME; + goto done; + } udelay(LOOPS_USEC); } /* Clear the semaphore */ - tmp = readl(&udc->op_regs->usbcmd); - tmp &= USBCMD_ATDTW_TRIPWIRE_CLEAR; - writel(tmp, &udc->op_regs->usbcmd); - - /* If endpoint is not active, we activate it now. */ - if (!epstatus) { - if (direction == EP_DIR_IN) { - struct mv_dtd *curr_dtd = dma_to_virt( - &udc->dev->dev, dqh->curr_dtd_ptr); - - loops = LOOPS(DTD_TIMEOUT); - while (curr_dtd->size_ioc_sts - & DTD_STATUS_ACTIVE) { - if (loops == 0) { - retval = -ETIME; - goto done; - } - loops--; - udelay(LOOPS_USEC); - } - } - /* No other transfers on the queue */ + usbcmd = readl(&udc->op_regs->usbcmd); + usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR; + writel(usbcmd, &udc->op_regs->usbcmd); - /* Write dQH next pointer and terminate bit to 0 */ - dqh->next_dtd_ptr = req->head->td_dma - & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - dqh->size_ioc_int_sts = 0; + if (epstatus) + goto done; + } - /* - * Ensure that updates to the QH will - * occur before priming. - */ - wmb(); + /* Write dQH next pointer and terminate bit to 0 */ + dqh->next_dtd_ptr = req->head->td_dma + & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - /* Prime the Endpoint */ - writel(bit_pos, &udc->op_regs->epprime); - } - } else { - /* Write dQH next pointer and terminate bit to 0 */ - dqh->next_dtd_ptr = req->head->td_dma - & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - dqh->size_ioc_int_sts = 0; + /* clear active and halt bit, in case set from a previous error */ + dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); - /* Ensure that updates to the QH will occur before priming. */ - wmb(); + /* Ensure that updates to the QH will occure before priming. */ + wmb(); - /* Prime the Endpoint */ - writel(bit_pos, &udc->op_regs->epprime); + /* Prime the Endpoint */ + writel(bit_pos, &udc->op_regs->epprime); - if (direction == EP_DIR_IN) { - /* FIXME add status check after prime the IN ep */ - int prime_again; - u32 curr_dtd_ptr = dqh->curr_dtd_ptr; - - loops = LOOPS(DTD_TIMEOUT); - prime_again = 0; - while ((curr_dtd_ptr != req->head->td_dma)) { - curr_dtd_ptr = dqh->curr_dtd_ptr; - if (loops == 0) { - dev_err(&udc->dev->dev, - "failed to prime %s\n", - ep->name); - retval = -ETIME; - goto done; - } - loops--; - udelay(LOOPS_USEC); - - if (loops == (LOOPS(DTD_TIMEOUT) >> 2)) { - if (prime_again) - goto done; - dev_info(&udc->dev->dev, - "prime again\n"); - writel(bit_pos, - &udc->op_regs->epprime); - prime_again = 1; - } - } - } - } done: return retval; } + static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length, dma_addr_t *dma, int *is_last) { @@ -841,6 +778,27 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) return 0; } +static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req) +{ + struct mv_dqh *dqh = ep->dqh; + u32 bit_pos; + + /* Write dQH next pointer and terminate bit to 0 */ + dqh->next_dtd_ptr = req->head->td_dma + & EP_QUEUE_HEAD_NEXT_POINTER_MASK; + + /* clear active and halt bit, in case set from a previous error */ + dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); + + /* Ensure that updates to the QH will occure before priming. */ + wmb(); + + bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num); + + /* Prime the Endpoint */ + writel(bit_pos, &ep->udc->op_regs->epprime); +} + /* dequeues (cancels, unlinks) an I/O request from an endpoint */ static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) { @@ -883,15 +841,13 @@ static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* The request isn't the last request in this ep queue */ if (req->queue.next != &ep->queue) { - struct mv_dqh *qh; struct mv_req *next_req; - qh = ep->dqh; - next_req = list_entry(req->queue.next, struct mv_req, - queue); + next_req = list_entry(req->queue.next, + struct mv_req, queue); /* Point the QH to the first TD of next request */ - writel((u32) next_req->head, &qh->curr_dtd_ptr); + mv_prime_ep(ep, next_req); } else { struct mv_dqh *qh; @@ -1056,6 +1012,8 @@ static void udc_stop(struct mv_udc *udc) USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN); writel(tmp, &udc->op_regs->usbintr); + udc->stopped = 1; + /* Reset the Run the bit in the command register to stop VUSB */ tmp = readl(&udc->op_regs->usbcmd); tmp &= ~USBCMD_RUN_STOP; @@ -1072,6 +1030,8 @@ static void udc_start(struct mv_udc *udc) /* Enable interrupts */ writel(usbintr, &udc->op_regs->usbintr); + udc->stopped = 0; + /* Set the Run bit in the command register */ writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd); } @@ -1134,11 +1094,11 @@ static int udc_reset(struct mv_udc *udc) return 0; } -static int mv_udc_enable(struct mv_udc *udc) +static int mv_udc_enable_internal(struct mv_udc *udc) { int retval; - if (udc->clock_gating == 0 || udc->active) + if (udc->active) return 0; dev_dbg(&udc->dev->dev, "enable udc\n"); @@ -1157,9 +1117,17 @@ static int mv_udc_enable(struct mv_udc *udc) return 0; } -static void mv_udc_disable(struct mv_udc *udc) +static int mv_udc_enable(struct mv_udc *udc) { - if (udc->clock_gating && udc->active) { + if (udc->clock_gating) + return mv_udc_enable_internal(udc); + + return 0; +} + +static void mv_udc_disable_internal(struct mv_udc *udc) +{ + if (udc->active) { dev_dbg(&udc->dev->dev, "disable udc\n"); if (udc->pdata->phy_deinit) udc->pdata->phy_deinit(udc->phy_regs); @@ -1168,6 +1136,12 @@ static void mv_udc_disable(struct mv_udc *udc) } } +static void mv_udc_disable(struct mv_udc *udc) +{ + if (udc->clock_gating) + mv_udc_disable_internal(udc); +} + static int mv_udc_get_frame(struct usb_gadget *gadget) { struct mv_udc *udc; @@ -1178,7 +1152,7 @@ static int mv_udc_get_frame(struct usb_gadget *gadget) udc = container_of(gadget, struct mv_udc, gadget); - retval = readl(udc->op_regs->frindex) & USB_FRINDEX_MASKS; + retval = readl(&udc->op_regs->frindex) & USB_FRINDEX_MASKS; return retval; } @@ -1212,10 +1186,11 @@ static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active) udc = container_of(gadget, struct mv_udc, gadget); spin_lock_irqsave(&udc->lock, flags); + udc->vbus_active = (is_active != 0); + dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", __func__, udc->softconnect, udc->vbus_active); - udc->vbus_active = (is_active != 0); if (udc->driver && udc->softconnect && udc->vbus_active) { retval = mv_udc_enable(udc); if (retval == 0) { @@ -1244,10 +1219,11 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on) udc = container_of(gadget, struct mv_udc, gadget); spin_lock_irqsave(&udc->lock, flags); + udc->softconnect = (is_on != 0); + dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", __func__, udc->softconnect, udc->vbus_active); - udc->softconnect = (is_on != 0); if (udc->driver && udc->softconnect && udc->vbus_active) { retval = mv_udc_enable(udc); if (retval == 0) { @@ -1407,6 +1383,20 @@ static int mv_udc_start(struct usb_gadget_driver *driver, return retval; } + if (udc->transceiver) { + retval = otg_set_peripheral(udc->transceiver, &udc->gadget); + if (retval) { + dev_err(&udc->dev->dev, + "unable to register peripheral to otg\n"); + if (driver->unbind) { + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + } + return retval; + } + } + /* pullup is always on */ mv_udc_pullup(&udc->gadget, 1); @@ -2026,6 +2016,10 @@ static irqreturn_t mv_udc_irq(int irq, void *dev) struct mv_udc *udc = (struct mv_udc *)dev; u32 status, intr; + /* Disable ISR when stopped bit is set */ + if (udc->stopped) + return IRQ_NONE; + spin_lock(&udc->lock); status = readl(&udc->op_regs->usbsts); @@ -2109,7 +2103,12 @@ static int __devexit mv_udc_remove(struct platform_device *dev) destroy_workqueue(udc->qwork); } - if (udc->pdata && udc->pdata->vbus && udc->clock_gating) + /* + * If we have transceiver inited, + * then vbus irq will not be requested in udc driver. + */ + if (udc->pdata && udc->pdata->vbus + && udc->clock_gating && udc->transceiver == NULL) free_irq(udc->pdata->vbus->irq, &dev->dev); /* free memory allocated in probe */ @@ -2129,11 +2128,9 @@ static int __devexit mv_udc_remove(struct platform_device *dev) if (udc->cap_regs) iounmap(udc->cap_regs); - udc->cap_regs = NULL; if (udc->phy_regs) - iounmap((void *)udc->phy_regs); - udc->phy_regs = 0; + iounmap(udc->phy_regs); if (udc->status_req) { kfree(udc->status_req->req.buf); @@ -2182,6 +2179,11 @@ static int __devinit mv_udc_probe(struct platform_device *dev) udc->dev = dev; +#ifdef CONFIG_USB_OTG_UTILS + if (pdata->mode == MV_USB_MODE_OTG) + udc->transceiver = otg_get_transceiver(); +#endif + udc->clknum = pdata->clknum; for (clk_i = 0; clk_i < udc->clknum; clk_i++) { udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]); @@ -2213,24 +2215,20 @@ static int __devinit mv_udc_probe(struct platform_device *dev) goto err_iounmap_capreg; } - udc->phy_regs = (unsigned int)ioremap(r->start, resource_size(r)); - if (udc->phy_regs == 0) { + udc->phy_regs = ioremap(r->start, resource_size(r)); + if (udc->phy_regs == NULL) { dev_err(&dev->dev, "failed to map phy I/O memory\n"); retval = -EBUSY; goto err_iounmap_capreg; } /* we will acces controller register, so enable the clk */ - udc_clock_enable(udc); - if (pdata->phy_init) { - retval = pdata->phy_init(udc->phy_regs); - if (retval) { - dev_err(&dev->dev, "phy init error %d\n", retval); - goto err_iounmap_phyreg; - } - } + retval = mv_udc_enable_internal(udc); + if (retval) + goto err_iounmap_phyreg; - udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs + udc->op_regs = + (struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs + (readl(&udc->cap_regs->caplength_hciversion) & CAPLENGTH_MASK)); udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK; @@ -2312,7 +2310,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev) udc->gadget.ep0 = &udc->eps[0].ep; /* gadget ep0 */ INIT_LIST_HEAD(&udc->gadget.ep_list); /* ep_list */ udc->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - udc->gadget.is_dualspeed = 1; /* support dual speed */ + udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&udc->gadget.dev, "gadget"); @@ -2328,7 +2326,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev) eps_init(udc); /* VBUS detect: we can disable/enable clock on demand.*/ - if (pdata->vbus) { + if (udc->transceiver) + udc->clock_gating = 1; + else if (pdata->vbus) { udc->clock_gating = 1; retval = request_threaded_irq(pdata->vbus->irq, NULL, mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc); @@ -2354,11 +2354,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev) * If not, it means that VBUS detection is not supported, we * have to enable vbus active all the time to let controller work. */ - if (udc->clock_gating) { - if (udc->pdata->phy_deinit) - udc->pdata->phy_deinit(udc->phy_regs); - udc_clock_disable(udc); - } else + if (udc->clock_gating) + mv_udc_disable_internal(udc); + else udc->vbus_active = 1; retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); @@ -2371,7 +2369,8 @@ static int __devinit mv_udc_probe(struct platform_device *dev) return 0; err_unregister: - if (udc->pdata && udc->pdata->vbus && udc->clock_gating) + if (udc->pdata && udc->pdata->vbus + && udc->clock_gating && udc->transceiver == NULL) free_irq(pdata->vbus->irq, &dev->dev); device_unregister(&udc->gadget.dev); err_free_irq: @@ -2387,11 +2386,9 @@ err_free_dma: dma_free_coherent(&dev->dev, udc->ep_dqh_size, udc->ep_dqh, udc->ep_dqh_dma); err_disable_clock: - if (udc->pdata->phy_deinit) - udc->pdata->phy_deinit(udc->phy_regs); - udc_clock_disable(udc); + mv_udc_disable_internal(udc); err_iounmap_phyreg: - iounmap((void *)udc->phy_regs); + iounmap(udc->phy_regs); err_iounmap_capreg: iounmap(udc->cap_regs); err_put_clk: @@ -2407,7 +2404,30 @@ static int mv_udc_suspend(struct device *_dev) { struct mv_udc *udc = the_controller; - udc_stop(udc); + /* if OTG is enabled, the following will be done in OTG driver*/ + if (udc->transceiver) + return 0; + + if (udc->pdata->vbus && udc->pdata->vbus->poll) + if (udc->pdata->vbus->poll() == VBUS_HIGH) { + dev_info(&udc->dev->dev, "USB cable is connected!\n"); + return -EAGAIN; + } + + /* + * only cable is unplugged, udc can suspend. + * So do not care about clock_gating == 1. + */ + if (!udc->clock_gating) { + udc_stop(udc); + + spin_lock_irq(&udc->lock); + /* stop all usb activities */ + stop_activity(udc, udc->driver); + spin_unlock_irq(&udc->lock); + + mv_udc_disable_internal(udc); + } return 0; } @@ -2417,20 +2437,22 @@ static int mv_udc_resume(struct device *_dev) struct mv_udc *udc = the_controller; int retval; - if (udc->pdata->phy_init) { - retval = udc->pdata->phy_init(udc->phy_regs); - if (retval) { - dev_err(&udc->dev->dev, - "init phy error %d when resume back\n", - retval); + /* if OTG is enabled, the following will be done in OTG driver*/ + if (udc->transceiver) + return 0; + + if (!udc->clock_gating) { + retval = mv_udc_enable_internal(udc); + if (retval) return retval; + + if (udc->driver && udc->softconnect) { + udc_reset(udc); + ep0_reset(udc); + udc_start(udc); } } - udc_reset(udc); - ep0_reset(udc); - udc_start(udc); - return 0; } @@ -2457,30 +2479,16 @@ static struct platform_driver udc_driver = { .shutdown = mv_udc_shutdown, .driver = { .owner = THIS_MODULE, - .name = "pxa-u2o", + .name = "mv-udc", #ifdef CONFIG_PM .pm = &mv_udc_pm_ops, #endif }, }; -MODULE_ALIAS("platform:pxa-u2o"); +module_platform_driver(udc_driver); +MODULE_ALIAS("platform:mv-udc"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>"); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - - -static int __init init(void) -{ - return platform_driver_register(&udc_driver); -} -module_init(init); - - -static void __exit cleanup(void) -{ - platform_driver_unregister(&udc_driver); -} -module_exit(cleanup); - diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index d1b76368472..4c81d540bc2 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -1459,7 +1459,7 @@ static int net2272_start(struct usb_gadget *_gadget, unsigned i; if (!driver || !driver->unbind || !driver->setup || - driver->speed != USB_SPEED_HIGH) + driver->max_speed != USB_SPEED_HIGH) return -EINVAL; dev = container_of(_gadget, struct net2272, gadget); @@ -2235,7 +2235,7 @@ net2272_probe_init(struct device *dev, unsigned int irq) ret->irq = irq; ret->dev = dev; ret->gadget.ops = &net2272_ops; - ret->gadget.is_dualspeed = 1; + ret->gadget.max_speed = USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&ret->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 7f1bc9a73cd..cf1f36454d0 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1881,7 +1881,7 @@ static int net2280_start(struct usb_gadget *_gadget, * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE) * "must not be used in normal operation" */ - if (!driver || driver->speed != USB_SPEED_HIGH + if (!driver || driver->max_speed < USB_SPEED_HIGH || !driver->setup) return -EINVAL; @@ -2698,7 +2698,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init (&dev->lock); dev->pdev = pdev; dev->gadget.ops = &net2280_ops; - dev->gadget.is_dualspeed = 1; + dev->gadget.max_speed = USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&dev->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 788989a1022..7db5bbe6251 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2110,7 +2110,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver, return -ENODEV; if (!driver // FIXME if otg, check: driver->is_otg - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->setup) return -EINVAL; @@ -2676,6 +2676,7 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) INIT_LIST_HEAD(&udc->gadget.ep_list); INIT_LIST_HEAD(&udc->iso); udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.max_speed = USB_SPEED_FULL; udc->gadget.name = driver_name; device_initialize(&udc->gadget.dev); diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 5048a0c0764..dd2313cce1d 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -2693,7 +2693,7 @@ static int pch_udc_start(struct usb_gadget_driver *driver, struct pch_udc_dev *dev = pch_udc; int retval; - if (!driver || (driver->speed == USB_SPEED_UNKNOWN) || !bind || + if (!driver || (driver->max_speed == USB_SPEED_UNKNOWN) || !bind || !driver->setup || !driver->unbind || !driver->disconnect) { dev_err(&dev->pdev->dev, "%s: invalid driver parameter\n", __func__); @@ -2941,7 +2941,7 @@ static int pch_udc_probe(struct pci_dev *pdev, dev->gadget.dev.dma_mask = pdev->dev.dma_mask; dev->gadget.dev.release = gadget_release; dev->gadget.name = KBUILD_MODNAME; - dev->gadget.is_dualspeed = 1; + dev->gadget.max_speed = USB_SPEED_HIGH; retval = device_register(&dev->gadget.dev); if (retval) diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 65a8834f274..d83134b0f78 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1141,7 +1141,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; #ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* * assumes ep0 uses the same value for both @@ -1155,7 +1155,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* FALLTHROUGH */ #endif /* CONFIG_USB_GADGET_DUALSPEED */ @@ -1535,7 +1535,7 @@ fail: /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver printer_driver = { - .speed = DEVSPEED, + .max_speed = DEVSPEED, .function = (char *) driver_desc, .unbind = printer_unbind, diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index c090a7e3ecf..dd470635f4f 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -1264,7 +1264,7 @@ static int pxa25x_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 18b6b091f2a..f4c44eb806c 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1807,7 +1807,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver, struct pxa_udc *udc = the_controller; int retval; - if (!driver || driver->speed < USB_SPEED_FULL || !bind + if (!driver || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; if (!udc) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 24f84b210ce..f5b8d215e1d 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1746,7 +1746,7 @@ static int r8a66597_start(struct usb_gadget *gadget, struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); if (!driver - || driver->speed != USB_SPEED_HIGH + || driver->max_speed < USB_SPEED_HIGH || !driver->setup) return -EINVAL; if (!r8a66597) @@ -1911,7 +1911,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597->gadget.ops = &r8a66597_gadget_ops; dev_set_name(&r8a66597->gadget.dev, "gadget"); - r8a66597->gadget.is_dualspeed = 1; + r8a66597->gadget.max_speed = USB_SPEED_HIGH; r8a66597->gadget.dev.parent = &pdev->dev; r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask; r8a66597->gadget.dev.release = pdev->dev.release; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index a552453dc94..69295ba9d99 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2586,10 +2586,8 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver, return -EINVAL; } - if (driver->speed != USB_SPEED_HIGH && - driver->speed != USB_SPEED_FULL) { + if (driver->max_speed < USB_SPEED_FULL) dev_err(hsotg->dev, "%s: bad speed\n", __func__); - } if (!bind || !driver->setup) { dev_err(hsotg->dev, "%s: missing entry points\n", __func__); @@ -3364,7 +3362,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) dev_set_name(&hsotg->gadget.dev, "gadget"); - hsotg->gadget.is_dualspeed = 1; + hsotg->gadget.max_speed = USB_SPEED_HIGH; hsotg->gadget.ops = &s3c_hsotg_gadget_ops; hsotg->gadget.name = dev_name(dev); @@ -3469,18 +3467,7 @@ static struct platform_driver s3c_hsotg_driver = { .resume = s3c_hsotg_resume, }; -static int __init s3c_hsotg_modinit(void) -{ - return platform_driver_register(&s3c_hsotg_driver); -} - -static void __exit s3c_hsotg_modexit(void) -{ - platform_driver_unregister(&s3c_hsotg_driver); -} - -module_init(s3c_hsotg_modinit); -module_exit(s3c_hsotg_modexit); +module_platform_driver(s3c_hsotg_driver); MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device"); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 8d54f893cef..df8661d266c 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -28,9 +28,10 @@ #include <linux/usb/gadget.h> #include <linux/usb/otg.h> #include <linux/prefetch.h> +#include <linux/platform_data/s3c-hsudc.h> +#include <linux/regulator/consumer.h> #include <mach/regs-s3c2443-clock.h> -#include <plat/udc.h> #define S3C_HSUDC_REG(x) (x) @@ -87,6 +88,12 @@ #define DATA_STATE_XMIT (1) #define DATA_STATE_RECV (2) +static const char * const s3c_hsudc_supply_names[] = { + "vdda", /* analog phy supply, 3.3V */ + "vddi", /* digital phy supply, 1.2V */ + "vddosc", /* oscillator supply, 1.8V - 3.3V */ +}; + /** * struct s3c_hsudc_ep - Endpoint representation used by driver. * @ep: USB gadget layer representation of device endpoint. @@ -139,6 +146,7 @@ struct s3c_hsudc { struct device *dev; struct s3c24xx_hsudc_platdata *pd; struct otg_transceiver *transceiver; + struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)]; spinlock_t lock; void __iomem *regs; struct resource *mem_rsrc; @@ -153,7 +161,6 @@ struct s3c_hsudc { #define ep_index(_ep) ((_ep)->bEndpointAddress & \ USB_ENDPOINT_NUMBER_MASK) -static struct s3c_hsudc *the_controller; static const char driver_name[] = "s3c-udc"; static const char ep0name[] = "ep0-control"; @@ -282,8 +289,7 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status) * All the endpoints are stopped and any pending transfer requests if any on * the endpoint are terminated. */ -static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc, - struct usb_gadget_driver *driver) +static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc) { struct s3c_hsudc_ep *hsep; int epnum; @@ -295,10 +301,6 @@ static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc, hsep->stopped = 1; s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN); } - - spin_unlock(&hsudc->lock); - driver->disconnect(&hsudc->gadget); - spin_lock(&hsudc->lock); } /** @@ -1135,17 +1137,15 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev) return IRQ_HANDLED; } -static int s3c_hsudc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int s3c_hsudc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct s3c_hsudc *hsudc = the_controller; + struct s3c_hsudc *hsudc = to_hsudc(gadget); int ret; if (!driver - || (driver->speed != USB_SPEED_FULL && - driver->speed != USB_SPEED_HIGH) - || !bind - || !driver->unbind || !driver->disconnect || !driver->setup) + || driver->max_speed < USB_SPEED_FULL + || !driver->setup) return -EINVAL; if (!hsudc) @@ -1156,21 +1156,12 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver, hsudc->driver = driver; hsudc->gadget.dev.driver = &driver->driver; - hsudc->gadget.speed = USB_SPEED_UNKNOWN; - ret = device_add(&hsudc->gadget.dev); - if (ret) { - dev_err(hsudc->dev, "failed to probe gadget device"); - return ret; - } - ret = bind(&hsudc->gadget); - if (ret) { - dev_err(hsudc->dev, "%s: bind failed\n", hsudc->gadget.name); - device_del(&hsudc->gadget.dev); - - hsudc->driver = NULL; - hsudc->gadget.dev.driver = NULL; - return ret; + ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies), + hsudc->supplies); + if (ret != 0) { + dev_err(hsudc->dev, "failed to enable supplies: %d\n", ret); + goto err_supplies; } /* connect to bus through transceiver */ @@ -1179,13 +1170,7 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver, if (ret) { dev_err(hsudc->dev, "%s: can't bind to transceiver\n", hsudc->gadget.name); - driver->unbind(&hsudc->gadget); - - device_del(&hsudc->gadget.dev); - - hsudc->driver = NULL; - hsudc->gadget.dev.driver = NULL; - return ret; + goto err_otg; } } @@ -1198,34 +1183,43 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver, hsudc->pd->gpio_init(); return 0; +err_otg: + regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); +err_supplies: + hsudc->driver = NULL; + hsudc->gadget.dev.driver = NULL; + return ret; } -static int s3c_hsudc_stop(struct usb_gadget_driver *driver) +static int s3c_hsudc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct s3c_hsudc *hsudc = the_controller; + struct s3c_hsudc *hsudc = to_hsudc(gadget); unsigned long flags; if (!hsudc) return -ENODEV; - if (!driver || driver != hsudc->driver || !driver->unbind) + if (!driver || driver != hsudc->driver) return -EINVAL; spin_lock_irqsave(&hsudc->lock, flags); - hsudc->driver = 0; + hsudc->driver = NULL; + hsudc->gadget.dev.driver = NULL; + hsudc->gadget.speed = USB_SPEED_UNKNOWN; s3c_hsudc_uninit_phy(); if (hsudc->pd->gpio_uninit) hsudc->pd->gpio_uninit(); - s3c_hsudc_stop_activity(hsudc, driver); + s3c_hsudc_stop_activity(hsudc); spin_unlock_irqrestore(&hsudc->lock, flags); if (hsudc->transceiver) (void) otg_set_peripheral(hsudc->transceiver, NULL); - driver->unbind(&hsudc->gadget); - device_del(&hsudc->gadget.dev); disable_irq(hsudc->irq); + regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); + dev_info(hsudc->dev, "unregistered gadget driver '%s'\n", driver->driver.name); return 0; @@ -1243,7 +1237,7 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget) static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA) { - struct s3c_hsudc *hsudc = the_controller; + struct s3c_hsudc *hsudc = to_hsudc(gadget); if (!hsudc) return -ENODEV; @@ -1256,18 +1250,18 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA) static struct usb_gadget_ops s3c_hsudc_gadget_ops = { .get_frame = s3c_hsudc_gadget_getframe, - .start = s3c_hsudc_start, - .stop = s3c_hsudc_stop, + .udc_start = s3c_hsudc_start, + .udc_stop = s3c_hsudc_stop, .vbus_draw = s3c_hsudc_vbus_draw, }; -static int s3c_hsudc_probe(struct platform_device *pdev) +static int __devinit s3c_hsudc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; struct s3c_hsudc *hsudc; struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data; - int ret; + int ret, i; hsudc = kzalloc(sizeof(struct s3c_hsudc) + sizeof(struct s3c_hsudc_ep) * pd->epnum, @@ -1277,13 +1271,22 @@ static int s3c_hsudc_probe(struct platform_device *pdev) return -ENOMEM; } - the_controller = hsudc; platform_set_drvdata(pdev, dev); hsudc->dev = dev; hsudc->pd = pdev->dev.platform_data; hsudc->transceiver = otg_get_transceiver(); + for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++) + hsudc->supplies[i].supply = s3c_hsudc_supply_names[i]; + + ret = regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies), + hsudc->supplies); + if (ret != 0) { + dev_err(dev, "failed to request supplies: %d\n", ret); + goto err_supplies; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "unable to obtain driver resource data\n"); @@ -1308,10 +1311,9 @@ static int s3c_hsudc_probe(struct platform_device *pdev) spin_lock_init(&hsudc->lock); - device_initialize(&hsudc->gadget.dev); dev_set_name(&hsudc->gadget.dev, "gadget"); - hsudc->gadget.is_dualspeed = 1; + hsudc->gadget.max_speed = USB_SPEED_HIGH; hsudc->gadget.ops = &s3c_hsudc_gadget_ops; hsudc->gadget.name = dev_name(dev); hsudc->gadget.dev.parent = dev; @@ -1320,6 +1322,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev) hsudc->gadget.is_otg = 0; hsudc->gadget.is_a_peripheral = 0; + hsudc->gadget.speed = USB_SPEED_UNKNOWN; s3c_hsudc_setup_ep(hsudc); @@ -1349,12 +1352,20 @@ static int s3c_hsudc_probe(struct platform_device *pdev) disable_irq(hsudc->irq); local_irq_enable(); + ret = device_register(&hsudc->gadget.dev); + if (ret) { + put_device(&hsudc->gadget.dev); + goto err_add_device; + } + ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget); if (ret) goto err_add_udc; return 0; err_add_udc: + device_unregister(&hsudc->gadget.dev); +err_add_device: clk_disable(hsudc->uclk); clk_put(hsudc->uclk); err_clk: @@ -1363,10 +1374,13 @@ err_irq: iounmap(hsudc->regs); err_remap: - release_resource(hsudc->mem_rsrc); - kfree(hsudc->mem_rsrc); - + release_mem_region(res->start, resource_size(res)); err_res: + if (hsudc->transceiver) + otg_put_transceiver(hsudc->transceiver); + + regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); +err_supplies: kfree(hsudc); return ret; } @@ -1378,21 +1392,10 @@ static struct platform_driver s3c_hsudc_driver = { }, .probe = s3c_hsudc_probe, }; -MODULE_ALIAS("platform:s3c-hsudc"); - -static int __init s3c_hsudc_modinit(void) -{ - return platform_driver_register(&s3c_hsudc_driver); -} -static void __exit s3c_hsudc_modexit(void) -{ - platform_driver_unregister(&s3c_hsudc_driver); -} - -module_init(s3c_hsudc_modinit); -module_exit(s3c_hsudc_modexit); +module_platform_driver(s3c_hsudc_driver); MODULE_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver"); MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:s3c-hsudc"); diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index b8643771fa8..3f87cb9344b 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -3,7 +3,7 @@ * * Samsung S3C24xx series on-chip full speed USB device controllers * - * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard + * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard * Additional cleanups by Ben Dooks <ben-linux@fluff.org> * * This program is free software; you can redistribute it and/or modify @@ -51,7 +51,7 @@ #define DRIVER_DESC "S3C2410 USB Device Controller Gadget" #define DRIVER_VERSION "29 Apr 2007" -#define DRIVER_AUTHOR "Herbert Pötzl <herbert@13thfloor.at>, " \ +#define DRIVER_AUTHOR "Herbert Pötzl <herbert@13thfloor.at>, " \ "Arnaud Patard <arnaud.patard@rtp-net.org>" static const char gadget_name[] = "s3c2410_udc"; @@ -1683,9 +1683,9 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver, if (udc->driver) return -EBUSY; - if (!bind || !driver->setup || driver->speed < USB_SPEED_FULL) { + if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) { printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", - bind, driver->setup, driver->speed); + bind, driver->setup, driver->max_speed); return -EINVAL; } #if defined(MODULE) diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h index a48f619cb1c..1653bae08b8 100644 --- a/drivers/usb/gadget/s3c2410_udc.h +++ b/drivers/usb/gadget/s3c2410_udc.h @@ -2,7 +2,7 @@ * linux/drivers/usb/gadget/s3c2410_udc.h * Samsung on-chip full speed USB device controllers * - * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard + * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard * Additional cleanups by Ben Dooks <ben-linux@fluff.org> * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 6939e17f458..0b0d12ccc48 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -371,14 +371,28 @@ static ssize_t usb_udc_softconn_store(struct device *dev, } static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); -static ssize_t usb_udc_speed_show(struct device *dev, +#define USB_UDC_SPEED_ATTR(name, param) \ +ssize_t usb_udc_##param##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ + return snprintf(buf, PAGE_SIZE, "%s\n", \ + usb_speed_string(udc->gadget->param)); \ +} \ +static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL) + +static USB_UDC_SPEED_ATTR(current_speed, speed); +static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); + +/* TODO: Scheduled for removal in 3.8. */ +static ssize_t usb_udc_is_dualspeed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - return snprintf(buf, PAGE_SIZE, "%s\n", - usb_speed_string(udc->gadget->speed)); + return snprintf(buf, PAGE_SIZE, "%d\n", + gadget_is_dualspeed(udc->gadget)); } -static DEVICE_ATTR(speed, S_IRUGO, usb_udc_speed_show, NULL); +static DEVICE_ATTR(is_dualspeed, S_IRUSR, usb_udc_is_dualspeed_show, NULL); #define USB_UDC_ATTR(name) \ ssize_t usb_udc_##name##_show(struct device *dev, \ @@ -391,7 +405,6 @@ ssize_t usb_udc_##name##_show(struct device *dev, \ } \ static DEVICE_ATTR(name, S_IRUGO, usb_udc_##name##_show, NULL) -static USB_UDC_ATTR(is_dualspeed); static USB_UDC_ATTR(is_otg); static USB_UDC_ATTR(is_a_peripheral); static USB_UDC_ATTR(b_hnp_enable); @@ -401,7 +414,8 @@ static USB_UDC_ATTR(a_alt_hnp_support); static struct attribute *usb_udc_attrs[] = { &dev_attr_srp.attr, &dev_attr_soft_connect.attr, - &dev_attr_speed.attr, + &dev_attr_current_speed.attr, + &dev_attr_maximum_speed.attr, &dev_attr_is_dualspeed.attr, &dev_attr_is_otg.attr, diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 58c4d37d312..4d25b9009ed 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -13,82 +13,17 @@ #include <linux/string.h> #include <linux/device.h> #include <linux/init.h> +#include <linux/nls.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> -#include <asm/unaligned.h> - - -static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len) -{ - int count = 0; - u8 c; - u16 uchar; - - /* this insists on correct encodings, though not minimal ones. - * BUT it currently rejects legit 4-byte UTF-8 code points, - * which need surrogate pairs. (Unicode 3.1 can use them.) - */ - while (len != 0 && (c = (u8) *s++) != 0) { - if (unlikely(c & 0x80)) { - // 2-byte sequence: - // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx - if ((c & 0xe0) == 0xc0) { - uchar = (c & 0x1f) << 6; - - c = (u8) *s++; - if ((c & 0xc0) != 0x80) - goto fail; - c &= 0x3f; - uchar |= c; - - // 3-byte sequence (most CJKV characters): - // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx - } else if ((c & 0xf0) == 0xe0) { - uchar = (c & 0x0f) << 12; - - c = (u8) *s++; - if ((c & 0xc0) != 0x80) - goto fail; - c &= 0x3f; - uchar |= c << 6; - - c = (u8) *s++; - if ((c & 0xc0) != 0x80) - goto fail; - c &= 0x3f; - uchar |= c; - - /* no bogus surrogates */ - if (0xd800 <= uchar && uchar <= 0xdfff) - goto fail; - - // 4-byte sequence (surrogate pairs, currently rare): - // 11101110wwwwzzzzyy + 110111yyyyxxxxxx - // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx - // (uuuuu = wwww + 1) - // FIXME accept the surrogate code points (only) - - } else - goto fail; - } else - uchar = c; - put_unaligned_le16(uchar, cp++); - count++; - len--; - } - return count; -fail: - return -1; -} - /** * usb_gadget_get_string - fill out a string descriptor * @table: of c strings encoded using UTF-8 * @id: string id, from low byte of wValue in get string descriptor - * @buf: at least 256 bytes + * @buf: at least 256 bytes, must be 16-bit aligned * * Finds the UTF-8 string matching the ID, and converts it into a * string descriptor in utf16-le. @@ -125,8 +60,8 @@ usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) /* string descriptors have length, tag, then UTF16-LE text */ len = min ((size_t) 126, strlen (s->s)); - memset (buf + 2, 0, 2 * len); /* zero all the bytes */ - len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len); + len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN, + (wchar_t *) &buf[2], 126); if (len < 0) return -EINVAL; buf [0] = (len + 1) * 2; |