diff options
Diffstat (limited to 'drivers/usb')
181 files changed, 4716 insertions, 3718 deletions
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 75eca764522..53a7bc07dd8 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -6,6 +6,8 @@  obj-$(CONFIG_USB)		+= core/ +obj-$(CONFIG_USB_OTG_UTILS)	+= otg/ +  obj-$(CONFIG_USB_DWC3)		+= dwc3/  obj-$(CONFIG_USB_MON)		+= mon/ @@ -51,7 +53,6 @@ obj-$(CONFIG_USB_SPEEDTOUCH)	+= atm/  obj-$(CONFIG_USB_MUSB_HDRC)	+= musb/  obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/ -obj-$(CONFIG_USB_OTG_UTILS)	+= otg/  obj-$(CONFIG_USB_GADGET)	+= gadget/  obj-$(CONFIG_USB_COMMON)	+= usb-common.o diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c index 57ae44cd0b8..6f3b6e26739 100644 --- a/drivers/usb/c67x00/c67x00-drv.c +++ b/drivers/usb/c67x00/c67x00-drv.c @@ -225,21 +225,10 @@ static struct platform_driver c67x00_driver = {  		.name = "c67x00",  	},  }; -MODULE_ALIAS("platform:c67x00"); - -static int __init c67x00_init(void) -{ -	return platform_driver_register(&c67x00_driver); -} -static void __exit c67x00_exit(void) -{ -	platform_driver_unregister(&c67x00_driver); -} - -module_init(c67x00_init); -module_exit(c67x00_exit); +module_platform_driver(c67x00_driver);  MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");  MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver");  MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:c67x00"); diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c index d3e1356d091..75e47b860a5 100644 --- a/drivers/usb/c67x00/c67x00-hcd.c +++ b/drivers/usb/c67x00/c67x00-hcd.c @@ -271,7 +271,6 @@ static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)  	if (int_status & SOFEOP_FLG(sie->sie_num)) {  		c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);  		c67x00_sched_kick(c67x00); -		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);  	}  } diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index a8078d0638f..9543b19d410 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -58,12 +58,62 @@ static struct usb_driver acm_driver;  static struct tty_driver *acm_tty_driver;  static struct acm *acm_table[ACM_TTY_MINORS]; -static DEFINE_MUTEX(open_mutex); +static DEFINE_MUTEX(acm_table_lock); -#define ACM_READY(acm)	(acm && acm->dev && acm->port.count) +/* + * acm_table accessors + */ -static const struct tty_port_operations acm_port_ops = { -}; +/* + * Look up an ACM structure by index. If found and not disconnected, increment + * its refcount and return it with its mutex held. + */ +static struct acm *acm_get_by_index(unsigned index) +{ +	struct acm *acm; + +	mutex_lock(&acm_table_lock); +	acm = acm_table[index]; +	if (acm) { +		mutex_lock(&acm->mutex); +		if (acm->disconnected) { +			mutex_unlock(&acm->mutex); +			acm = NULL; +		} else { +			tty_port_get(&acm->port); +			mutex_unlock(&acm->mutex); +		} +	} +	mutex_unlock(&acm_table_lock); +	return acm; +} + +/* + * Try to find an available minor number and if found, associate it with 'acm'. + */ +static int acm_alloc_minor(struct acm *acm) +{ +	int minor; + +	mutex_lock(&acm_table_lock); +	for (minor = 0; minor < ACM_TTY_MINORS; minor++) { +		if (!acm_table[minor]) { +			acm_table[minor] = acm; +			break; +		} +	} +	mutex_unlock(&acm_table_lock); + +	return minor; +} + +/* Release the minor number associated with 'acm'.  */ +static void acm_release_minor(struct acm *acm) +{ +	mutex_lock(&acm_table_lock); +	acm_table[acm->minor] = NULL; +	mutex_unlock(&acm_table_lock); +}  /*   * Functions for ACM control messages. @@ -267,9 +317,6 @@ static void acm_ctrl_irq(struct urb *urb)  		goto exit;  	} -	if (!ACM_READY(acm)) -		goto exit; -  	usb_mark_last_busy(acm->dev);  	data = (unsigned char *)(dr + 1); @@ -429,8 +476,7 @@ static void acm_write_bulk(struct urb *urb)  	spin_lock_irqsave(&acm->write_lock, flags);  	acm_write_done(acm, wb);  	spin_unlock_irqrestore(&acm->write_lock, flags); -	if (ACM_READY(acm)) -		schedule_work(&acm->work); +	schedule_work(&acm->work);  }  static void acm_softint(struct work_struct *work) @@ -440,8 +486,6 @@ static void acm_softint(struct work_struct *work)  	dev_vdbg(&acm->data->dev, "%s\n", __func__); -	if (!ACM_READY(acm)) -		return;  	tty = tty_port_tty_get(&acm->port);  	if (!tty)  		return; @@ -453,93 +497,122 @@ static void acm_softint(struct work_struct *work)   * TTY handlers   */ -static int acm_tty_open(struct tty_struct *tty, struct file *filp) +static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)  {  	struct acm *acm; -	int rv = -ENODEV; - -	mutex_lock(&open_mutex); +	int retval; -	acm = acm_table[tty->index]; -	if (!acm || !acm->dev) -		goto out; -	else -		rv = 0; +	dev_dbg(tty->dev, "%s\n", __func__); -	dev_dbg(&acm->control->dev, "%s\n", __func__); +	acm = acm_get_by_index(tty->index); +	if (!acm) +		return -ENODEV; -	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); +	retval = tty_init_termios(tty); +	if (retval) +		goto error_init_termios;  	tty->driver_data = acm; -	tty_port_tty_set(&acm->port, tty); -	if (usb_autopm_get_interface(acm->control) < 0) -		goto early_bail; -	else -		acm->control->needs_remote_wakeup = 1; +	/* Final install (we use the default method) */ +	tty_driver_kref_get(driver); +	tty->count++; +	driver->ttys[tty->index] = tty; + +	return 0; + +error_init_termios: +	tty_port_put(&acm->port); +	return retval; +} + +static int acm_tty_open(struct tty_struct *tty, struct file *filp) +{ +	struct acm *acm = tty->driver_data; + +	dev_dbg(tty->dev, "%s\n", __func__); + +	return tty_port_open(&acm->port, tty, filp); +} + +static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) +{ +	struct acm *acm = container_of(port, struct acm, port); +	int retval = -ENODEV; + +	dev_dbg(&acm->control->dev, "%s\n", __func__);  	mutex_lock(&acm->mutex); -	if (acm->port.count++) { -		mutex_unlock(&acm->mutex); -		usb_autopm_put_interface(acm->control); -		goto out; -	} +	if (acm->disconnected) +		goto disconnected; + +	retval = usb_autopm_get_interface(acm->control); +	if (retval) +		goto error_get_interface; + +	/* +	 * FIXME: Why do we need this? Allocating 64K of physically contiguous +	 * memory is really nasty... +	 */ +	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); +	acm->control->needs_remote_wakeup = 1;  	acm->ctrlurb->dev = acm->dev;  	if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {  		dev_err(&acm->control->dev,  			"%s - usb_submit_urb(ctrl irq) failed\n", __func__); -		goto bail_out; +		goto error_submit_urb;  	} -	if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && +	acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS; +	if (acm_set_control(acm, acm->ctrlout) < 0 &&  	    (acm->ctrl_caps & USB_CDC_CAP_LINE)) -		goto bail_out; +		goto error_set_control;  	usb_autopm_put_interface(acm->control);  	if (acm_submit_read_urbs(acm, GFP_KERNEL)) -		goto bail_out; - -	set_bit(ASYNCB_INITIALIZED, &acm->port.flags); -	rv = tty_port_block_til_ready(&acm->port, tty, filp); +		goto error_submit_read_urbs;  	mutex_unlock(&acm->mutex); -out: -	mutex_unlock(&open_mutex); -	return rv; -bail_out: -	acm->port.count--; -	mutex_unlock(&acm->mutex); +	return 0; + +error_submit_read_urbs: +	acm->ctrlout = 0; +	acm_set_control(acm, acm->ctrlout); +error_set_control: +	usb_kill_urb(acm->ctrlurb); +error_submit_urb:  	usb_autopm_put_interface(acm->control); -early_bail: -	mutex_unlock(&open_mutex); -	tty_port_tty_set(&acm->port, NULL); -	return -EIO; +error_get_interface: +disconnected: +	mutex_unlock(&acm->mutex); +	return retval;  } -static void acm_tty_unregister(struct acm *acm) +static void acm_port_destruct(struct tty_port *port)  { -	int i; +	struct acm *acm = container_of(port, struct acm, port); + +	dev_dbg(&acm->control->dev, "%s\n", __func__);  	tty_unregister_device(acm_tty_driver, acm->minor); +	acm_release_minor(acm);  	usb_put_intf(acm->control); -	acm_table[acm->minor] = NULL; -	usb_free_urb(acm->ctrlurb); -	for (i = 0; i < ACM_NW; i++) -		usb_free_urb(acm->wb[i].urb); -	for (i = 0; i < acm->rx_buflimit; i++) -		usb_free_urb(acm->read_urbs[i]);  	kfree(acm->country_codes);  	kfree(acm);  } -static void acm_port_down(struct acm *acm) +static void acm_port_shutdown(struct tty_port *port)  { +	struct acm *acm = container_of(port, struct acm, port);  	int i; -	if (acm->dev) { +	dev_dbg(&acm->control->dev, "%s\n", __func__); + +	mutex_lock(&acm->mutex); +	if (!acm->disconnected) {  		usb_autopm_get_interface(acm->control);  		acm_set_control(acm, acm->ctrlout = 0);  		usb_kill_urb(acm->ctrlurb); @@ -550,40 +623,28 @@ static void acm_port_down(struct acm *acm)  		acm->control->needs_remote_wakeup = 0;  		usb_autopm_put_interface(acm->control);  	} +	mutex_unlock(&acm->mutex); +} + +static void acm_tty_cleanup(struct tty_struct *tty) +{ +	struct acm *acm = tty->driver_data; +	dev_dbg(&acm->control->dev, "%s\n", __func__); +	tty_port_put(&acm->port);  }  static void acm_tty_hangup(struct tty_struct *tty)  {  	struct acm *acm = tty->driver_data; +	dev_dbg(&acm->control->dev, "%s\n", __func__);  	tty_port_hangup(&acm->port); -	mutex_lock(&open_mutex); -	acm_port_down(acm); -	mutex_unlock(&open_mutex);  }  static void acm_tty_close(struct tty_struct *tty, struct file *filp)  {  	struct acm *acm = tty->driver_data; - -	/* Perform the closing process and see if we need to do the hardware -	   shutdown */ -	if (!acm) -		return; - -	mutex_lock(&open_mutex); -	if (tty_port_close_start(&acm->port, tty, filp) == 0) { -		if (!acm->dev) { -			tty_port_tty_set(&acm->port, NULL); -			acm_tty_unregister(acm); -			tty->driver_data = NULL; -		} -		mutex_unlock(&open_mutex); -		return; -	} -	acm_port_down(acm); -	tty_port_close_end(&acm->port, tty); -	tty_port_tty_set(&acm->port, NULL); -	mutex_unlock(&open_mutex); +	dev_dbg(&acm->control->dev, "%s\n", __func__); +	tty_port_close(&acm->port, tty, filp);  }  static int acm_tty_write(struct tty_struct *tty, @@ -595,8 +656,6 @@ static int acm_tty_write(struct tty_struct *tty,  	int wbn;  	struct acm_wb *wb; -	if (!ACM_READY(acm)) -		return -EINVAL;  	if (!count)  		return 0; @@ -625,8 +684,6 @@ static int acm_tty_write(struct tty_struct *tty,  static int acm_tty_write_room(struct tty_struct *tty)  {  	struct acm *acm = tty->driver_data; -	if (!ACM_READY(acm)) -		return -EINVAL;  	/*  	 * Do not let the line discipline to know that we have a reserve,  	 * or it might get too enthusiastic. @@ -637,7 +694,11 @@ static int acm_tty_write_room(struct tty_struct *tty)  static int acm_tty_chars_in_buffer(struct tty_struct *tty)  {  	struct acm *acm = tty->driver_data; -	if (!ACM_READY(acm)) +	/* +	 * if the device was unplugged then any remaining characters fell out +	 * of the connector ;) +	 */ +	if (acm->disconnected)  		return 0;  	/*  	 * This is inaccurate (overcounts), but it works. @@ -649,9 +710,6 @@ static void acm_tty_throttle(struct tty_struct *tty)  {  	struct acm *acm = tty->driver_data; -	if (!ACM_READY(acm)) -		return; -  	spin_lock_irq(&acm->read_lock);  	acm->throttle_req = 1;  	spin_unlock_irq(&acm->read_lock); @@ -662,9 +720,6 @@ static void acm_tty_unthrottle(struct tty_struct *tty)  	struct acm *acm = tty->driver_data;  	unsigned int was_throttled; -	if (!ACM_READY(acm)) -		return; -  	spin_lock_irq(&acm->read_lock);  	was_throttled = acm->throttled;  	acm->throttled = 0; @@ -679,8 +734,7 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state)  {  	struct acm *acm = tty->driver_data;  	int retval; -	if (!ACM_READY(acm)) -		return -EINVAL; +  	retval = acm_send_break(acm, state ? 0xffff : 0);  	if (retval < 0)  		dev_dbg(&acm->control->dev, "%s - send break failed\n", @@ -692,9 +746,6 @@ static int acm_tty_tiocmget(struct tty_struct *tty)  {  	struct acm *acm = tty->driver_data; -	if (!ACM_READY(acm)) -		return -EINVAL; -  	return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |  	       (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |  	       (acm->ctrlin  & ACM_CTRL_DSR ? TIOCM_DSR : 0) | @@ -709,9 +760,6 @@ static int acm_tty_tiocmset(struct tty_struct *tty,  	struct acm *acm = tty->driver_data;  	unsigned int newctrl; -	if (!ACM_READY(acm)) -		return -EINVAL; -  	newctrl = acm->ctrlout;  	set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |  					(set & TIOCM_RTS ? ACM_CTRL_RTS : 0); @@ -728,11 +776,6 @@ static int acm_tty_tiocmset(struct tty_struct *tty,  static int acm_tty_ioctl(struct tty_struct *tty,  					unsigned int cmd, unsigned long arg)  { -	struct acm *acm = tty->driver_data; - -	if (!ACM_READY(acm)) -		return -EINVAL; -  	return -ENOIOCTLCMD;  } @@ -756,9 +799,6 @@ static void acm_tty_set_termios(struct tty_struct *tty,  	struct usb_cdc_line_coding newline;  	int newctrl = acm->ctrlout; -	if (!ACM_READY(acm)) -		return; -  	newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));  	newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;  	newline.bParityType = termios->c_cflag & PARENB ? @@ -788,6 +828,12 @@ static void acm_tty_set_termios(struct tty_struct *tty,  	}  } +static const struct tty_port_operations acm_port_ops = { +	.shutdown = acm_port_shutdown, +	.activate = acm_port_activate, +	.destruct = acm_port_destruct, +}; +  /*   * USB probe and disconnect routines.   */ @@ -1047,12 +1093,6 @@ skip_normal_probe:  	}  made_compressed_probe:  	dev_dbg(&intf->dev, "interfaces are valid\n"); -	for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); - -	if (minor == ACM_TTY_MINORS) { -		dev_err(&intf->dev, "no more free acm devices\n"); -		return -ENODEV; -	}  	acm = kzalloc(sizeof(struct acm), GFP_KERNEL);  	if (acm == NULL) { @@ -1060,6 +1100,13 @@ made_compressed_probe:  		goto alloc_fail;  	} +	minor = acm_alloc_minor(acm); +	if (minor == ACM_TTY_MINORS) { +		dev_err(&intf->dev, "no more free acm devices\n"); +		kfree(acm); +		return -ENODEV; +	} +  	ctrlsize = usb_endpoint_maxp(epctrl);  	readsize = usb_endpoint_maxp(epread) *  				(quirks == SINGLE_RX_URB ? 1 : 2); @@ -1183,6 +1230,8 @@ made_compressed_probe:  		i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);  		if (i < 0) {  			kfree(acm->country_codes); +			acm->country_codes = NULL; +			acm->country_code_size = 0;  			goto skip_countries;  		} @@ -1191,6 +1240,8 @@ made_compressed_probe:  		if (i < 0) {  			device_remove_file(&intf->dev, &dev_attr_wCountryCodes);  			kfree(acm->country_codes); +			acm->country_codes = NULL; +			acm->country_code_size = 0;  			goto skip_countries;  		}  	} @@ -1218,8 +1269,6 @@ skip_countries:  	usb_get_intf(control_interface);  	tty_register_device(acm_tty_driver, minor, &control_interface->dev); -	acm_table[minor] = acm; -  	return 0;  alloc_fail7:  	for (i = 0; i < ACM_NW; i++) @@ -1234,6 +1283,7 @@ alloc_fail5:  alloc_fail4:  	usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);  alloc_fail2: +	acm_release_minor(acm);  	kfree(acm);  alloc_fail:  	return -ENOMEM; @@ -1259,12 +1309,16 @@ static void acm_disconnect(struct usb_interface *intf)  	struct acm *acm = usb_get_intfdata(intf);  	struct usb_device *usb_dev = interface_to_usbdev(intf);  	struct tty_struct *tty; +	int i; + +	dev_dbg(&intf->dev, "%s\n", __func__);  	/* sibling interface is already cleaning up */  	if (!acm)  		return; -	mutex_lock(&open_mutex); +	mutex_lock(&acm->mutex); +	acm->disconnected = true;  	if (acm->country_codes) {  		device_remove_file(&acm->control->dev,  				&dev_attr_wCountryCodes); @@ -1272,33 +1326,32 @@ static void acm_disconnect(struct usb_interface *intf)  				&dev_attr_iCountryCodeRelDate);  	}  	device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); -	acm->dev = NULL;  	usb_set_intfdata(acm->control, NULL);  	usb_set_intfdata(acm->data, NULL); +	mutex_unlock(&acm->mutex); + +	tty = tty_port_tty_get(&acm->port); +	if (tty) { +		tty_vhangup(tty); +		tty_kref_put(tty); +	}  	stop_data_traffic(acm); +	usb_free_urb(acm->ctrlurb); +	for (i = 0; i < ACM_NW; i++) +		usb_free_urb(acm->wb[i].urb); +	for (i = 0; i < acm->rx_buflimit; i++) +		usb_free_urb(acm->read_urbs[i]);  	acm_write_buffers_free(acm); -	usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, -			  acm->ctrl_dma); +	usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);  	acm_read_buffers_free(acm);  	if (!acm->combined_interfaces)  		usb_driver_release_interface(&acm_driver, intf == acm->control ?  					acm->data : acm->control); -	if (acm->port.count == 0) { -		acm_tty_unregister(acm); -		mutex_unlock(&open_mutex); -		return; -	} - -	mutex_unlock(&open_mutex); -	tty = tty_port_tty_get(&acm->port); -	if (tty) { -		tty_hangup(tty); -		tty_kref_put(tty); -	} +	tty_port_put(&acm->port);  }  #ifdef CONFIG_PM @@ -1325,16 +1378,10 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)  	if (cnt)  		return 0; -	/* -	we treat opened interfaces differently, -	we must guard against open -	*/ -	mutex_lock(&acm->mutex); -	if (acm->port.count) +	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))  		stop_data_traffic(acm); -	mutex_unlock(&acm->mutex);  	return 0;  } @@ -1353,8 +1400,7 @@ static int acm_resume(struct usb_interface *intf)  	if (cnt)  		return 0; -	mutex_lock(&acm->mutex); -	if (acm->port.count) { +	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {  		rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);  		spin_lock_irq(&acm->write_lock); @@ -1378,7 +1424,6 @@ static int acm_resume(struct usb_interface *intf)  	}  err_out: -	mutex_unlock(&acm->mutex);  	return rv;  } @@ -1387,15 +1432,14 @@ static int acm_reset_resume(struct usb_interface *intf)  	struct acm *acm = usb_get_intfdata(intf);  	struct tty_struct *tty; -	mutex_lock(&acm->mutex); -	if (acm->port.count) { +	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {  		tty = tty_port_tty_get(&acm->port);  		if (tty) {  			tty_hangup(tty);  			tty_kref_put(tty);  		}  	} -	mutex_unlock(&acm->mutex); +  	return acm_resume(intf);  } @@ -1604,8 +1648,10 @@ static struct usb_driver acm_driver = {   */  static const struct tty_operations acm_ops = { +	.install =		acm_tty_install,  	.open =			acm_tty_open,  	.close =		acm_tty_close, +	.cleanup =		acm_tty_cleanup,  	.hangup =		acm_tty_hangup,  	.write =		acm_tty_write,  	.write_room =		acm_tty_write_room, diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index ca7937f26e2..35ef887b741 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -101,6 +101,7 @@ struct acm {  	int transmitting;  	spinlock_t write_lock;  	struct mutex mutex; +	bool disconnected;  	struct usb_cdc_line_coding line;		/* bits, stop, parity */  	struct work_struct work;			/* work queue entry for line discipline waking up */  	unsigned int ctrlin;				/* input control lines (DCD, DSR, RI, break, overruns) */ diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e3beaf229ee..3af5e2dd1d8 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -86,6 +86,7 @@ struct async {  	void __user *userbuffer;  	void __user *userurb;  	struct urb *urb; +	unsigned int mem_usage;  	int status;  	u32 secid;  	u8 bulk_addr; @@ -108,8 +109,44 @@ enum snoop_when {  #define USB_DEVICE_DEV		MKDEV(USB_DEVICE_MAJOR, 0) -#define	MAX_USBFS_BUFFER_SIZE	16384 +/* Limit on the total amount of memory we can allocate for transfers */ +static unsigned usbfs_memory_mb = 16; +module_param(usbfs_memory_mb, uint, 0644); +MODULE_PARM_DESC(usbfs_memory_mb, +		"maximum MB allowed for usbfs buffers (0 = no limit)"); +/* Hard limit, necessary to avoid aithmetic overflow */ +#define USBFS_XFER_MAX		(UINT_MAX / 2 - 1000000) + +static atomic_t usbfs_memory_usage;	/* Total memory currently allocated */ + +/* Check whether it's okay to allocate more memory for a transfer */ +static int usbfs_increase_memory_usage(unsigned amount) +{ +	unsigned lim; + +	/* +	 * Convert usbfs_memory_mb to bytes, avoiding overflows. +	 * 0 means use the hard limit (effectively unlimited). +	 */ +	lim = ACCESS_ONCE(usbfs_memory_mb); +	if (lim == 0 || lim > (USBFS_XFER_MAX >> 20)) +		lim = USBFS_XFER_MAX; +	else +		lim <<= 20; + +	atomic_add(amount, &usbfs_memory_usage); +	if (atomic_read(&usbfs_memory_usage) <= lim) +		return 0; +	atomic_sub(amount, &usbfs_memory_usage); +	return -ENOMEM; +} + +/* Memory for a transfer is being deallocated */ +static void usbfs_decrease_memory_usage(unsigned amount) +{ +	atomic_sub(amount, &usbfs_memory_usage); +}  static int connected(struct dev_state *ps)  { @@ -249,10 +286,12 @@ static struct async *alloc_async(unsigned int numisoframes)  static void free_async(struct async *as)  {  	put_pid(as->pid); -	put_cred(as->cred); +	if (as->cred) +		put_cred(as->cred);  	kfree(as->urb->transfer_buffer);  	kfree(as->urb->setup_packet);  	usb_free_urb(as->urb); +	usbfs_decrease_memory_usage(as->mem_usage);  	kfree(as);  } @@ -792,9 +831,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)  	wLength = ctrl.wLength;		/* To suppress 64k PAGE_SIZE warning */  	if (wLength > PAGE_SIZE)  		return -EINVAL; +	ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) + +			sizeof(struct usb_ctrlrequest)); +	if (ret) +		return ret;  	tbuf = (unsigned char *)__get_free_page(GFP_KERNEL); -	if (!tbuf) -		return -ENOMEM; +	if (!tbuf) { +		ret = -ENOMEM; +		goto done; +	}  	tmo = ctrl.timeout;  	snoop(&dev->dev, "control urb: bRequestType=%02x "  		"bRequest=%02x wValue=%04x " @@ -806,8 +851,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)  	if (ctrl.bRequestType & 0x80) {  		if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,  					       ctrl.wLength)) { -			free_page((unsigned long)tbuf); -			return -EINVAL; +			ret = -EINVAL; +			goto done;  		}  		pipe = usb_rcvctrlpipe(dev, 0);  		snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0); @@ -821,15 +866,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)  			  tbuf, max(i, 0));  		if ((i > 0) && ctrl.wLength) {  			if (copy_to_user(ctrl.data, tbuf, i)) { -				free_page((unsigned long)tbuf); -				return -EFAULT; +				ret = -EFAULT; +				goto done;  			}  		}  	} else {  		if (ctrl.wLength) {  			if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { -				free_page((unsigned long)tbuf); -				return -EFAULT; +				ret = -EFAULT; +				goto done;  			}  		}  		pipe = usb_sndctrlpipe(dev, 0); @@ -843,14 +888,18 @@ static int proc_control(struct dev_state *ps, void __user *arg)  		usb_lock_device(dev);  		snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);  	} -	free_page((unsigned long)tbuf);  	if (i < 0 && i != -EPIPE) {  		dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "  			   "failed cmd %s rqt %u rq %u len %u ret %d\n",  			   current->comm, ctrl.bRequestType, ctrl.bRequest,  			   ctrl.wLength, i);  	} -	return i; +	ret = i; + done: +	free_page((unsigned long) tbuf); +	usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) + +			sizeof(struct usb_ctrlrequest)); +	return ret;  }  static int proc_bulk(struct dev_state *ps, void __user *arg) @@ -877,15 +926,20 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)  	if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))  		return -EINVAL;  	len1 = bulk.len; -	if (len1 > MAX_USBFS_BUFFER_SIZE) +	if (len1 >= USBFS_XFER_MAX)  		return -EINVAL; -	if (!(tbuf = kmalloc(len1, GFP_KERNEL))) -		return -ENOMEM; +	ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); +	if (ret) +		return ret; +	if (!(tbuf = kmalloc(len1, GFP_KERNEL))) { +		ret = -ENOMEM; +		goto done; +	}  	tmo = bulk.timeout;  	if (bulk.ep & 0x80) {  		if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { -			kfree(tbuf); -			return -EINVAL; +			ret = -EINVAL; +			goto done;  		}  		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0); @@ -896,15 +950,15 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)  		if (!i && len2) {  			if (copy_to_user(bulk.data, tbuf, len2)) { -				kfree(tbuf); -				return -EFAULT; +				ret = -EFAULT; +				goto done;  			}  		}  	} else {  		if (len1) {  			if (copy_from_user(tbuf, bulk.data, len1)) { -				kfree(tbuf); -				return -EFAULT; +				ret = -EFAULT; +				goto done;  			}  		}  		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1); @@ -914,10 +968,11 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)  		usb_lock_device(dev);  		snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);  	} +	ret = (i < 0 ? i : len2); + done:  	kfree(tbuf); -	if (i < 0) -		return i; -	return len2; +	usbfs_decrease_memory_usage(len1 + sizeof(struct urb)); +	return ret;  }  static int proc_resetep(struct dev_state *ps, void __user *arg) @@ -1062,7 +1117,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  {  	struct usbdevfs_iso_packet_desc *isopkt = NULL;  	struct usb_host_endpoint *ep; -	struct async *as; +	struct async *as = NULL;  	struct usb_ctrlrequest *dr = NULL;  	unsigned int u, totlen, isofrmlen;  	int ret, ifnum = -1; @@ -1095,32 +1150,30 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	}  	if (!ep)  		return -ENOENT; + +	u = 0;  	switch(uurb->type) {  	case USBDEVFS_URB_TYPE_CONTROL:  		if (!usb_endpoint_xfer_control(&ep->desc))  			return -EINVAL; -		/* min 8 byte setup packet, -		 * max 8 byte setup plus an arbitrary data stage */ -		if (uurb->buffer_length < 8 || -		    uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) +		/* min 8 byte setup packet */ +		if (uurb->buffer_length < 8)  			return -EINVAL;  		dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);  		if (!dr)  			return -ENOMEM;  		if (copy_from_user(dr, uurb->buffer, 8)) { -			kfree(dr); -			return -EFAULT; +			ret = -EFAULT; +			goto error;  		}  		if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { -			kfree(dr); -			return -EINVAL; +			ret = -EINVAL; +			goto error;  		}  		ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,  				      le16_to_cpup(&dr->wIndex)); -		if (ret) { -			kfree(dr); -			return ret; -		} +		if (ret) +			goto error;  		uurb->number_of_packets = 0;  		uurb->buffer_length = le16_to_cpup(&dr->wLength);  		uurb->buffer += 8; @@ -1138,6 +1191,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  			__le16_to_cpup(&dr->wValue),  			__le16_to_cpup(&dr->wIndex),  			__le16_to_cpup(&dr->wLength)); +		u = sizeof(struct usb_ctrlrequest);  		break;  	case USBDEVFS_URB_TYPE_BULK: @@ -1151,8 +1205,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  			goto interrupt_urb;  		}  		uurb->number_of_packets = 0; -		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) -			return -EINVAL;  		break;  	case USBDEVFS_URB_TYPE_INTERRUPT: @@ -1160,8 +1212,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  			return -EINVAL;   interrupt_urb:  		uurb->number_of_packets = 0; -		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) -			return -EINVAL;  		break;  	case USBDEVFS_URB_TYPE_ISO: @@ -1176,50 +1226,53 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))  			return -ENOMEM;  		if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { -			kfree(isopkt); -			return -EFAULT; +			ret = -EFAULT; +			goto error;  		}  		for (totlen = u = 0; u < uurb->number_of_packets; u++) {  			/* arbitrary limit,  			 * sufficient for USB 2.0 high-bandwidth iso */  			if (isopkt[u].length > 8192) { -				kfree(isopkt); -				return -EINVAL; +				ret = -EINVAL; +				goto error;  			}  			totlen += isopkt[u].length;  		} -		/* 3072 * 64 microframes */ -		if (totlen > 196608) { -			kfree(isopkt); -			return -EINVAL; -		} +		u *= sizeof(struct usb_iso_packet_descriptor);  		uurb->buffer_length = totlen;  		break;  	default:  		return -EINVAL;  	} + +	if (uurb->buffer_length >= USBFS_XFER_MAX) { +		ret = -EINVAL; +		goto error; +	}  	if (uurb->buffer_length > 0 &&  			!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,  				uurb->buffer, uurb->buffer_length)) { -		kfree(isopkt); -		kfree(dr); -		return -EFAULT; +		ret = -EFAULT; +		goto error;  	}  	as = alloc_async(uurb->number_of_packets);  	if (!as) { -		kfree(isopkt); -		kfree(dr); -		return -ENOMEM; +		ret = -ENOMEM; +		goto error;  	} +	u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length; +	ret = usbfs_increase_memory_usage(u); +	if (ret) +		goto error; +	as->mem_usage = u; +  	if (uurb->buffer_length > 0) {  		as->urb->transfer_buffer = kmalloc(uurb->buffer_length,  				GFP_KERNEL);  		if (!as->urb->transfer_buffer) { -			kfree(isopkt); -			kfree(dr); -			free_async(as); -			return -ENOMEM; +			ret = -ENOMEM; +			goto error;  		}  		/* Isochronous input data may end up being discontiguous  		 * if some of the packets are short.  Clear the buffer so @@ -1253,6 +1306,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	as->urb->transfer_buffer_length = uurb->buffer_length;  	as->urb->setup_packet = (unsigned char *)dr; +	dr = NULL;  	as->urb->start_frame = uurb->start_frame;  	as->urb->number_of_packets = uurb->number_of_packets;  	if (uurb->type == USBDEVFS_URB_TYPE_ISO || @@ -1268,6 +1322,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  		totlen += isopkt[u].length;  	}  	kfree(isopkt); +	isopkt = NULL;  	as->ps = ps;  	as->userurb = arg;  	if (is_in && uurb->buffer_length > 0) @@ -1282,8 +1337,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	if (!is_in && uurb->buffer_length > 0) {  		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,  				uurb->buffer_length)) { -			free_async(as); -			return -EFAULT; +			ret = -EFAULT; +			goto error;  		}  	}  	snoop_urb(ps->dev, as->userurb, as->urb->pipe, @@ -1329,10 +1384,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  		snoop_urb(ps->dev, as->userurb, as->urb->pipe,  				0, ret, COMPLETE, NULL, 0);  		async_removepending(as); -		free_async(as); -		return ret; +		goto error;  	}  	return 0; + + error: +	kfree(isopkt); +	kfree(dr); +	if (as) +		free_async(as); +	return ret;  }  static int proc_submiturb(struct dev_state *ps, void __user *arg) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 45887a0ff87..d40ff956881 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -45,10 +45,12 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,  	struct usb_dynid *dynid;  	u32 idVendor = 0;  	u32 idProduct = 0; +	unsigned int bInterfaceClass = 0;  	int fields = 0;  	int retval = 0; -	fields = sscanf(buf, "%x %x", &idVendor, &idProduct); +	fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct, +					&bInterfaceClass);  	if (fields < 2)  		return -EINVAL; @@ -60,6 +62,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,  	dynid->id.idVendor = idVendor;  	dynid->id.idProduct = idProduct;  	dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; +	if (fields == 3) { +		dynid->id.bInterfaceClass = (u8)bInterfaceClass; +		dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS; +	}  	spin_lock(&dynids->lock);  	list_add_tail(&dynid->node, &dynids->list); @@ -1073,17 +1079,10 @@ static int usb_suspend_interface(struct usb_device *udev,  		goto done;  	driver = to_usb_driver(intf->dev.driver); -	if (driver->suspend) { -		status = driver->suspend(intf, msg); -		if (status && !PMSG_IS_AUTO(msg)) -			dev_err(&intf->dev, "%s error %d\n", -					"suspend", status); -	} else { -		/* Later we will unbind the driver and reprobe */ -		intf->needs_binding = 1; -		dev_warn(&intf->dev, "no %s for driver %s?\n", -				"suspend", driver->name); -	} +	/* at this time we know the driver supports suspend */ +	status = driver->suspend(intf, msg); +	if (status && !PMSG_IS_AUTO(msg)) +		dev_err(&intf->dev, "suspend error %d\n", status);   done:  	dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status); @@ -1132,16 +1131,9 @@ static int usb_resume_interface(struct usb_device *udev,  					"reset_resume", driver->name);  		}  	} else { -		if (driver->resume) { -			status = driver->resume(intf); -			if (status) -				dev_err(&intf->dev, "%s error %d\n", -						"resume", status); -		} else { -			intf->needs_binding = 1; -			dev_warn(&intf->dev, "no %s for driver %s?\n", -					"resume", driver->name); -		} +		status = driver->resume(intf); +		if (status) +			dev_err(&intf->dev, "resume error %d\n", status);  	}  done: diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index a004db35f6d..d136b8f4c8a 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -453,10 +453,6 @@ static int resume_common(struct device *dev, int event)  	pci_set_master(pci_dev); -	clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); -	if (hcd->shared_hcd) -		clear_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); -  	if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {  		if (event != PM_EVENT_AUTO_RESUME)  			wait_for_companions(pci_dev, hcd); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 13222d352a6..eb19cba34ac 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -658,7 +658,7 @@ error:  				len > offsetof(struct usb_device_descriptor,  						bDeviceProtocol))  			((struct usb_device_descriptor *) ubuf)-> -					bDeviceProtocol = 1; +				bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT;  	}  	/* any errors get returned through the urb completion */ @@ -1168,20 +1168,6 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,  	if (urb->unlinked)  		return -EBUSY;  	urb->unlinked = status; - -	/* IRQ setup can easily be broken so that USB controllers -	 * never get completion IRQs ... maybe even the ones we need to -	 * finish unlinking the initial failed usb_set_address() -	 * or device descriptor fetch. -	 */ -	if (!HCD_SAW_IRQ(hcd) && !is_root_hub(urb->dev)) { -		dev_warn(hcd->self.controller, "Unlink after no-IRQ?  " -			"Controller is probably using the wrong IRQ.\n"); -		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); -		if (hcd->shared_hcd) -			set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); -	} -  	return 0;  }  EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb); @@ -1412,11 +1398,10 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,  					ret = -EAGAIN;  				else  					urb->transfer_flags |= URB_DMA_MAP_SG; -				if (n != urb->num_sgs) { -					urb->num_sgs = n; +				urb->num_mapped_sgs = n; +				if (n != urb->num_sgs)  					urb->transfer_flags |=  							URB_DMA_SG_COMBINED; -				}  			} else if (urb->sg) {  				struct scatterlist *sg = urb->sg;  				urb->transfer_dma = dma_map_page( @@ -2148,16 +2133,12 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)  	 */  	local_irq_save(flags); -	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) { +	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))  		rc = IRQ_NONE; -	} else if (hcd->driver->irq(hcd) == IRQ_NONE) { +	else if (hcd->driver->irq(hcd) == IRQ_NONE)  		rc = IRQ_NONE; -	} else { -		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); -		if (hcd->shared_hcd) -			set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); +	else  		rc = IRQ_HANDLED; -	}  	local_irq_restore(flags);  	return rc; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 79781461eec..79d339e2e70 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -84,7 +84,7 @@ struct usb_hub {  static inline int hub_is_superspeed(struct usb_device *hdev)  { -	return (hdev->descriptor.bDeviceProtocol == 3); +	return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);  }  /* Protect struct usb_device->state and ->children members @@ -1041,58 +1041,58 @@ static int hub_configure(struct usb_hub *hub,  		dev_dbg(hub_dev, "standalone hub\n");  	switch (wHubCharacteristics & HUB_CHAR_LPSM) { -		case 0x00: -			dev_dbg(hub_dev, "ganged power switching\n"); -			break; -		case 0x01: -			dev_dbg(hub_dev, "individual port power switching\n"); -			break; -		case 0x02: -		case 0x03: -			dev_dbg(hub_dev, "no power switching (usb 1.0)\n"); -			break; +	case HUB_CHAR_COMMON_LPSM: +		dev_dbg(hub_dev, "ganged power switching\n"); +		break; +	case HUB_CHAR_INDV_PORT_LPSM: +		dev_dbg(hub_dev, "individual port power switching\n"); +		break; +	case HUB_CHAR_NO_LPSM: +	case HUB_CHAR_LPSM: +		dev_dbg(hub_dev, "no power switching (usb 1.0)\n"); +		break;  	}  	switch (wHubCharacteristics & HUB_CHAR_OCPM) { -		case 0x00: -			dev_dbg(hub_dev, "global over-current protection\n"); -			break; -		case 0x08: -			dev_dbg(hub_dev, "individual port over-current protection\n"); -			break; -		case 0x10: -		case 0x18: -			dev_dbg(hub_dev, "no over-current protection\n"); -                        break; +	case HUB_CHAR_COMMON_OCPM: +		dev_dbg(hub_dev, "global over-current protection\n"); +		break; +	case HUB_CHAR_INDV_PORT_OCPM: +		dev_dbg(hub_dev, "individual port over-current protection\n"); +		break; +	case HUB_CHAR_NO_OCPM: +	case HUB_CHAR_OCPM: +		dev_dbg(hub_dev, "no over-current protection\n"); +		break;  	}  	spin_lock_init (&hub->tt.lock);  	INIT_LIST_HEAD (&hub->tt.clear_list);  	INIT_WORK(&hub->tt.clear_work, hub_tt_work);  	switch (hdev->descriptor.bDeviceProtocol) { -		case 0: -			break; -		case 1: -			dev_dbg(hub_dev, "Single TT\n"); -			hub->tt.hub = hdev; -			break; -		case 2: -			ret = usb_set_interface(hdev, 0, 1); -			if (ret == 0) { -				dev_dbg(hub_dev, "TT per port\n"); -				hub->tt.multi = 1; -			} else -				dev_err(hub_dev, "Using single TT (err %d)\n", -					ret); -			hub->tt.hub = hdev; -			break; -		case 3: -			/* USB 3.0 hubs don't have a TT */ -			break; -		default: -			dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", -				hdev->descriptor.bDeviceProtocol); -			break; +	case USB_HUB_PR_FS: +		break; +	case USB_HUB_PR_HS_SINGLE_TT: +		dev_dbg(hub_dev, "Single TT\n"); +		hub->tt.hub = hdev; +		break; +	case USB_HUB_PR_HS_MULTI_TT: +		ret = usb_set_interface(hdev, 0, 1); +		if (ret == 0) { +			dev_dbg(hub_dev, "TT per port\n"); +			hub->tt.multi = 1; +		} else +			dev_err(hub_dev, "Using single TT (err %d)\n", +				ret); +		hub->tt.hub = hdev; +		break; +	case USB_HUB_PR_SS: +		/* USB 3.0 hubs don't have a TT */ +		break; +	default: +		dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", +			hdev->descriptor.bDeviceProtocol); +		break;  	}  	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ @@ -1360,7 +1360,6 @@ descriptor_error:  	return -ENODEV;  } -/* No BKL needed */  static int  hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)  { diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index ecf12e15a7e..4c65eb6a867 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -117,9 +117,12 @@ static const struct usb_device_id usb_quirk_list[] = {  	{ USB_DEVICE(0x06a3, 0x0006), .driver_info =  			USB_QUIRK_CONFIG_INTF_STRINGS }, -	/* Guillemot Webcam Hercules Dualpix Exchange*/ +	/* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */  	{ USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME }, +	/* Guillemot Webcam Hercules Dualpix Exchange*/ +	{ USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME }, +  	/* M-Systems Flash Disk Pioneers */  	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 3888778582c..45e8479c377 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -132,20 +132,6 @@ static inline int is_usb_device_driver(struct device_driver *drv)  			for_devices;  } -/* translate USB error codes to codes user space understands */ -static inline int usb_translate_errors(int error_code) -{ -	switch (error_code) { -	case 0: -	case -ENOMEM: -	case -ENODEV: -		return error_code; -	default: -		return -EIO; -	} -} - -  /* for labeling diagnostics */  extern const char *usbcore_name; diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 3c1d67d324f..d8f741f9e56 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -1,7 +1,10 @@  config USB_DWC3  	tristate "DesignWare USB3 DRD Core Support" -	depends on (USB || USB_GADGET) +	depends on (USB && USB_GADGET)  	select USB_OTG_UTILS +	select USB_GADGET_DUALSPEED +	select USB_GADGET_SUPERSPEED +	select USB_XHCI_PLATFORM  	help  	  Say Y or M here if your system has a Dual Role SuperSpeed  	  USB controller based on the DesignWare USB3 IP Core. diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 593d1dbc465..900ae74357f 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -4,10 +4,8 @@ ccflags-$(CONFIG_USB_DWC3_VERBOSE)	+= -DVERBOSE_DEBUG  obj-$(CONFIG_USB_DWC3)			+= dwc3.o  dwc3-y					:= core.o - -ifneq ($(CONFIG_USB_GADGET_DWC3),) -	dwc3-y				+= gadget.o ep0.o -endif +dwc3-y					+= host.o +dwc3-y					+= gadget.o ep0.o  ifneq ($(CONFIG_DEBUG_FS),)  	dwc3-y				+= debugfs.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 600d8234851..7c9df630dbe 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -59,6 +59,60 @@  #include "debug.h" +static char *maximum_speed = "super"; +module_param(maximum_speed, charp, 0); +MODULE_PARM_DESC(maximum_speed, "Maximum supported speed."); + +/* -------------------------------------------------------------------------- */ + +#define DWC3_DEVS_POSSIBLE	32 + +static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE); + +int dwc3_get_device_id(void) +{ +	int		id; + +again: +	id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE); +	if (id < DWC3_DEVS_POSSIBLE) { +		int old; + +		old = test_and_set_bit(id, dwc3_devs); +		if (old) +			goto again; +	} else { +		pr_err("dwc3: no space for new device\n"); +		id = -ENOMEM; +	} + +	return 0; +} +EXPORT_SYMBOL_GPL(dwc3_get_device_id); + +void dwc3_put_device_id(int id) +{ +	int			ret; + +	if (id < 0) +		return; + +	ret = test_bit(id, dwc3_devs); +	WARN(!ret, "dwc3: ID %d not in use\n", id); +	clear_bit(id, dwc3_devs); +} +EXPORT_SYMBOL_GPL(dwc3_put_device_id); + +void dwc3_set_mode(struct dwc3 *dwc, u32 mode) +{ +	u32 reg; + +	reg = dwc3_readl(dwc->regs, DWC3_GCTL); +	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); +	reg |= DWC3_GCTL_PRTCAPDIR(mode); +	dwc3_writel(dwc->regs, DWC3_GCTL, reg); +} +  /**   * dwc3_core_soft_reset - Issues core soft reset and PHY reset   * @dwc: pointer to our context structure @@ -150,7 +204,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)  	struct dwc3_event_buffer	*evt;  	int i; -	for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) { +	for (i = 0; i < dwc->num_event_buffers; i++) {  		evt = dwc->ev_buffs[i];  		if (evt) {  			dwc3_free_one_event_buffer(dwc, evt); @@ -162,17 +216,25 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)  /**   * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length   * @dwc: Pointer to out controller context structure - * @num: number of event buffers to allocate   * @length: size of event buffer   *   * Returns 0 on success otherwise negative errno. In error the case, dwc   * may contain some buffers allocated but not all which were requested.   */ -static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num, -		unsigned length) +static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)  { +	int			num;  	int			i; +	num = DWC3_NUM_INT(dwc->hwparams.hwparams1); +	dwc->num_event_buffers = num; + +	dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL); +	if (!dwc->ev_buffs) { +		dev_err(dwc->dev, "can't allocate event buffers array\n"); +		return -ENOMEM; +	} +  	for (i = 0; i < num; i++) {  		struct dwc3_event_buffer	*evt; @@ -198,7 +260,7 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)  	struct dwc3_event_buffer	*evt;  	int				n; -	for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) { +	for (n = 0; n < dwc->num_event_buffers; n++) {  		evt = dwc->ev_buffs[n];  		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",  				evt->buf, (unsigned long long) evt->dma, @@ -221,7 +283,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)  	struct dwc3_event_buffer	*evt;  	int				n; -	for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) { +	for (n = 0; n < dwc->num_event_buffers; n++) {  		evt = dwc->ev_buffs[n];  		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);  		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); @@ -285,8 +347,32 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)  		cpu_relax();  	} while (true); -	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM, -			DWC3_EVENT_BUFFERS_SIZE); +	dwc3_cache_hwparams(dwc); + +	reg = dwc3_readl(dwc->regs, DWC3_GCTL); +	reg &= ~DWC3_GCTL_SCALEDOWN(3); +	reg &= ~DWC3_GCTL_DISSCRAMBLE; + +	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { +	case DWC3_GHWPARAMS1_EN_PWROPT_CLK: +		reg &= ~DWC3_GCTL_DSBLCLKGTNG; +		break; +	default: +		dev_dbg(dwc->dev, "No power optimization available\n"); +	} + +	/* +	 * WORKAROUND: DWC3 revisions <1.90a have a bug +	 * when The device fails to connect at SuperSpeed +	 * and falls back to high-speed mode which causes +	 * the device to enter in a Connect/Disconnect loop +	 */ +	if (dwc->revision < DWC3_REVISION_190A) +		reg |= DWC3_GCTL_U2RSTECN; + +	dwc3_writel(dwc->regs, DWC3_GCTL, reg); + +	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);  	if (ret) {  		dev_err(dwc->dev, "failed to allocate event buffers\n");  		ret = -ENOMEM; @@ -299,8 +385,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)  		goto err1;  	} -	dwc3_cache_hwparams(dwc); -  	return 0;  err1: @@ -320,15 +404,17 @@ static void dwc3_core_exit(struct dwc3 *dwc)  static int __devinit dwc3_probe(struct platform_device *pdev)  { -	const struct platform_device_id *id = platform_get_device_id(pdev);  	struct resource		*res;  	struct dwc3		*dwc; -	void __iomem		*regs; -	unsigned int		features = id->driver_data; +  	int			ret = -ENOMEM;  	int			irq; + +	void __iomem		*regs;  	void			*mem; +	u8			mode; +  	mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);  	if (!mem) {  		dev_err(&pdev->dev, "not enough memory\n"); @@ -343,6 +429,8 @@ static int __devinit dwc3_probe(struct platform_device *pdev)  		goto err1;  	} +	dwc->res = res; +  	res = request_mem_region(res->start, resource_size(res),  			dev_name(&pdev->dev));  	if (!res) { @@ -370,6 +458,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev)  	dwc->dev	= &pdev->dev;  	dwc->irq	= irq; +	if (!strncmp("super", maximum_speed, 5)) +		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; +	else if (!strncmp("high", maximum_speed, 4)) +		dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; +	else if (!strncmp("full", maximum_speed, 4)) +		dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; +	else if (!strncmp("low", maximum_speed, 3)) +		dwc->maximum_speed = DWC3_DCFG_LOWSPEED; +	else +		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; +  	pm_runtime_enable(&pdev->dev);  	pm_runtime_get_sync(&pdev->dev);  	pm_runtime_forbid(&pdev->dev); @@ -380,13 +479,44 @@ static int __devinit dwc3_probe(struct platform_device *pdev)  		goto err3;  	} -	if (features & DWC3_HAS_PERIPHERAL) { +	mode = DWC3_MODE(dwc->hwparams.hwparams0); + +	switch (mode) { +	case DWC3_MODE_DEVICE: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); +		ret = dwc3_gadget_init(dwc); +		if (ret) { +			dev_err(&pdev->dev, "failed to initialize gadget\n"); +			goto err4; +		} +		break; +	case DWC3_MODE_HOST: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); +		ret = dwc3_host_init(dwc); +		if (ret) { +			dev_err(&pdev->dev, "failed to initialize host\n"); +			goto err4; +		} +		break; +	case DWC3_MODE_DRD: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); +		ret = dwc3_host_init(dwc); +		if (ret) { +			dev_err(&pdev->dev, "failed to initialize host\n"); +			goto err4; +		} +  		ret = dwc3_gadget_init(dwc);  		if (ret) { -			dev_err(&pdev->dev, "failed to initialized gadget\n"); +			dev_err(&pdev->dev, "failed to initialize gadget\n");  			goto err4;  		} +		break; +	default: +		dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode); +		goto err4;  	} +	dwc->mode = mode;  	ret = dwc3_debugfs_init(dwc);  	if (ret) { @@ -399,8 +529,21 @@ static int __devinit dwc3_probe(struct platform_device *pdev)  	return 0;  err5: -	if (features & DWC3_HAS_PERIPHERAL) +	switch (mode) { +	case DWC3_MODE_DEVICE:  		dwc3_gadget_exit(dwc); +		break; +	case DWC3_MODE_HOST: +		dwc3_host_exit(dwc); +		break; +	case DWC3_MODE_DRD: +		dwc3_host_exit(dwc); +		dwc3_gadget_exit(dwc); +		break; +	default: +		/* do nothing */ +		break; +	}  err4:  	dwc3_core_exit(dwc); @@ -420,10 +563,8 @@ err0:  static int __devexit dwc3_remove(struct platform_device *pdev)  { -	const struct platform_device_id *id = platform_get_device_id(pdev);  	struct dwc3	*dwc = platform_get_drvdata(pdev);  	struct resource	*res; -	unsigned int	features = id->driver_data;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -432,8 +573,21 @@ static int __devexit dwc3_remove(struct platform_device *pdev)  	dwc3_debugfs_exit(dwc); -	if (features & DWC3_HAS_PERIPHERAL) +	switch (dwc->mode) { +	case DWC3_MODE_DEVICE:  		dwc3_gadget_exit(dwc); +		break; +	case DWC3_MODE_HOST: +		dwc3_host_exit(dwc); +		break; +	case DWC3_MODE_DRD: +		dwc3_host_exit(dwc); +		dwc3_gadget_exit(dwc); +		break; +	default: +		/* do nothing */ +		break; +	}  	dwc3_core_exit(dwc);  	release_mem_region(res->start, resource_size(res)); @@ -443,30 +597,15 @@ static int __devexit dwc3_remove(struct platform_device *pdev)  	return 0;  } -static const struct platform_device_id dwc3_id_table[] __devinitconst = { -	{ -		.name	= "dwc3-omap", -		.driver_data = (DWC3_HAS_PERIPHERAL -			| DWC3_HAS_XHCI -			| DWC3_HAS_OTG), -	}, -	{ -		.name	= "dwc3-pci", -		.driver_data = DWC3_HAS_PERIPHERAL, -	}, -	{  },	/* Terminating Entry */ -}; -MODULE_DEVICE_TABLE(platform, dwc3_id_table); -  static struct platform_driver dwc3_driver = {  	.probe		= dwc3_probe,  	.remove		= __devexit_p(dwc3_remove),  	.driver		= {  		.name	= "dwc3",  	}, -	.id_table	= dwc3_id_table,  }; +MODULE_ALIAS("platform:dwc3");  MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");  MODULE_LICENSE("Dual BSD/GPL");  MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 29a8e1679e1..9e57f8e9bf1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -41,6 +41,7 @@  #include <linux/device.h>  #include <linux/spinlock.h> +#include <linux/ioport.h>  #include <linux/list.h>  #include <linux/dma-mapping.h>  #include <linux/mm.h> @@ -52,7 +53,6 @@  /* Global constants */  #define DWC3_ENDPOINTS_NUM	32 -#define DWC3_EVENT_BUFFERS_NUM	2  #define DWC3_EVENT_BUFFERS_SIZE	PAGE_SIZE  #define DWC3_EVENT_TYPE_MASK	0xfe @@ -153,6 +153,7 @@  #define DWC3_GCTL_CLK_PIPEHALF	(2)  #define DWC3_GCTL_CLK_MASK	(3) +#define DWC3_GCTL_PRTCAP(n)	(((n) & (3 << 12)) >> 12)  #define DWC3_GCTL_PRTCAPDIR(n)	(n << 12)  #define DWC3_GCTL_PRTCAP_HOST	1  #define DWC3_GCTL_PRTCAP_DEVICE	2 @@ -347,6 +348,7 @@ struct dwc3_ep {  	u32			free_slot;  	u32			busy_slot;  	const struct usb_endpoint_descriptor *desc; +	const struct usb_ss_ep_comp_descriptor *comp_desc;  	struct dwc3		*dwc;  	unsigned		flags; @@ -536,6 +538,31 @@ struct dwc3_hwparams {  	u32	hwparams8;  }; +/* HWPARAMS0 */ +#define DWC3_MODE(n)		((n) & 0x7) + +#define DWC3_MODE_DEVICE	0 +#define DWC3_MODE_HOST		1 +#define DWC3_MODE_DRD		2 +#define DWC3_MODE_HUB		3 + +/* HWPARAMS1 */ +#define DWC3_NUM_INT(n)	(((n) & (0x3f << 15)) >> 15) + +struct dwc3_request { +	struct usb_request	request; +	struct list_head	list; +	struct dwc3_ep		*dep; + +	u8			epnum; +	struct dwc3_trb_hw	*trb; +	dma_addr_t		trb_dma; + +	unsigned		direction:1; +	unsigned		mapped:1; +	unsigned		queued:1; +}; +  /**   * struct dwc3 - representation of our controller   * @ctrl_req: usb control request which is used for ep0 @@ -549,19 +576,24 @@ struct dwc3_hwparams {   * @ep0_bounce_addr: dma address of ep0_bounce   * @lock: for synchronizing   * @dev: pointer to our struct device + * @xhci: pointer to our xHCI child   * @event_buffer_list: a list of event buffers   * @gadget: device side representation of the peripheral controller   * @gadget_driver: pointer to the gadget driver   * @regs: base address for our registers   * @regs_size: address space size   * @irq: IRQ number + * @num_event_buffers: calculated number of event buffers + * @u1u2: only used on revisions <1.83a for workaround + * @maximum_speed: maximum speed requested (mainly for testing purposes)   * @revision: revision register contents + * @mode: mode of operation   * @is_selfpowered: true when we are selfpowered   * @three_stage_setup: set if we perform a three phase setup - * @ep0_status_pending: ep0 status response without a req is pending   * @ep0_bounced: true when we used bounce buffer   * @ep0_expect_in: true when we expect a DATA IN transfer   * @start_config_issued: true when StartConfig command has been issued + * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround   * @ep0_next_event: hold the next expected event   * @ep0state: state of endpoint zero   * @link_state: link state @@ -579,12 +611,15 @@ struct dwc3 {  	dma_addr_t		ep0_trb_addr;  	dma_addr_t		setup_buf_addr;  	dma_addr_t		ep0_bounce_addr; -	struct usb_request	ep0_usb_req; +	struct dwc3_request	ep0_usb_req;  	/* device lock */  	spinlock_t		lock;  	struct device		*dev; -	struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM]; +	struct platform_device	*xhci; +	struct resource		*res; + +	struct dwc3_event_buffer **ev_buffs;  	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];  	struct usb_gadget	gadget; @@ -595,7 +630,11 @@ struct dwc3 {  	int			irq; +	u32			num_event_buffers; +	u32			u1u2; +	u32			maximum_speed;  	u32			revision; +	u32			mode;  #define DWC3_REVISION_173A	0x5533173a  #define DWC3_REVISION_175A	0x5533175a @@ -607,10 +646,11 @@ struct dwc3 {  	unsigned		is_selfpowered:1;  	unsigned		three_stage_setup:1; -	unsigned		ep0_status_pending:1;  	unsigned		ep0_bounced:1;  	unsigned		ep0_expect_in:1;  	unsigned		start_config_issued:1; +	unsigned		setup_packet_pending:1; +	unsigned		delayed_status:1;  	enum dwc3_ep0_next	ep0_next_event;  	enum dwc3_ep0_state	ep0state; @@ -765,4 +805,16 @@ union dwc3_event {  #define DWC3_HAS_XHCI			BIT(1)  #define DWC3_HAS_OTG			BIT(3) +/* prototypes */ +void dwc3_set_mode(struct dwc3 *dwc, u32 mode); + +int dwc3_host_init(struct dwc3 *dwc); +void dwc3_host_exit(struct dwc3 *dwc); + +int dwc3_gadget_init(struct dwc3 *dwc); +void dwc3_gadget_exit(struct dwc3 *dwc); + +extern int dwc3_get_device_id(void); +extern void dwc3_put_device_id(int id); +  #endif /* __DRIVERS_USB_DWC3_CORE_H */ diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index fcfa91517ea..433c97c15fc 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -44,12 +44,12 @@  #include <linux/debugfs.h>  #include <linux/seq_file.h>  #include <linux/delay.h> - -#include <asm/uaccess.h> +#include <linux/uaccess.h>  #include "core.h"  #include "gadget.h"  #include "io.h" +#include "debug.h"  #define dump_register(nm)				\  {							\ @@ -395,6 +395,75 @@ static const struct file_operations dwc3_regdump_fops = {  	.release		= single_release,  }; +static int dwc3_mode_show(struct seq_file *s, void *unused) +{ +	struct dwc3		*dwc = s->private; +	unsigned long		flags; +	u32			reg; + +	spin_lock_irqsave(&dwc->lock, flags); +	reg = dwc3_readl(dwc->regs, DWC3_GCTL); +	spin_unlock_irqrestore(&dwc->lock, flags); + +	switch (DWC3_GCTL_PRTCAP(reg)) { +	case DWC3_GCTL_PRTCAP_HOST: +		seq_printf(s, "host\n"); +		break; +	case DWC3_GCTL_PRTCAP_DEVICE: +		seq_printf(s, "device\n"); +		break; +	case DWC3_GCTL_PRTCAP_OTG: +		seq_printf(s, "OTG\n"); +		break; +	default: +		seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg)); +	} + +	return 0; +} + +static int dwc3_mode_open(struct inode *inode, struct file *file) +{ +	return single_open(file, dwc3_mode_show, inode->i_private); +} + +static ssize_t dwc3_mode_write(struct file *file, +		const char __user *ubuf, size_t count, loff_t *ppos) +{ +	struct seq_file		*s = file->private_data; +	struct dwc3		*dwc = s->private; +	unsigned long		flags; +	u32			mode = 0; +	char			buf[32]; + +	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) +		return -EFAULT; + +	if (!strncmp(buf, "host", 4)) +		mode |= DWC3_GCTL_PRTCAP_HOST; + +	if (!strncmp(buf, "device", 6)) +		mode |= DWC3_GCTL_PRTCAP_DEVICE; + +	if (!strncmp(buf, "otg", 3)) +		mode |= DWC3_GCTL_PRTCAP_OTG; + +	if (mode) { +		spin_lock_irqsave(&dwc->lock, flags); +		dwc3_set_mode(dwc, mode); +		spin_unlock_irqrestore(&dwc->lock, flags); +	} +	return count; +} + +static const struct file_operations dwc3_mode_fops = { +	.open			= dwc3_mode_open, +	.write			= dwc3_mode_write, +	.read			= seq_read, +	.llseek			= seq_lseek, +	.release		= single_release, +}; +  int __devinit dwc3_debugfs_init(struct dwc3 *dwc)  {  	struct dentry		*root; @@ -402,7 +471,7 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)  	int			ret;  	root = debugfs_create_dir(dev_name(dwc->dev), NULL); -	if (IS_ERR(root)){ +	if (IS_ERR(root)) {  		ret = PTR_ERR(root);  		goto err0;  	} @@ -415,6 +484,14 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)  		ret = PTR_ERR(file);  		goto err1;  	} + +	file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, +			dwc, &dwc3_mode_fops); +	if (IS_ERR(file)) { +		ret = PTR_ERR(file); +		goto err1; +	} +  	return 0;  err1: diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 062552b5fc8..3274ac8f120 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -48,6 +48,7 @@  #include <linux/io.h>  #include <linux/module.h> +#include "core.h"  #include "io.h"  /* @@ -200,6 +201,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)  	struct dwc3_omap	*omap;  	struct resource		*res; +	int			devid;  	int			ret = -ENOMEM;  	int			irq; @@ -236,16 +238,20 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)  		goto err1;  	} -	dwc3 = platform_device_alloc("dwc3-omap", -1); +	devid = dwc3_get_device_id(); +	if (devid < 0) +		goto err2; + +	dwc3 = platform_device_alloc("dwc3", devid);  	if (!dwc3) {  		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); -		goto err2; +		goto err3;  	}  	context = kzalloc(resource_size(res), GFP_KERNEL);  	if (!context) {  		dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n"); -		goto err3; +		goto err4;  	}  	spin_lock_init(&omap->lock); @@ -299,7 +305,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)  	if (ret) {  		dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",  				omap->irq, ret); -		goto err4; +		goto err5;  	}  	/* enable all IRQs */ @@ -322,26 +328,29 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)  			pdev->num_resources);  	if (ret) {  		dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n"); -		goto err5; +		goto err6;  	}  	ret = platform_device_add(dwc3);  	if (ret) {  		dev_err(&pdev->dev, "failed to register dwc3 device\n"); -		goto err5; +		goto err6;  	}  	return 0; -err5: +err6:  	free_irq(omap->irq, omap); -err4: +err5:  	kfree(omap->context); -err3: +err4:  	platform_device_put(dwc3); +err3: +	dwc3_put_device_id(devid); +  err2:  	iounmap(base); @@ -358,6 +367,7 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev)  	platform_device_unregister(omap->dwc3); +	dwc3_put_device_id(omap->dwc3->id);  	free_irq(omap->irq, omap);  	iounmap(omap->base); @@ -384,18 +394,9 @@ static struct platform_driver dwc3_omap_driver = {  	},  }; +module_platform_driver(dwc3_omap_driver); + +MODULE_ALIAS("platform:omap-dwc3");  MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");  MODULE_LICENSE("Dual BSD/GPL");  MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer"); - -static int __devinit dwc3_omap_init(void) -{ -	return platform_driver_register(&dwc3_omap_driver); -} -module_init(dwc3_omap_init); - -static void __exit dwc3_omap_exit(void) -{ -	platform_driver_unregister(&dwc3_omap_driver); -} -module_exit(dwc3_omap_exit); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index f77c0004268..64e1f7c67b0 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -42,52 +42,17 @@  #include <linux/pci.h>  #include <linux/platform_device.h> +#include "core.h" +  /* FIXME define these in <linux/pci_ids.h> */  #define PCI_VENDOR_ID_SYNOPSYS		0x16c3  #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3	0xabcd -#define DWC3_PCI_DEVS_POSSIBLE	32 -  struct dwc3_pci {  	struct device		*dev;  	struct platform_device	*dwc3;  }; -static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE); - -static int dwc3_pci_get_device_id(struct dwc3_pci *glue) -{ -	int		id; - -again: -	id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE); -	if (id < DWC3_PCI_DEVS_POSSIBLE) { -		int old; - -		old = test_and_set_bit(id, dwc3_pci_devs); -		if (old) -			goto again; -	} else { -		dev_err(glue->dev, "no space for new device\n"); -		id = -ENOMEM; -	} - -	return 0; -} - -static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id) -{ -	int			ret; - -	if (id < 0) -		return; - -	ret = test_bit(id, dwc3_pci_devs); -	WARN(!ret, "Device: %s\nID %d not in use\n", -			dev_driver_string(glue->dev), id); -	clear_bit(id, dwc3_pci_devs); -} -  static int __devinit dwc3_pci_probe(struct pci_dev *pci,  		const struct pci_device_id *id)  { @@ -114,11 +79,11 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,  	pci_set_power_state(pci, PCI_D0);  	pci_set_master(pci); -	devid = dwc3_pci_get_device_id(glue); +	devid = dwc3_get_device_id();  	if (devid < 0)  		goto err2; -	dwc3 = platform_device_alloc("dwc3-pci", devid); +	dwc3 = platform_device_alloc("dwc3", devid);  	if (!dwc3) {  		dev_err(&pci->dev, "couldn't allocate dwc3 device\n");  		goto err3; @@ -163,13 +128,13 @@ err4:  	platform_device_put(dwc3);  err3: -	dwc3_pci_put_device_id(glue, devid); +	dwc3_put_device_id(devid);  err2:  	pci_disable_device(pci);  err1: -	kfree(pci); +	kfree(glue);  err0:  	return ret; @@ -179,7 +144,7 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)  {  	struct dwc3_pci	*glue = pci_get_drvdata(pci); -	dwc3_pci_put_device_id(glue, glue->dwc3->id); +	dwc3_put_device_id(glue->dwc3->id);  	platform_device_unregister(glue->dwc3);  	pci_set_drvdata(pci, NULL);  	pci_disable_device(pci); @@ -196,7 +161,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {  MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);  static struct pci_driver dwc3_pci_driver = { -	.name		= "pci-dwc3", +	.name		= "dwc3-pci",  	.id_table	= dwc3_pci_id_table,  	.probe		= dwc3_pci_probe,  	.remove		= __devexit_p(dwc3_pci_remove), diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 69a4e43ddf5..2f51de57593 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -48,13 +48,13 @@  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> +#include <linux/usb/composite.h>  #include "core.h"  #include "gadget.h"  #include "io.h" -static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, -		const struct dwc3_event_depevt *event); +static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);  static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)  { @@ -125,6 +125,8 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,  static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,  		struct dwc3_request *req)  { +	struct dwc3		*dwc = dep->dwc; +	u32			type;  	int			ret = 0;  	req->request.actual	= 0; @@ -143,9 +145,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,  	 * IRQ we were waiting for is long gone.  	 */  	if (dep->flags & DWC3_EP_PENDING_REQUEST) { -		struct dwc3	*dwc = dep->dwc;  		unsigned	direction; -		u32		type;  		direction = !!(dep->flags & DWC3_EP0_DIR_IN); @@ -165,6 +165,13 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,  				req->request.dma, req->request.length, type);  		dep->flags &= ~(DWC3_EP_PENDING_REQUEST |  				DWC3_EP0_DIR_IN); +	} else if (dwc->delayed_status) { +		dwc->delayed_status = false; + +		if (dwc->ep0state == EP0_STATUS_PHASE) +			dwc3_ep0_do_control_status(dwc, 1); +		else +			dev_dbg(dwc->dev, "too early for delayed status\n");  	}  	return ret; @@ -190,9 +197,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,  	}  	/* we share one TRB for ep0/1 */ -	if (!list_empty(&dwc->eps[0]->request_list) || -			!list_empty(&dwc->eps[1]->request_list) || -			dwc->ep0_status_pending) { +	if (!list_empty(&dep->request_list)) {  		ret = -EBUSY;  		goto out;  	} @@ -214,8 +219,9 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)  	struct dwc3_ep		*dep = dwc->eps[0];  	/* stall is always issued on EP0 */ -	__dwc3_gadget_ep_set_halt(dwc->eps[0], 1); -	dwc->eps[0]->flags = DWC3_EP_ENABLED; +	__dwc3_gadget_ep_set_halt(dep, 1); +	dep->flags = DWC3_EP_ENABLED; +	dwc->delayed_status = false;  	if (!list_empty(&dep->request_list)) {  		struct dwc3_request	*req; @@ -254,17 +260,14 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)  	return NULL;  } -static void dwc3_ep0_send_status_response(struct dwc3 *dwc) +static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req)  { -	dwc3_ep0_start_trans(dwc, 1, dwc->setup_buf_addr, -			dwc->ep0_usb_req.length, -			DWC3_TRBCTL_CONTROL_DATA);  } -  /*   * ch 9.4.5   */ -static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) +static int dwc3_ep0_handle_status(struct dwc3 *dwc, +		struct usb_ctrlrequest *ctrl)  {  	struct dwc3_ep		*dep;  	u32			recip; @@ -291,7 +294,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl  	case USB_RECIP_ENDPOINT:  		dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);  		if (!dep) -		       return -EINVAL; +			return -EINVAL;  		if (dep->flags & DWC3_EP_STALL)  			usb_status = 1 << USB_ENDPOINT_HALT; @@ -302,10 +305,14 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl  	response_pkt = (__le16 *) dwc->setup_buf;  	*response_pkt = cpu_to_le16(usb_status); -	dwc->ep0_usb_req.length = sizeof(*response_pkt); -	dwc->ep0_status_pending = 1; -	return 0; +	dep = dwc->eps[0]; +	dwc->ep0_usb_req.dep = dep; +	dwc->ep0_usb_req.request.length = sizeof(*response_pkt); +	dwc->ep0_usb_req.request.dma = dwc->setup_buf_addr; +	dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; + +	return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);  }  static int dwc3_ep0_handle_feature(struct dwc3 *dwc, @@ -396,8 +403,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,  	case USB_RECIP_ENDPOINT:  		switch (wValue) {  		case USB_ENDPOINT_HALT: - -			dep =  dwc3_wIndex_to_dep(dwc, ctrl->wIndex); +			dep =  dwc3_wIndex_to_dep(dwc, wIndex);  			if (!dep)  				return -EINVAL;  			ret = __dwc3_gadget_ep_set_halt(dep, set); @@ -422,8 +428,15 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)  	u32 reg;  	addr = le16_to_cpu(ctrl->wValue); -	if (addr > 127) +	if (addr > 127) { +		dev_dbg(dwc->dev, "invalid device address %d\n", addr);  		return -EINVAL; +	} + +	if (dwc->dev_state == DWC3_CONFIGURED_STATE) { +		dev_dbg(dwc->dev, "trying to set address when configured\n"); +		return -EINVAL; +	}  	reg = dwc3_readl(dwc->regs, DWC3_DCFG);  	reg &= ~(DWC3_DCFG_DEVADDR_MASK); @@ -473,8 +486,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)  		if (!cfg)  			dwc->dev_state = DWC3_ADDRESS_STATE;  		break; +	default: +		ret = -EINVAL;  	} -	return 0; +	return ret;  }  static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) @@ -537,6 +552,9 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,  	else  		ret = dwc3_ep0_delegate_req(dwc, ctrl); +	if (ret == USB_GADGET_DELAYED_STATUS) +		dwc->delayed_status = true; +  	if (ret >= 0)  		return; @@ -550,27 +568,21 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,  	struct dwc3_request	*r = NULL;  	struct usb_request	*ur;  	struct dwc3_trb		trb; -	struct dwc3_ep		*dep; +	struct dwc3_ep		*ep0;  	u32			transferred;  	u8			epnum;  	epnum = event->endpoint_number; -	dep = dwc->eps[epnum]; +	ep0 = dwc->eps[0];  	dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; -	if (!dwc->ep0_status_pending) { -		r = next_request(&dwc->eps[0]->request_list); -		ur = &r->request; -	} else { -		ur = &dwc->ep0_usb_req; -		dwc->ep0_status_pending = 0; -	} +	r = next_request(&ep0->request_list); +	ur = &r->request;  	dwc3_trb_to_nat(dwc->ep0_trb, &trb);  	if (dwc->ep0_bounced) { -		struct dwc3_ep	*ep0 = dwc->eps[0];  		transferred = min_t(u32, ur->length,  				ep0->endpoint.maxpacket - trb.length); @@ -591,7 +603,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,  		 * seems to be case when req.length > maxpacket. Could it be?  		 */  		if (r) -			dwc3_gadget_giveback(dep, r, 0); +			dwc3_gadget_giveback(ep0, r, 0);  	}  } @@ -619,6 +631,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,  	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];  	dep->flags &= ~DWC3_EP_BUSY; +	dwc->setup_packet_pending = false;  	switch (dwc->ep0state) {  	case EP0_SETUP_PHASE: @@ -643,7 +656,6 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,  static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,  		const struct dwc3_event_depevt *event)  { -	dwc->ep0state = EP0_SETUP_PHASE;  	dwc3_ep0_out_start(dwc);  } @@ -655,12 +667,6 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,  	int			ret;  	dep = dwc->eps[0]; -	dwc->ep0state = EP0_DATA_PHASE; - -	if (dwc->ep0_status_pending) { -		dwc3_ep0_send_status_response(dwc); -		return; -	}  	if (list_empty(&dep->request_list)) {  		dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); @@ -674,7 +680,6 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,  	req = next_request(&dep->request_list);  	req->direction = !!event->endpoint_number; -	dwc->ep0state = EP0_DATA_PHASE;  	if (req->request.length == 0) {  		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,  				dwc->ctrl_req_addr, 0, @@ -706,35 +711,79 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,  	WARN_ON(ret < 0);  } -static void dwc3_ep0_do_control_status(struct dwc3 *dwc, -		const struct dwc3_event_depevt *event) +static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)  { +	struct dwc3		*dwc = dep->dwc;  	u32			type; -	int			ret; - -	dwc->ep0state = EP0_STATUS_PHASE;  	type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3  		: DWC3_TRBCTL_CONTROL_STATUS2; -	ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, +	return dwc3_ep0_start_trans(dwc, dep->number,  			dwc->ctrl_req_addr, 0, type); +} -	WARN_ON(ret < 0); +static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum) +{ +	struct dwc3_ep		*dep = dwc->eps[epnum]; + +	WARN_ON(dwc3_ep0_start_control_status(dep));  }  static void dwc3_ep0_xfernotready(struct dwc3 *dwc,  		const struct dwc3_event_depevt *event)  { +	dwc->setup_packet_pending = true; + +	/* +	 * This part is very tricky: If we has just handled +	 * XferNotReady(Setup) and we're now expecting a +	 * XferComplete but, instead, we receive another +	 * XferNotReady(Setup), we should STALL and restart +	 * the state machine. +	 * +	 * In all other cases, we just continue waiting +	 * for the XferComplete event. +	 * +	 * We are a little bit unsafe here because we're +	 * not trying to ensure that last event was, indeed, +	 * XferNotReady(Setup). +	 * +	 * Still, we don't expect any condition where that +	 * should happen and, even if it does, it would be +	 * another error condition. +	 */ +	if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) { +		switch (event->status) { +		case DEPEVT_STATUS_CONTROL_SETUP: +			dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n"); +			dwc3_ep0_stall_and_restart(dwc); +			break; +		case DEPEVT_STATUS_CONTROL_DATA: +			/* FALLTHROUGH */ +		case DEPEVT_STATUS_CONTROL_STATUS: +			/* FALLTHROUGH */ +		default: +			dev_vdbg(dwc->dev, "waiting for XferComplete\n"); +		} + +		return; +	} +  	switch (event->status) {  	case DEPEVT_STATUS_CONTROL_SETUP:  		dev_vdbg(dwc->dev, "Control Setup\n"); + +		dwc->ep0state = EP0_SETUP_PHASE; +  		dwc3_ep0_do_control_setup(dwc, event);  		break;  	case DEPEVT_STATUS_CONTROL_DATA:  		dev_vdbg(dwc->dev, "Control Data\n"); +		dwc->ep0state = EP0_DATA_PHASE; +  		if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {  			dev_vdbg(dwc->dev, "Expected %d got %d\n",  					dwc->ep0_next_event, @@ -764,6 +813,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,  	case DEPEVT_STATUS_CONTROL_STATUS:  		dev_vdbg(dwc->dev, "Control Status\n"); +		dwc->ep0state = EP0_STATUS_PHASE; +  		if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {  			dev_vdbg(dwc->dev, "Expected %d got %d\n",  					dwc->ep0_next_event, @@ -772,12 +823,19 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,  			dwc3_ep0_stall_and_restart(dwc);  			return;  		} -		dwc3_ep0_do_control_status(dwc, event); + +		if (dwc->delayed_status) { +			WARN_ON_ONCE(event->endpoint_number != 1); +			dev_vdbg(dwc->dev, "Mass Storage delayed status\n"); +			return; +		} + +		dwc3_ep0_do_control_status(dwc, event->endpoint_number);  	}  }  void dwc3_ep0_interrupt(struct dwc3 *dwc, -		const const struct dwc3_event_depevt *event) +		const struct dwc3_event_depevt *event)  {  	u8			epnum = event->endpoint_number; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 25dbd8614e7..a696bde5322 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -65,6 +65,22 @@ void dwc3_map_buffer_to_dma(struct dwc3_request *req)  		return;  	} +	if (req->request.num_sgs) { +		int	mapped; + +		mapped = dma_map_sg(dwc->dev, req->request.sg, +				req->request.num_sgs, +				req->direction ? DMA_TO_DEVICE +				: DMA_FROM_DEVICE); +		if (mapped < 0) { +			dev_err(dwc->dev, "failed to map SGs\n"); +			return; +		} + +		req->request.num_mapped_sgs = mapped; +		return; +	} +  	if (req->request.dma == DMA_ADDR_INVALID) {  		req->request.dma = dma_map_single(dwc->dev, req->request.buf,  				req->request.length, req->direction @@ -82,6 +98,17 @@ void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)  		return;  	} +	if (req->request.num_mapped_sgs) { +		req->request.dma = DMA_ADDR_INVALID; +		dma_unmap_sg(dwc->dev, req->request.sg, +				req->request.num_sgs, +				req->direction ? DMA_TO_DEVICE +				: DMA_FROM_DEVICE); + +		req->request.num_mapped_sgs = 0; +		return; +	} +  	if (req->mapped) {  		dma_unmap_single(dwc->dev, req->request.dma,  				req->request.length, req->direction @@ -97,7 +124,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,  	struct dwc3			*dwc = dep->dwc;  	if (req->queued) { -		dep->busy_slot++; +		if (req->request.num_mapped_sgs) +			dep->busy_slot += req->request.num_mapped_sgs; +		else +			dep->busy_slot++; +  		/*  		 * Skip LINK TRB. We can't use req->trb and check for  		 * DWC3_TRBCTL_LINK_TRB because it points the TRB we just @@ -108,6 +139,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,  			dep->busy_slot++;  	}  	list_del(&req->list); +	req->trb = NULL;  	if (req->request.status == -EINPROGRESS)  		req->request.status = status; @@ -251,7 +283,8 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)  }  static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, -		const struct usb_endpoint_descriptor *desc) +		const struct usb_endpoint_descriptor *desc, +		const struct usb_ss_ep_comp_descriptor *comp_desc)  {  	struct dwc3_gadget_ep_cmd_params params; @@ -264,7 +297,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,  	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN  		| DWC3_DEPCFG_XFER_NOT_READY_EN; -	if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) { +	if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {  		params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE  			| DWC3_DEPCFG_STREAM_EVENT_EN;  		dep->stream_capable = true; @@ -317,7 +350,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)   * Caller should take care of locking   */  static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, -		const struct usb_endpoint_descriptor *desc) +		const struct usb_endpoint_descriptor *desc, +		const struct usb_ss_ep_comp_descriptor *comp_desc)  {  	struct dwc3		*dwc = dep->dwc;  	u32			reg; @@ -329,7 +363,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,  			return ret;  	} -	ret = dwc3_gadget_set_ep_config(dwc, dep, desc); +	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc);  	if (ret)  		return ret; @@ -343,6 +377,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,  			return ret;  		dep->desc = desc; +		dep->comp_desc = comp_desc;  		dep->type = usb_endpoint_type(desc);  		dep->flags |= DWC3_EP_ENABLED; @@ -405,6 +440,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)  	dep->stream_capable = false;  	dep->desc = NULL; +	dep->comp_desc = NULL;  	dep->type = 0;  	dep->flags = 0; @@ -473,7 +509,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,  	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);  	spin_lock_irqsave(&dwc->lock, flags); -	ret = __dwc3_gadget_ep_enable(dep, desc); +	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc);  	spin_unlock_irqrestore(&dwc->lock, flags);  	return ret; @@ -539,6 +575,85 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,  	kfree(req);  } +/** + * dwc3_prepare_one_trb - setup one TRB from one request + * @dep: endpoint for which this request is prepared + * @req: dwc3_request pointer + */ +static void dwc3_prepare_one_trb(struct dwc3_ep *dep, +		struct dwc3_request *req, dma_addr_t dma, +		unsigned length, unsigned last, unsigned chain) +{ +	struct dwc3		*dwc = dep->dwc; +	struct dwc3_trb_hw	*trb_hw; +	struct dwc3_trb		trb; + +	unsigned int		cur_slot; + +	dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n", +			dep->name, req, (unsigned long long) dma, +			length, last ? " last" : "", +			chain ? " chain" : ""); + +	trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK]; +	cur_slot = dep->free_slot; +	dep->free_slot++; + +	/* Skip the LINK-TRB on ISOC */ +	if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && +			usb_endpoint_xfer_isoc(dep->desc)) +		return; + +	memset(&trb, 0, sizeof(trb)); +	if (!req->trb) { +		dwc3_gadget_move_request_queued(req); +		req->trb = trb_hw; +		req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw); +	} + +	if (usb_endpoint_xfer_isoc(dep->desc)) { +		trb.isp_imi = true; +		trb.csp = true; +	} else { +		trb.chn = chain; +		trb.lst = last; +	} + +	if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable) +		trb.sid_sofn = req->request.stream_id; + +	switch (usb_endpoint_type(dep->desc)) { +	case USB_ENDPOINT_XFER_CONTROL: +		trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP; +		break; + +	case USB_ENDPOINT_XFER_ISOC: +		trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST; + +		/* IOC every DWC3_TRB_NUM / 4 so we can refill */ +		if (!(cur_slot % (DWC3_TRB_NUM / 4))) +			trb.ioc = last; +		break; + +	case USB_ENDPOINT_XFER_BULK: +	case USB_ENDPOINT_XFER_INT: +		trb.trbctl = DWC3_TRBCTL_NORMAL; +		break; +	default: +		/* +		 * This is only possible with faulty memory because we +		 * checked it already :) +		 */ +		BUG(); +	} + +	trb.length	= length; +	trb.bplh	= dma; +	trb.hwo		= true; + +	dwc3_trb_to_hw(&trb, trb_hw); +} +  /*   * dwc3_prepare_trbs - setup TRBs from requests   * @dep: endpoint for which requests are being prepared @@ -548,18 +663,17 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,   * transfers. The functions returns once there are not more TRBs available or   * it run out of requests.   */ -static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep, -		bool starting) +static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)  { -	struct dwc3_request	*req, *n, *ret = NULL; -	struct dwc3_trb_hw	*trb_hw; -	struct dwc3_trb		trb; +	struct dwc3_request	*req, *n;  	u32			trbs_left; +	unsigned int		last_one = 0;  	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);  	/* the first request must not be queued */  	trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK; +  	/*  	 * if busy & slot are equal than it is either full or empty. If we are  	 * starting to proceed requests then we are empty. Otherwise we ar @@ -567,7 +681,7 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,  	 */  	if (!trbs_left) {  		if (!starting) -			return NULL; +			return;  		trbs_left = DWC3_TRB_NUM;  		/*  		 * In case we start from scratch, we queue the ISOC requests @@ -591,94 +705,62 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,  	/* The last TRB is a link TRB, not used for xfer */  	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc)) -		return NULL; +		return;  	list_for_each_entry_safe(req, n, &dep->request_list, list) { -		unsigned int last_one = 0; -		unsigned int cur_slot; +		unsigned	length; +		dma_addr_t	dma; -		trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK]; -		cur_slot = dep->free_slot; -		dep->free_slot++; +		if (req->request.num_mapped_sgs > 0) { +			struct usb_request *request = &req->request; +			struct scatterlist *sg = request->sg; +			struct scatterlist *s; +			int		i; -		/* Skip the LINK-TRB on ISOC */ -		if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && -				usb_endpoint_xfer_isoc(dep->desc)) -			continue; +			for_each_sg(sg, s, request->num_mapped_sgs, i) { +				unsigned chain = true; -		dwc3_gadget_move_request_queued(req); -		memset(&trb, 0, sizeof(trb)); -		trbs_left--; +				length = sg_dma_len(s); +				dma = sg_dma_address(s); -		/* Is our TRB pool empty? */ -		if (!trbs_left) -			last_one = 1; -		/* Is this the last request? */ -		if (list_empty(&dep->request_list)) -			last_one = 1; +				if (i == (request->num_mapped_sgs - 1) +						|| sg_is_last(s)) { +					last_one = true; +					chain = false; +				} -		/* -		 * FIXME we shouldn't need to set LST bit always but we are -		 * facing some weird problem with the Hardware where it doesn't -		 * complete even though it has been previously started. -		 * -		 * While we're debugging the problem, as a workaround to -		 * multiple TRBs handling, use only one TRB at a time. -		 */ -		last_one = 1; +				trbs_left--; +				if (!trbs_left) +					last_one = true; -		req->trb = trb_hw; -		if (!ret) -			ret = req; +				if (last_one) +					chain = false; -		trb.bplh = req->request.dma; +				dwc3_prepare_one_trb(dep, req, dma, length, +						last_one, chain); -		if (usb_endpoint_xfer_isoc(dep->desc)) { -			trb.isp_imi = true; -			trb.csp = true; +				if (last_one) +					break; +			}  		} else { -			trb.lst = last_one; -		} +			dma = req->request.dma; +			length = req->request.length; +			trbs_left--; -		if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable) -			trb.sid_sofn = req->request.stream_id; +			if (!trbs_left) +				last_one = 1; -		switch (usb_endpoint_type(dep->desc)) { -		case USB_ENDPOINT_XFER_CONTROL: -			trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP; -			break; - -		case USB_ENDPOINT_XFER_ISOC: -			trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST; +			/* Is this the last request? */ +			if (list_is_last(&req->list, &dep->request_list)) +				last_one = 1; -			/* IOC every DWC3_TRB_NUM / 4 so we can refill */ -			if (!(cur_slot % (DWC3_TRB_NUM / 4))) -				trb.ioc = last_one; -			break; +			dwc3_prepare_one_trb(dep, req, dma, length, +					last_one, false); -		case USB_ENDPOINT_XFER_BULK: -		case USB_ENDPOINT_XFER_INT: -			trb.trbctl = DWC3_TRBCTL_NORMAL; -			break; -		default: -			/* -			 * This is only possible with faulty memory because we -			 * checked it already :) -			 */ -			BUG(); +			if (last_one) +				break;  		} - -		trb.length	= req->request.length; -		trb.hwo = true; - -		dwc3_trb_to_hw(&trb, trb_hw); -		req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw); - -		if (last_one) -			break;  	} - -	return ret;  }  static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, @@ -707,11 +789,13 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,  		/* req points to the first request which will be sent */  		req = next_request(&dep->req_queued);  	} else { +		dwc3_prepare_trbs(dep, start_new); +  		/*  		 * req points to the first request where HWO changed  		 * from 0 to 1  		 */ -		req = dwc3_prepare_trbs(dep, start_new); +		req = next_request(&dep->req_queued);  	}  	if (!req) {  		dep->flags |= DWC3_EP_PENDING_REQUEST; @@ -745,8 +829,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,  	dep->flags |= DWC3_EP_BUSY;  	dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,  			dep->number); -	if (!dep->res_trans_idx) -		printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__); + +	WARN_ON_ONCE(!dep->res_trans_idx); +  	return 0;  } @@ -1155,35 +1240,9 @@ static int dwc3_gadget_start(struct usb_gadget *g,  	dwc->gadget_driver	= driver;  	dwc->gadget.dev.driver	= &driver->driver; -	reg = dwc3_readl(dwc->regs, DWC3_GCTL); - -	reg &= ~DWC3_GCTL_SCALEDOWN(3); -	reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG); -	reg &= ~DWC3_GCTL_DISSCRAMBLE; -	reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE); - -	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) { -	case DWC3_GHWPARAMS1_EN_PWROPT_CLK: -		reg &= ~DWC3_GCTL_DSBLCLKGTNG; -		break; -	default: -		dev_dbg(dwc->dev, "No power optimization available\n"); -	} - -	/* -	 * WORKAROUND: DWC3 revisions <1.90a have a bug -	 * when The device fails to connect at SuperSpeed -	 * and falls back to high-speed mode which causes -	 * the device to enter in a Connect/Disconnect loop -	 */ -	if (dwc->revision < DWC3_REVISION_190A) -		reg |= DWC3_GCTL_U2RSTECN; - -	dwc3_writel(dwc->regs, DWC3_GCTL, reg); -  	reg = dwc3_readl(dwc->regs, DWC3_DCFG);  	reg &= ~(DWC3_DCFG_SPEED_MASK); -	reg |= DWC3_DCFG_SUPERSPEED; +	reg |= dwc->maximum_speed;  	dwc3_writel(dwc->regs, DWC3_DCFG, reg);  	dwc->start_config_issued = false; @@ -1192,14 +1251,14 @@ static int dwc3_gadget_start(struct usb_gadget *g,  	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);  	dep = dwc->eps[0]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		goto err0;  	}  	dep = dwc->eps[1]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		goto err1; @@ -1290,11 +1349,10 @@ static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)  					&dwc->gadget.ep_list);  			ret = dwc3_alloc_trb_pool(dep); -			if (ret) { -				dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name); +			if (ret)  				return ret; -			}  		} +  		INIT_LIST_HEAD(&dep->request_list);  		INIT_LIST_HEAD(&dep->req_queued);  	} @@ -1334,8 +1392,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,  	do {  		req = next_request(&dep->req_queued); -		if (!req) -			break; +		if (!req) { +			WARN_ON_ONCE(1); +			return 1; +		}  		dwc3_trb_to_nat(req->trb, &trb); @@ -1400,6 +1460,31 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,  		dep->flags &= ~DWC3_EP_BUSY;  		dep->res_trans_idx = 0;  	} + +	/* +	 * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround. +	 * See dwc3_gadget_linksts_change_interrupt() for 1st half. +	 */ +	if (dwc->revision < DWC3_REVISION_183A) { +		u32		reg; +		int		i; + +		for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { +			struct dwc3_ep	*dep = dwc->eps[i]; + +			if (!(dep->flags & DWC3_EP_ENABLED)) +				continue; + +			if (!list_empty(&dep->req_queued)) +				return; +		} + +		reg = dwc3_readl(dwc->regs, DWC3_DCTL); +		reg |= dwc->u1u2; +		dwc3_writel(dwc->regs, DWC3_DCTL, reg); + +		dwc->u1u2 = 0; +	}  }  static void dwc3_gadget_start_isoc(struct dwc3 *dwc, @@ -1639,6 +1724,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)  	dwc->start_config_issued = false;  	dwc->gadget.speed = USB_SPEED_UNKNOWN; +	dwc->setup_packet_pending = false;  }  static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on) @@ -1675,6 +1761,40 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)  	dev_vdbg(dwc->dev, "%s\n", __func__); +	/* +	 * WORKAROUND: DWC3 revisions <1.88a have an issue which +	 * would cause a missing Disconnect Event if there's a +	 * pending Setup Packet in the FIFO. +	 * +	 * There's no suggested workaround on the official Bug +	 * report, which states that "unless the driver/application +	 * is doing any special handling of a disconnect event, +	 * there is no functional issue". +	 * +	 * Unfortunately, it turns out that we _do_ some special +	 * handling of a disconnect event, namely complete all +	 * pending transfers, notify gadget driver of the +	 * disconnection, and so on. +	 * +	 * Our suggested workaround is to follow the Disconnect +	 * Event steps here, instead, based on a setup_packet_pending +	 * flag. Such flag gets set whenever we have a XferNotReady +	 * event on EP0 and gets cleared on XferComplete for the +	 * same endpoint. +	 * +	 * Refers to: +	 * +	 * STAR#9000466709: RTL: Device : Disconnect event not +	 * generated if setup packet pending in FIFO +	 */ +	if (dwc->revision < DWC3_REVISION_188A) { +		if (dwc->setup_packet_pending) +			dwc3_gadget_disconnect_interrupt(dwc); +	} + +	/* after reset -> Default State */ +	dwc->dev_state = DWC3_DEFAULT_STATE; +  	/* Enable PHYs */  	dwc3_gadget_usb2_phy_power(dwc, true);  	dwc3_gadget_usb3_phy_power(dwc, true); @@ -1755,6 +1875,22 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)  	switch (speed) {  	case DWC3_DCFG_SUPERSPEED: +		/* +		 * WORKAROUND: DWC3 revisions <1.90a have an issue which +		 * would cause a missing USB3 Reset event. +		 * +		 * In such situations, we should force a USB3 Reset +		 * event by calling our dwc3_gadget_reset_interrupt() +		 * routine. +		 * +		 * Refers to: +		 * +		 * STAR#9000483510: RTL: SS : USB3 reset event may +		 * not be generated always when the link enters poll +		 */ +		if (dwc->revision < DWC3_REVISION_190A) +			dwc3_gadget_reset_interrupt(dwc); +  		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);  		dwc->gadget.ep0->maxpacket = 512;  		dwc->gadget.speed = USB_SPEED_SUPER; @@ -1781,14 +1917,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)  	dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);  	dep = dwc->eps[0]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		return;  	}  	dep = dwc->eps[1]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		return; @@ -1818,8 +1954,55 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)  static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,  		unsigned int evtinfo)  { -	/*  The fith bit says SuperSpeed yes or no. */ -	dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK; +	enum dwc3_link_state	next = evtinfo & DWC3_LINK_STATE_MASK; + +	/* +	 * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending +	 * on the link partner, the USB session might do multiple entry/exit +	 * of low power states before a transfer takes place. +	 * +	 * Due to this problem, we might experience lower throughput. The +	 * suggested workaround is to disable DCTL[12:9] bits if we're +	 * transitioning from U1/U2 to U0 and enable those bits again +	 * after a transfer completes and there are no pending transfers +	 * on any of the enabled endpoints. +	 * +	 * This is the first half of that workaround. +	 * +	 * Refers to: +	 * +	 * STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us +	 * core send LGO_Ux entering U0 +	 */ +	if (dwc->revision < DWC3_REVISION_183A) { +		if (next == DWC3_LINK_STATE_U0) { +			u32	u1u2; +			u32	reg; + +			switch (dwc->link_state) { +			case DWC3_LINK_STATE_U1: +			case DWC3_LINK_STATE_U2: +				reg = dwc3_readl(dwc->regs, DWC3_DCTL); +				u1u2 = reg & (DWC3_DCTL_INITU2ENA +						| DWC3_DCTL_ACCEPTU2ENA +						| DWC3_DCTL_INITU1ENA +						| DWC3_DCTL_ACCEPTU1ENA); + +				if (!dwc->u1u2) +					dwc->u1u2 = reg & u1u2; + +				reg &= ~u1u2; + +				dwc3_writel(dwc->regs, DWC3_DCTL, reg); +				break; +			default: +				/* do nothing */ +				break; +			} +		} +	} + +	dwc->link_state = next;  	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);  } @@ -1925,7 +2108,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)  	spin_lock(&dwc->lock); -	for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) { +	for (i = 0; i < dwc->num_event_buffers; i++) {  		irqreturn_t status;  		status = dwc3_process_event_buf(dwc, i); @@ -1986,9 +2169,10 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)  	dev_set_name(&dwc->gadget.dev, "gadget");  	dwc->gadget.ops			= &dwc3_gadget_ops; -	dwc->gadget.is_dualspeed	= true; +	dwc->gadget.max_speed		= USB_SPEED_SUPER;  	dwc->gadget.speed		= USB_SPEED_UNKNOWN;  	dwc->gadget.dev.parent		= dwc->dev; +	dwc->gadget.sg_supported	= true;  	dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask); @@ -2076,7 +2260,6 @@ err0:  void dwc3_gadget_exit(struct dwc3 *dwc)  {  	int			irq; -	int			i;  	usb_del_gadget_udc(&dwc->gadget);  	irq = platform_get_irq(to_platform_device(dwc->dev), 0); @@ -2084,9 +2267,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc)  	dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);  	free_irq(irq, dwc); -	for (i = 0; i < ARRAY_SIZE(dwc->eps); i++) -		__dwc3_gadget_ep_disable(dwc->eps[i]); -  	dwc3_gadget_free_endpoints(dwc);  	dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce, diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 71145a449d9..d97f467d41c 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -79,19 +79,6 @@ struct dwc3_gadget_ep_cmd_params {  /* -------------------------------------------------------------------------- */ -struct dwc3_request { -	struct usb_request	request; -	struct list_head	list; -	struct dwc3_ep		*dep; - -	u8			epnum; -	struct dwc3_trb_hw	*trb; -	dma_addr_t		trb_dma; - -	unsigned		direction:1; -	unsigned		mapped:1; -	unsigned		queued:1; -};  #define to_dwc3_request(r)	(container_of(r, struct dwc3_request, request))  static inline struct dwc3_request *next_request(struct list_head *list) @@ -110,23 +97,11 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)  	list_move_tail(&req->list, &dep->req_queued);  } -#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE) -int dwc3_gadget_init(struct dwc3 *dwc); -void dwc3_gadget_exit(struct dwc3 *dwc); -#else -static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; } -static inline void dwc3_gadget_exit(struct dwc3 *dwc) { } -static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, -		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) -{ -	return 0; -} -#endif -  void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,  		int status); -void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event); +void dwc3_ep0_interrupt(struct dwc3 *dwc, +		const struct dwc3_event_depevt *event);  void dwc3_ep0_out_start(struct dwc3 *dwc);  int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,  		gfp_t gfp_flags); diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c new file mode 100644 index 00000000000..7cfe211b6c3 --- /dev/null +++ b/drivers/usb/dwc3/host.c @@ -0,0 +1,102 @@ +/** + * host.c - DesignWare USB3 DRD Controller Host Glue + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: Felipe Balbi <balbi@ti.com>, + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2, as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/platform_device.h> + +#include "core.h" + +static struct resource generic_resources[] = { +	{ +		.flags = IORESOURCE_IRQ, +	}, +	{ +		.flags = IORESOURCE_MEM, +	}, +}; + +int dwc3_host_init(struct dwc3 *dwc) +{ +	struct platform_device	*xhci; +	int			ret; + +	xhci = platform_device_alloc("xhci", -1); +	if (!xhci) { +		dev_err(dwc->dev, "couldn't allocate xHCI device\n"); +		ret = -ENOMEM; +		goto err0; +	} + +	dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask); + +	xhci->dev.parent	= dwc->dev; +	xhci->dev.dma_mask	= dwc->dev->dma_mask; +	xhci->dev.dma_parms	= dwc->dev->dma_parms; + +	dwc->xhci = xhci; + +	/* setup resources */ +	generic_resources[0].start = dwc->irq; + +	generic_resources[1].start = dwc->res->start; +	generic_resources[1].end = dwc->res->start + 0x7fff; + +	ret = platform_device_add_resources(xhci, generic_resources, +			ARRAY_SIZE(generic_resources)); +	if (ret) { +		dev_err(dwc->dev, "couldn't add resources to xHCI device\n"); +		goto err1; +	} + +	ret = platform_device_add(xhci); +	if (ret) { +		dev_err(dwc->dev, "failed to register xHCI device\n"); +		goto err1; +	} + +	return 0; + +err1: +	platform_device_put(xhci); + +err0: +	return ret; +} + +void dwc3_host_exit(struct dwc3 *dwc) +{ +	platform_device_unregister(dwc->xhci); +} diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index bc957db1ea4..071d561f3e6 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -39,7 +39,7 @@  #ifndef __DRIVERS_USB_DWC3_IO_H  #define __DRIVERS_USB_DWC3_IO_H -#include <asm/io.h> +#include <linux/io.h>  static inline u32 dwc3_readl(void __iomem *base, u32 offset)  { diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 12a401a144b..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 @@ -309,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 @@ -543,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  # @@ -556,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 45f422ac103..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..ac41f71bf9c 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"); 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 4dff83d2f26..753aa0683ac 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -149,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 */ @@ -157,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 b5f6f9fef9c..f63dc6c150d 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1399,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 1a6f415c0d0..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; 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_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index e00cf92409c..b95697c03d0 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2336,7 +2336,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver,  	if (!udc_controller)  		return -ENODEV; -	if (!driver || driver->speed < USB_SPEED_FULL +	if (!driver || driver->max_speed < USB_SPEED_FULL  			|| !bind || !driver->disconnect || !driver->setup)  		return -EINVAL; @@ -2350,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); @@ -2814,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 dd28ef3def7..d7ea6c076ce 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1934,7 +1934,7 @@ static int fsl_start(struct usb_gadget_driver *driver,  	if (!udc_controller)  		return -ENODEV; -	if (!driver || driver->speed < USB_SPEED_FULL +	if (!driver || driver->max_speed < USB_SPEED_FULL  			|| !bind || !driver->disconnect || !driver->setup)  		return -EINVAL; @@ -2525,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/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 6b7ea25af0f..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, 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 9aa1cbbee45..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); +		usbcmd = readl(&udc->op_regs->usbcmd); +		usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR; +		writel(usbcmd, &udc->op_regs->usbcmd); -				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 */ +		if (epstatus) +			goto done; +	} -			/* Write dQH next pointer and terminate bit to 0 */ -			dqh->next_dtd_ptr = req->head->td_dma +	/* 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; - -			/* -			 * Ensure that updates to the QH will -			 * occur before priming. -			 */ -			wmb(); - -			/* 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; - -		/* Ensure that updates to the QH will occur before priming. */ -		wmb(); -		/* Prime the Endpoint */ -		writel(bit_pos, &udc->op_regs->epprime); +	/* clear active and halt bit, in case set from a previous error */ +	dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); -		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; +	/* Ensure that updates to the QH will occure before priming. */ +	wmb(); -			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); +	/* Prime the Endpoint */ +	writel(bit_pos, &udc->op_regs->epprime); -				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 da2b9d0be3c..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 fc719a3f855..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 b31448229f0..69295ba9d99 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2586,7 +2586,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,  		return -EINVAL;  	} -	if (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) { @@ -3362,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); @@ -3467,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 20a553b46ae..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,16 +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 -		|| !bind -		|| !driver->unbind || !driver->disconnect || !driver->setup) +		|| driver->max_speed < USB_SPEED_FULL +		|| !driver->setup)  		return -EINVAL;  	if (!hsudc) @@ -1155,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 */ @@ -1178,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;  		}  	} @@ -1197,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; @@ -1242,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; @@ -1255,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, @@ -1276,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"); @@ -1307,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; @@ -1319,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); @@ -1348,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: @@ -1362,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;  } @@ -1377,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 fac4c650d4b..3f87cb9344b 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -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/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; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 060e0e2b1ae..a52769b5c90 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -194,6 +194,15 @@ config USB_EHCI_S5P         help  	 Enable support for the S5P SOC's on-chip EHCI controller. +config USB_EHCI_MV +	bool "EHCI support for Marvell on-chip controller" +	depends on USB_EHCI_HCD +	select USB_EHCI_ROOT_HUB_TT +	---help--- +	  Enables support for Marvell (including PXA and MMP series) on-chip +	  USB SPH and OTG controller. SPH is a single port host, and it can +	  only be EHCI host. OTG is controller that can switch to host mode. +  config USB_W90X900_EHCI  	bool "W90X900(W90P910) EHCI support"  	depends on USB_EHCI_HCD && ARCH_W90X900 diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index 18bafa99fe5..bf7441afed1 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -23,6 +23,7 @@ static int au1xxx_ehci_setup(struct usb_hcd *hcd)  	int ret = ehci_init(hcd);  	ehci->need_io_watchdog = 0; +	ehci_reset(ehci);  	return ret;  } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 3ff9f82f726..e311a511529 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -48,6 +48,10 @@  #include <asm/system.h>  #include <asm/unaligned.h> +#if defined(CONFIG_PPC_PS3) +#include <asm/firmware.h> +#endif +  /*-------------------------------------------------------------------------*/  /* @@ -230,12 +234,58 @@ static int ehci_halt (struct ehci_hcd *ehci)  			  STS_HALT, STS_HALT, 16 * 125);  } +#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_PPC_PS3) + +/* + * The EHCI controller of the Cell Super Companion Chip used in the + * PS3 will stop the root hub after all root hub ports are suspended. + * When in this condition handshake will return -ETIMEDOUT.  The + * STS_HLT bit will not be set, so inspection of the frame index is + * used here to test for the condition.  If the condition is found + * return success to allow the USB suspend to complete. + */ + +static int handshake_for_broken_root_hub(struct ehci_hcd *ehci, +					 void __iomem *ptr, u32 mask, u32 done, +					 int usec) +{ +	unsigned int old_index; +	int error; + +	if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) +		return -ETIMEDOUT; + +	old_index = ehci_read_frame_index(ehci); + +	error = handshake(ehci, ptr, mask, done, usec); + +	if (error == -ETIMEDOUT && ehci_read_frame_index(ehci) == old_index) +		return 0; + +	return error; +} + +#else + +static int handshake_for_broken_root_hub(struct ehci_hcd *ehci, +					 void __iomem *ptr, u32 mask, u32 done, +					 int usec) +{ +	return -ETIMEDOUT; +} + +#endif +  static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,  				       u32 mask, u32 done, int usec)  {  	int error;  	error = handshake(ehci, ptr, mask, done, usec); +	if (error == -ETIMEDOUT) +		error = handshake_for_broken_root_hub(ehci, ptr, mask, done, +						      usec); +  	if (error) {  		ehci_halt(ehci);  		ehci->rh_state = EHCI_RH_HALTED; @@ -620,6 +670,7 @@ static int ehci_init(struct usb_hcd *hcd)  	hw = ehci->async->hw;  	hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);  	hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD); +	hw->hw_info1 |= cpu_to_hc32(ehci, (1 << 7));	/* I = 1 */  	hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);  	hw->hw_qtd_next = EHCI_LIST_END(ehci);  	ehci->async->qh_state = QH_STATE_LINKED; @@ -677,22 +728,13 @@ static int ehci_init(struct usb_hcd *hcd)  static int ehci_run (struct usb_hcd *hcd)  {  	struct ehci_hcd		*ehci = hcd_to_ehci (hcd); -	int			retval;  	u32			temp;  	u32			hcc_params;  	hcd->uses_new_polling = 1;  	/* EHCI spec section 4.1 */ -	/* -	 * TDI driver does the ehci_reset in their reset callback. -	 * Don't reset here, because configuration settings will -	 * vanish. -	 */ -	if (!ehci_is_TDI(ehci) && (retval = ehci_reset(ehci)) != 0) { -		ehci_mem_cleanup(ehci); -		return retval; -	} +  	ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);  	ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); @@ -1324,11 +1366,16 @@ MODULE_LICENSE ("GPL");  #define PLATFORM_DRIVER		ehci_pxa168_driver  #endif -#ifdef CONFIG_NLM_XLR +#ifdef CONFIG_CPU_XLR  #include "ehci-xls.c"  #define PLATFORM_DRIVER		ehci_xls_driver  #endif +#ifdef CONFIG_USB_EHCI_MV +#include "ehci-mv.c" +#define        PLATFORM_DRIVER         ehci_mv_driver +#endif +  #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \      !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \      !defined(XILINX_OF_PLATFORM_DRIVER) diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c new file mode 100644 index 00000000000..52a604fb932 --- /dev/null +++ b/drivers/usb/host/ehci-mv.c @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * Author: Chao Xie <chao.xie@marvell.com> + *        Neil Zhang <zhangwm@marvell.com> + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/usb/otg.h> +#include <linux/platform_data/mv_usb.h> + +#define CAPLENGTH_MASK         (0xff) + +struct ehci_hcd_mv { +	struct usb_hcd *hcd; + +	/* Which mode does this ehci running OTG/Host ? */ +	int mode; + +	void __iomem *phy_regs; +	void __iomem *cap_regs; +	void __iomem *op_regs; + +	struct otg_transceiver *otg; + +	struct mv_usb_platform_data *pdata; + +	/* clock source and total clock number */ +	unsigned int clknum; +	struct clk *clk[0]; +}; + +static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) +{ +	unsigned int i; + +	for (i = 0; i < ehci_mv->clknum; i++) +		clk_enable(ehci_mv->clk[i]); +} + +static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) +{ +	unsigned int i; + +	for (i = 0; i < ehci_mv->clknum; i++) +		clk_disable(ehci_mv->clk[i]); +} + +static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) +{ +	int retval; + +	ehci_clock_enable(ehci_mv); +	if (ehci_mv->pdata->phy_init) { +		retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs); +		if (retval) +			return retval; +	} + +	return 0; +} + +static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv) +{ +	if (ehci_mv->pdata->phy_deinit) +		ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs); +	ehci_clock_disable(ehci_mv); +} + +static int mv_ehci_reset(struct usb_hcd *hcd) +{ +	struct ehci_hcd *ehci = hcd_to_ehci(hcd); +	struct device *dev = hcd->self.controller; +	struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev); +	int retval; + +	if (ehci_mv == NULL) { +		dev_err(dev, "Can not find private ehci data\n"); +		return -ENODEV; +	} + +	/* +	 * data structure init +	 */ +	retval = ehci_init(hcd); +	if (retval) { +		dev_err(dev, "ehci_init failed %d\n", retval); +		return retval; +	} + +	hcd->has_tt = 1; +	ehci->sbrn = 0x20; + +	retval = ehci_reset(ehci); +	if (retval) { +		dev_err(dev, "ehci_reset failed %d\n", retval); +		return retval; +	} + +	return 0; +} + +static const struct hc_driver mv_ehci_hc_driver = { +	.description = hcd_name, +	.product_desc = "Marvell EHCI", +	.hcd_priv_size = sizeof(struct ehci_hcd), + +	/* +	 * generic hardware linkage +	 */ +	.irq = ehci_irq, +	.flags = HCD_MEMORY | HCD_USB2, + +	/* +	 * basic lifecycle operations +	 */ +	.reset = mv_ehci_reset, +	.start = ehci_run, +	.stop = ehci_stop, +	.shutdown = ehci_shutdown, + +	/* +	 * managing i/o requests and associated device resources +	 */ +	.urb_enqueue = ehci_urb_enqueue, +	.urb_dequeue = ehci_urb_dequeue, +	.endpoint_disable = ehci_endpoint_disable, +	.endpoint_reset = ehci_endpoint_reset, +	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, + +	/* +	 * scheduling support +	 */ +	.get_frame_number = ehci_get_frame, + +	/* +	 * root hub support +	 */ +	.hub_status_data = ehci_hub_status_data, +	.hub_control = ehci_hub_control, +	.bus_suspend = ehci_bus_suspend, +	.bus_resume = ehci_bus_resume, +}; + +static int mv_ehci_probe(struct platform_device *pdev) +{ +	struct mv_usb_platform_data *pdata = pdev->dev.platform_data; +	struct usb_hcd *hcd; +	struct ehci_hcd *ehci; +	struct ehci_hcd_mv *ehci_mv; +	struct resource *r; +	int clk_i, retval = -ENODEV; +	u32 offset; +	size_t size; + +	if (!pdata) { +		dev_err(&pdev->dev, "missing platform_data\n"); +		return -ENODEV; +	} + +	if (usb_disabled()) +		return -ENODEV; + +	hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci"); +	if (!hcd) +		return -ENOMEM; + +	size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum; +	ehci_mv = kzalloc(size, GFP_KERNEL); +	if (ehci_mv == NULL) { +		dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n"); +		retval = -ENOMEM; +		goto err_put_hcd; +	} + +	platform_set_drvdata(pdev, ehci_mv); +	ehci_mv->pdata = pdata; +	ehci_mv->hcd = hcd; + +	ehci_mv->clknum = pdata->clknum; +	for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) { +		ehci_mv->clk[clk_i] = +		    clk_get(&pdev->dev, pdata->clkname[clk_i]); +		if (IS_ERR(ehci_mv->clk[clk_i])) { +			dev_err(&pdev->dev, "error get clck \"%s\"\n", +				pdata->clkname[clk_i]); +			retval = PTR_ERR(ehci_mv->clk[clk_i]); +			goto err_put_clk; +		} +	} + +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs"); +	if (r == NULL) { +		dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); +		retval = -ENODEV; +		goto err_put_clk; +	} + +	ehci_mv->phy_regs = ioremap(r->start, resource_size(r)); +	if (ehci_mv->phy_regs == 0) { +		dev_err(&pdev->dev, "failed to map phy I/O memory\n"); +		retval = -EFAULT; +		goto err_put_clk; +	} + +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs"); +	if (!r) { +		dev_err(&pdev->dev, "no I/O memory resource defined\n"); +		retval = -ENODEV; +		goto err_iounmap_phyreg; +	} + +	ehci_mv->cap_regs = ioremap(r->start, resource_size(r)); +	if (ehci_mv->cap_regs == NULL) { +		dev_err(&pdev->dev, "failed to map I/O memory\n"); +		retval = -EFAULT; +		goto err_iounmap_phyreg; +	} + +	retval = mv_ehci_enable(ehci_mv); +	if (retval) { +		dev_err(&pdev->dev, "init phy error %d\n", retval); +		goto err_iounmap_capreg; +	} + +	offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; +	ehci_mv->op_regs = +		(void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset); + +	hcd->rsrc_start = r->start; +	hcd->rsrc_len = r->end - r->start + 1; +	hcd->regs = ehci_mv->op_regs; + +	hcd->irq = platform_get_irq(pdev, 0); +	if (!hcd->irq) { +		dev_err(&pdev->dev, "Cannot get irq."); +		retval = -ENODEV; +		goto err_disable_clk; +	} + +	ehci = hcd_to_ehci(hcd); +	ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs; +	ehci->regs = (struct ehci_regs *) ehci_mv->op_regs; +	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + +	ehci_mv->mode = pdata->mode; +	if (ehci_mv->mode == MV_USB_MODE_OTG) { +#ifdef CONFIG_USB_OTG_UTILS +		ehci_mv->otg = otg_get_transceiver(); +		if (!ehci_mv->otg) { +			dev_err(&pdev->dev, +				"unable to find transceiver\n"); +			retval = -ENODEV; +			goto err_disable_clk; +		} + +		retval = otg_set_host(ehci_mv->otg, &hcd->self); +		if (retval < 0) { +			dev_err(&pdev->dev, +				"unable to register with transceiver\n"); +			retval = -ENODEV; +			goto err_put_transceiver; +		} +		/* otg will enable clock before use as host */ +		mv_ehci_disable(ehci_mv); +#else +		dev_info(&pdev->dev, "MV_USB_MODE_OTG " +			 "must have CONFIG_USB_OTG_UTILS enabled\n"); +		goto err_disable_clk; +#endif +	} else { +		if (pdata->set_vbus) +			pdata->set_vbus(1); + +		retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); +		if (retval) { +			dev_err(&pdev->dev, +				"failed to add hcd with err %d\n", retval); +			goto err_set_vbus; +		} +	} + +	if (pdata->private_init) +		pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs); + +	dev_info(&pdev->dev, +		 "successful find EHCI device with regs 0x%p irq %d" +		 " working in %s mode\n", hcd->regs, hcd->irq, +		 ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host"); + +	return 0; + +err_set_vbus: +	if (pdata->set_vbus) +		pdata->set_vbus(0); +#ifdef CONFIG_USB_OTG_UTILS +err_put_transceiver: +	if (ehci_mv->otg) +		otg_put_transceiver(ehci_mv->otg); +#endif +err_disable_clk: +	mv_ehci_disable(ehci_mv); +err_iounmap_capreg: +	iounmap(ehci_mv->cap_regs); +err_iounmap_phyreg: +	iounmap(ehci_mv->phy_regs); +err_put_clk: +	for (clk_i--; clk_i >= 0; clk_i--) +		clk_put(ehci_mv->clk[clk_i]); +	platform_set_drvdata(pdev, NULL); +	kfree(ehci_mv); +err_put_hcd: +	usb_put_hcd(hcd); + +	return retval; +} + +static int mv_ehci_remove(struct platform_device *pdev) +{ +	struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); +	struct usb_hcd *hcd = ehci_mv->hcd; +	int clk_i; + +	if (hcd->rh_registered) +		usb_remove_hcd(hcd); + +	if (ehci_mv->otg) { +		otg_set_host(ehci_mv->otg, NULL); +		otg_put_transceiver(ehci_mv->otg); +	} + +	if (ehci_mv->mode == MV_USB_MODE_HOST) { +		if (ehci_mv->pdata->set_vbus) +			ehci_mv->pdata->set_vbus(0); + +		mv_ehci_disable(ehci_mv); +	} + +	iounmap(ehci_mv->cap_regs); +	iounmap(ehci_mv->phy_regs); + +	for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) +		clk_put(ehci_mv->clk[clk_i]); + +	platform_set_drvdata(pdev, NULL); + +	kfree(ehci_mv); +	usb_put_hcd(hcd); + +	return 0; +} + +MODULE_ALIAS("mv-ehci"); + +static const struct platform_device_id ehci_id_table[] = { +	{"pxa-u2oehci", PXA_U2OEHCI}, +	{"pxa-sph", PXA_SPH}, +	{"mmp3-hsic", MMP3_HSIC}, +	{"mmp3-fsic", MMP3_FSIC}, +	{}, +}; + +static void mv_ehci_shutdown(struct platform_device *pdev) +{ +	struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); +	struct usb_hcd *hcd = ehci_mv->hcd; + +	if (!hcd->rh_registered) +		return; + +	if (hcd->driver->shutdown) +		hcd->driver->shutdown(hcd); +} + +static struct platform_driver ehci_mv_driver = { +	.probe = mv_ehci_probe, +	.remove = mv_ehci_remove, +	.shutdown = mv_ehci_shutdown, +	.driver = { +		   .name = "mv-ehci", +		   .bus = &platform_bus_type, +		   }, +	.id_table = ehci_id_table, +}; diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c index ba1f5136113..c0104882c72 100644 --- a/drivers/usb/host/ehci-octeon.c +++ b/drivers/usb/host/ehci-octeon.c @@ -155,6 +155,8 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)  	/* cache this readonly data; minimize chip reads */  	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); +	ehci_reset(ehci); +  	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (ret) {  		dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index e39b0297bad..e33baf9052c 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -228,6 +228,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  	/* cache this readonly data; minimize chip reads */  	omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params); +	ehci_reset(omap_ehci); +  	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (ret) {  		dev_err(dev, "failed to add hcd with err %d\n", ret); diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 2dc32da75cf..a20e496eb47 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -21,6 +21,34 @@  #include <asm/firmware.h>  #include <asm/ps3.h> +static void ps3_ehci_setup_insnreg(struct ehci_hcd *ehci) +{ +	/* PS3 HC internal setup register offsets. */ + +	enum ps3_ehci_hc_insnreg { +		ps3_ehci_hc_insnreg01 = 0x084, +		ps3_ehci_hc_insnreg02 = 0x088, +		ps3_ehci_hc_insnreg03 = 0x08c, +	}; + +	/* PS3 EHCI HC errata fix 316 - The PS3 EHCI HC will reset its +	 * internal INSNREGXX setup regs back to the chip default values +	 * on Host Controller Reset (CMD_RESET) or Light Host Controller +	 * Reset (CMD_LRESET).  The work-around for this is for the HC +	 * driver to re-initialise these regs when ever the HC is reset. +	 */ + +	/* Set burst transfer counts to 256 out, 32 in. */ + +	writel_be(0x01000020, (void __iomem *)ehci->regs + +		ps3_ehci_hc_insnreg01); + +	/* Enable burst transfer counts. */ + +	writel_be(0x00000001, (void __iomem *)ehci->regs + +		ps3_ehci_hc_insnreg03); +} +  static int ps3_ehci_hc_reset(struct usb_hcd *hcd)  {  	int result; @@ -49,6 +77,8 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)  	ehci_reset(ehci); +	ps3_ehci_setup_insnreg(ehci); +  	return result;  } diff --git a/drivers/usb/host/ehci-pxa168.c b/drivers/usb/host/ehci-pxa168.c index ac0c16e8f53..8d0e7a22e71 100644 --- a/drivers/usb/host/ehci-pxa168.c +++ b/drivers/usb/host/ehci-pxa168.c @@ -299,7 +299,7 @@ static int __devinit ehci_pxa168_drv_probe(struct platform_device *pdev)  	ehci = hcd_to_ehci(hcd);  	ehci->caps = hcd->regs + 0x100;  	ehci->regs = hcd->regs + 0x100 + -		HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); +		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));  	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);  	hcd->has_tt = 1;  	ehci->sbrn = 0x20; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 4e4066c35a0..36ca5077cdf 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -373,6 +373,17 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)   retry_xacterr:  		if ((token & QTD_STS_ACTIVE) == 0) { +			/* Report Data Buffer Error: non-fatal but useful */ +			if (token & QTD_STS_DBE) +				ehci_dbg(ehci, +					"detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n", +					urb, +					usb_endpoint_num(&urb->ep->desc), +					usb_endpoint_dir_in(&urb->ep->desc) ? "in" : "out", +					urb->transfer_buffer_length, +					qtd, +					qh); +  			/* on STALL, error, and short reads this urb must  			 * complete and all its qtds must be recycled.  			 */ @@ -647,7 +658,7 @@ qh_urb_transaction (  	/*  	 * data transfer stage:  buffer setup  	 */ -	i = urb->num_sgs; +	i = urb->num_mapped_sgs;  	if (len > 0 && i > 0) {  		sg = urb->sg;  		buf = sg_dma_address(sg); diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 024b65c4990..293f7412992 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -14,8 +14,6 @@  #include <linux/clk.h>  #include <linux/platform_device.h> -#include <mach/regs-pmu.h> -#include <plat/cpu.h>  #include <plat/ehci.h>  #include <plat/usb-phy.h> @@ -136,6 +134,8 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)  	/* cache this readonly data; minimize chip reads */  	ehci->hcs_params = readl(&ehci->caps->hcs_params); +	ehci_reset(ehci); +  	err = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (err) {  		dev_err(&pdev->dev, "Failed to add USB HCD\n"); diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c index 54d1ab8aec4..c1eda73916c 100644 --- a/drivers/usb/host/ehci-vt8500.c +++ b/drivers/usb/host/ehci-vt8500.c @@ -132,6 +132,8 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)  	ehci_port_power(ehci, 1); +	ehci_reset(ehci); +  	ret = usb_add_hcd(hcd, pdev->resource[1].start,  			  IRQF_SHARED);  	if (ret == 0) { diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c index d661cf7de14..3d2e26cbb34 100644 --- a/drivers/usb/host/ehci-w90x900.c +++ b/drivers/usb/host/ehci-w90x900.c @@ -78,6 +78,8 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,  	if (irq < 0)  		goto err4; +	ehci_reset(ehci); +  	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (retval != 0)  		goto err4; diff --git a/drivers/usb/host/ehci-xls.c b/drivers/usb/host/ehci-xls.c index b4fb511d24b..72f08196f8c 100644 --- a/drivers/usb/host/ehci-xls.c +++ b/drivers/usb/host/ehci-xls.c @@ -69,7 +69,7 @@ int ehci_xls_probe_internal(const struct hc_driver *driver,  	}  	hcd->rsrc_start = res->start; -	hcd->rsrc_len = res->end - res->start + 1; +	hcd->rsrc_len = resource_size(res);  	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,  				driver->description)) { diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 4ed6d19f2a5..d2623747b48 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -824,17 +824,7 @@ static struct platform_driver of_fhci_driver = {  	.remove		= __devexit_p(of_fhci_remove),  }; -static int __init fhci_module_init(void) -{ -	return platform_driver_register(&of_fhci_driver); -} -module_init(fhci_module_init); - -static void __exit fhci_module_exit(void) -{ -	platform_driver_unregister(&of_fhci_driver); -} -module_exit(fhci_module_exit); +module_platform_driver(of_fhci_driver);  MODULE_DESCRIPTION("USB Freescale Host Controller Interface Driver");  MODULE_AUTHOR("Shlomi Gridish <gridish@freescale.com>, " diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 9037035ad1e..7916e56a725 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -297,17 +297,7 @@ static struct platform_driver fsl_usb2_mph_dr_driver = {  	.remove	= __devexit_p(fsl_usb2_mph_dr_of_remove),  }; -static int __init fsl_usb2_mph_dr_init(void) -{ -	return platform_driver_register(&fsl_usb2_mph_dr_driver); -} -module_init(fsl_usb2_mph_dr_init); - -static void __exit fsl_usb2_mph_dr_exit(void) -{ -	platform_driver_unregister(&fsl_usb2_mph_dr_driver); -} -module_exit(fsl_usb2_mph_dr_exit); +module_platform_driver(fsl_usb2_mph_dr_driver);  MODULE_DESCRIPTION("FSL MPH DR OF devices driver");  MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 43b3ca48d75..104730dabd2 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -776,7 +776,6 @@ static int hwahc_probe(struct usb_interface *usb_iface,  		goto error_alloc;  	}  	usb_hcd->wireless = 1; -	set_bit(HCD_FLAG_SAW_IRQ, &usb_hcd->flags);  	wusbhc = usb_hcd_to_wusbhc(usb_hcd);  	hwahc = container_of(wusbhc, struct hwahc, wusbhc);  	hwahc_init(hwahc); diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index dbf0f156ed9..ff471c1c165 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -1924,18 +1924,7 @@ static struct platform_driver imx21_hcd_driver = {  	.resume = NULL,  }; -static int __init imx21_hcd_init(void) -{ -	return platform_driver_register(&imx21_hcd_driver); -} - -static void __exit imx21_hcd_cleanup(void) -{ -	platform_driver_unregister(&imx21_hcd_driver); -} - -module_init(imx21_hcd_init); -module_exit(imx21_hcd_cleanup); +module_platform_driver(imx21_hcd_driver);  MODULE_DESCRIPTION("i.MX21 USB Host controller");  MODULE_AUTHOR("Martin Fuzzey"); diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 27dfab80ed8..fc72d44bf78 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -32,6 +32,13 @@ static struct kmem_cache *qtd_cachep;  static struct kmem_cache *qh_cachep;  static struct kmem_cache *urb_listitem_cachep; +enum queue_head_types { +	QH_CONTROL, +	QH_BULK, +	QH_INTERRUPT, +	QH_END +}; +  struct isp1760_hcd {  	u32 hcs_params;  	spinlock_t		lock; @@ -40,7 +47,7 @@ struct isp1760_hcd {  	struct slotinfo		int_slots[32];  	int			int_done_map;  	struct memory_chunk memory_pool[BLOCKS]; -	struct list_head	controlqhs, bulkqhs, interruptqhs; +	struct list_head	qh_list[QH_END];  	/* periodic schedule support */  #define	DEFAULT_I_TDPS		1024 @@ -406,12 +413,12 @@ static int priv_init(struct usb_hcd *hcd)  {  	struct isp1760_hcd		*priv = hcd_to_priv(hcd);  	u32			hcc_params; +	int i;  	spin_lock_init(&priv->lock); -	INIT_LIST_HEAD(&priv->interruptqhs); -	INIT_LIST_HEAD(&priv->controlqhs); -	INIT_LIST_HEAD(&priv->bulkqhs); +	for (i = 0; i < QH_END; i++) +		INIT_LIST_HEAD(&priv->qh_list[i]);  	/*  	 * hw default: 1K periodic list heads, one per frame. @@ -930,9 +937,9 @@ void schedule_ptds(struct usb_hcd *hcd)  	struct isp1760_hcd *priv;  	struct isp1760_qh *qh, *qh_next;  	struct list_head *ep_queue; -	struct usb_host_endpoint *ep;  	LIST_HEAD(urb_list);  	struct urb_listitem *urb_listitem, *urb_listitem_next; +	int i;  	if (!hcd) {  		WARN_ON(1); @@ -944,28 +951,13 @@ void schedule_ptds(struct usb_hcd *hcd)  	/*  	 * check finished/retired xfers, transfer payloads, call urb_done()  	 */ -	ep_queue = &priv->interruptqhs; -	while (ep_queue) { +	for (i = 0; i < QH_END; i++) { +		ep_queue = &priv->qh_list[i];  		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) { -			ep = list_entry(qh->qtd_list.next, struct isp1760_qtd, -							qtd_list)->urb->ep;  			collect_qtds(hcd, qh, &urb_list); -			if (list_empty(&qh->qtd_list)) { +			if (list_empty(&qh->qtd_list))  				list_del(&qh->qh_list); -				if (ep->hcpriv == NULL) { -					/* Endpoint has been disabled, so we -					can free the associated queue head. */ -					qh_free(qh); -				} -			}  		} - -		if (ep_queue == &priv->interruptqhs) -			ep_queue = &priv->controlqhs; -		else if (ep_queue == &priv->controlqhs) -			ep_queue = &priv->bulkqhs; -		else -			ep_queue = NULL;  	}  	list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list, @@ -998,17 +990,10 @@ void schedule_ptds(struct usb_hcd *hcd)  	 *  	 * I'm sure this scheme could be improved upon!  	 */ -	ep_queue = &priv->controlqhs; -	while (ep_queue) { +	for (i = 0; i < QH_END; i++) { +		ep_queue = &priv->qh_list[i];  		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)  			enqueue_qtds(hcd, qh); - -		if (ep_queue == &priv->controlqhs) -			ep_queue = &priv->interruptqhs; -		else if (ep_queue == &priv->interruptqhs) -			ep_queue = &priv->bulkqhs; -		else -			ep_queue = NULL;  	}  } @@ -1543,16 +1528,16 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,  	switch (usb_pipetype(urb->pipe)) {  	case PIPE_CONTROL: -		ep_queue = &priv->controlqhs; +		ep_queue = &priv->qh_list[QH_CONTROL];  		break;  	case PIPE_BULK: -		ep_queue = &priv->bulkqhs; +		ep_queue = &priv->qh_list[QH_BULK];  		break;  	case PIPE_INTERRUPT:  		if (urb->interval < 0)  			return -EINVAL;  		/* FIXME: Check bandwidth  */ -		ep_queue = &priv->interruptqhs; +		ep_queue = &priv->qh_list[QH_INTERRUPT];  		break;  	case PIPE_ISOCHRONOUS:  		dev_err(hcd->self.controller, "%s: isochronous USB packets " @@ -1714,8 +1699,8 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,  {  	struct isp1760_hcd *priv = hcd_to_priv(hcd);  	unsigned long spinflags; -	struct isp1760_qh *qh; -	struct isp1760_qtd *qtd; +	struct isp1760_qh *qh, *qh_iter; +	int i;  	spin_lock_irqsave(&priv->lock, spinflags); @@ -1723,14 +1708,17 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,  	if (!qh)  		goto out; -	list_for_each_entry(qtd, &qh->qtd_list, qtd_list) -		if (qtd->status != QTD_RETIRE) { -			dequeue_urb_from_qtd(hcd, qh, qtd); -			qtd->urb->status = -ECONNRESET; -		} +	WARN_ON(!list_empty(&qh->qtd_list)); +	for (i = 0; i < QH_END; i++) +		list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list) +			if (qh_iter == qh) { +				list_del(&qh_iter->qh_list); +				i = QH_END; +				break; +			} +	qh_free(qh);  	ep->hcpriv = NULL; -	/* Cannot free qh here since it will be parsed by schedule_ptds() */  	schedule_ptds(hcd); diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 2ac4ac2e4ef..4592dc17a9f 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -47,23 +47,27 @@ static int of_isp1760_probe(struct platform_device *dev)  	int virq;  	resource_size_t res_len;  	int ret; -	const unsigned int *prop;  	unsigned int devflags = 0;  	enum of_gpio_flags gpio_flags; +	u32 bus_width = 0;  	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);  	if (!drvdata)  		return -ENOMEM;  	ret = of_address_to_resource(dp, 0, &memory); -	if (ret) -		return -ENXIO; +	if (ret) { +		ret = -ENXIO; +		goto free_data; +	}  	res_len = resource_size(&memory);  	res = request_mem_region(memory.start, res_len, dev_name(&dev->dev)); -	if (!res) -		return -EBUSY; +	if (!res) { +		ret = -EBUSY; +		goto free_data; +	}  	if (of_irq_map_one(dp, 0, &oirq)) {  		ret = -ENODEV; @@ -77,8 +81,8 @@ static int of_isp1760_probe(struct platform_device *dev)  		devflags |= ISP1760_FLAG_ISP1761;  	/* Some systems wire up only 16 of the 32 data lines */ -	prop = of_get_property(dp, "bus-width", NULL); -	if (prop && *prop == 16) +	of_property_read_u32(dp, "bus-width", &bus_width); +	if (bus_width == 16)  		devflags |= ISP1760_FLAG_BUS_WIDTH_16;  	if (of_get_property(dp, "port1-otg", NULL) != NULL) @@ -125,6 +129,7 @@ free_gpio:  		gpio_free(drvdata->rst_gpio);  release_reg:  	release_mem_region(memory.start, res_len); +free_data:  	kfree(drvdata);  	return ret;  } diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 9b66df8278f..40d886adff5 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -173,12 +173,9 @@ static int ohci_hcd_au1xxx_drv_suspend(struct device *dev)  	 * mark HW unaccessible, bail out if RH has been resumed. Use  	 * the spinlock to properly synchronize with possible pending  	 * RH suspend or resume activity. -	 * -	 * This is still racy as hcd->state is manipulated outside of -	 * any locks =P But that will be a different fix.  	 */  	spin_lock_irqsave(&ohci->lock, flags); -	if (hcd->state != HC_STATE_SUSPENDED) { +	if (ohci->rh_state != OHCI_RH_SUSPENDED) {  		rc = -EINVAL;  		goto bail;  	} diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index d7d34492934..5179fcd73d8 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -127,6 +127,19 @@ static char *hcfs2string (int state)  	return "?";  } +static const char *rh_state_string(struct ohci_hcd *ohci) +{ +	switch (ohci->rh_state) { +	case OHCI_RH_HALTED: +		return "halted"; +	case OHCI_RH_SUSPENDED: +		return "suspended"; +	case OHCI_RH_RUNNING: +		return "running"; +	} +	return "?"; +} +  // dump control and status registers  static void  ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) @@ -136,9 +149,10 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)  	temp = ohci_readl (controller, ®s->revision) & 0xff;  	ohci_dbg_sw (controller, next, size, -		"OHCI %d.%d, %s legacy support registers\n", +		"OHCI %d.%d, %s legacy support registers, rh state %s\n",  		0x03 & (temp >> 4), (temp & 0x0f), -		(temp & 0x0100) ? "with" : "NO"); +		(temp & 0x0100) ? "with" : "NO", +		rh_state_string(controller));  	temp = ohci_readl (controller, ®s->control);  	ohci_dbg_sw (controller, next, size, diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index dc45d489d00..3d63574d2c7 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -179,8 +179,6 @@ static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_  	ohci->next_statechange = jiffies;  	ep93xx_stop_hc(&pdev->dev); -	hcd->state = HC_STATE_SUSPENDED; -  	return 0;  } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index b2639191549..4fa5d8c4d23 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -209,7 +209,7 @@ static int ohci_urb_enqueue (  		retval = -ENODEV;  		goto fail;  	} -	if (!HC_IS_RUNNING(hcd->state)) { +	if (ohci->rh_state != OHCI_RH_RUNNING) {  		retval = -ENODEV;  		goto fail;  	} @@ -274,7 +274,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  	rc = usb_hcd_check_unlink_urb(hcd, urb, status);  	if (rc) {  		;	/* Do nothing */ -	} else if (HC_IS_RUNNING(hcd->state)) { +	} else if (ohci->rh_state == OHCI_RH_RUNNING) {  		urb_priv_t  *urb_priv;  		/* Unless an IRQ completed the unlink while it was being @@ -321,7 +321,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)  rescan:  	spin_lock_irqsave (&ohci->lock, flags); -	if (!HC_IS_RUNNING (hcd->state)) { +	if (ohci->rh_state != OHCI_RH_RUNNING) {  sanitize:  		ed->state = ED_IDLE;  		if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) @@ -377,6 +377,7 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)  	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);  	ohci->hc_control &= OHCI_CTRL_RWC;  	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); +	ohci->rh_state = OHCI_RH_HALTED;  }  /* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and @@ -500,7 +501,7 @@ static int ohci_init (struct ohci_hcd *ohci)  	if (distrust_firmware)  		ohci->flags |= OHCI_QUIRK_HUB_POWER; -	disable (ohci); +	ohci->rh_state = OHCI_RH_HALTED;  	ohci->regs = hcd->regs;  	/* REVISIT this BIOS handshake is now moved into PCI "quirks", and @@ -575,7 +576,7 @@ static int ohci_run (struct ohci_hcd *ohci)  	int			first = ohci->fminterval == 0;  	struct usb_hcd		*hcd = ohci_to_hcd(ohci); -	disable (ohci); +	ohci->rh_state = OHCI_RH_HALTED;  	/* boot firmware should have set this up (5.1.1.3.1) */  	if (first) { @@ -688,7 +689,7 @@ retry:  	ohci->hc_control &= OHCI_CTRL_RWC;  	ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;  	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); -	hcd->state = HC_STATE_RUNNING; +	ohci->rh_state = OHCI_RH_RUNNING;  	/* wake on ConnectStatusChange, matching external hubs */  	ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status); @@ -725,7 +726,6 @@ retry:  	// POTPGT delay is bits 24-31, in 2 ms units.  	mdelay ((val >> 23) & 0x1fe); -	hcd->state = HC_STATE_RUNNING;  	if (quirk_zfmicro(ohci)) {  		/* Create timer to watch for bad queue state on ZF Micro */ @@ -761,7 +761,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)  	 * of dead, unclocked, or unplugged (CardBus...) devices  	 */  	if (ints == ~(u32)0) { -		disable (ohci); +		ohci->rh_state = OHCI_RH_HALTED;  		ohci_dbg (ohci, "device removed!\n");  		usb_hc_died(hcd);  		return IRQ_HANDLED; @@ -771,7 +771,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)  	ints &= ohci_readl(ohci, ®s->intrenable);  	/* interrupt for some other device? */ -	if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT)) +	if (ints == 0 || unlikely(ohci->rh_state == OHCI_RH_HALTED))  		return IRQ_NOTMINE;  	if (ints & OHCI_INTR_UE) { @@ -786,8 +786,8 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)  			schedule_work (&ohci->nec_work);  		} else { -			disable (ohci);  			ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); +			ohci->rh_state = OHCI_RH_HALTED;  			usb_hc_died(hcd);  		} @@ -871,11 +871,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)  	if ((ints & OHCI_INTR_SF) != 0  			&& !ohci->ed_rm_list  			&& !ohci->ed_to_check -			&& HC_IS_RUNNING(hcd->state)) +			&& ohci->rh_state == OHCI_RH_RUNNING)  		ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable);  	spin_unlock (&ohci->lock); -	if (HC_IS_RUNNING(hcd->state)) { +	if (ohci->rh_state == OHCI_RH_RUNNING) {  		ohci_writel (ohci, ints, ®s->intrstatus);  		ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable);  		// flush those writes @@ -929,7 +929,7 @@ static int ohci_restart (struct ohci_hcd *ohci)  	struct urb_priv *priv;  	spin_lock_irq(&ohci->lock); -	disable (ohci); +	ohci->rh_state = OHCI_RH_HALTED;  	/* Recycle any "live" eds/tds (and urbs). */  	if (!list_empty (&ohci->pending)) @@ -1111,7 +1111,7 @@ MODULE_LICENSE ("GPL");  #define PLATFORM_DRIVER		ohci_hcd_ath79_driver  #endif -#ifdef CONFIG_NLM_XLR +#ifdef CONFIG_CPU_XLR  #include "ohci-xls.c"  #define PLATFORM_DRIVER		ohci_xls_driver  #endif diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 2f00040fc40..836772dfabd 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -111,6 +111,7 @@ __acquires(ohci->lock)  	if (!autostop) {  		ohci->next_statechange = jiffies + msecs_to_jiffies (5);  		ohci->autostop = 0; +		ohci->rh_state = OHCI_RH_SUSPENDED;  	}  done: @@ -140,7 +141,7 @@ __acquires(ohci->lock)  	if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {  		/* this can happen after resuming a swsusp snapshot */ -		if (hcd->state == HC_STATE_RESUMING) { +		if (ohci->rh_state != OHCI_RH_RUNNING) {  			ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",  					ohci->hc_control);  			status = -EBUSY; @@ -274,6 +275,7 @@ skip_resume:  		(void) ohci_readl (ohci, &ohci->regs->control);  	} +	ohci->rh_state = OHCI_RH_RUNNING;  	return 0;  } @@ -336,11 +338,8 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)  	/* If needed, reinitialize and suspend the root hub */  	if (need_reinit) {  		spin_lock_irq(&ohci->lock); -		hcd->state = HC_STATE_RESUMING;  		ohci_rh_resume(ohci); -		hcd->state = HC_STATE_QUIESCING;  		ohci_rh_suspend(ohci, 0); -		hcd->state = HC_STATE_SUSPENDED;  		spin_unlock_irq(&ohci->lock);  	} diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index e4b8782cc6e..db3968656d2 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -516,7 +516,6 @@ static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message)  	ohci->next_statechange = jiffies;  	omap_ohci_clock_power(0); -	ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;  	return 0;  } diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index bc01b064585..6109810cc2d 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -308,12 +308,9 @@ static int ohci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)  	 * mark HW unaccessible, bail out if RH has been resumed. Use  	 * the spinlock to properly synchronize with possible pending  	 * RH suspend or resume activity. -	 * -	 * This is still racy as hcd->state is manipulated outside of -	 * any locks =P But that will be a different fix.  	 */  	spin_lock_irqsave (&ohci->lock, flags); -	if (hcd->state != HC_STATE_SUSPENDED) { +	if (ohci->rh_state != OHCI_RH_SUSPENDED) {  		rc = -EINVAL;  		goto bail;  	} diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 29dfefe1c72..6313e4439f3 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -502,8 +502,6 @@ static int ohci_hcd_pxa27x_drv_suspend(struct device *dev)  	ohci->ohci.next_statechange = jiffies;  	pxa27x_stop_hc(ohci, dev); -	hcd->state = HC_STATE_SUSPENDED; -  	return 0;  } diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 15dc51ded61..c5a1ea9145f 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -912,7 +912,7 @@ rescan_all:  		/* only take off EDs that the HC isn't using, accounting for  		 * frame counter wraps and EDs with partially retired TDs  		 */ -		if (likely (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) { +		if (likely(ohci->rh_state == OHCI_RH_RUNNING)) {  			if (tick_before (tick, ed->tick)) {  skip_ed:  				last = &ed->ed_next; @@ -1012,7 +1012,7 @@ rescan_this:  		/* but if there's work queued, reschedule */  		if (!list_empty (&ed->td_list)) { -			if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)) +			if (ohci->rh_state == OHCI_RH_RUNNING)  				ed_schedule (ohci, ed);  		} @@ -1021,9 +1021,7 @@ rescan_this:  	}  	/* maybe reenable control and bulk lists */ -	if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state) -			&& ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING -			&& !ohci->ed_rm_list) { +	if (ohci->rh_state == OHCI_RH_RUNNING && !ohci->ed_rm_list) {  		u32	command = 0, control = 0;  		if (ohci->ed_controltail) { diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index a1877c47601..56dcf069246 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -486,15 +486,66 @@ static int __devexit ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)  	return 0;  } +#ifdef CONFIG_PM +static int ohci_hcd_s3c2410_drv_suspend(struct device *dev) +{ +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct ohci_hcd *ohci = hcd_to_ohci(hcd); +	struct platform_device *pdev = to_platform_device(dev); +	unsigned long flags; +	int rc = 0; + +	/* +	 * Root hub was already suspended. Disable irq emission and +	 * mark HW unaccessible, bail out if RH has been resumed. Use +	 * the spinlock to properly synchronize with possible pending +	 * RH suspend or resume activity. +	 */ +	spin_lock_irqsave(&ohci->lock, flags); +	if (ohci->rh_state != OHCI_RH_SUSPENDED) { +		rc = -EINVAL; +		goto bail; +	} + +	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + +	s3c2410_stop_hc(pdev); +bail: +	spin_unlock_irqrestore(&ohci->lock, flags); + +	return rc; +} + +static int ohci_hcd_s3c2410_drv_resume(struct device *dev) +{ +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct platform_device *pdev = to_platform_device(dev); + +	s3c2410_start_hc(pdev, hcd); + +	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); +	ohci_finish_controller_resume(hcd); + +	return 0; +} +#else +#define ohci_hcd_s3c2410_drv_suspend	NULL +#define ohci_hcd_s3c2410_drv_resume	NULL +#endif + +static const struct dev_pm_ops ohci_hcd_s3c2410_pm_ops = { +	.suspend	= ohci_hcd_s3c2410_drv_suspend, +	.resume		= ohci_hcd_s3c2410_drv_resume, +}; +  static struct platform_driver ohci_hcd_s3c2410_driver = {  	.probe		= ohci_hcd_s3c2410_drv_probe,  	.remove		= __devexit_p(ohci_hcd_s3c2410_drv_remove),  	.shutdown	= usb_hcd_platform_shutdown, -	/*.suspend	= ohci_hcd_s3c2410_drv_suspend, */ -	/*.resume	= ohci_hcd_s3c2410_drv_resume, */  	.driver		= {  		.owner	= THIS_MODULE,  		.name	= "s3c2410-ohci", +		.pm	= &ohci_hcd_s3c2410_pm_ops,  	},  }; diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c index afc4eb6bb9d..84686d90805 100644 --- a/drivers/usb/host/ohci-sh.c +++ b/drivers/usb/host/ohci-sh.c @@ -29,7 +29,6 @@ static int ohci_sh_start(struct usb_hcd *hcd)  	ohci_hcd_init(ohci);  	ohci_init(ohci);  	ohci_run(ohci); -	hcd->state = HC_STATE_RUNNING;  	return 0;  } diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index 968cea2b6d4..5596ac2ba1c 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -224,7 +224,6 @@ static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg)  	ohci->next_statechange = jiffies;  	sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0); -	ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;  	return 0;  } diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index 69874654f3b..95c16489e88 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -203,7 +203,6 @@ static int spear_ohci_hcd_drv_suspend(struct platform_device *dev,  	ohci->next_statechange = jiffies;  	spear_stop_ohci(ohci_p); -	ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;  	return 0;  } diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index 06331d93117..120bfe6ede3 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -318,9 +318,6 @@ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t s  		if (ret)  			return ret;  	} - -	hcd->state = HC_STATE_SUSPENDED; -  	return 0;  } diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c index a3a9c6f45b9..a2247867af8 100644 --- a/drivers/usb/host/ohci-xls.c +++ b/drivers/usb/host/ohci-xls.c @@ -40,7 +40,7 @@ static int ohci_xls_probe_internal(const struct hc_driver *driver,  		goto err1;  	}  	hcd->rsrc_start = res->start; -	hcd->rsrc_len = res->end - res->start + 1; +	hcd->rsrc_len = resource_size(res);  	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,  			driver->description)) { diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 0795b934d00..8ff6f7ea96f 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -344,6 +344,12 @@ typedef struct urb_priv {   * a subset of what the full implementation needs. (Linus)   */ +enum ohci_rh_state { +	OHCI_RH_HALTED, +	OHCI_RH_SUSPENDED, +	OHCI_RH_RUNNING +}; +  struct ohci_hcd {  	spinlock_t		lock; @@ -384,6 +390,7 @@ struct ohci_hcd {  	/*  	 * driver state  	 */ +	enum ohci_rh_state	rh_state;  	int			num_ports;  	int			load [NUM_INTS];  	u32			hc_control;	/* copy of hc control reg */ @@ -679,11 +686,6 @@ static inline u16 ohci_hwPSW(const struct ohci_hcd *ohci,  /*-------------------------------------------------------------------------*/ -static inline void disable (struct ohci_hcd *ohci) -{ -	ohci_to_hcd(ohci)->state = HC_STATE_HALT; -} -  #define	FI			0x2edf		/* 12000 bits per frame (-1) */  #define	FSMP(fi)		(0x7fff & ((6 * ((fi) - 210)) / 7))  #define	FIT			(1 << 31) @@ -707,7 +709,7 @@ static inline void periodic_reinit (struct ohci_hcd *ohci)  #define read_roothub(hc, register, mask) ({ \  	u32 temp = ohci_readl (hc, &hc->regs->roothub.register); \  	if (temp == -1) \ -		disable (hc); \ +		hc->rh_state = OHCI_RH_HALTED; \  	else if (hc->flags & OHCI_QUIRK_AMD756) \  		while (temp & mask) \  			temp = ohci_readl (hc, &hc->regs->roothub.register); \ diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index dcd889803f0..6f62de5c6e3 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -3951,24 +3951,7 @@ static struct platform_driver oxu_driver = {  	}  }; -static int __init oxu_module_init(void) -{ -	int retval = 0; - -	retval = platform_driver_register(&oxu_driver); -	if (retval < 0) -		return retval; - -	return retval; -} - -static void __exit oxu_module_cleanup(void) -{ -	platform_driver_unregister(&oxu_driver); -} - -module_init(oxu_module_init); -module_exit(oxu_module_cleanup); +module_platform_driver(oxu_driver);  MODULE_DESCRIPTION("Oxford OXU210HP HCD driver - ver. " DRIVER_VERSION);  MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index f6ca80ee4ce..d2c6f5ac462 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -943,7 +943,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,  	if (usb_pipein(urb->pipe))  		status |= TD_CTRL_SPD; -	i = urb->num_sgs; +	i = urb->num_mapped_sgs;  	if (len > 0 && i > 0) {  		sg = urb->sg;  		data = sg_dma_address(sg); diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index a403b53e86b..76083ae9213 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -443,7 +443,7 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u  	remaining = urb->transfer_buffer_length; -	for_each_sg(urb->sg, sg, urb->num_sgs, i) { +	for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {  		dma_addr_t dma_addr;  		size_t dma_remaining;  		dma_addr_t sp, ep; @@ -561,7 +561,7 @@ static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,  	remaining = urb->transfer_buffer_length; -	for_each_sg(urb->sg, sg, urb->num_sgs, i) { +	for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {  		size_t len;  		size_t sg_remaining;  		void *orig; diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 430e88fd3f6..35e257f79c7 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -57,17 +57,15 @@ static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,  	desc->bHubContrCurrent = 0;  	desc->bNbrPorts = ports; -	/* Ugh, these should be #defines, FIXME */ -	/* Using table 11-13 in USB 2.0 spec. */  	temp = 0; -	/* Bits 1:0 - support port power switching, or power always on */ +	/* Bits 1:0 - support per-port power switching, or power always on */  	if (HCC_PPC(xhci->hcc_params)) -		temp |= 0x0001; +		temp |= HUB_CHAR_INDV_PORT_LPSM;  	else -		temp |= 0x0002; +		temp |= HUB_CHAR_NO_LPSM;  	/* Bit  2 - root hubs are not part of a compound device */  	/* Bits 4:3 - individual port over current protection */ -	temp |= 0x0008; +	temp |= HUB_CHAR_INDV_PORT_OCPM;  	/* Bits 6:5 - no TTs in root ports */  	/* Bit  7 - no port indicators */  	desc->wHubCharacteristics = cpu_to_le16(temp); @@ -86,9 +84,9 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,  	ports = xhci->num_usb2_ports;  	xhci_common_hub_descriptor(xhci, desc, ports); -	desc->bDescriptorType = 0x29; +	desc->bDescriptorType = USB_DT_HUB;  	temp = 1 + (ports / 8); -	desc->bDescLength = 7 + 2 * temp; +	desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp;  	/* The Device Removable bits are reported on a byte granularity.  	 * If the port doesn't exist within that byte, the bit is set to 0. @@ -137,8 +135,8 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,  	ports = xhci->num_usb3_ports;  	xhci_common_hub_descriptor(xhci, desc, ports); -	desc->bDescriptorType = 0x2a; -	desc->bDescLength = 12; +	desc->bDescriptorType = USB_DT_SS_HUB; +	desc->bDescLength = USB_DT_SS_HUB_SIZE;  	/* header decode latency should be zero for roothubs,  	 * see section 4.23.5.2. diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 0e4b25fa3bc..36cbe2226a4 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -42,15 +42,12 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flag  	seg = kzalloc(sizeof *seg, flags);  	if (!seg)  		return NULL; -	xhci_dbg(xhci, "Allocating priv segment structure at %p\n", seg);  	seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma);  	if (!seg->trbs) {  		kfree(seg);  		return NULL;  	} -	xhci_dbg(xhci, "// Allocating segment at %p (virtual) 0x%llx (DMA)\n", -			seg->trbs, (unsigned long long)dma);  	memset(seg->trbs, 0, SEGMENT_SIZE);  	seg->dma = dma; @@ -62,12 +59,9 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flag  static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)  {  	if (seg->trbs) { -		xhci_dbg(xhci, "Freeing DMA segment at %p (virtual) 0x%llx (DMA)\n", -				seg->trbs, (unsigned long long)seg->dma);  		dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);  		seg->trbs = NULL;  	} -	xhci_dbg(xhci, "Freeing priv segment structure at %p\n", seg);  	kfree(seg);  } @@ -101,9 +95,6 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,  			val |= TRB_CHAIN;  		prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);  	} -	xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n", -			(unsigned long long)prev->dma, -			(unsigned long long)next->dma);  }  /* XXX: Do we need the hcd structure in all these functions? */ @@ -117,7 +108,6 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)  	if (ring->first_seg) {  		first_seg = ring->first_seg;  		seg = first_seg->next; -		xhci_dbg(xhci, "Freeing ring at %p\n", ring);  		while (seg != first_seg) {  			struct xhci_segment *next = seg->next;  			xhci_segment_free(xhci, seg); @@ -160,7 +150,6 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,  	struct xhci_segment	*prev;  	ring = kzalloc(sizeof *(ring), flags); -	xhci_dbg(xhci, "Allocating ring at %p\n", ring);  	if (!ring)  		return NULL; @@ -191,9 +180,6 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,  		/* See section 4.9.2.1 and 6.4.4.1 */  		prev->trbs[TRBS_PER_SEGMENT-1].link.control |=  			cpu_to_le32(LINK_TOGGLE); -		xhci_dbg(xhci, "Wrote link toggle flag to" -				" segment %p (virtual), 0x%llx (DMA)\n", -				prev, (unsigned long long)prev->dma);  	}  	xhci_initialize_ring_info(ring);  	return ring; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9f1d4b15d81..b90e1386418 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -155,10 +155,6 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer  	while (last_trb(xhci, ring, ring->deq_seg, next)) {  		if (consumer && last_trb_on_last_seg(xhci, ring, ring->deq_seg, next)) {  			ring->cycle_state = (ring->cycle_state ? 0 : 1); -			if (!in_interrupt()) -				xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n", -						ring, -						(unsigned int) ring->cycle_state);  		}  		ring->deq_seg = ring->deq_seg->next;  		ring->dequeue = ring->deq_seg->trbs; @@ -231,10 +227,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,  			/* Toggle the cycle bit after the last ring segment. */  			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {  				ring->cycle_state = (ring->cycle_state ? 0 : 1); -				if (!in_interrupt()) -					xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n", -							ring, -							(unsigned int) ring->cycle_state);  			}  		}  		ring->enq_seg = ring->enq_seg->next; @@ -560,12 +552,9 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,  					cpu_to_le32(TRB_CYCLE);  			cur_trb->generic.field[3] |= cpu_to_le32(  				TRB_TYPE(TRB_TR_NOOP)); -			xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) " -					"in seg %p (0x%llx dma)\n", -					cur_trb, -					(unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb), -					cur_seg, -					(unsigned long long)cur_seg->dma); +			xhci_dbg(xhci, "TRB to noop at offset 0x%llx\n", +					(unsigned long long) +					xhci_trb_virt_to_dma(cur_seg, cur_trb));  		}  		if (cur_trb == cur_td->last_trb)  			break; @@ -705,9 +694,9 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,  	 */  	list_for_each(entry, &ep->cancelled_td_list) {  		cur_td = list_entry(entry, struct xhci_td, cancelled_td_list); -		xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n", -				cur_td->first_trb, -				(unsigned long long)xhci_trb_virt_to_dma(cur_td->start_seg, cur_td->first_trb)); +		xhci_dbg(xhci, "Removing canceled TD starting at 0x%llx (dma).\n", +				(unsigned long long)xhci_trb_virt_to_dma( +					cur_td->start_seg, cur_td->first_trb));  		ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb);  		if (!ep_ring) {  			/* This shouldn't happen unless a driver is mucking @@ -1627,7 +1616,6 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,  	ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);  	trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); -	xhci_debug_trb(xhci, xhci->event_ring->dequeue);  	switch (trb_comp_code) {  	case COMP_SUCCESS:  		if (event_trb == ep_ring->dequeue) { @@ -1643,7 +1631,6 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,  		}  		break;  	case COMP_SHORT_TX: -		xhci_warn(xhci, "WARN: short transfer on control ep\n");  		if (td->urb->transfer_flags & URB_SHORT_NOT_OK)  			*status = -EREMOTEIO;  		else @@ -1946,6 +1933,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,  	xdev = xhci->devs[slot_id];  	if (!xdev) {  		xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n"); +		xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n", +			 (unsigned long long) xhci_trb_virt_to_dma( +				 xhci->event_ring->deq_seg, +				 xhci->event_ring->dequeue), +			 lower_32_bits(le64_to_cpu(event->buffer)), +			 upper_32_bits(le64_to_cpu(event->buffer)), +			 le32_to_cpu(event->transfer_len), +			 le32_to_cpu(event->flags)); +		xhci_dbg(xhci, "Event ring:\n"); +		xhci_debug_segment(xhci, xhci->event_ring->deq_seg);  		return -ENODEV;  	} @@ -1959,6 +1956,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,  	    EP_STATE_DISABLED) {  		xhci_err(xhci, "ERROR Transfer event for disabled endpoint "  				"or incorrect stream ring\n"); +		xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n", +			 (unsigned long long) xhci_trb_virt_to_dma( +				 xhci->event_ring->deq_seg, +				 xhci->event_ring->dequeue), +			 lower_32_bits(le64_to_cpu(event->buffer)), +			 upper_32_bits(le64_to_cpu(event->buffer)), +			 le32_to_cpu(event->transfer_len), +			 le32_to_cpu(event->flags)); +		xhci_dbg(xhci, "Event ring:\n"); +		xhci_debug_segment(xhci, xhci->event_ring->deq_seg);  		return -ENODEV;  	} @@ -1985,7 +1992,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,  		xhci_dbg(xhci, "Stopped on No-op or Link TRB\n");  		break;  	case COMP_STALL: -		xhci_warn(xhci, "WARN: Stalled endpoint\n"); +		xhci_dbg(xhci, "Stalled endpoint\n");  		ep->ep_state |= EP_HALTED;  		status = -EPIPE;  		break; @@ -1995,11 +2002,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,  		break;  	case COMP_SPLIT_ERR:  	case COMP_TX_ERR: -		xhci_warn(xhci, "WARN: transfer error on endpoint\n"); +		xhci_dbg(xhci, "Transfer error on endpoint\n");  		status = -EPROTO;  		break;  	case COMP_BABBLE: -		xhci_warn(xhci, "WARN: babble error on endpoint\n"); +		xhci_dbg(xhci, "Babble error on endpoint\n");  		status = -EOVERFLOW;  		break;  	case COMP_DB_ERR: @@ -2390,17 +2397,7 @@ hw_died:  irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)  { -	irqreturn_t ret; -	struct xhci_hcd *xhci; - -	xhci = hcd_to_xhci(hcd); -	set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); -	if (xhci->shared_hcd) -		set_bit(HCD_FLAG_SAW_IRQ, &xhci->shared_hcd->flags); - -	ret = xhci_irq(hcd); - -	return ret; +	return xhci_irq(hcd);  }  /****		Endpoint Ring Operations	****/ @@ -2488,11 +2485,6 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,  			/* Toggle the cycle bit after the last ring segment. */  			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {  				ring->cycle_state = (ring->cycle_state ? 0 : 1); -				if (!in_interrupt()) { -					xhci_dbg(xhci, "queue_trb: Toggle cycle " -						"state for ring %p = %i\n", -						ring, (unsigned int)ring->cycle_state); -				}  			}  			ring->enq_seg = ring->enq_seg->next;  			ring->enqueue = ring->enq_seg->trbs; @@ -2561,13 +2553,11 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)  	struct scatterlist *sg;  	sg = NULL; -	num_sgs = urb->num_sgs; +	num_sgs = urb->num_mapped_sgs;  	temp = urb->transfer_buffer_length; -	xhci_dbg(xhci, "count sg list trbs: \n");  	num_trbs = 0;  	for_each_sg(urb->sg, sg, num_sgs, i) { -		unsigned int previous_total_trbs = num_trbs;  		unsigned int len = sg_dma_len(sg);  		/* Scatter gather list entries may cross 64KB boundaries */ @@ -2582,22 +2572,11 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)  			num_trbs++;  			running_total += TRB_MAX_BUFF_SIZE;  		} -		xhci_dbg(xhci, " sg #%d: dma = %#llx, len = %#x (%d), num_trbs = %d\n", -				i, (unsigned long long)sg_dma_address(sg), -				len, len, num_trbs - previous_total_trbs); -  		len = min_t(int, len, temp);  		temp -= len;  		if (temp == 0)  			break;  	} -	xhci_dbg(xhci, "\n"); -	if (!in_interrupt()) -		xhci_dbg(xhci, "ep %#x - urb len = %d, sglist used, " -				"num_trbs = %d\n", -				urb->ep->desc.bEndpointAddress, -				urb->transfer_buffer_length, -				num_trbs);  	return num_trbs;  } @@ -2745,7 +2724,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  		return -EINVAL;  	num_trbs = count_sg_trbs_needed(xhci, urb); -	num_sgs = urb->num_sgs; +	num_sgs = urb->num_mapped_sgs;  	total_packet_count = roundup(urb->transfer_buffer_length,  			usb_endpoint_maxp(&urb->ep->desc)); @@ -2783,8 +2762,6 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  	trb_buff_len = min_t(int, trb_buff_len, this_sg_len);  	if (trb_buff_len > urb->transfer_buffer_length)  		trb_buff_len = urb->transfer_buffer_length; -	xhci_dbg(xhci, "First length to xfer from 1st sglist entry = %u\n", -			trb_buff_len);  	first_trb = true;  	/* Queue the first TRB, even if it's zero-length */ @@ -2816,11 +2793,6 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  		if (usb_urb_dir_in(urb))  			field |= TRB_ISP; -		xhci_dbg(xhci, " sg entry: dma = %#x, len = %#x (%d), " -				"64KB boundary at %#x, end dma = %#x\n", -				(unsigned int) addr, trb_buff_len, trb_buff_len, -				(unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), -				(unsigned int) addr + trb_buff_len);  		if (TRB_MAX_BUFF_SIZE -  				(addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) {  			xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n"); @@ -2926,15 +2898,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  	}  	/* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */ -	if (!in_interrupt()) -		xhci_dbg(xhci, "ep %#x - urb len = %#x (%d), " -				"addr = %#llx, num_trbs = %d\n", -				urb->ep->desc.bEndpointAddress, -				urb->transfer_buffer_length, -				urb->transfer_buffer_length, -				(unsigned long long)urb->transfer_dma, -				num_trbs); -  	ret = prepare_transfer(xhci, xhci->devs[slot_id],  			ep_index, urb->stream_id,  			num_trbs, urb, 0, false, mem_flags); @@ -3055,9 +3018,6 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  	if (!urb->setup_packet)  		return -EINVAL; -	if (!in_interrupt()) -		xhci_dbg(xhci, "Queueing ctrl tx for slot id %d, ep %d\n", -				slot_id, ep_index);  	/* 1 TRB for setup, 1 for status */  	num_trbs = 2;  	/* @@ -3249,15 +3209,6 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  		return -EINVAL;  	} -	if (!in_interrupt()) -		xhci_dbg(xhci, "ep %#x - urb len = %#x (%d)," -				" addr = %#llx, num_tds = %d\n", -				urb->ep->desc.bEndpointAddress, -				urb->transfer_buffer_length, -				urb->transfer_buffer_length, -				(unsigned long long)urb->transfer_dma, -				num_tds); -  	start_addr = (u64) urb->transfer_dma;  	start_trb = &ep_ring->enqueue->generic;  	start_cycle = ep_ring->cycle_state; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index a1afb7c39f7..6bbe3c3a711 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -200,14 +200,14 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)  	ret = pci_enable_msi(pdev);  	if (ret) { -		xhci_err(xhci, "failed to allocate MSI entry\n"); +		xhci_dbg(xhci, "failed to allocate MSI entry\n");  		return ret;  	}  	ret = request_irq(pdev->irq, (irq_handler_t)xhci_msi_irq,  				0, "xhci_hcd", xhci_to_hcd(xhci));  	if (ret) { -		xhci_err(xhci, "disable MSI interrupt\n"); +		xhci_dbg(xhci, "disable MSI interrupt\n");  		pci_disable_msi(pdev);  	} @@ -270,7 +270,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)  	ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);  	if (ret) { -		xhci_err(xhci, "Failed to enable MSI-X\n"); +		xhci_dbg(xhci, "Failed to enable MSI-X\n");  		goto free_entries;  	} @@ -286,7 +286,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)  	return ret;  disable_msix: -	xhci_err(xhci, "disable MSI-X interrupt\n"); +	xhci_dbg(xhci, "disable MSI-X interrupt\n");  	xhci_free_irq(xhci);  	pci_disable_msix(pdev);  free_entries: @@ -1333,9 +1333,6 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  		goto done;  	} -	xhci_dbg(xhci, "Cancel URB %p\n", urb); -	xhci_dbg(xhci, "Event ring:\n"); -	xhci_debug_ring(xhci, xhci->event_ring);  	ep_index = xhci_get_endpoint_index(&urb->ep->desc);  	ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];  	ep_ring = xhci_urb_to_transfer_ring(xhci, urb); @@ -1344,12 +1341,18 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  		goto done;  	} -	xhci_dbg(xhci, "Endpoint ring:\n"); -	xhci_debug_ring(xhci, ep_ring); -  	urb_priv = urb->hcpriv; +	i = urb_priv->td_cnt; +	if (i < urb_priv->length) +		xhci_dbg(xhci, "Cancel URB %p, dev %s, ep 0x%x, " +				"starting at offset 0x%llx\n", +				urb, urb->dev->devpath, +				urb->ep->desc.bEndpointAddress, +				(unsigned long long) xhci_trb_virt_to_dma( +					urb_priv->td[i]->start_seg, +					urb_priv->td[i]->first_trb)); -	for (i = urb_priv->td_cnt; i < urb_priv->length; i++) { +	for (; i < urb_priv->length; i++) {  		td = urb_priv->td[i];  		list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list);  	} @@ -1620,6 +1623,7 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,  		/* FIXME: can we allocate more resources for the HC? */  		break;  	case COMP_BW_ERR: +	case COMP_2ND_BW_ERR:  		dev_warn(&udev->dev, "Not enough bandwidth "  				"for new device state.\n");  		ret = -ENOSPC; @@ -2796,8 +2800,7 @@ static int xhci_calculate_streams_and_bitmask(struct xhci_hcd *xhci,  		if (ret < 0)  			return ret; -		max_streams = USB_SS_MAX_STREAMS( -				eps[i]->ss_ep_comp.bmAttributes); +		max_streams = usb_ss_max_streams(&eps[i]->ss_ep_comp);  		if (max_streams < (*num_streams - 1)) {  			xhci_dbg(xhci, "Ep 0x%x only supports %u stream IDs.\n",  					eps[i]->desc.bEndpointAddress, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3c8fbd2772e..fb99c837914 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1033,7 +1033,6 @@ struct xhci_transfer_event {  /* Invalid Stream ID Error */  #define COMP_STRID_ERR	34  /* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */ -/* FIXME - check for this */  #define COMP_2ND_BW_ERR	35  /* Split Transaction Error */  #define	COMP_SPLIT_ERR	36 @@ -1356,7 +1355,7 @@ static inline unsigned int hcd_index(struct usb_hcd *hcd)  		return 1;  } -/* There is one ehci_hci structure per controller */ +/* There is one xhci_hcd structure per controller */  struct xhci_hcd {  	struct usb_hcd *main_hcd;  	struct usb_hcd *shared_hcd; diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c index 1dc7e9581cc..1c61830e96f 100644 --- a/drivers/usb/misc/isight_firmware.c +++ b/drivers/usb/misc/isight_firmware.c @@ -55,8 +55,9 @@ static int isight_firmware_load(struct usb_interface *intf,  	ptr = firmware->data; +	buf[0] = 0x01;  	if (usb_control_msg -	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\1", 1, +	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1,  	     300) != 1) {  		printk(KERN_ERR  		       "Failed to initialise isight firmware loader\n"); @@ -100,8 +101,9 @@ static int isight_firmware_load(struct usb_interface *intf,  		}  	} +	buf[0] = 0x00;  	if (usb_control_msg -	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1, +	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1,  	     300) != 1) {  		printk(KERN_ERR "isight firmware loading completion failed\n");  		ret = -ENODEV; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index bd6d00802ea..959145baf3c 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -1765,7 +1765,6 @@ static int test_unaligned_bulk(   * off just killing the userspace task and waiting for it to exit.   */ -/* No BKL needed */  static int  usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)  { diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 07a03460a59..f70cab3beee 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -5,14 +5,13 @@  # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller  config USB_MUSB_HDRC +	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'  	depends on USB && USB_GADGET -	depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))  	select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)  	select TWL4030_USB if MACH_OMAP_3430SDP  	select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA  	select USB_OTG_UTILS  	select USB_GADGET_DUALSPEED -	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'  	help  	  Say Y here if your system has a dual role high speed USB  	  controller based on the Mentor Graphics silicon IP.  Then @@ -31,9 +30,10 @@ config USB_MUSB_HDRC  	  To compile this driver as a module, choose M here; the  	  module will be called "musb-hdrc". +if USB_MUSB_HDRC +  choice  	prompt "Platform Glue Layer" -	depends on USB_MUSB_HDRC  config USB_MUSB_DAVINCI  	tristate "DaVinci" @@ -45,7 +45,6 @@ config USB_MUSB_DA8XX  config USB_MUSB_TUSB6010  	tristate "TUSB6010" -	depends on ARCH_OMAP  config USB_MUSB_OMAP2PLUS  	tristate "OMAP2430 and onwards" @@ -65,46 +64,54 @@ config USB_MUSB_UX500  endchoice -config MUSB_PIO_ONLY -	bool 'Disable DMA (always use PIO)' -	depends on USB_MUSB_HDRC -	default USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X +choice +	prompt 'MUSB DMA mode' +	default USB_UX500_DMA if USB_MUSB_UX500 +	default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN +	default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI +	default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010 +	default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X  	help -	  All data is copied between memory and FIFO by the CPU. -	  DMA controllers are ignored. - -	  Do not select 'n' here unless DMA support for your SOC or board -	  is unavailable (or unstable).  When DMA is enabled at compile time, -	  you can still disable it at run time using the "use_dma=n" module -	  parameter. +	  Unfortunately, only one option can be enabled here. Ideally one +	  should be able to build all these drivers into one kernel to +	  allow using DMA on multiplatform kernels.  config USB_UX500_DMA -	bool -	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY -	default USB_MUSB_UX500 +	bool 'ST Ericsson U8500 and U5500' +	depends on USB_MUSB_UX500  	help  	  Enable DMA transfers on UX500 platforms.  config USB_INVENTRA_DMA -	bool -	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY -	default USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN +	bool 'Inventra' +	depends on USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN  	help  	  Enable DMA transfers using Mentor's engine.  config USB_TI_CPPI_DMA -	bool -	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY -	default USB_MUSB_DAVINCI +	bool 'TI CPPI (Davinci)' +	depends on USB_MUSB_DAVINCI  	help  	  Enable DMA transfers when TI CPPI DMA is available.  config USB_TUSB_OMAP_DMA -	bool -	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY +	bool 'TUSB 6010'  	depends on USB_MUSB_TUSB6010  	depends on ARCH_OMAP -	default y  	help  	  Enable DMA transfers on TUSB 6010 when OMAP DMA is available. +config MUSB_PIO_ONLY +	bool 'Disable DMA (always use PIO)' +	help +	  All data is copied between memory and FIFO by the CPU. +	  DMA controllers are ignored. + +	  Do not choose this unless DMA support for your SOC or board +	  is unavailable (or unstable).  When DMA is enabled at compile time, +	  you can still disable it at run time using the "use_dma=n" module +	  parameter. + +endchoice + +endif # USB_MUSB_HDRC diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index d8fd9d092de..88bfb9dee4b 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -24,25 +24,7 @@ obj-$(CONFIG_USB_MUSB_UX500)			+= ux500.o  # PIO only, or DMA (several potential schemes).  # though PIO is always there to back up DMA, and for ep0 -ifneq ($(CONFIG_MUSB_PIO_ONLY),y) - -  ifeq ($(CONFIG_USB_INVENTRA_DMA),y) -    musb_hdrc-y			+= musbhsdma.o - -  else -    ifeq ($(CONFIG_USB_TI_CPPI_DMA),y) -      musb_hdrc-y		+= cppi_dma.o - -    else -      ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y) -	musb_hdrc-y		+= tusb6010_omap.o - -      else -        ifeq ($(CONFIG_USB_UX500_DMA),y) -	  musb_hdrc-y		+= ux500_dma.o - -        endif -      endif -    endif -  endif -endif +musb_hdrc-$(CONFIG_USB_INVENTRA_DMA)		+= musbhsdma.o +musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA)		+= cppi_dma.o +musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA)		+= tusb6010_omap.o +musb_hdrc-$(CONFIG_USB_UX500_DMA)		+= ux500_dma.o diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index b63ab157010..f6ff7923048 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -661,7 +661,6 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  		handled = IRQ_HANDLED;  		musb->is_active = 1; -		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);  		musb->ep0_stage = MUSB_EP0_START; @@ -1432,7 +1431,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)  		struct musb_hw_ep	*hw_ep = musb->endpoints + i;  		hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase; -#ifdef CONFIG_USB_MUSB_TUSB6010 +#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)  		hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);  		hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);  		hw_ep->fifo_sync_va = @@ -1631,6 +1630,7 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)  		}  	}  } +EXPORT_SYMBOL_GPL(musb_dma_completion);  #else  #define use_dma			0 @@ -2012,8 +2012,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  	if (status < 0)  		goto fail3; -	pm_runtime_put(musb->controller); -  	status = musb_init_debugfs(musb);  	if (status < 0)  		goto fail4; @@ -2158,6 +2156,7 @@ static void musb_save_context(struct musb *musb)  		if (!epio)  			continue; +		musb_writeb(musb_base, MUSB_INDEX, i);  		musb->context.index_regs[i].txmaxp =  			musb_readw(epio, MUSB_TXMAXP);  		musb->context.index_regs[i].txcsr = @@ -2233,6 +2232,7 @@ static void musb_restore_context(struct musb *musb)  		if (!epio)  			continue; +		musb_writeb(musb_base, MUSB_INDEX, i);  		musb_writew(epio, MUSB_TXMAXP,  			musb->context.index_regs[i].txmaxp);  		musb_writew(epio, MUSB_TXCSR, diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index b3c065ab9db..3d28fb8a2dc 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -40,7 +40,6 @@  #include <linux/interrupt.h>  #include <linux/errno.h>  #include <linux/timer.h> -#include <linux/clk.h>  #include <linux/device.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> @@ -311,6 +310,7 @@ struct musb_context_registers {  	u8 index, testmode;  	u8 devctl, busctl, misc; +	u32 otg_interfsel;  	struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];  }; @@ -327,6 +327,7 @@ struct musb {  	irqreturn_t		(*isr)(int, void *);  	struct work_struct	irq_work; +	struct work_struct	otg_notifier_work;  	u16			hwvers;  /* this hub status bit is reserved by USB 2.0 and not seen by usbcore */ @@ -372,6 +373,7 @@ struct musb {  	u16			int_tx;  	struct otg_transceiver	*xceiv; +	u8			xceiv_event;  	int nIrq;  	unsigned		irq_wake:1; diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h index 742eada5002..27ba8f79946 100644 --- a/drivers/usb/musb/musb_debug.h +++ b/drivers/usb/musb/musb_debug.h @@ -43,8 +43,8 @@  #define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args)  #ifdef CONFIG_DEBUG_FS -extern int musb_init_debugfs(struct musb *musb); -extern void musb_exit_debugfs(struct musb *musb); +int musb_init_debugfs(struct musb *musb); +void musb_exit_debugfs(struct musb *musb);  #else  static inline int musb_init_debugfs(struct musb *musb)  { diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 61f4ee466df..13d9af9bf92 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -33,11 +33,7 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/sched.h>  #include <linux/init.h> -#include <linux/list.h> -#include <linux/platform_device.h> -#include <linux/io.h>  #include <linux/debugfs.h>  #include <linux/seq_file.h> @@ -46,10 +42,6 @@  #include "musb_core.h"  #include "musb_debug.h" -#ifdef CONFIG_ARCH_DAVINCI -#include "davinci.h" -#endif -  struct musb_register_map {  	char			*name;  	unsigned		offset; diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 922148ff8d2..ac3d2eec20f 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -40,8 +40,6 @@  #include <linux/smp.h>  #include <linux/spinlock.h>  #include <linux/delay.h> -#include <linux/moduleparam.h> -#include <linux/stat.h>  #include <linux/dma-mapping.h>  #include <linux/slab.h> @@ -1844,7 +1842,7 @@ int __init musb_gadget_setup(struct musb *musb)  	 */  	musb->g.ops = &musb_gadget_operations; -	musb->g.is_dualspeed = 1; +	musb->g.max_speed = USB_SPEED_HIGH;  	musb->g.speed = USB_SPEED_UNKNOWN;  	/* this "gadget" abstracts/virtualizes the controller */ @@ -1903,7 +1901,7 @@ static int musb_gadget_start(struct usb_gadget *g,  	unsigned long		flags;  	int			retval = -EINVAL; -	if (driver->speed < USB_SPEED_HIGH) +	if (driver->max_speed < USB_SPEED_HIGH)  		goto err0;  	pm_runtime_get_sync(musb->controller); diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 6a0d0467ec7..e40d7647caf 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -37,7 +37,6 @@  #include <linux/list.h>  #include <linux/timer.h>  #include <linux/spinlock.h> -#include <linux/init.h>  #include <linux/device.h>  #include <linux/interrupt.h> diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h index 03c6ccdbb3b..e61aa95f2d2 100644 --- a/drivers/usb/musb/musb_io.h +++ b/drivers/usb/musb/musb_io.h @@ -74,7 +74,7 @@ static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)  	{ __raw_writel(data, addr + offset); } -#ifdef CONFIG_USB_MUSB_TUSB6010 +#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)  /*   * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum. diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index ba85f273e48..c27bbbf32b5 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -29,7 +29,6 @@  #include <linux/sched.h>  #include <linux/init.h>  #include <linux/list.h> -#include <linux/clk.h>  #include <linux/io.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> @@ -228,21 +227,25 @@ static int musb_otg_notifications(struct notifier_block *nb,  		unsigned long event, void *unused)  {  	struct musb	*musb = container_of(nb, struct musb, nb); + +	musb->xceiv_event = event; +	schedule_work(&musb->otg_notifier_work); + +	return 0; +} + +static void musb_otg_notifier_work(struct work_struct *data_notifier_work) +{ +	struct musb *musb = container_of(data_notifier_work, struct musb, otg_notifier_work);  	struct device *dev = musb->controller;  	struct musb_hdrc_platform_data *pdata = dev->platform_data;  	struct omap_musb_board_data *data = pdata->board_data; -	switch (event) { +	switch (musb->xceiv_event) {  	case USB_EVENT_ID:  		dev_dbg(musb->controller, "ID GND\n"); -		if (is_otg_enabled(musb)) { -			if (musb->gadget_driver) { -				pm_runtime_get_sync(musb->controller); -				otg_init(musb->xceiv); -				omap2430_musb_set_vbus(musb, 1); -			} -		} else { +		if (!is_otg_enabled(musb) || musb->gadget_driver) {  			pm_runtime_get_sync(musb->controller);  			otg_init(musb->xceiv);  			omap2430_musb_set_vbus(musb, 1); @@ -274,10 +277,7 @@ static int musb_otg_notifications(struct notifier_block *nb,  		break;  	default:  		dev_dbg(musb->controller, "ID float\n"); -		return NOTIFY_DONE;  	} - -	return NOTIFY_OK;  }  static int omap2430_musb_init(struct musb *musb) @@ -297,6 +297,8 @@ static int omap2430_musb_init(struct musb *musb)  		return -ENODEV;  	} +	INIT_WORK(&musb->otg_notifier_work, musb_otg_notifier_work); +  	status = pm_runtime_get_sync(dev);  	if (status < 0) {  		dev_err(dev, "pm_runtime_get_sync FAILED"); @@ -334,7 +336,6 @@ static int omap2430_musb_init(struct musb *musb)  	return 0;  err1: -	pm_runtime_disable(dev);  	return status;  } @@ -350,20 +351,19 @@ static void omap2430_musb_enable(struct musb *musb)  	case USB_EVENT_ID:  		otg_init(musb->xceiv); -		if (data->interface_type == MUSB_INTERFACE_UTMI) { -			devctl = musb_readb(musb->mregs, MUSB_DEVCTL); -			/* start the session */ -			devctl |= MUSB_DEVCTL_SESSION; -			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); -			while (musb_readb(musb->mregs, MUSB_DEVCTL) & -						MUSB_DEVCTL_BDEVICE) { -				cpu_relax(); +		if (data->interface_type != MUSB_INTERFACE_UTMI) +			break; +		devctl = musb_readb(musb->mregs, MUSB_DEVCTL); +		/* start the session */ +		devctl |= MUSB_DEVCTL_SESSION; +		musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); +		while (musb_readb(musb->mregs, MUSB_DEVCTL) & +				MUSB_DEVCTL_BDEVICE) { +			cpu_relax(); -				if (time_after(jiffies, timeout)) { -					dev_err(musb->controller, -					"configured as A device timeout"); -					break; -				} +			if (time_after(jiffies, timeout)) { +				dev_err(dev, "configured as A device timeout"); +				break;  			}  		}  		break; @@ -478,7 +478,6 @@ static int __exit omap2430_remove(struct platform_device *pdev)  	platform_device_del(glue->musb);  	platform_device_put(glue->musb);  	pm_runtime_put(&pdev->dev); -	pm_runtime_disable(&pdev->dev);  	kfree(glue);  	return 0; @@ -491,6 +490,9 @@ static int omap2430_runtime_suspend(struct device *dev)  	struct omap2430_glue		*glue = dev_get_drvdata(dev);  	struct musb			*musb = glue_to_musb(glue); +	musb->context.otg_interfsel = musb_readl(musb->mregs, +						OTG_INTERFSEL); +  	omap2430_low_level_exit(musb);  	otg_set_suspend(musb->xceiv, 1); @@ -503,6 +505,9 @@ static int omap2430_runtime_resume(struct device *dev)  	struct musb			*musb = glue_to_musb(glue);  	omap2430_low_level_init(musb); +	musb_writel(musb->mregs, OTG_INTERFSEL, +					musb->context.otg_interfsel); +  	otg_set_suspend(musb->xceiv, 0);  	return 0; diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index ec1480191f7..1f405616e6c 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -56,6 +56,7 @@ u8 tusb_get_revision(struct musb *musb)  	return rev;  } +EXPORT_SYMBOL_GPL(tusb_get_revision);  static int tusb_print_revision(struct musb *musb)  { diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index ef4333f4bbe..a163632877a 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -37,7 +37,6 @@ struct ux500_dma_channel {  	struct dma_channel channel;  	struct ux500_dma_controller *controller;  	struct musb_hw_ep *hw_ep; -	struct work_struct channel_work;  	struct dma_chan *dma_chan;  	unsigned int cur_len;  	dma_cookie_t cookie; @@ -56,31 +55,11 @@ struct ux500_dma_controller {  	dma_addr_t phy_base;  }; -/* Work function invoked from DMA callback to handle tx transfers. */ -static void ux500_tx_work(struct work_struct *data) -{ -	struct ux500_dma_channel *ux500_channel = container_of(data, -		struct ux500_dma_channel, channel_work); -	struct musb_hw_ep       *hw_ep = ux500_channel->hw_ep; -	struct musb *musb = hw_ep->musb; -	unsigned long flags; - -	dev_dbg(musb->controller, "DMA tx transfer done on hw_ep=%d\n", -		hw_ep->epnum); - -	spin_lock_irqsave(&musb->lock, flags); -	ux500_channel->channel.actual_len = ux500_channel->cur_len; -	ux500_channel->channel.status = MUSB_DMA_STATUS_FREE; -	musb_dma_completion(musb, hw_ep->epnum, -				ux500_channel->is_tx); -	spin_unlock_irqrestore(&musb->lock, flags); -} -  /* Work function invoked from DMA callback to handle rx transfers. */ -static void ux500_rx_work(struct work_struct *data) +void ux500_dma_callback(void *private_data)  { -	struct ux500_dma_channel *ux500_channel = container_of(data, -		struct ux500_dma_channel, channel_work); +	struct dma_channel *channel = private_data; +	struct ux500_dma_channel *ux500_channel = channel->private_data;  	struct musb_hw_ep       *hw_ep = ux500_channel->hw_ep;  	struct musb *musb = hw_ep->musb;  	unsigned long flags; @@ -94,14 +73,7 @@ static void ux500_rx_work(struct work_struct *data)  	musb_dma_completion(musb, hw_ep->epnum,  		ux500_channel->is_tx);  	spin_unlock_irqrestore(&musb->lock, flags); -} - -void ux500_dma_callback(void *private_data) -{ -	struct dma_channel *channel = (struct dma_channel *)private_data; -	struct ux500_dma_channel *ux500_channel = channel->private_data; -	schedule_work(&ux500_channel->channel_work);  }  static bool ux500_configure_channel(struct dma_channel *channel, @@ -330,7 +302,6 @@ static int ux500_dma_controller_start(struct dma_controller *c)  	void **param_array;  	struct ux500_dma_channel *channel_array;  	u32 ch_count; -	void (*musb_channel_work)(struct work_struct *);  	dma_cap_mask_t mask;  	if ((data->num_rx_channels > UX500_MUSB_DMA_NUM_RX_CHANNELS) || @@ -347,7 +318,6 @@ static int ux500_dma_controller_start(struct dma_controller *c)  	channel_array = controller->rx_channel;  	ch_count = data->num_rx_channels;  	param_array = data->dma_rx_param_array; -	musb_channel_work = ux500_rx_work;  	for (dir = 0; dir < 2; dir++) {  		for (ch_num = 0; ch_num < ch_count; ch_num++) { @@ -374,15 +344,12 @@ static int ux500_dma_controller_start(struct dma_controller *c)  				return -EBUSY;  			} -			INIT_WORK(&ux500_channel->channel_work, -				musb_channel_work);  		}  		/* Prepare the loop for TX channels */  		channel_array = controller->tx_channel;  		ch_count = data->num_tx_channels;  		param_array = data->dma_tx_param_array; -		musb_channel_work = ux500_tx_work;  		is_tx = 1;  	} diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index c66481ad98d..2a25955881f 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -82,9 +82,9 @@ config NOP_USB_XCEIV  	tristate "NOP USB Transceiver Driver"  	select USB_OTG_UTILS  	help -	 this driver is to be used by all the usb transceiver which are either -	 built-in with usb ip or which are autonomous and doesn't require any -	 phy programming such as ISP1x04 etc. +	  This driver is to be used by all the usb transceiver which are either +	  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" @@ -114,13 +114,13 @@ config USB_MSM_OTG  	  has an external PHY.  config AB8500_USB -        tristate "AB8500 USB Transceiver Driver" -        depends on AB8500_CORE -        select USB_OTG_UTILS -        help -          Enable this to support the USB OTG transceiver in AB8500 chip. -          This transceiver supports high and full speed devices plus, -          in host mode, low speed. +	tristate "AB8500 USB Transceiver Driver" +	depends on AB8500_CORE +	select USB_OTG_UTILS +	help +	  Enable this to support the USB OTG transceiver in AB8500 chip. +	  This transceiver supports high and full speed devices plus, +	  in host mode, low speed.  config FSL_USB2_OTG  	bool "Freescale USB OTG Transceiver Driver" @@ -130,4 +130,16 @@ config FSL_USB2_OTG  	help  	  Enable this to support Freescale USB OTG transceiver. +config USB_MV_OTG +	tristate "Marvell USB OTG support" +	depends on USB_MV_UDC +	select USB_OTG +	select USB_OTG_UTILS +	help +	  Say Y here if you want to build Marvell USB OTG transciever +	  driver in kernel (including PXA and MMP series). This driver +	  implements role switch between EHCI host driver and gadget driver. + +	  To compile this driver as a module, choose M here. +  endif # USB || OTG diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 566655c5333..b2c5a959863 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_USB_MSM_OTG)	+= msm_otg.o  obj-$(CONFIG_AB8500_USB)	+= ab8500-usb.o  fsl_usb2_otg-objs		:= fsl_otg.o otg_fsm.o  obj-$(CONFIG_FSL_USB2_OTG)	+= fsl_usb2_otg.o +obj-$(CONFIG_USB_MV_OTG)	+= mv_otg.o diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c index 2d9cc445fc7..a190850d2d3 100644 --- a/drivers/usb/otg/fsl_otg.c +++ b/drivers/usb/otg/fsl_otg.c @@ -1151,18 +1151,7 @@ struct platform_driver fsl_otg_driver = {  	},  }; -static int __init fsl_usb_otg_init(void) -{ -	pr_info(DRIVER_INFO "\n"); -	return platform_driver_register(&fsl_otg_driver); -} -module_init(fsl_usb_otg_init); - -static void __exit fsl_usb_otg_exit(void) -{ -	platform_driver_unregister(&fsl_otg_driver); -} -module_exit(fsl_usb_otg_exit); +module_platform_driver(fsl_otg_driver);  MODULE_DESCRIPTION(DRIVER_INFO);  MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c new file mode 100644 index 00000000000..db0d4fcdc8e --- /dev/null +++ b/drivers/usb/otg/mv_otg.c @@ -0,0 +1,957 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * Author: Chao Xie <chao.xie@marvell.com> + *	   Neil Zhang <zhangwm@marvell.com> + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/device.h> +#include <linux/proc_fs.h> +#include <linux/clk.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> + +#include <linux/usb.h> +#include <linux/usb/ch9.h> +#include <linux/usb/otg.h> +#include <linux/usb/gadget.h> +#include <linux/usb/hcd.h> +#include <linux/platform_data/mv_usb.h> + +#include "mv_otg.h" + +#define	DRIVER_DESC	"Marvell USB OTG transceiver driver" +#define	DRIVER_VERSION	"Jan 20, 2010" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + +static const char driver_name[] = "mv-otg"; + +static char *state_string[] = { +	"undefined", +	"b_idle", +	"b_srp_init", +	"b_peripheral", +	"b_wait_acon", +	"b_host", +	"a_idle", +	"a_wait_vrise", +	"a_wait_bcon", +	"a_host", +	"a_suspend", +	"a_peripheral", +	"a_wait_vfall", +	"a_vbus_err" +}; + +static int mv_otg_set_vbus(struct otg_transceiver *otg, bool on) +{ +	struct mv_otg *mvotg = container_of(otg, struct mv_otg, otg); +	if (mvotg->pdata->set_vbus == NULL) +		return -ENODEV; + +	return mvotg->pdata->set_vbus(on); +} + +static int mv_otg_set_host(struct otg_transceiver *otg, +			   struct usb_bus *host) +{ +	otg->host = host; + +	return 0; +} + +static int mv_otg_set_peripheral(struct otg_transceiver *otg, +				 struct usb_gadget *gadget) +{ +	otg->gadget = gadget; + +	return 0; +} + +static void mv_otg_run_state_machine(struct mv_otg *mvotg, +				     unsigned long delay) +{ +	dev_dbg(&mvotg->pdev->dev, "transceiver is updated\n"); +	if (!mvotg->qwork) +		return; + +	queue_delayed_work(mvotg->qwork, &mvotg->work, delay); +} + +static void mv_otg_timer_await_bcon(unsigned long data) +{ +	struct mv_otg *mvotg = (struct mv_otg *) data; + +	mvotg->otg_ctrl.a_wait_bcon_timeout = 1; + +	dev_info(&mvotg->pdev->dev, "B Device No Response!\n"); + +	if (spin_trylock(&mvotg->wq_lock)) { +		mv_otg_run_state_machine(mvotg, 0); +		spin_unlock(&mvotg->wq_lock); +	} +} + +static int mv_otg_cancel_timer(struct mv_otg *mvotg, unsigned int id) +{ +	struct timer_list *timer; + +	if (id >= OTG_TIMER_NUM) +		return -EINVAL; + +	timer = &mvotg->otg_ctrl.timer[id]; + +	if (timer_pending(timer)) +		del_timer(timer); + +	return 0; +} + +static int mv_otg_set_timer(struct mv_otg *mvotg, unsigned int id, +			    unsigned long interval, +			    void (*callback) (unsigned long)) +{ +	struct timer_list *timer; + +	if (id >= OTG_TIMER_NUM) +		return -EINVAL; + +	timer = &mvotg->otg_ctrl.timer[id]; +	if (timer_pending(timer)) { +		dev_err(&mvotg->pdev->dev, "Timer%d is already running\n", id); +		return -EBUSY; +	} + +	init_timer(timer); +	timer->data = (unsigned long) mvotg; +	timer->function = callback; +	timer->expires = jiffies + interval; +	add_timer(timer); + +	return 0; +} + +static int mv_otg_reset(struct mv_otg *mvotg) +{ +	unsigned int loops; +	u32 tmp; + +	/* Stop the controller */ +	tmp = readl(&mvotg->op_regs->usbcmd); +	tmp &= ~USBCMD_RUN_STOP; +	writel(tmp, &mvotg->op_regs->usbcmd); + +	/* Reset the controller to get default values */ +	writel(USBCMD_CTRL_RESET, &mvotg->op_regs->usbcmd); + +	loops = 500; +	while (readl(&mvotg->op_regs->usbcmd) & USBCMD_CTRL_RESET) { +		if (loops == 0) { +			dev_err(&mvotg->pdev->dev, +				"Wait for RESET completed TIMEOUT\n"); +			return -ETIMEDOUT; +		} +		loops--; +		udelay(20); +	} + +	writel(0x0, &mvotg->op_regs->usbintr); +	tmp = readl(&mvotg->op_regs->usbsts); +	writel(tmp, &mvotg->op_regs->usbsts); + +	return 0; +} + +static void mv_otg_init_irq(struct mv_otg *mvotg) +{ +	u32 otgsc; + +	mvotg->irq_en = OTGSC_INTR_A_SESSION_VALID +	    | OTGSC_INTR_A_VBUS_VALID; +	mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID +	    | OTGSC_INTSTS_A_VBUS_VALID; + +	if (mvotg->pdata->vbus == NULL) { +		mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID +		    | OTGSC_INTR_B_SESSION_END; +		mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID +		    | OTGSC_INTSTS_B_SESSION_END; +	} + +	if (mvotg->pdata->id == NULL) { +		mvotg->irq_en |= OTGSC_INTR_USB_ID; +		mvotg->irq_status |= OTGSC_INTSTS_USB_ID; +	} + +	otgsc = readl(&mvotg->op_regs->otgsc); +	otgsc |= mvotg->irq_en; +	writel(otgsc, &mvotg->op_regs->otgsc); +} + +static void mv_otg_start_host(struct mv_otg *mvotg, int on) +{ +	struct otg_transceiver *otg = &mvotg->otg; +	struct usb_hcd *hcd; + +	if (!otg->host) +		return; + +	dev_info(&mvotg->pdev->dev, "%s host\n", on ? "start" : "stop"); + +	hcd = bus_to_hcd(otg->host); + +	if (on) +		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); +	else +		usb_remove_hcd(hcd); +} + +static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on) +{ +	struct otg_transceiver *otg = &mvotg->otg; + +	if (!otg->gadget) +		return; + +	dev_info(otg->dev, "gadget %s\n", on ? "on" : "off"); + +	if (on) +		usb_gadget_vbus_connect(otg->gadget); +	else +		usb_gadget_vbus_disconnect(otg->gadget); +} + +static void otg_clock_enable(struct mv_otg *mvotg) +{ +	unsigned int i; + +	for (i = 0; i < mvotg->clknum; i++) +		clk_enable(mvotg->clk[i]); +} + +static void otg_clock_disable(struct mv_otg *mvotg) +{ +	unsigned int i; + +	for (i = 0; i < mvotg->clknum; i++) +		clk_disable(mvotg->clk[i]); +} + +static int mv_otg_enable_internal(struct mv_otg *mvotg) +{ +	int retval = 0; + +	if (mvotg->active) +		return 0; + +	dev_dbg(&mvotg->pdev->dev, "otg enabled\n"); + +	otg_clock_enable(mvotg); +	if (mvotg->pdata->phy_init) { +		retval = mvotg->pdata->phy_init(mvotg->phy_regs); +		if (retval) { +			dev_err(&mvotg->pdev->dev, +				"init phy error %d\n", retval); +			otg_clock_disable(mvotg); +			return retval; +		} +	} +	mvotg->active = 1; + +	return 0; + +} + +static int mv_otg_enable(struct mv_otg *mvotg) +{ +	if (mvotg->clock_gating) +		return mv_otg_enable_internal(mvotg); + +	return 0; +} + +static void mv_otg_disable_internal(struct mv_otg *mvotg) +{ +	if (mvotg->active) { +		dev_dbg(&mvotg->pdev->dev, "otg disabled\n"); +		if (mvotg->pdata->phy_deinit) +			mvotg->pdata->phy_deinit(mvotg->phy_regs); +		otg_clock_disable(mvotg); +		mvotg->active = 0; +	} +} + +static void mv_otg_disable(struct mv_otg *mvotg) +{ +	if (mvotg->clock_gating) +		mv_otg_disable_internal(mvotg); +} + +static void mv_otg_update_inputs(struct mv_otg *mvotg) +{ +	struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; +	u32 otgsc; + +	otgsc = readl(&mvotg->op_regs->otgsc); + +	if (mvotg->pdata->vbus) { +		if (mvotg->pdata->vbus->poll() == VBUS_HIGH) { +			otg_ctrl->b_sess_vld = 1; +			otg_ctrl->b_sess_end = 0; +		} else { +			otg_ctrl->b_sess_vld = 0; +			otg_ctrl->b_sess_end = 1; +		} +	} else { +		otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID); +		otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END); +	} + +	if (mvotg->pdata->id) +		otg_ctrl->id = !!mvotg->pdata->id->poll(); +	else +		otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID); + +	if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id) +		otg_ctrl->a_bus_req = 1; + +	otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID); +	otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID); + +	dev_dbg(&mvotg->pdev->dev, "%s: ", __func__); +	dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id); +	dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld); +	dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end); +	dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld); +	dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld); +} + +static void mv_otg_update_state(struct mv_otg *mvotg) +{ +	struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; +	struct otg_transceiver *otg = &mvotg->otg; +	int old_state = otg->state; + +	switch (old_state) { +	case OTG_STATE_UNDEFINED: +		otg->state = OTG_STATE_B_IDLE; +		/* FALL THROUGH */ +	case OTG_STATE_B_IDLE: +		if (otg_ctrl->id == 0) +			otg->state = OTG_STATE_A_IDLE; +		else if (otg_ctrl->b_sess_vld) +			otg->state = OTG_STATE_B_PERIPHERAL; +		break; +	case OTG_STATE_B_PERIPHERAL: +		if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0) +			otg->state = OTG_STATE_B_IDLE; +		break; +	case OTG_STATE_A_IDLE: +		if (otg_ctrl->id) +			otg->state = OTG_STATE_B_IDLE; +		else if (!(otg_ctrl->a_bus_drop) && +			 (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det)) +			otg->state = OTG_STATE_A_WAIT_VRISE; +		break; +	case OTG_STATE_A_WAIT_VRISE: +		if (otg_ctrl->a_vbus_vld) +			otg->state = OTG_STATE_A_WAIT_BCON; +		break; +	case OTG_STATE_A_WAIT_BCON: +		if (otg_ctrl->id || otg_ctrl->a_bus_drop +		    || otg_ctrl->a_wait_bcon_timeout) { +			mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); +			mvotg->otg_ctrl.a_wait_bcon_timeout = 0; +			otg->state = OTG_STATE_A_WAIT_VFALL; +			otg_ctrl->a_bus_req = 0; +		} else if (!otg_ctrl->a_vbus_vld) { +			mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); +			mvotg->otg_ctrl.a_wait_bcon_timeout = 0; +			otg->state = OTG_STATE_A_VBUS_ERR; +		} else if (otg_ctrl->b_conn) { +			mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); +			mvotg->otg_ctrl.a_wait_bcon_timeout = 0; +			otg->state = OTG_STATE_A_HOST; +		} +		break; +	case OTG_STATE_A_HOST: +		if (otg_ctrl->id || !otg_ctrl->b_conn +		    || otg_ctrl->a_bus_drop) +			otg->state = OTG_STATE_A_WAIT_BCON; +		else if (!otg_ctrl->a_vbus_vld) +			otg->state = OTG_STATE_A_VBUS_ERR; +		break; +	case OTG_STATE_A_WAIT_VFALL: +		if (otg_ctrl->id +		    || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld) +		    || otg_ctrl->a_bus_req) +			otg->state = OTG_STATE_A_IDLE; +		break; +	case OTG_STATE_A_VBUS_ERR: +		if (otg_ctrl->id || otg_ctrl->a_clr_err +		    || otg_ctrl->a_bus_drop) { +			otg_ctrl->a_clr_err = 0; +			otg->state = OTG_STATE_A_WAIT_VFALL; +		} +		break; +	default: +		break; +	} +} + +static void mv_otg_work(struct work_struct *work) +{ +	struct mv_otg *mvotg; +	struct otg_transceiver *otg; +	int old_state; + +	mvotg = container_of((struct delayed_work *)work, struct mv_otg, work); + +run: +	/* work queue is single thread, or we need spin_lock to protect */ +	otg = &mvotg->otg; +	old_state = otg->state; + +	if (!mvotg->active) +		return; + +	mv_otg_update_inputs(mvotg); +	mv_otg_update_state(mvotg); + +	if (old_state != otg->state) { +		dev_info(&mvotg->pdev->dev, "change from state %s to %s\n", +			 state_string[old_state], +			 state_string[otg->state]); + +		switch (otg->state) { +		case OTG_STATE_B_IDLE: +			mvotg->otg.default_a = 0; +			if (old_state == OTG_STATE_B_PERIPHERAL) +				mv_otg_start_periphrals(mvotg, 0); +			mv_otg_reset(mvotg); +			mv_otg_disable(mvotg); +			break; +		case OTG_STATE_B_PERIPHERAL: +			mv_otg_enable(mvotg); +			mv_otg_start_periphrals(mvotg, 1); +			break; +		case OTG_STATE_A_IDLE: +			mvotg->otg.default_a = 1; +			mv_otg_enable(mvotg); +			if (old_state == OTG_STATE_A_WAIT_VFALL) +				mv_otg_start_host(mvotg, 0); +			mv_otg_reset(mvotg); +			break; +		case OTG_STATE_A_WAIT_VRISE: +			mv_otg_set_vbus(&mvotg->otg, 1); +			break; +		case OTG_STATE_A_WAIT_BCON: +			if (old_state != OTG_STATE_A_HOST) +				mv_otg_start_host(mvotg, 1); +			mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER, +					 T_A_WAIT_BCON, +					 mv_otg_timer_await_bcon); +			/* +			 * Now, we directly enter A_HOST. So set b_conn = 1 +			 * here. In fact, it need host driver to notify us. +			 */ +			mvotg->otg_ctrl.b_conn = 1; +			break; +		case OTG_STATE_A_HOST: +			break; +		case OTG_STATE_A_WAIT_VFALL: +			/* +			 * Now, we has exited A_HOST. So set b_conn = 0 +			 * here. In fact, it need host driver to notify us. +			 */ +			mvotg->otg_ctrl.b_conn = 0; +			mv_otg_set_vbus(&mvotg->otg, 0); +			break; +		case OTG_STATE_A_VBUS_ERR: +			break; +		default: +			break; +		} +		goto run; +	} +} + +static irqreturn_t mv_otg_irq(int irq, void *dev) +{ +	struct mv_otg *mvotg = dev; +	u32 otgsc; + +	otgsc = readl(&mvotg->op_regs->otgsc); +	writel(otgsc, &mvotg->op_regs->otgsc); + +	/* +	 * if we have vbus, then the vbus detection for B-device +	 * will be done by mv_otg_inputs_irq(). +	 */ +	if (mvotg->pdata->vbus) +		if ((otgsc & OTGSC_STS_USB_ID) && +		    !(otgsc & OTGSC_INTSTS_USB_ID)) +			return IRQ_NONE; + +	if ((otgsc & mvotg->irq_status) == 0) +		return IRQ_NONE; + +	mv_otg_run_state_machine(mvotg, 0); + +	return IRQ_HANDLED; +} + +static irqreturn_t mv_otg_inputs_irq(int irq, void *dev) +{ +	struct mv_otg *mvotg = dev; + +	/* The clock may disabled at this time */ +	if (!mvotg->active) { +		mv_otg_enable(mvotg); +		mv_otg_init_irq(mvotg); +	} + +	mv_otg_run_state_machine(mvotg, 0); + +	return IRQ_HANDLED; +} + +static ssize_t +get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct mv_otg *mvotg = dev_get_drvdata(dev); +	return scnprintf(buf, PAGE_SIZE, "%d\n", +			 mvotg->otg_ctrl.a_bus_req); +} + +static ssize_t +set_a_bus_req(struct device *dev, struct device_attribute *attr, +	      const char *buf, size_t count) +{ +	struct mv_otg *mvotg = dev_get_drvdata(dev); + +	if (count > 2) +		return -1; + +	/* We will use this interface to change to A device */ +	if (mvotg->otg.state != OTG_STATE_B_IDLE +	    && mvotg->otg.state != OTG_STATE_A_IDLE) +		return -1; + +	/* The clock may disabled and we need to set irq for ID detected */ +	mv_otg_enable(mvotg); +	mv_otg_init_irq(mvotg); + +	if (buf[0] == '1') { +		mvotg->otg_ctrl.a_bus_req = 1; +		mvotg->otg_ctrl.a_bus_drop = 0; +		dev_dbg(&mvotg->pdev->dev, +			"User request: a_bus_req = 1\n"); + +		if (spin_trylock(&mvotg->wq_lock)) { +			mv_otg_run_state_machine(mvotg, 0); +			spin_unlock(&mvotg->wq_lock); +		} +	} + +	return count; +} + +static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, +		   set_a_bus_req); + +static ssize_t +set_a_clr_err(struct device *dev, struct device_attribute *attr, +	      const char *buf, size_t count) +{ +	struct mv_otg *mvotg = dev_get_drvdata(dev); +	if (!mvotg->otg.default_a) +		return -1; + +	if (count > 2) +		return -1; + +	if (buf[0] == '1') { +		mvotg->otg_ctrl.a_clr_err = 1; +		dev_dbg(&mvotg->pdev->dev, +			"User request: a_clr_err = 1\n"); +	} + +	if (spin_trylock(&mvotg->wq_lock)) { +		mv_otg_run_state_machine(mvotg, 0); +		spin_unlock(&mvotg->wq_lock); +	} + +	return count; +} + +static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err); + +static ssize_t +get_a_bus_drop(struct device *dev, struct device_attribute *attr, +	       char *buf) +{ +	struct mv_otg *mvotg = dev_get_drvdata(dev); +	return scnprintf(buf, PAGE_SIZE, "%d\n", +			 mvotg->otg_ctrl.a_bus_drop); +} + +static ssize_t +set_a_bus_drop(struct device *dev, struct device_attribute *attr, +	       const char *buf, size_t count) +{ +	struct mv_otg *mvotg = dev_get_drvdata(dev); +	if (!mvotg->otg.default_a) +		return -1; + +	if (count > 2) +		return -1; + +	if (buf[0] == '0') { +		mvotg->otg_ctrl.a_bus_drop = 0; +		dev_dbg(&mvotg->pdev->dev, +			"User request: a_bus_drop = 0\n"); +	} else if (buf[0] == '1') { +		mvotg->otg_ctrl.a_bus_drop = 1; +		mvotg->otg_ctrl.a_bus_req = 0; +		dev_dbg(&mvotg->pdev->dev, +			"User request: a_bus_drop = 1\n"); +		dev_dbg(&mvotg->pdev->dev, +			"User request: and a_bus_req = 0\n"); +	} + +	if (spin_trylock(&mvotg->wq_lock)) { +		mv_otg_run_state_machine(mvotg, 0); +		spin_unlock(&mvotg->wq_lock); +	} + +	return count; +} + +static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, +		   get_a_bus_drop, set_a_bus_drop); + +static struct attribute *inputs_attrs[] = { +	&dev_attr_a_bus_req.attr, +	&dev_attr_a_clr_err.attr, +	&dev_attr_a_bus_drop.attr, +	NULL, +}; + +static struct attribute_group inputs_attr_group = { +	.name = "inputs", +	.attrs = inputs_attrs, +}; + +int mv_otg_remove(struct platform_device *pdev) +{ +	struct mv_otg *mvotg = platform_get_drvdata(pdev); +	int clk_i; + +	sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group); + +	if (mvotg->irq) +		free_irq(mvotg->irq, mvotg); + +	if (mvotg->pdata->vbus) +		free_irq(mvotg->pdata->vbus->irq, mvotg); +	if (mvotg->pdata->id) +		free_irq(mvotg->pdata->id->irq, mvotg); + +	if (mvotg->qwork) { +		flush_workqueue(mvotg->qwork); +		destroy_workqueue(mvotg->qwork); +	} + +	mv_otg_disable(mvotg); + +	if (mvotg->cap_regs) +		iounmap(mvotg->cap_regs); + +	if (mvotg->phy_regs) +		iounmap(mvotg->phy_regs); + +	for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++) +		clk_put(mvotg->clk[clk_i]); + +	otg_set_transceiver(NULL); +	platform_set_drvdata(pdev, NULL); + +	kfree(mvotg); + +	return 0; +} + +static int mv_otg_probe(struct platform_device *pdev) +{ +	struct mv_usb_platform_data *pdata = pdev->dev.platform_data; +	struct mv_otg *mvotg; +	struct resource *r; +	int retval = 0, clk_i, i; +	size_t size; + +	if (pdata == NULL) { +		dev_err(&pdev->dev, "failed to get platform data\n"); +		return -ENODEV; +	} + +	size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum; +	mvotg = kzalloc(size, GFP_KERNEL); +	if (!mvotg) { +		dev_err(&pdev->dev, "failed to allocate memory!\n"); +		return -ENOMEM; +	} + +	platform_set_drvdata(pdev, mvotg); + +	mvotg->pdev = pdev; +	mvotg->pdata = pdata; + +	mvotg->clknum = pdata->clknum; +	for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) { +		mvotg->clk[clk_i] = clk_get(&pdev->dev, pdata->clkname[clk_i]); +		if (IS_ERR(mvotg->clk[clk_i])) { +			retval = PTR_ERR(mvotg->clk[clk_i]); +			goto err_put_clk; +		} +	} + +	mvotg->qwork = create_singlethread_workqueue("mv_otg_queue"); +	if (!mvotg->qwork) { +		dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n"); +		retval = -ENOMEM; +		goto err_put_clk; +	} + +	INIT_DELAYED_WORK(&mvotg->work, mv_otg_work); + +	/* OTG common part */ +	mvotg->pdev = pdev; +	mvotg->otg.dev = &pdev->dev; +	mvotg->otg.label = driver_name; +	mvotg->otg.set_host = mv_otg_set_host; +	mvotg->otg.set_peripheral = mv_otg_set_peripheral; +	mvotg->otg.set_vbus = mv_otg_set_vbus; +	mvotg->otg.state = OTG_STATE_UNDEFINED; + +	for (i = 0; i < OTG_TIMER_NUM; i++) +		init_timer(&mvotg->otg_ctrl.timer[i]); + +	r = platform_get_resource_byname(mvotg->pdev, +					 IORESOURCE_MEM, "phyregs"); +	if (r == NULL) { +		dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); +		retval = -ENODEV; +		goto err_destroy_workqueue; +	} + +	mvotg->phy_regs = ioremap(r->start, resource_size(r)); +	if (mvotg->phy_regs == NULL) { +		dev_err(&pdev->dev, "failed to map phy I/O memory\n"); +		retval = -EFAULT; +		goto err_destroy_workqueue; +	} + +	r = platform_get_resource_byname(mvotg->pdev, +					 IORESOURCE_MEM, "capregs"); +	if (r == NULL) { +		dev_err(&pdev->dev, "no I/O memory resource defined\n"); +		retval = -ENODEV; +		goto err_unmap_phyreg; +	} + +	mvotg->cap_regs = ioremap(r->start, resource_size(r)); +	if (mvotg->cap_regs == NULL) { +		dev_err(&pdev->dev, "failed to map I/O memory\n"); +		retval = -EFAULT; +		goto err_unmap_phyreg; +	} + +	/* we will acces controller register, so enable the udc controller */ +	retval = mv_otg_enable_internal(mvotg); +	if (retval) { +		dev_err(&pdev->dev, "mv otg enable error %d\n", retval); +		goto err_unmap_capreg; +	} + +	mvotg->op_regs = +		(struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs +			+ (readl(mvotg->cap_regs) & CAPLENGTH_MASK)); + +	if (pdata->id) { +		retval = request_threaded_irq(pdata->id->irq, NULL, +					      mv_otg_inputs_irq, +					      IRQF_ONESHOT, "id", mvotg); +		if (retval) { +			dev_info(&pdev->dev, +				 "Failed to request irq for ID\n"); +			pdata->id = NULL; +		} +	} + +	if (pdata->vbus) { +		mvotg->clock_gating = 1; +		retval = request_threaded_irq(pdata->vbus->irq, NULL, +					      mv_otg_inputs_irq, +					      IRQF_ONESHOT, "vbus", mvotg); +		if (retval) { +			dev_info(&pdev->dev, +				 "Failed to request irq for VBUS, " +				 "disable clock gating\n"); +			mvotg->clock_gating = 0; +			pdata->vbus = NULL; +		} +	} + +	if (pdata->disable_otg_clock_gating) +		mvotg->clock_gating = 0; + +	mv_otg_reset(mvotg); +	mv_otg_init_irq(mvotg); + +	r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0); +	if (r == NULL) { +		dev_err(&pdev->dev, "no IRQ resource defined\n"); +		retval = -ENODEV; +		goto err_disable_clk; +	} + +	mvotg->irq = r->start; +	if (request_irq(mvotg->irq, mv_otg_irq, IRQF_SHARED, +			driver_name, mvotg)) { +		dev_err(&pdev->dev, "Request irq %d for OTG failed\n", +			mvotg->irq); +		mvotg->irq = 0; +		retval = -ENODEV; +		goto err_disable_clk; +	} + +	retval = otg_set_transceiver(&mvotg->otg); +	if (retval < 0) { +		dev_err(&pdev->dev, "can't register transceiver, %d\n", +			retval); +		goto err_free_irq; +	} + +	retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group); +	if (retval < 0) { +		dev_dbg(&pdev->dev, +			"Can't register sysfs attr group: %d\n", retval); +		goto err_set_transceiver; +	} + +	spin_lock_init(&mvotg->wq_lock); +	if (spin_trylock(&mvotg->wq_lock)) { +		mv_otg_run_state_machine(mvotg, 2 * HZ); +		spin_unlock(&mvotg->wq_lock); +	} + +	dev_info(&pdev->dev, +		 "successful probe OTG device %s clock gating.\n", +		 mvotg->clock_gating ? "with" : "without"); + +	return 0; + +err_set_transceiver: +	otg_set_transceiver(NULL); +err_free_irq: +	free_irq(mvotg->irq, mvotg); +err_disable_clk: +	if (pdata->vbus) +		free_irq(pdata->vbus->irq, mvotg); +	if (pdata->id) +		free_irq(pdata->id->irq, mvotg); +	mv_otg_disable_internal(mvotg); +err_unmap_capreg: +	iounmap(mvotg->cap_regs); +err_unmap_phyreg: +	iounmap(mvotg->phy_regs); +err_destroy_workqueue: +	flush_workqueue(mvotg->qwork); +	destroy_workqueue(mvotg->qwork); +err_put_clk: +	for (clk_i--; clk_i >= 0; clk_i--) +		clk_put(mvotg->clk[clk_i]); + +	platform_set_drvdata(pdev, NULL); +	kfree(mvotg); + +	return retval; +} + +#ifdef CONFIG_PM +static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state) +{ +	struct mv_otg *mvotg = platform_get_drvdata(pdev); + +	if (mvotg->otg.state != OTG_STATE_B_IDLE) { +		dev_info(&pdev->dev, +			 "OTG state is not B_IDLE, it is %d!\n", +			 mvotg->otg.state); +		return -EAGAIN; +	} + +	if (!mvotg->clock_gating) +		mv_otg_disable_internal(mvotg); + +	return 0; +} + +static int mv_otg_resume(struct platform_device *pdev) +{ +	struct mv_otg *mvotg = platform_get_drvdata(pdev); +	u32 otgsc; + +	if (!mvotg->clock_gating) { +		mv_otg_enable_internal(mvotg); + +		otgsc = readl(&mvotg->op_regs->otgsc); +		otgsc |= mvotg->irq_en; +		writel(otgsc, &mvotg->op_regs->otgsc); + +		if (spin_trylock(&mvotg->wq_lock)) { +			mv_otg_run_state_machine(mvotg, 0); +			spin_unlock(&mvotg->wq_lock); +		} +	} +	return 0; +} +#endif + +static struct platform_driver mv_otg_driver = { +	.probe = mv_otg_probe, +	.remove = __exit_p(mv_otg_remove), +	.driver = { +		   .owner = THIS_MODULE, +		   .name = driver_name, +		   }, +#ifdef CONFIG_PM +	.suspend = mv_otg_suspend, +	.resume = mv_otg_resume, +#endif +}; + +static int __init mv_otg_init(void) +{ +	return platform_driver_register(&mv_otg_driver); +} + +static void __exit mv_otg_exit(void) +{ +	platform_driver_unregister(&mv_otg_driver); +} + +module_init(mv_otg_init); +module_exit(mv_otg_exit); diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/otg/mv_otg.h new file mode 100644 index 00000000000..be6ca143764 --- /dev/null +++ b/drivers/usb/otg/mv_otg.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + */ + +#ifndef	__MV_USB_OTG_CONTROLLER__ +#define	__MV_USB_OTG_CONTROLLER__ + +#include <linux/types.h> + +/* Command Register Bit Masks */ +#define USBCMD_RUN_STOP			(0x00000001) +#define USBCMD_CTRL_RESET		(0x00000002) + +/* otgsc Register Bit Masks */ +#define OTGSC_CTRL_VUSB_DISCHARGE		0x00000001 +#define OTGSC_CTRL_VUSB_CHARGE			0x00000002 +#define OTGSC_CTRL_OTG_TERM			0x00000008 +#define OTGSC_CTRL_DATA_PULSING			0x00000010 +#define OTGSC_STS_USB_ID			0x00000100 +#define OTGSC_STS_A_VBUS_VALID			0x00000200 +#define OTGSC_STS_A_SESSION_VALID		0x00000400 +#define OTGSC_STS_B_SESSION_VALID		0x00000800 +#define OTGSC_STS_B_SESSION_END			0x00001000 +#define OTGSC_STS_1MS_TOGGLE			0x00002000 +#define OTGSC_STS_DATA_PULSING			0x00004000 +#define OTGSC_INTSTS_USB_ID			0x00010000 +#define OTGSC_INTSTS_A_VBUS_VALID		0x00020000 +#define OTGSC_INTSTS_A_SESSION_VALID		0x00040000 +#define OTGSC_INTSTS_B_SESSION_VALID		0x00080000 +#define OTGSC_INTSTS_B_SESSION_END		0x00100000 +#define OTGSC_INTSTS_1MS			0x00200000 +#define OTGSC_INTSTS_DATA_PULSING		0x00400000 +#define OTGSC_INTR_USB_ID			0x01000000 +#define OTGSC_INTR_A_VBUS_VALID			0x02000000 +#define OTGSC_INTR_A_SESSION_VALID		0x04000000 +#define OTGSC_INTR_B_SESSION_VALID		0x08000000 +#define OTGSC_INTR_B_SESSION_END		0x10000000 +#define OTGSC_INTR_1MS_TIMER			0x20000000 +#define OTGSC_INTR_DATA_PULSING			0x40000000 + +#define CAPLENGTH_MASK		(0xff) + +/* Timer's interval, unit 10ms */ +#define T_A_WAIT_VRISE		100 +#define T_A_WAIT_BCON		2000 +#define T_A_AIDL_BDIS		100 +#define T_A_BIDL_ADIS		20 +#define T_B_ASE0_BRST		400 +#define T_B_SE0_SRP		300 +#define T_B_SRP_FAIL		2000 +#define T_B_DATA_PLS		10 +#define T_B_SRP_INIT		100 +#define T_A_SRP_RSPNS		10 +#define T_A_DRV_RSM		5 + +enum otg_function { +	OTG_B_DEVICE = 0, +	OTG_A_DEVICE +}; + +enum mv_otg_timer { +	A_WAIT_BCON_TIMER = 0, +	OTG_TIMER_NUM +}; + +/* PXA OTG state machine */ +struct mv_otg_ctrl { +	/* internal variables */ +	u8 a_set_b_hnp_en;	/* A-Device set b_hnp_en */ +	u8 b_srp_done; +	u8 b_hnp_en; + +	/* OTG inputs */ +	u8 a_bus_drop; +	u8 a_bus_req; +	u8 a_clr_err; +	u8 a_bus_resume; +	u8 a_bus_suspend; +	u8 a_conn; +	u8 a_sess_vld; +	u8 a_srp_det; +	u8 a_vbus_vld; +	u8 b_bus_req;		/* B-Device Require Bus */ +	u8 b_bus_resume; +	u8 b_bus_suspend; +	u8 b_conn; +	u8 b_se0_srp; +	u8 b_sess_end; +	u8 b_sess_vld; +	u8 id; +	u8 a_suspend_req; + +	/*Timer event */ +	u8 a_aidl_bdis_timeout; +	u8 b_ase0_brst_timeout; +	u8 a_bidl_adis_timeout; +	u8 a_wait_bcon_timeout; + +	struct timer_list timer[OTG_TIMER_NUM]; +}; + +#define VUSBHS_MAX_PORTS	8 + +struct mv_otg_regs { +	u32 usbcmd;		/* Command register */ +	u32 usbsts;		/* Status register */ +	u32 usbintr;		/* Interrupt enable */ +	u32 frindex;		/* Frame index */ +	u32 reserved1[1]; +	u32 deviceaddr;		/* Device Address */ +	u32 eplistaddr;		/* Endpoint List Address */ +	u32 ttctrl;		/* HOST TT status and control */ +	u32 burstsize;		/* Programmable Burst Size */ +	u32 txfilltuning;	/* Host Transmit Pre-Buffer Packet Tuning */ +	u32 reserved[4]; +	u32 epnak;		/* Endpoint NAK */ +	u32 epnaken;		/* Endpoint NAK Enable */ +	u32 configflag;		/* Configured Flag register */ +	u32 portsc[VUSBHS_MAX_PORTS];	/* Port Status/Control x, x = 1..8 */ +	u32 otgsc; +	u32 usbmode;		/* USB Host/Device mode */ +	u32 epsetupstat;	/* Endpoint Setup Status */ +	u32 epprime;		/* Endpoint Initialize */ +	u32 epflush;		/* Endpoint De-initialize */ +	u32 epstatus;		/* Endpoint Status */ +	u32 epcomplete;		/* Endpoint Interrupt On Complete */ +	u32 epctrlx[16];	/* Endpoint Control, where x = 0.. 15 */ +	u32 mcr;		/* Mux Control */ +	u32 isr;		/* Interrupt Status */ +	u32 ier;		/* Interrupt Enable */ +}; + +struct mv_otg { +	struct otg_transceiver otg; +	struct mv_otg_ctrl otg_ctrl; + +	/* base address */ +	void __iomem *phy_regs; +	void __iomem *cap_regs; +	struct mv_otg_regs __iomem *op_regs; + +	struct platform_device *pdev; +	int irq; +	u32 irq_status; +	u32 irq_en; + +	struct delayed_work work; +	struct workqueue_struct *qwork; + +	spinlock_t wq_lock; + +	struct mv_usb_platform_data *pdata; + +	unsigned int active; +	unsigned int clock_gating; +	unsigned int clknum; +	struct clk *clk[0]; +}; + +#endif diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 08c679c0dde..e9a5b1d2615 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -95,25 +95,15 @@ struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev)  /*   *		syscfg functions   */ -void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable) +static void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable)  {  	usbhs_bset(priv, SYSCFG, SCKE, enable ? SCKE : 0);  } -void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable) -{ -	usbhs_bset(priv, SYSCFG, HSE, enable ? HSE : 0); -} - -void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable) -{ -	usbhs_bset(priv, SYSCFG, USBE, enable ? USBE : 0); -} -  void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)  { -	u16 mask = DCFM | DRPD | DPRPU; -	u16 val  = DCFM | DRPD; +	u16 mask = DCFM | DRPD | DPRPU | HSE | USBE; +	u16 val  = DCFM | DRPD | HSE | USBE;  	int has_otg = usbhs_get_dparam(priv, has_otg);  	if (has_otg) @@ -130,8 +120,8 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)  void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)  { -	u16 mask = DCFM | DRPD | DPRPU; -	u16 val  = DPRPU; +	u16 mask = DCFM | DRPD | DPRPU | HSE | USBE; +	u16 val  = DPRPU | HSE | USBE;  	/*  	 * if enable @@ -142,6 +132,11 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)  	usbhs_bset(priv, SYSCFG, mask, enable ? val : 0);  } +void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode) +{ +	usbhs_write(priv, TESTMODE, mode); +} +  /*   *		frame functions   */ @@ -229,7 +224,7 @@ static void usbhsc_bus_init(struct usbhs_priv *priv)  /*   *		device configuration   */ -int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, +int usbhs_set_device_config(struct usbhs_priv *priv, int devnum,  			   u16 upphub, u16 hubport, u16 speed)  {  	struct device *dev = usbhs_priv_to_dev(priv); @@ -301,18 +296,25 @@ static u32 usbhsc_default_pipe_type[] = {   */  static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable)  { +	struct platform_device *pdev = usbhs_priv_to_pdev(priv);  	struct device *dev = usbhs_priv_to_dev(priv);  	if (enable) {  		/* enable PM */  		pm_runtime_get_sync(dev); +		/* enable platform power */ +		usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); +  		/* USB on */  		usbhs_sys_clock_ctrl(priv, enable);  	} else {  		/* USB off */  		usbhs_sys_clock_ctrl(priv, enable); +		/* disable platform power */ +		usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); +  		/* disable PM */  		pm_runtime_put_sync(dev);  	} @@ -388,7 +390,7 @@ static void usbhsc_notify_hotplug(struct work_struct *work)  	usbhsc_hotplug(priv);  } -int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) +static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)  {  	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);  	int delay = usbhs_get_dparam(priv, detection_delay); @@ -398,7 +400,8 @@ int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)  	 * To make sure safety context,  	 * use workqueue for usbhs_notify_hotplug  	 */ -	schedule_delayed_work(&priv->notify_hotplug_work, delay); +	schedule_delayed_work(&priv->notify_hotplug_work, +			      msecs_to_jiffies(delay));  	return 0;  } @@ -637,18 +640,7 @@ static struct platform_driver renesas_usbhs_driver = {  	.remove		= __devexit_p(usbhs_remove),  }; -static int __init usbhs_init(void) -{ -	return platform_driver_register(&renesas_usbhs_driver); -} - -static void __exit usbhs_exit(void) -{ -	platform_driver_unregister(&renesas_usbhs_driver); -} - -module_init(usbhs_init); -module_exit(usbhs_exit); +module_platform_driver(renesas_usbhs_driver);  MODULE_LICENSE("GPL");  MODULE_DESCRIPTION("Renesas USB driver"); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 8729da5c3be..d79b3e27db9 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -33,6 +33,7 @@ struct usbhs_priv;  #define SYSCFG		0x0000  #define BUSWAIT		0x0002  #define DVSTCTR		0x0008 +#define TESTMODE	0x000C  #define CFIFO		0x0014  #define CFIFOSEL	0x0020  #define CFIFOCTR	0x0022 @@ -275,19 +276,15 @@ u16 usbhs_read(struct usbhs_priv *priv, u32 reg);  void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data);  void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data); -int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev); -  #define usbhs_lock(p, f) spin_lock_irqsave(usbhs_priv_to_lock(p), f)  #define usbhs_unlock(p, f) spin_unlock_irqrestore(usbhs_priv_to_lock(p), f)  /*   * sysconfig   */ -void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable); -void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable); -void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable);  void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable);  void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); +void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode);  /*   * usb request @@ -311,7 +308,7 @@ int usbhs_frame_get_num(struct usbhs_priv *priv);  /*   * device config   */ -int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, u16 upphub, +int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, u16 upphub,  			   u16 hubport, u16 speed);  /* diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index ffdf5d15085..b51fcd80d24 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -56,7 +56,7 @@ static struct usbhs_pkt_handle usbhsf_null_handler = {  void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,  		    void (*done)(struct usbhs_priv *priv,  				 struct usbhs_pkt *pkt), -		    void *buf, int len, int zero) +		    void *buf, int len, int zero, int sequence)  {  	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);  	struct device *dev = usbhs_priv_to_dev(priv); @@ -90,6 +90,7 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,  	pkt->zero	= zero;  	pkt->actual	= 0;  	pkt->done	= done; +	pkt->sequence	= sequence;  	usbhs_unlock(priv, flags);  	/********************  spin unlock ******************/ @@ -481,6 +482,9 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)  	int i, ret, len;  	int is_short; +	usbhs_pipe_data_sequence(pipe, pkt->sequence); +	pkt->sequence = -1; /* -1 sequence will be ignored */ +  	ret = usbhsf_fifo_select(pipe, fifo, 1);  	if (ret < 0)  		return 0; @@ -584,6 +588,8 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)  	/*  	 * pipe enable to prepare packet receive  	 */ +	usbhs_pipe_data_sequence(pipe, pkt->sequence); +	pkt->sequence = -1; /* -1 sequence will be ignored */  	usbhs_pipe_enable(pipe);  	usbhsf_rx_irq_ctrl(pipe, 1); @@ -641,6 +647,7 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done)  	 * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"  	 */  	if (0 == rcv_len) { +		pkt->zero = 1;  		usbhsf_fifo_clear(pipe, fifo);  		goto usbhs_fifo_read_end;  	} diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index 32a7b246b28..f68609c0f48 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -59,6 +59,7 @@ struct usbhs_pkt {  	int trans;  	int actual;  	int zero; +	int sequence;  };  struct usbhs_pkt_handle { @@ -95,7 +96,7 @@ void usbhs_pkt_init(struct usbhs_pkt *pkt);  void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,  		    void (*done)(struct usbhs_priv *priv,  				 struct usbhs_pkt *pkt), -		    void *buf, int len, int zero); +		    void *buf, int len, int zero, int sequence);  struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);  void usbhs_pkt_start(struct usbhs_pipe *pipe); diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index ad96a389672..1b97fb12694 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -50,7 +50,9 @@ static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv,  {  	struct platform_device *pdev = usbhs_priv_to_pdev(priv); -	return usbhsc_drvcllbck_notify_hotplug(pdev); +	renesas_usbhs_call_notify_hotplug(pdev); + +	return 0;  }  void usbhs_mod_autonomy_mode(struct usbhs_priv *priv) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 7f4e8033857..528691d5f3e 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -14,6 +14,7 @@   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA   *   */ +#include <linux/delay.h>  #include <linux/dma-mapping.h>  #include <linux/io.h>  #include <linux/module.h> @@ -44,7 +45,6 @@ struct usbhsg_uep {  struct usbhsg_gpriv {  	struct usb_gadget	 gadget;  	struct usbhs_mod	 mod; -	struct list_head	 link;  	struct usbhsg_uep	*uep;  	int			 uep_size; @@ -114,16 +114,6 @@ struct usbhsg_recip_handle {  #define usbhsg_status_clr(gp, b) (gp->status &= ~b)  #define usbhsg_status_has(gp, b) (gp->status &   b) -/* controller */ -LIST_HEAD(the_controller_link); - -#define usbhsg_for_each_controller(gpriv)\ -	list_for_each_entry(gpriv, &the_controller_link, link) -#define usbhsg_controller_register(gpriv)\ -	list_add_tail(&(gpriv)->link, &the_controller_link) -#define usbhsg_controller_unregister(gpriv)\ -	list_del_init(&(gpriv)->link) -  /*   *		queue push/pop   */ @@ -164,7 +154,7 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep,  	req->actual = 0;  	req->status = -EINPROGRESS;  	usbhs_pkt_push(pipe, pkt, usbhsg_queue_done, -		       req->buf, req->length, req->zero); +		       req->buf, req->length, req->zero, -1);  	usbhs_pkt_start(pipe);  	dev_dbg(dev, "pipe %d : queue push (%d)\n", @@ -195,7 +185,7 @@ static int usbhsg_dma_map(struct device *dev,  	}  	if (dma_mapping_error(dev, pkt->dma)) { -		dev_err(dev, "dma mapping error %x\n", pkt->dma); +		dev_err(dev, "dma mapping error %llx\n", (u64)pkt->dma);  		return -EIO;  	} @@ -271,6 +261,8 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv,  	usbhsg_recip_handler_std_control_done(priv, uep, ctrl); +	usbhs_pkt_start(pipe); +  	return 0;  } @@ -282,6 +274,145 @@ struct usbhsg_recip_handle req_clear_feature = {  };  /* + *		USB_TYPE_STANDARD / set feature functions + */ +static int usbhsg_recip_handler_std_set_device(struct usbhs_priv *priv, +						 struct usbhsg_uep *uep, +						 struct usb_ctrlrequest *ctrl) +{ +	switch (le16_to_cpu(ctrl->wValue)) { +	case USB_DEVICE_TEST_MODE: +		usbhsg_recip_handler_std_control_done(priv, uep, ctrl); +		udelay(100); +		usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex >> 8)); +		break; +	default: +		usbhsg_recip_handler_std_control_done(priv, uep, ctrl); +		break; +	} + +	return 0; +} + +static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv, +						 struct usbhsg_uep *uep, +						 struct usb_ctrlrequest *ctrl) +{ +	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + +	usbhs_pipe_stall(pipe); + +	usbhsg_recip_handler_std_control_done(priv, uep, ctrl); + +	return 0; +} + +struct usbhsg_recip_handle req_set_feature = { +	.name		= "set feature", +	.device		= usbhsg_recip_handler_std_set_device, +	.interface	= usbhsg_recip_handler_std_control_done, +	.endpoint	= usbhsg_recip_handler_std_set_endpoint, +}; + +/* + *		USB_TYPE_STANDARD / get status functions + */ +static void __usbhsg_recip_send_complete(struct usb_ep *ep, +					 struct usb_request *req) +{ +	struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); + +	/* free allocated recip-buffer/usb_request */ +	kfree(ureq->pkt.buf); +	usb_ep_free_request(ep, req); +} + +static void __usbhsg_recip_send_status(struct usbhsg_gpriv *gpriv, +				       unsigned short status) +{ +	struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); +	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); +	struct device *dev = usbhsg_gpriv_to_dev(gpriv); +	struct usb_request *req; +	unsigned short *buf; + +	/* alloc new usb_request for recip */ +	req = usb_ep_alloc_request(&dcp->ep, GFP_ATOMIC); +	if (!req) { +		dev_err(dev, "recip request allocation fail\n"); +		return; +	} + +	/* alloc recip data buffer */ +	buf = kmalloc(sizeof(*buf), GFP_ATOMIC); +	if (!buf) { +		usb_ep_free_request(&dcp->ep, req); +		dev_err(dev, "recip data allocation fail\n"); +		return; +	} + +	/* recip data is status */ +	*buf = cpu_to_le16(status); + +	/* allocated usb_request/buffer will be freed */ +	req->complete	= __usbhsg_recip_send_complete; +	req->buf	= buf; +	req->length	= sizeof(*buf); +	req->zero	= 0; + +	/* push packet */ +	pipe->handler = &usbhs_fifo_pio_push_handler; +	usbhsg_queue_push(dcp, usbhsg_req_to_ureq(req)); +} + +static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv, +					       struct usbhsg_uep *uep, +					       struct usb_ctrlrequest *ctrl) +{ +	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); +	unsigned short status = 1 << USB_DEVICE_SELF_POWERED; + +	__usbhsg_recip_send_status(gpriv, status); + +	return 0; +} + +static int usbhsg_recip_handler_std_get_interface(struct usbhs_priv *priv, +						  struct usbhsg_uep *uep, +						  struct usb_ctrlrequest *ctrl) +{ +	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); +	unsigned short status = 0; + +	__usbhsg_recip_send_status(gpriv, status); + +	return 0; +} + +static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv, +						 struct usbhsg_uep *uep, +						 struct usb_ctrlrequest *ctrl) +{ +	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); +	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); +	unsigned short status = 0; + +	if (usbhs_pipe_is_stall(pipe)) +		status = 1 << USB_ENDPOINT_HALT; + +	__usbhsg_recip_send_status(gpriv, status); + +	return 0; +} + +struct usbhsg_recip_handle req_get_status = { +	.name		= "get status", +	.device		= usbhsg_recip_handler_std_get_device, +	.interface	= usbhsg_recip_handler_std_get_interface, +	.endpoint	= usbhsg_recip_handler_std_get_endpoint, +}; + +/*   *		USB_TYPE handler   */  static int usbhsg_recip_run_handle(struct usbhs_priv *priv, @@ -303,8 +434,7 @@ static int usbhsg_recip_run_handle(struct usbhs_priv *priv,  	pipe = usbhsg_uep_to_pipe(uep);  	if (!pipe) {  		dev_err(dev, "wrong recip request\n"); -		ret = -EINVAL; -		goto usbhsg_recip_run_handle_end; +		return -EINVAL;  	}  	switch (recip) { @@ -327,20 +457,10 @@ static int usbhsg_recip_run_handle(struct usbhs_priv *priv,  	}  	if (func) { -		unsigned long flags; -  		dev_dbg(dev, "%s (pipe %d :%s)\n", handler->name, nth, msg); - -		/********************  spin lock ********************/ -		usbhs_lock(priv, flags);  		ret = func(priv, uep, ctrl); -		usbhs_unlock(priv, flags); -		/********************  spin unlock ******************/  	} -usbhsg_recip_run_handle_end: -	usbhs_pkt_start(pipe); -  	return ret;  } @@ -412,6 +532,12 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv,  		case USB_REQ_CLEAR_FEATURE:  			recip_handler = &req_clear_feature;  			break; +		case USB_REQ_SET_FEATURE: +			recip_handler = &req_set_feature; +			break; +		case USB_REQ_GET_STATUS: +			recip_handler = &req_get_status; +			break;  		}  	} @@ -439,14 +565,16 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep)  	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);  	struct usbhs_pkt *pkt; -	usbhs_pipe_disable(pipe); -  	while (1) {  		pkt = usbhs_pkt_pop(pipe, NULL);  		if (!pkt)  			break; + +		usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ECONNRESET);  	} +	usbhs_pipe_disable(pipe); +  	return 0;  } @@ -681,9 +809,7 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status)  	 * - function  	 * - usb module  	 */ -	usbhs_sys_hispeed_ctrl(priv, 1);  	usbhs_sys_function_ctrl(priv, 1); -	usbhs_sys_usb_ctrl(priv, 1);  	/*  	 * enable irq callback @@ -731,9 +857,8 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)  	gpriv->gadget.speed = USB_SPEED_UNKNOWN;  	/* disable sys */ -	usbhs_sys_hispeed_ctrl(priv, 0); +	usbhs_sys_set_test_mode(priv, 0);  	usbhs_sys_function_ctrl(priv, 0); -	usbhs_sys_usb_ctrl(priv, 0);  	usbhsg_pipe_disable(dcp); @@ -755,7 +880,7 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget,  	if (!driver		||  	    !driver->setup	|| -	    driver->speed < USB_SPEED_FULL) +	    driver->max_speed < USB_SPEED_FULL)  		return -EINVAL;  	/* first hook up the driver ... */ @@ -866,7 +991,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)  	gpriv->gadget.dev.parent	= dev;  	gpriv->gadget.name		= "renesas_usbhs_udc";  	gpriv->gadget.ops		= &usbhsg_gadget_ops; -	gpriv->gadget.is_dualspeed	= 1; +	gpriv->gadget.max_speed		= USB_SPEED_HIGH;  	ret = device_register(&gpriv->gadget.dev);  	if (ret < 0)  		goto err_add_udc; @@ -896,8 +1021,6 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)  		}  	} -	usbhsg_controller_register(gpriv); -  	ret = usb_add_gadget_udc(dev, &gpriv->gadget);  	if (ret)  		goto err_register; @@ -926,8 +1049,6 @@ void usbhs_mod_gadget_remove(struct usbhs_priv *priv)  	device_unregister(&gpriv->gadget.dev); -	usbhsg_controller_unregister(gpriv); -  	kfree(gpriv->uep);  	kfree(gpriv);  } diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 7955de58995..1834cf50888 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -45,36 +45,34 @@   *   * +--------+					pipes are reused for each uep.   * | udev 1 |-+- [uep 0 (dcp) ] --+		pipe will be switched when - * +--------+ |			  |		target device was changed + * +--------+ |			  |		other device requested   *	      +- [uep 1 (bulk)]	--|---+		   +--------------+   *	      |			  +--------------> | pipe0 (dcp)  | - *	      +- [uep 2 (bulk)]	--|---|---+	   +--------------+ - *				  |   |	  |	   | pipe1 (isoc) | - * +--------+			  |   |	  |	   +--------------+ - * | udev 2 |-+- [uep 0 (dcp) ]	--+   +-- |------> | pipe2 (bulk) | - * +--------+ |			  |   |	  |	   +--------------+ - *	      +- [uep 1 (int) ]	--|-+ |	  +------> | pipe3 (bulk) | - *				  | | |	  |	   +--------------+ - * +--------+			  | +-|---|------> | pipe4 (int)  | - * | udev 3 |-+- [uep 0 (dcp) ]	--+   |	  |	   +--------------+ - * +--------+ |			      |	  |	   | ....	  | - *	      +- [uep 1 (bulk)]	------+	  |	   | ....	  | + *	      +- [uep 2 (bulk)]	-@    |		   +--------------+ + *				      |		   | pipe1 (isoc) | + * +--------+			      |		   +--------------+ + * | udev 2 |-+- [uep 0 (dcp) ]	-@    +----------> | pipe2 (bulk) | + * +--------+ |					   +--------------+ + *	      +- [uep 1 (int) ]	----+	  +------> | pipe3 (bulk) | + *				    |	  |	   +--------------+ + * +--------+			    +-----|------> | pipe4 (int)  | + * | udev 3 |-+- [uep 0 (dcp) ]	-@	  |	   +--------------+ + * +--------+ |				  |	   | ....	  | + *	      +- [uep 1 (bulk)]	-@	  |	   | ....	  |   *	      |				  |   *	      +- [uep 2 (bulk)]-----------+ + * + * @ :	uep requested free pipe, but all have been used. + *	now it is waiting for free pipe   */  /*   *		struct   */ -struct usbhsh_pipe_info { -	unsigned int		usr_cnt; /* see usbhsh_endpoint_alloc() */ -}; -  struct usbhsh_request {  	struct urb		*urb;  	struct usbhs_pkt	pkt; -	struct list_head	ureq_link; /* see hpriv :: ureq_link_xxx */  };  struct usbhsh_device { @@ -83,11 +81,10 @@ struct usbhsh_device {  };  struct usbhsh_ep { -	struct usbhs_pipe	*pipe; +	struct usbhs_pipe	*pipe;   /* attached pipe */  	struct usbhsh_device	*udev;   /* attached udev */ +	struct usb_host_endpoint *ep;  	struct list_head	ep_list; /* list to usbhsh_device */ - -	int maxp;  };  #define USBHSH_DEVICE_MAX	10 /* see DEVADDn / DCPMAXP / PIPEMAXP */ @@ -98,16 +95,9 @@ struct usbhsh_hpriv {  	struct usbhsh_device	udev[USBHSH_DEVICE_MAX]; -	struct usbhsh_pipe_info	*pipe_info; -	int			 pipe_size; -  	u32	port_stat;	/* USB_PORT_STAT_xxx */  	struct completion	setup_ack_done; - -	/* see usbhsh_req_alloc/free */ -	struct list_head	ureq_link_active; -	struct list_head	ureq_link_free;  }; @@ -119,17 +109,6 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";  #define usbhsh_priv_to_hpriv(priv) \  	container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod) -#define __usbhsh_for_each_hpipe(start, pos, h, i)	\ -	for (i = start, pos = (h)->hpipe + i;		\ -	     i < (h)->hpipe_size;			\ -	     i++, pos = (h)->hpipe + i) - -#define usbhsh_for_each_hpipe(pos, hpriv, i)	\ -	__usbhsh_for_each_hpipe(1, pos, hpriv, i) - -#define usbhsh_for_each_hpipe_with_dcp(pos, hpriv, i)	\ -	__usbhsh_for_each_hpipe(0, pos, hpriv, i) -  #define __usbhsh_for_each_udev(start, pos, h, i)	\  	for (i = start, pos = (h)->udev + i;		\  	     i < USBHSH_DEVICE_MAX;			\ @@ -152,15 +131,20 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";  #define usbhsh_ep_to_uep(u)	((u)->hcpriv)  #define usbhsh_uep_to_pipe(u)	((u)->pipe)  #define usbhsh_uep_to_udev(u)	((u)->udev) +#define usbhsh_uep_to_ep(u)	((u)->ep) +  #define usbhsh_urb_to_ureq(u)	((u)->hcpriv)  #define usbhsh_urb_to_usbv(u)	((u)->dev)  #define usbhsh_usbv_to_udev(d)	dev_get_drvdata(&(d)->dev)  #define usbhsh_udev_to_usbv(h)	((h)->usbv) +#define usbhsh_udev_is_used(h)	usbhsh_udev_to_usbv(h) -#define usbhsh_pipe_info(p)	((p)->mod_private) +#define usbhsh_pipe_to_uep(p)	((p)->mod_private) +#define usbhsh_device_parent(d)		(usbhsh_usbv_to_udev((d)->usbv->parent)) +#define usbhsh_device_hubport(d)	((d)->usbv->portnum)  #define usbhsh_device_number(h, d)	((int)((d) - (h)->udev))  #define usbhsh_device_nth(h, d)		((h)->udev + d)  #define usbhsh_device0(h)		usbhsh_device_nth(h, 0) @@ -170,156 +154,428 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";  #define usbhsh_port_stat_clear(h, s)	((h)->port_stat &= ~(s))  #define usbhsh_port_stat_get(h)		((h)->port_stat) -#define usbhsh_pkt_to_req(p)	\ +#define usbhsh_pkt_to_ureq(p)	\  	container_of((void *)p, struct usbhsh_request, pkt)  /*   *		req alloc/free   */ -static void usbhsh_req_list_init(struct usbhsh_hpriv *hpriv) +static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, +					       struct urb *urb, +					       gfp_t mem_flags)  { -	INIT_LIST_HEAD(&hpriv->ureq_link_active); -	INIT_LIST_HEAD(&hpriv->ureq_link_free); +	struct usbhsh_request *ureq; +	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); +	struct device *dev = usbhs_priv_to_dev(priv); + +	ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); +	if (!ureq) { +		dev_err(dev, "ureq alloc fail\n"); +		return NULL; +	} + +	usbhs_pkt_init(&ureq->pkt); +	ureq->urb = urb; +	usbhsh_urb_to_ureq(urb) = ureq; + +	return ureq;  } -static void usbhsh_req_list_quit(struct usbhsh_hpriv *hpriv) +static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, +			    struct usbhsh_request *ureq)  { -	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); -	struct device *dev = usbhsh_hcd_to_dev(hcd); -	struct usbhsh_request *ureq, *next; +	usbhsh_urb_to_ureq(ureq->urb) = NULL; +	ureq->urb = NULL; -	/* kfree all active ureq */ -	list_for_each_entry_safe(ureq, next, -				 &hpriv->ureq_link_active, -				 ureq_link) { -		dev_err(dev, "active ureq (%p) is force freed\n", ureq); -		kfree(ureq); -	} +	kfree(ureq); +} -	/* kfree all free ureq */ -	list_for_each_entry_safe(ureq, next, &hpriv->ureq_link_free, ureq_link) -		kfree(ureq); +/* + *		status + */ +static int usbhsh_is_running(struct usbhsh_hpriv *hpriv) +{ +	/* +	 * we can decide some device is attached or not +	 * by checking mod.irq_attch +	 * see +	 *	usbhsh_irq_attch() +	 *	usbhsh_irq_dtch() +	 */ +	return (hpriv->mod.irq_attch == NULL);  } -static struct usbhsh_request *usbhsh_req_alloc(struct usbhsh_hpriv *hpriv, -					       struct urb *urb, -					       gfp_t mem_flags) +/* + *		pipe control + */ +static void usbhsh_endpoint_sequence_save(struct usbhsh_hpriv *hpriv, +					  struct urb *urb, +					  struct usbhs_pkt *pkt) +{ +	int len = urb->actual_length; +	int maxp = usb_endpoint_maxp(&urb->ep->desc); +	int t = 0; + +	/* DCP is out of sequence control */ +	if (usb_pipecontrol(urb->pipe)) +		return; + +	/* +	 * renesas_usbhs pipe has a limitation in a number. +	 * So, driver should re-use the limited pipe for each device/endpoint. +	 * DATA0/1 sequence should be saved for it. +	 * see [image of mod_host] +	 *     [HARDWARE LIMITATION] +	 */ + +	/* +	 * next sequence depends on actual_length +	 * +	 * ex) actual_length = 1147, maxp = 512 +	 * data0 : 512 +	 * data1 : 512 +	 * data0 : 123 +	 * data1 is the next sequence +	 */ +	t = len / maxp; +	if (len % maxp) +		t++; +	if (pkt->zero) +		t++; +	t %= 2; + +	if (t) +		usb_dotoggle(urb->dev, +			     usb_pipeendpoint(urb->pipe), +			     usb_pipeout(urb->pipe)); +} + +static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, +					       struct urb *urb); + +static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv, +			      struct urb *urb)  { -	struct usbhsh_request *ureq;  	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); +	struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); +	struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); +	struct usbhs_pipe *pipe; +	struct usb_endpoint_descriptor *desc = &urb->ep->desc;  	struct device *dev = usbhs_priv_to_dev(priv); +	unsigned long flags; +	int dir_in_req = !!usb_pipein(urb->pipe); +	int is_dcp = usb_endpoint_xfer_control(desc); +	int i, dir_in; +	int ret = -EBUSY; + +	/********************  spin lock ********************/ +	usbhs_lock(priv, flags); + +	if (unlikely(usbhsh_uep_to_pipe(uep))) { +		dev_err(dev, "uep already has pipe\n"); +		goto usbhsh_pipe_attach_done; +	} + +	usbhs_for_each_pipe_with_dcp(pipe, priv, i) { + +		/* check pipe type */ +		if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc))) +			continue; + +		/* check pipe direction if normal pipe */ +		if (!is_dcp) { +			dir_in = !!usbhs_pipe_is_dir_in(pipe); +			if (0 != (dir_in - dir_in_req)) +				continue; +		} + +		/* check pipe is free */ +		if (usbhsh_pipe_to_uep(pipe)) +			continue; -	if (list_empty(&hpriv->ureq_link_free)) {  		/* -		 * create new one if there is no free ureq +		 * attach pipe to uep +		 * +		 * usbhs_pipe_config_update() should be called after +		 * usbhs_set_device_config() +		 * see +		 *  DCPMAXP/PIPEMAXP  		 */ -		ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); -		if (ureq) -			INIT_LIST_HEAD(&ureq->ureq_link); +		usbhsh_uep_to_pipe(uep)		= pipe; +		usbhsh_pipe_to_uep(pipe)	= uep; + +		usbhs_pipe_config_update(pipe, +					 usbhsh_device_number(hpriv, udev), +					 usb_endpoint_num(desc), +					 usb_endpoint_maxp(desc)); + +		dev_dbg(dev, "%s [%d-%d(%s:%s)]\n", __func__, +			usbhsh_device_number(hpriv, udev), +			usb_endpoint_num(desc), +			usbhs_pipe_name(pipe), +			dir_in_req ? "in" : "out"); + +		ret = 0; +		break; +	} + +usbhsh_pipe_attach_done: +	usbhs_unlock(priv, flags); +	/********************  spin unlock ******************/ + +	return ret; +} + +static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv, +			       struct usbhsh_ep *uep) +{ +	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); +	struct usbhs_pipe *pipe; +	struct device *dev = usbhs_priv_to_dev(priv); +	unsigned long flags; + +	/********************  spin lock ********************/ +	usbhs_lock(priv, flags); + +	pipe = usbhsh_uep_to_pipe(uep); + +	if (unlikely(!pipe)) { +		dev_err(dev, "uep doens't have pipe\n");  	} else { -		/* -		 * reuse "free" ureq if exist -		 */ -		ureq = list_entry(hpriv->ureq_link_free.next, -				  struct usbhsh_request, -				  ureq_link); -		if (ureq) -			list_del_init(&ureq->ureq_link); +		struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep); +		struct usbhsh_device *udev = usbhsh_uep_to_udev(uep); + +		/* detach pipe from uep */ +		usbhsh_uep_to_pipe(uep)		= NULL; +		usbhsh_pipe_to_uep(pipe)	= NULL; + +		dev_dbg(dev, "%s [%d-%d(%s)]\n", __func__, +			usbhsh_device_number(hpriv, udev), +			usb_endpoint_num(&ep->desc), +			usbhs_pipe_name(pipe));  	} -	if (!ureq) { -		dev_err(dev, "ureq alloc fail\n"); -		return NULL; +	usbhs_unlock(priv, flags); +	/********************  spin unlock ******************/ +} + +/* + *		endpoint control + */ +static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, +				  struct urb *urb, +				  gfp_t mem_flags) +{ +	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); +	struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); +	struct usb_host_endpoint *ep = urb->ep; +	struct usbhsh_ep *uep; +	struct device *dev = usbhs_priv_to_dev(priv); +	struct usb_endpoint_descriptor *desc = &ep->desc; +	unsigned long flags; + +	uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); +	if (!uep) { +		dev_err(dev, "usbhsh_ep alloc fail\n"); +		return -ENOMEM;  	} -	usbhs_pkt_init(&ureq->pkt); +	/********************  spin lock ********************/ +	usbhs_lock(priv, flags);  	/* -	 * push it to "active" list +	 * init endpoint  	 */ -	list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_active); -	ureq->urb = urb; +	INIT_LIST_HEAD(&uep->ep_list); +	list_add_tail(&uep->ep_list, &udev->ep_list_head); -	return ureq; +	usbhsh_uep_to_udev(uep)	= udev; +	usbhsh_uep_to_ep(uep)	= ep; +	usbhsh_ep_to_uep(ep)	= uep; + +	usbhs_unlock(priv, flags); +	/********************  spin unlock ******************/ + +	dev_dbg(dev, "%s [%d-%d]\n", __func__, +		usbhsh_device_number(hpriv, udev), +		usb_endpoint_num(desc)); + +	return 0;  } -static void usbhsh_req_free(struct usbhsh_hpriv *hpriv, -			    struct usbhsh_request *ureq) +static void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv, +				   struct usb_host_endpoint *ep)  { -	struct usbhs_pkt *pkt = &ureq->pkt; +	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); +	struct device *dev = usbhs_priv_to_dev(priv); +	struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); +	unsigned long flags; -	usbhs_pkt_init(pkt); +	if (!uep) +		return; -	/* -	 * removed from "active" list, -	 * and push it to "free" list -	 */ -	ureq->urb = NULL; -	list_del_init(&ureq->ureq_link); -	list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_free); +	dev_dbg(dev, "%s [%d-%d]\n", __func__, +		usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)), +		usb_endpoint_num(&ep->desc)); + +	if (usbhsh_uep_to_pipe(uep)) +		usbhsh_pipe_detach(hpriv, uep); + +	/********************  spin lock ********************/ +	usbhs_lock(priv, flags); + +	/* remove this endpoint from udev */ +	list_del_init(&uep->ep_list); + +	usbhsh_uep_to_udev(uep)	= NULL; +	usbhsh_uep_to_ep(uep)	= NULL; +	usbhsh_ep_to_uep(ep)	= NULL; + +	usbhs_unlock(priv, flags); +	/********************  spin unlock ******************/ + +	kfree(uep); +} + +static void usbhsh_endpoint_detach_all(struct usbhsh_hpriv *hpriv, +				       struct usbhsh_device *udev) +{ +	struct usbhsh_ep *uep, *next; + +	list_for_each_entry_safe(uep, next, &udev->ep_list_head, ep_list) +		usbhsh_endpoint_detach(hpriv, usbhsh_uep_to_ep(uep));  }  /*   *		device control   */ +static int usbhsh_connected_to_rhdev(struct usb_hcd *hcd, +				     struct usbhsh_device *udev) +{ +	struct usb_device *usbv = usbhsh_udev_to_usbv(udev); + +	return hcd->self.root_hub == usbv->parent; +}  static int usbhsh_device_has_endpoint(struct usbhsh_device *udev)  {  	return !list_empty(&udev->ep_list_head);  } -static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv, +static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, +					       struct urb *urb) +{ +	struct usb_device *usbv = usbhsh_urb_to_usbv(urb); +	struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv); + +	/* usbhsh_device_attach() is still not called */ +	if (!udev) +		return NULL; + +	/* if it is device0, return it */ +	if (0 == usb_pipedevice(urb->pipe)) +		return usbhsh_device0(hpriv); + +	/* return attached device */ +	return udev; +} + +static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv,  						 struct urb *urb)  {  	struct usbhsh_device *udev = NULL; +	struct usbhsh_device *udev0 = usbhsh_device0(hpriv); +	struct usbhsh_device *pos;  	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);  	struct device *dev = usbhsh_hcd_to_dev(hcd);  	struct usb_device *usbv = usbhsh_urb_to_usbv(urb);  	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); +	unsigned long flags; +	u16 upphub, hubport;  	int i;  	/* -	 * device 0 +	 * This function should be called only while urb is pointing to device0. +	 * It will attach unused usbhsh_device to urb (usbv), +	 * and initialize device0. +	 * You can use usbhsh_device_get() to get "current" udev, +	 * and usbhsh_usbv_to_udev() is for "attached" udev.  	 */ -	if (0 == usb_pipedevice(urb->pipe)) { -		udev = usbhsh_device0(hpriv); -		goto usbhsh_device_find; +	if (0 != usb_pipedevice(urb->pipe)) { +		dev_err(dev, "%s fail: urb isn't pointing device0\n", __func__); +		return NULL;  	} +	/********************  spin lock ********************/ +	usbhs_lock(priv, flags); +  	/*  	 * find unused device  	 */ -	usbhsh_for_each_udev(udev, hpriv, i) { -		if (usbhsh_udev_to_usbv(udev)) +	usbhsh_for_each_udev(pos, hpriv, i) { +		if (usbhsh_udev_is_used(pos))  			continue; -		goto usbhsh_device_find; +		udev = pos; +		break;  	} -	dev_err(dev, "no free usbhsh_device\n"); +	if (udev) { +		/* +		 * usbhsh_usbv_to_udev() +		 * usbhsh_udev_to_usbv() +		 * will be enable +		 */ +		dev_set_drvdata(&usbv->dev, udev); +		udev->usbv = usbv; +	} + +	usbhs_unlock(priv, flags); +	/********************  spin unlock ******************/ -	return NULL; +	if (!udev) { +		dev_err(dev, "no free usbhsh_device\n"); +		return NULL; +	} -usbhsh_device_find: -	if (usbhsh_device_has_endpoint(udev)) +	if (usbhsh_device_has_endpoint(udev)) {  		dev_warn(dev, "udev have old endpoint\n"); +		usbhsh_endpoint_detach_all(hpriv, udev); +	} + +	if (usbhsh_device_has_endpoint(udev0)) { +		dev_warn(dev, "udev0 have old endpoint\n"); +		usbhsh_endpoint_detach_all(hpriv, udev0); +	}  	/* uep will be attached */ +	INIT_LIST_HEAD(&udev0->ep_list_head);  	INIT_LIST_HEAD(&udev->ep_list_head);  	/* -	 * usbhsh_usbv_to_udev() -	 * usbhsh_udev_to_usbv() -	 * will be enable +	 * set device0 config  	 */ -	dev_set_drvdata(&usbv->dev, udev); -	udev->usbv = usbv; +	usbhs_set_device_config(priv, +				0, 0, 0, usbv->speed); -	/* set device config */ -	usbhs_set_device_speed(priv, -			       usbhsh_device_number(hpriv, udev), +	/* +	 * set new device config +	 */ +	upphub	= 0; +	hubport	= 0; +	if (!usbhsh_connected_to_rhdev(hcd, udev)) { +		/* if udev is not connected to rhdev, it means parent is Hub */ +		struct usbhsh_device *parent = usbhsh_device_parent(udev); + +		upphub	= usbhsh_device_number(hpriv, parent); +		hubport	= usbhsh_device_hubport(udev); + +		dev_dbg(dev, "%s connecte to Hub [%d:%d](%p)\n", __func__, +			upphub, hubport, parent); +	} + +	usbhs_set_device_config(priv,  			       usbhsh_device_number(hpriv, udev), -			       0, /* FIXME no parent */ -			       usbv->speed); +			       upphub, hubport, usbv->speed);  	dev_dbg(dev, "%s [%d](%p)\n", __func__,  		usbhsh_device_number(hpriv, udev), udev); @@ -327,152 +583,45 @@ usbhsh_device_find:  	return udev;  } -static void usbhsh_device_free(struct usbhsh_hpriv *hpriv, +static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv,  			       struct usbhsh_device *udev)  {  	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); +	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);  	struct device *dev = usbhsh_hcd_to_dev(hcd);  	struct usb_device *usbv = usbhsh_udev_to_usbv(udev); +	unsigned long flags;  	dev_dbg(dev, "%s [%d](%p)\n", __func__,  		usbhsh_device_number(hpriv, udev), udev); -	if (usbhsh_device_has_endpoint(udev)) +	if (usbhsh_device_has_endpoint(udev)) {  		dev_warn(dev, "udev still have endpoint\n"); - -	/* -	 * usbhsh_usbv_to_udev() -	 * usbhsh_udev_to_usbv() -	 * will be disable -	 */ -	dev_set_drvdata(&usbv->dev, NULL); -	udev->usbv = NULL; -} - -/* - *		end-point control - */ -struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, -					struct usbhsh_device *udev, -					struct usb_host_endpoint *ep, -					int dir_in_req, -					gfp_t mem_flags) -{ -	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); -	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); -	struct usbhsh_ep *uep; -	struct usbhsh_pipe_info *info; -	struct usbhs_pipe *pipe, *best_pipe; -	struct device *dev = usbhsh_hcd_to_dev(hcd); -	struct usb_endpoint_descriptor *desc = &ep->desc; -	int type, i, dir_in; -	unsigned int min_usr; - -	dir_in_req = !!dir_in_req; - -	uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); -	if (!uep) { -		dev_err(dev, "usbhsh_ep alloc fail\n"); -		return NULL; -	} - -	if (usb_endpoint_xfer_control(desc)) { -		best_pipe = usbhsh_hpriv_to_dcp(hpriv); -		goto usbhsh_endpoint_alloc_find_pipe; +		usbhsh_endpoint_detach_all(hpriv, udev);  	}  	/* -	 * find best pipe for endpoint +	 * There is nothing to do if it is device0.  	 * see -	 *	HARDWARE LIMITATION +	 *  usbhsh_device_attach() +	 *  usbhsh_device_get()  	 */ -	type = usb_endpoint_type(desc); -	min_usr = ~0; -	best_pipe = NULL; -	usbhs_for_each_pipe(pipe, priv, i) { -		if (!usbhs_pipe_type_is(pipe, type)) -			continue; - -		dir_in = !!usbhs_pipe_is_dir_in(pipe); -		if (0 != (dir_in - dir_in_req)) -			continue; - -		info = usbhsh_pipe_info(pipe); - -		if (min_usr > info->usr_cnt) { -			min_usr		= info->usr_cnt; -			best_pipe	= pipe; -		} -	} - -	if (unlikely(!best_pipe)) { -		dev_err(dev, "couldn't find best pipe\n"); -		kfree(uep); -		return NULL; -	} -usbhsh_endpoint_alloc_find_pipe: -	/* -	 * init uep -	 */ -	uep->pipe	= best_pipe; -	uep->maxp	= usb_endpoint_maxp(desc); -	usbhsh_uep_to_udev(uep)	= udev; -	usbhsh_ep_to_uep(ep)	= uep; - -	/* -	 * update pipe user count -	 */ -	info = usbhsh_pipe_info(best_pipe); -	info->usr_cnt++; +	if (0 == usbhsh_device_number(hpriv, udev)) +		return; -	/* init this endpoint, and attach it to udev */ -	INIT_LIST_HEAD(&uep->ep_list); -	list_add_tail(&uep->ep_list, &udev->ep_list_head); +	/********************  spin lock ********************/ +	usbhs_lock(priv, flags);  	/* -	 * usbhs_pipe_config_update() should be called after -	 * usbhs_device_config() -	 * see -	 *  DCPMAXP/PIPEMAXP +	 * usbhsh_usbv_to_udev() +	 * usbhsh_udev_to_usbv() +	 * will be disable  	 */ -	usbhs_pipe_sequence_data0(uep->pipe); -	usbhs_pipe_config_update(uep->pipe, -				 usbhsh_device_number(hpriv, udev), -				 usb_endpoint_num(desc), -				 uep->maxp); - -	dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, -		usbhsh_device_number(hpriv, udev), -		usbhs_pipe_name(uep->pipe), uep); - -	return uep; -} - -void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv, -			  struct usb_host_endpoint *ep) -{ -	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); -	struct device *dev = usbhs_priv_to_dev(priv); -	struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); -	struct usbhsh_pipe_info *info; - -	if (!uep) -		return; - -	dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, -		usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)), -		usbhs_pipe_name(uep->pipe), uep); - -	info = usbhsh_pipe_info(uep->pipe); -	info->usr_cnt--; - -	/* remove this endpoint from udev */ -	list_del_init(&uep->ep_list); - -	usbhsh_uep_to_udev(uep) = NULL; -	usbhsh_ep_to_uep(ep) = NULL; +	dev_set_drvdata(&usbv->dev, NULL); +	udev->usbv = NULL; -	kfree(uep); +	usbhs_unlock(priv, flags); +	/********************  spin unlock ******************/  }  /* @@ -480,11 +629,12 @@ void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv,   */  static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)  { -	struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt); +	struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);  	struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);  	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);  	struct urb *urb = ureq->urb;  	struct device *dev = usbhs_priv_to_dev(priv); +	int status = 0;  	dev_dbg(dev, "%s\n", __func__); @@ -493,29 +643,43 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)  		return;  	} +	if (!usbhsh_is_running(hpriv)) +		status = -ESHUTDOWN; +  	urb->actual_length = pkt->actual; -	usbhsh_req_free(hpriv, ureq); -	usbhsh_urb_to_ureq(urb) = NULL; +	usbhsh_ureq_free(hpriv, ureq); + +	usbhsh_endpoint_sequence_save(hpriv, urb, pkt); +	usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep));  	usb_hcd_unlink_urb_from_ep(hcd, urb); -	usb_hcd_giveback_urb(hcd, urb, 0); +	usb_hcd_giveback_urb(hcd, urb, status);  }  static int usbhsh_queue_push(struct usb_hcd *hcd, -			     struct usbhs_pipe *pipe, -			     struct urb *urb) +			     struct urb *urb, +			     gfp_t mem_flags)  { -	struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb); -	struct usbhs_pkt *pkt = &ureq->pkt; +	struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); +	struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); +	struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep);  	struct device *dev = usbhsh_hcd_to_dev(hcd); +	struct usbhsh_request *ureq;  	void *buf; -	int len; +	int len, sequence;  	if (usb_pipeisoc(urb->pipe)) {  		dev_err(dev, "pipe iso is not supported now\n");  		return -EIO;  	} +	/* this ureq will be freed on usbhsh_queue_done() */ +	ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); +	if (unlikely(!ureq)) { +		dev_err(dev, "ureq alloc fail\n"); +		return -ENOMEM; +	} +  	if (usb_pipein(urb->pipe))  		pipe->handler = &usbhs_fifo_pio_pop_handler;  	else @@ -524,25 +688,59 @@ static int usbhsh_queue_push(struct usb_hcd *hcd,  	buf = (void *)(urb->transfer_buffer + urb->actual_length);  	len = urb->transfer_buffer_length - urb->actual_length; +	sequence = usb_gettoggle(urb->dev, +				 usb_pipeendpoint(urb->pipe), +				 usb_pipeout(urb->pipe)); +  	dev_dbg(dev, "%s\n", __func__); -	usbhs_pkt_push(pipe, pkt, usbhsh_queue_done, -		       buf, len, (urb->transfer_flags & URB_ZERO_PACKET)); +	usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done, +		       buf, len, (urb->transfer_flags & URB_ZERO_PACKET), +		       sequence); +  	usbhs_pkt_start(pipe);  	return 0;  } +static void usbhsh_queue_force_pop(struct usbhs_priv *priv, +				   struct usbhs_pipe *pipe) +{ +	struct usbhs_pkt *pkt; + +	while (1) { +		pkt = usbhs_pkt_pop(pipe, NULL); +		if (!pkt) +			break; + +		/* +		 * if all packet are gone, usbhsh_endpoint_disable() +		 * will be called. +		 * then, attached device/endpoint/pipe will be detached +		 */ +		usbhsh_queue_done(priv, pkt); +	} +} + +static void usbhsh_queue_force_pop_all(struct usbhs_priv *priv) +{ +	struct usbhs_pipe *pos; +	int i; + +	usbhs_for_each_pipe_with_dcp(pos, priv, i) +		usbhsh_queue_force_pop(priv, pos); +} +  /*   *		DCP setup stage   */  static int usbhsh_is_request_address(struct urb *urb)  { -	struct usb_ctrlrequest *cmd; +	struct usb_ctrlrequest *req; -	cmd = (struct usb_ctrlrequest *)urb->setup_packet; +	req = (struct usb_ctrlrequest *)urb->setup_packet; -	if ((DeviceOutRequest    == cmd->bRequestType << 8) && -	    (USB_REQ_SET_ADDRESS == cmd->bRequest)) +	if ((DeviceOutRequest    == req->bRequestType << 8) && +	    (USB_REQ_SET_ADDRESS == req->bRequest))  		return 1;  	else  		return 0; @@ -570,11 +768,15 @@ static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv,  	/*  	 * renesas_usbhs can not use original usb address.  	 * see HARDWARE LIMITATION. -	 * modify usb address here. +	 * modify usb address here to use attached device. +	 * see usbhsh_device_attach()  	 */  	if (usbhsh_is_request_address(urb)) { -		/* FIXME */ -		req.wValue = 1; +		struct usb_device *usbv = usbhsh_urb_to_usbv(urb); +		struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv); + +		/* udev is a attached device */ +		req.wValue = usbhsh_device_number(hpriv, udev);  		dev_dbg(dev, "create new address - %d\n", req.wValue);  	} @@ -595,82 +797,80 @@ static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv,  static void usbhsh_data_stage_packet_done(struct usbhs_priv *priv,  					  struct usbhs_pkt *pkt)  { -	struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt); +	struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);  	struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); -	struct urb *urb = ureq->urb;  	/* this ureq was connected to urb when usbhsh_urb_enqueue()  */ -	usbhsh_req_free(hpriv, ureq); -	usbhsh_urb_to_ureq(urb) = NULL; +	usbhsh_ureq_free(hpriv, ureq);  } -static void usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, -					  struct urb *urb, -					  struct usbhs_pipe *pipe) +static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, +					 struct urb *urb, +					 struct usbhs_pipe *pipe, +					 gfp_t mem_flags) +  {  	struct usbhsh_request *ureq; -	struct usbhs_pkt *pkt; -	/* -	 * FIXME -	 * -	 * data stage uses ureq which is connected to urb -	 * see usbhsh_urb_enqueue() :: alloc new request. -	 * it will be freed in usbhsh_data_stage_packet_done() -	 */ -	ureq	= usbhsh_urb_to_ureq(urb); -	pkt	= &ureq->pkt; +	/* this ureq will be freed on usbhsh_data_stage_packet_done() */ +	ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); +	if (unlikely(!ureq)) +		return -ENOMEM;  	if (usb_pipein(urb->pipe))  		pipe->handler = &usbhs_dcp_data_stage_in_handler;  	else  		pipe->handler = &usbhs_dcp_data_stage_out_handler; -	usbhs_pkt_push(pipe, pkt, +	usbhs_pkt_push(pipe, &ureq->pkt,  		       usbhsh_data_stage_packet_done,  		       urb->transfer_buffer,  		       urb->transfer_buffer_length, -		       (urb->transfer_flags & URB_ZERO_PACKET)); +		       (urb->transfer_flags & URB_ZERO_PACKET), +		       -1); + +	return 0;  }  /*   *		DCP status stage   */ -static void usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, +static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv,  					    struct urb *urb, -					    struct usbhs_pipe *pipe) +					    struct usbhs_pipe *pipe, +					    gfp_t mem_flags)  {  	struct usbhsh_request *ureq; -	struct usbhs_pkt *pkt; -	/* -	 * FIXME -	 * -	 * status stage uses allocated ureq. -	 * it will be freed on usbhsh_queue_done() -	 */ -	ureq	= usbhsh_req_alloc(hpriv, urb, GFP_KERNEL); -	pkt	= &ureq->pkt; +	/* This ureq will be freed on usbhsh_queue_done() */ +	ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); +	if (unlikely(!ureq)) +		return -ENOMEM;  	if (usb_pipein(urb->pipe))  		pipe->handler = &usbhs_dcp_status_stage_in_handler;  	else  		pipe->handler = &usbhs_dcp_status_stage_out_handler; -	usbhs_pkt_push(pipe, pkt, +	usbhs_pkt_push(pipe, &ureq->pkt,  		       usbhsh_queue_done,  		       NULL,  		       urb->transfer_buffer_length, -		       0); +		       0, -1); + +	return 0;  }  static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, -				 struct usbhsh_hpriv *hpriv, -				 struct usbhs_pipe *pipe, -				 struct urb *urb) +				 struct urb *urb, +				 gfp_t mflags)  { +	struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); +	struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); +	struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep);  	struct device *dev = usbhsh_hcd_to_dev(hcd); +	int ret;  	dev_dbg(dev, "%s\n", __func__); @@ -686,13 +886,22 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd,  	 *  	 * It is pushed only when urb has buffer.  	 */ -	if (urb->transfer_buffer_length) -		usbhsh_data_stage_packet_push(hpriv, urb, pipe); +	if (urb->transfer_buffer_length) { +		ret = usbhsh_data_stage_packet_push(hpriv, urb, pipe, mflags); +		if (ret < 0) { +			dev_err(dev, "data stage failed\n"); +			return ret; +		} +	}  	/*  	 * status stage  	 */ -	usbhsh_status_stage_packet_push(hpriv, urb, pipe); +	ret = usbhsh_status_stage_packet_push(hpriv, urb, pipe, mflags); +	if (ret < 0) { +		dev_err(dev, "status stage failed\n"); +		return ret; +	}  	/*  	 * start pushed packets @@ -729,71 +938,82 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd,  	struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);  	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);  	struct device *dev = usbhs_priv_to_dev(priv); -	struct usb_device *usbv = usbhsh_urb_to_usbv(urb);  	struct usb_host_endpoint *ep = urb->ep; -	struct usbhsh_request *ureq; -	struct usbhsh_device *udev, *new_udev = NULL; -	struct usbhs_pipe *pipe; -	struct usbhsh_ep *uep; +	struct usbhsh_device *new_udev = NULL;  	int is_dir_in = usb_pipein(urb->pipe); - +	int i;  	int ret;  	dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out"); +	if (!usbhsh_is_running(hpriv)) { +		ret = -EIO; +		dev_err(dev, "host is not running\n"); +		goto usbhsh_urb_enqueue_error_not_linked; +	} +  	ret = usb_hcd_link_urb_to_ep(hcd, urb); -	if (ret) +	if (ret) { +		dev_err(dev, "urb link failed\n");  		goto usbhsh_urb_enqueue_error_not_linked; +	}  	/* -	 * get udev +	 * attach udev if needed +	 * see [image of mod_host]  	 */ -	udev = usbhsh_usbv_to_udev(usbv); -	if (!udev) { -		new_udev = usbhsh_device_alloc(hpriv, urb); -		if (!new_udev) +	if (!usbhsh_device_get(hpriv, urb)) { +		new_udev = usbhsh_device_attach(hpriv, urb); +		if (!new_udev) { +			ret = -EIO; +			dev_err(dev, "device attach failed\n");  			goto usbhsh_urb_enqueue_error_not_linked; - -		udev = new_udev; +		}  	}  	/* -	 * get uep +	 * attach endpoint if needed +	 * see [image of mod_host]  	 */ -	uep = usbhsh_ep_to_uep(ep); -	if (!uep) { -		uep = usbhsh_endpoint_alloc(hpriv, udev, ep, -					    is_dir_in, mem_flags); -		if (!uep) +	if (!usbhsh_ep_to_uep(ep)) { +		ret = usbhsh_endpoint_attach(hpriv, urb, mem_flags); +		if (ret < 0) { +			dev_err(dev, "endpoint attach failed\n");  			goto usbhsh_urb_enqueue_error_free_device; +		}  	} -	pipe = usbhsh_uep_to_pipe(uep);  	/* -	 * alloc new request +	 * attach pipe to endpoint +	 * see [image of mod_host]  	 */ -	ureq = usbhsh_req_alloc(hpriv, urb, mem_flags); -	if (unlikely(!ureq)) { -		ret = -ENOMEM; +	for (i = 0; i < 1024; i++) { +		ret = usbhsh_pipe_attach(hpriv, urb); +		if (ret < 0) +			msleep(100); +		else +			break; +	} +	if (ret < 0) { +		dev_err(dev, "pipe attach failed\n");  		goto usbhsh_urb_enqueue_error_free_endpoint;  	} -	usbhsh_urb_to_ureq(urb) = ureq;  	/*  	 * push packet  	 */  	if (usb_pipecontrol(urb->pipe)) -		usbhsh_dcp_queue_push(hcd, hpriv, pipe, urb); +		ret = usbhsh_dcp_queue_push(hcd, urb, mem_flags);  	else -		usbhsh_queue_push(hcd, pipe, urb); +		ret = usbhsh_queue_push(hcd, urb, mem_flags); -	return 0; +	return ret;  usbhsh_urb_enqueue_error_free_endpoint: -	usbhsh_endpoint_free(hpriv, ep); +	usbhsh_endpoint_detach(hpriv, ep);  usbhsh_urb_enqueue_error_free_device:  	if (new_udev) -		usbhsh_device_free(hpriv, new_udev); +		usbhsh_device_detach(hpriv, new_udev);  usbhsh_urb_enqueue_error_not_linked:  	dev_dbg(dev, "%s error\n", __func__); @@ -807,8 +1027,11 @@ static int usbhsh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  	struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb);  	if (ureq) { -		usbhsh_req_free(hpriv, ureq); -		usbhsh_urb_to_ureq(urb) = NULL; +		struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); +		struct usbhs_pkt *pkt = &ureq->pkt; + +		usbhs_pkt_pop(pkt->pipe, pkt); +		usbhsh_queue_done(priv, pkt);  	}  	return 0; @@ -823,7 +1046,7 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd,  	/*  	 * this function might be called manytimes by same hcd/ep -	 * in-endpoitn == out-endpoint if ep == dcp. +	 * in-endpoint == out-endpoint if ep == dcp.  	 */  	if (!uep)  		return; @@ -831,15 +1054,14 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd,  	udev	= usbhsh_uep_to_udev(uep);  	hpriv	= usbhsh_hcd_to_hpriv(hcd); -	usbhsh_endpoint_free(hpriv, ep); -	ep->hcpriv = NULL; +	usbhsh_endpoint_detach(hpriv, ep);  	/*  	 * if there is no endpoint,  	 * free device  	 */  	if (!usbhsh_device_has_endpoint(udev)) -		usbhsh_device_free(hpriv, udev); +		usbhsh_device_detach(hpriv, udev);  }  static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf) @@ -919,6 +1141,8 @@ static int __usbhsh_hub_port_feature(struct usbhsh_hpriv *hpriv,  				       USB_PORT_STAT_HIGH_SPEED |  				       USB_PORT_STAT_LOW_SPEED); +		usbhsh_queue_force_pop_all(priv); +  		usbhs_bus_send_reset(priv);  		msleep(20);  		usbhs_bus_send_sof_enable(priv); @@ -1082,6 +1306,20 @@ static int usbhsh_irq_attch(struct usbhs_priv *priv,  	usbhsh_port_stat_set(hpriv, USB_PORT_STAT_CONNECTION);  	usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16); +	/* +	 * attch interrupt might happen infinitely on some device +	 * (on self power USB hub ?) +	 * disable it here. +	 * +	 * usbhsh_is_running() becomes effective +	 * according to this process. +	 * see +	 *	usbhsh_is_running() +	 *	usbhsh_urb_enqueue() +	 */ +	hpriv->mod.irq_attch = NULL; +	usbhs_irq_callback_update(priv, &hpriv->mod); +  	return 0;  } @@ -1096,6 +1334,24 @@ static int usbhsh_irq_dtch(struct usbhs_priv *priv,  	usbhsh_port_stat_clear(hpriv, USB_PORT_STAT_CONNECTION);  	usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16); +	/* +	 * enable attch interrupt again +	 * +	 * usbhsh_is_running() becomes invalid +	 * according to this process. +	 * see +	 *	usbhsh_is_running() +	 *	usbhsh_urb_enqueue() +	 */ +	hpriv->mod.irq_attch = usbhsh_irq_attch; +	usbhs_irq_callback_update(priv, &hpriv->mod); + +	/* +	 * usbhsh_queue_force_pop_all() should be called +	 * after usbhsh_is_running() becomes invalid. +	 */ +	usbhsh_queue_force_pop_all(priv); +  	return 0;  } @@ -1131,7 +1387,6 @@ static int usbhsh_irq_setup_err(struct usbhs_priv *priv,  static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)  {  	struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); -	struct usbhsh_pipe_info *pipe_info = hpriv->pipe_info;  	struct usbhs_pipe *pipe;  	u32 *pipe_type = usbhs_get_dparam(priv, pipe_type);  	int pipe_size = usbhs_get_dparam(priv, pipe_size); @@ -1140,7 +1395,6 @@ static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)  	/* init all pipe */  	old_type = USB_ENDPOINT_XFER_CONTROL;  	for (i = 0; i < pipe_size; i++) { -		pipe_info[i].usr_cnt	= 0;  		/*  		 * data "output" will be finished as soon as possible, @@ -1174,7 +1428,7 @@ static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)  						 dir_in);  		} -		pipe->mod_private = pipe_info + i; +		pipe->mod_private = NULL;  	}  } @@ -1205,9 +1459,7 @@ static int usbhsh_start(struct usbhs_priv *priv)  	 * - host  	 * - usb module  	 */ -	usbhs_sys_hispeed_ctrl(priv, 1);  	usbhs_sys_host_ctrl(priv, 1); -	usbhs_sys_usb_ctrl(priv, 1);  	/*  	 * enable irq callback @@ -1242,9 +1494,7 @@ static int usbhsh_stop(struct usbhs_priv *priv)  	usb_remove_hcd(hcd);  	/* disable sys */ -	usbhs_sys_hispeed_ctrl(priv, 0);  	usbhs_sys_host_ctrl(priv, 0); -	usbhs_sys_usb_ctrl(priv, 0);  	dev_dbg(dev, "quit host\n"); @@ -1255,10 +1505,8 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv)  {  	struct usbhsh_hpriv *hpriv;  	struct usb_hcd *hcd; -	struct usbhsh_pipe_info *pipe_info;  	struct usbhsh_device *udev;  	struct device *dev = usbhs_priv_to_dev(priv); -	int pipe_size = usbhs_get_dparam(priv, pipe_size);  	int i;  	/* initialize hcd */ @@ -1269,12 +1517,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv)  	}  	hcd->has_tt = 1; /* for low/full speed */ -	pipe_info = kzalloc(sizeof(*pipe_info) * pipe_size, GFP_KERNEL); -	if (!pipe_info) { -		dev_err(dev, "Could not allocate pipe_info\n"); -		goto usbhs_mod_host_probe_err; -	} -  	/*  	 * CAUTION  	 * @@ -1294,9 +1536,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv)  	hpriv->mod.name		= "host";  	hpriv->mod.start	= usbhsh_start;  	hpriv->mod.stop		= usbhsh_stop; -	hpriv->pipe_info	= pipe_info; -	hpriv->pipe_size	= pipe_size; -	usbhsh_req_list_init(hpriv);  	usbhsh_port_stat_init(hpriv);  	/* init all device */ @@ -1308,11 +1547,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv)  	dev_info(dev, "host probed\n");  	return 0; - -usbhs_mod_host_probe_err: -	usb_put_hcd(hcd); - -	return -ENOMEM;  }  int usbhs_mod_host_remove(struct usbhs_priv *priv) @@ -1320,8 +1554,6 @@ int usbhs_mod_host_remove(struct usbhs_priv *priv)  	struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);  	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); -	usbhsh_req_list_quit(hpriv); -  	usb_put_hcd(hcd);  	return 0; diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index c74389ce217..feb06d6d281 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -257,6 +257,13 @@ void usbhs_pipe_stall(struct usbhs_pipe *pipe)  	}  } +int usbhs_pipe_is_stall(struct usbhs_pipe *pipe) +{ +	u16 pid = usbhsp_pipectrl_get(pipe) & PID_MASK; + +	return (int)(pid == PID_STALL10 || pid == PID_STALL11); +} +  /*   *		pipe setup   */ @@ -323,8 +330,7 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,  	if (dir_in)  		usbhsp_flags_set(pipe, IS_DIR_HOST); -	if ((is_host  && !dir_in) || -	    (!is_host && dir_in)) +	if (!!is_host ^ !!dir_in)  		dir |= DIR_OUT;  	if (!dir) @@ -471,10 +477,27 @@ int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe)  	return usbhsp_flags_has(pipe, IS_DIR_HOST);  } -void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data) +void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence)  {  	u16 mask = (SQCLR | SQSET); -	u16 val = (data) ? SQSET : SQCLR; +	u16 val; + +	/* +	 * sequence +	 *  0  : data0 +	 *  1  : data1 +	 *  -1 : no change +	 */ +	switch (sequence) { +	case 0: +		val = SQCLR; +		break; +	case 1: +		val = SQSET; +		break; +	default: +		return; +	}  	usbhsp_pipectrl_set(pipe, mask, val);  } diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 6334fc644cc..fa18b7dc2b2 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -87,6 +87,7 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);  void usbhs_pipe_enable(struct usbhs_pipe *pipe);  void usbhs_pipe_disable(struct usbhs_pipe *pipe);  void usbhs_pipe_stall(struct usbhs_pipe *pipe); +int usbhs_pipe_is_stall(struct usbhs_pipe *pipe);  void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo);  void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,  			      u16 epnum, u16 maxp); diff --git a/drivers/usb/serial/ChangeLog.history b/drivers/usb/serial/ChangeLog.history deleted file mode 100644 index f13fd488ebe..00000000000 --- a/drivers/usb/serial/ChangeLog.history +++ /dev/null @@ -1,730 +0,0 @@ -This is the contents of some of the drivers/usb/serial/ files that had  old -changelog comments.  They were quite old, and out of date, and we don't keep -them anymore, so I've put them here, away from the source files, in case -people still care to see them. - -- Greg Kroah-Hartman <greg@kroah.com> October 20, 2005 - ------------------------------------------------------------------------ -usb-serial.h Change Log comments: - - (03/26/2002) gkh -	removed the port->tty check from port_paranoia_check() due to serial -	consoles not having a tty device assigned to them. - - (12/03/2001) gkh -	removed active from the port structure. -	added documentation to the usb_serial_device_type structure - - (10/10/2001) gkh -	added vendor and product to serial structure.  Needed to determine device -	owner when the device is disconnected. - - (05/30/2001) gkh -	added sem to port structure and removed port_lock - - (10/05/2000) gkh -	Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help -	fix bug with urb->dev not being set properly, now that the usb core -	needs it. - - (09/11/2000) gkh -	Added usb_serial_debug_data function to help get rid of #DEBUG in the -	drivers. - - (08/28/2000) gkh -	Added port_lock to port structure. - - (08/08/2000) gkh -	Added open_count to port structure. - - (07/23/2000) gkh -	Added bulk_out_endpointAddress to port structure. - - (07/19/2000) gkh, pberger, and borchers -	Modifications to allow usb-serial drivers to be modules. - ------------------------------------------------------------------------ -usb-serial.c Change Log comments: - - (12/10/2002) gkh -	Split the ports off into their own struct device, and added a -	usb-serial bus driver. - - (11/19/2002) gkh -	removed a few #ifdefs for the generic code and cleaned up the failure -	logic in initialization. - - (10/02/2002) gkh -	moved the console code to console.c and out of this file. - - (06/05/2002) gkh -	moved location of startup() call in serial_probe() until after all -	of the port information and endpoints are initialized.  This makes -	things easier for some drivers. - - (04/10/2002) gkh -	added serial_read_proc function which creates a -	/proc/tty/driver/usb-serial file. - - (03/27/2002) gkh -	Got USB serial console code working properly and merged into the main -	version of the tree.  Thanks to Randy Dunlap for the initial version -	of this code, and for pushing me to finish it up. -	The USB serial console works with any usb serial driver device. - - (03/21/2002) gkh -	Moved all manipulation of port->open_count into the core.  Now the -	individual driver's open and close functions are called only when the -	first open() and last close() is called.  Making the drivers a bit -	smaller and simpler. -	Fixed a bug if a driver didn't have the owner field set. - - (02/26/2002) gkh -	Moved all locking into the main serial_* functions, instead of having -	the individual drivers have to grab the port semaphore.  This should -	reduce races. -	Reworked the MOD_INC logic a bit to always increment and decrement, even -	if the generic driver is being used. - - (10/10/2001) gkh -	usb_serial_disconnect() now sets the serial->dev pointer is to NULL to -	help prevent child drivers from accessing the device since it is now -	gone. - - (09/13/2001) gkh -	Moved generic driver initialize after we have registered with the USB -	core.  Thanks to Randy Dunlap for pointing this problem out. - - (07/03/2001) gkh -	Fixed module paramater size.  Thanks to John Brockmeyer for the pointer. -	Fixed vendor and product getting defined through the MODULE_PARM macro -	if the Generic driver wasn't compiled in. -	Fixed problem with generic_shutdown() not being called for drivers that -	don't have a shutdown() function. - - (06/06/2001) gkh -	added evil hack that is needed for the prolific pl2303 device due to the -	crazy way its endpoints are set up. - - (05/30/2001) gkh -	switched from using spinlock to a semaphore, which fixes lots of problems. - - (04/08/2001) gb -	Identify version on module load. - - 2001_02_05 gkh -	Fixed buffer overflows bug with the generic serial driver.  Thanks to -	Todd Squires <squirest@ct0.com> for fixing this. - - (01/10/2001) gkh -	Fixed bug where the generic serial adaptor grabbed _any_ device that was -	offered to it. - - (12/12/2000) gkh -	Removed MOD_INC and MOD_DEC from poll and disconnect functions, and -	moved them to the serial_open and serial_close functions. -	Also fixed bug with there not being a MOD_DEC for the generic driver -	(thanks to Gary Brubaker for finding this.) - - (11/29/2000) gkh -	Small NULL pointer initialization cleanup which saves a bit of disk image - - (11/01/2000) Adam J. Richter -	instead of using idVendor/idProduct pairs, usb serial drivers -	now identify their hardware interest with usb_device_id tables, -	which they usually have anyhow for use with MODULE_DEVICE_TABLE. - - (10/05/2000) gkh -	Fixed bug with urb->dev not being set properly, now that the usb -	core needs it. - - (09/11/2000) gkh -	Removed DEBUG #ifdefs with call to usb_serial_debug_data - - (08/28/2000) gkh -	Added port_lock to port structure. -	Added locks for SMP safeness to generic driver -	Fixed the ability to open a generic device's port more than once. - - (07/23/2000) gkh -	Added bulk_out_endpointAddress to port structure. - - (07/19/2000) gkh, pberger, and borchers -	Modifications to allow usb-serial drivers to be modules. - - (07/03/2000) gkh -	Added more debugging to serial_ioctl call - - (06/25/2000) gkh -	Changed generic_write_bulk_callback to not call wake_up_interruptible -	directly, but to have port_softint do it at a safer time. - - (06/23/2000) gkh -	Cleaned up debugging statements in a quest to find UHCI timeout bug. - - (05/22/2000) gkh -	Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be -	removed from the individual device source files. - - (05/03/2000) gkh -	Added the Digi Acceleport driver from Al Borchers and Peter Berger. - - (05/02/2000) gkh -	Changed devfs and tty register code to work properly now. This was based on -	the ACM driver changes by Vojtech Pavlik. - - (04/27/2000) Ryan VanderBijl - 	Put calls to *_paranoia_checks into one function. - - (04/23/2000) gkh -	Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports. -	Moved when the startup code printed out the devices that are supported. - - (04/19/2000) gkh -	Added driver for ZyXEL omni.net lcd plus ISDN TA -	Made startup info message specify which drivers were compiled in. - - (04/03/2000) gkh -	Changed the probe process to remove the module unload races. -	Changed where the tty layer gets initialized to have devfs work nicer. -	Added initial devfs support. - - (03/26/2000) gkh -	Split driver up into device specific pieces. - - (03/19/2000) gkh -	Fixed oops that could happen when device was removed while a program -	was talking to the device. -	Removed the static urbs and now all urbs are created and destroyed -	dynamically. -	Reworked the internal interface. Now everything is based on the -	usb_serial_port structure instead of the larger usb_serial structure. -	This fixes the bug that a multiport device could not have more than -	one port open at one time. - - (03/17/2000) gkh -	Added config option for debugging messages. -	Added patch for keyspan pda from Brian Warner. - - (03/06/2000) gkh -	Added the keyspan pda code from Brian Warner <warner@lothar.com> -	Moved a bunch of the port specific stuff into its own structure. This -	is in anticipation of the true multiport devices (there's a bug if you -	try to access more than one port of any multiport device right now) - - (02/21/2000) gkh -	Made it so that any serial devices only have to specify which functions -	they want to overload from the generic function calls (great, -	inheritance in C, in a driver, just what I wanted...) -	Added support for set_termios and ioctl function calls. No drivers take -	advantage of this yet. -	Removed the #ifdef MODULE, now there is no module specific code. -	Cleaned up a few comments in usb-serial.h that were wrong (thanks again -	to Miles Lott). -	Small fix to get_free_serial. - - (02/14/2000) gkh -	Removed the Belkin and Peracom functionality from the driver due to -	the lack of support from the vendor, and me not wanting people to -	accidenatly buy the device, expecting it to work with Linux. -	Added read_bulk_callback and write_bulk_callback to the type structure -	for the needs of the FTDI and WhiteHEAT driver. -	Changed all reverences to FTDI to FTDI_SIO at the request of Bill -	Ryder. -	Changed the output urb size back to the max endpoint size to make -	the ftdi_sio driver have it easier, and due to the fact that it didn't -	really increase the speed any. - - (02/11/2000) gkh -	Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a -	patch from Miles Lott (milos@insync.net). -	Fixed bug with not restoring the minor range that a device grabs, if -	the startup function fails (thanks Miles for finding this). - - (02/05/2000) gkh -	Added initial framework for the Keyspan PDA serial converter so that -	Brian Warner has a place to put his code. -	Made the ezusb specific functions generic enough that different -	devices can use them (whiteheat and keyspan_pda both need them). -	Split out a whole bunch of structure and other stuff to a separate -	usb-serial.h file. -	Made the Visor connection messages a little more understandable, now -	that Miles Lott (milos@insync.net) has gotten the Generic channel to -	work. Also made them always show up in the log file. - - (01/25/2000) gkh -	Added initial framework for FTDI serial converter so that Bill Ryder -	has a place to put his code. -	Added the vendor specific info from Handspring. Now we can print out -	informational debug messages as well as understand what is happening. - - (01/23/2000) gkh -	Fixed problem of crash when trying to open a port that didn't have a -	device assigned to it. Made the minor node finding a little smarter, -	now it looks to find a continuous space for the new device. - - (01/21/2000) gkh -	Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net) -	Fixed get_serial_by_minor which was all messed up for multi port -	devices. Fixed multi port problem for generic devices. Now the number -	of ports is determined by the number of bulk out endpoints for the -	generic device. - - (01/19/2000) gkh -	Removed lots of cruft that was around from the old (pre urb) driver -	interface. -	Made the serial_table dynamic. This should save lots of memory when -	the number of minor nodes goes up to 256. -	Added initial support for devices that have more than one port. -	Added more debugging comments for the Visor, and added a needed -	set_configuration call. - - (01/17/2000) gkh -	Fixed the WhiteHEAT firmware (my processing tool had a bug) -	and added new debug loader firmware for it. -	Removed the put_char function as it isn't really needed. -	Added visor startup commands as found by the Win98 dump. - - (01/13/2000) gkh -	Fixed the vendor id for the generic driver to the one I meant it to be. - - (01/12/2000) gkh -	Forget the version numbering...that's pretty useless... -	Made the driver able to be compiled so that the user can select which -	converter they want to use. This allows people who only want the Visor -	support to not pay the memory size price of the WhiteHEAT. -	Fixed bug where the generic driver (idVendor=0000 and idProduct=0000) -	grabbed the root hub. Not good. - - version 0.4.0 (01/10/2000) gkh -	Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT -	device. Added startup function to allow firmware to be downloaded to -	a device if it needs to be. -	Added firmware download logic to the WhiteHEAT device. -	Started to add #defines to split up the different drivers for potential -	configuration option. - - version 0.3.1 (12/30/99) gkh -      Fixed problems with urb for bulk out. -      Added initial support for multiple sets of endpoints. This enables -      the Handspring Visor to be attached successfully. Only the first -      bulk in / bulk out endpoint pair is being used right now. - - version 0.3.0 (12/27/99) gkh -	Added initial support for the Handspring Visor based on a patch from -	Miles Lott (milos@sneety.insync.net) -	Cleaned up the code a bunch and converted over to using urbs only. - - version 0.2.3 (12/21/99) gkh -	Added initial support for the Connect Tech WhiteHEAT converter. -	Incremented the number of ports in expectation of getting the -	WhiteHEAT to work properly (4 ports per connection). -	Added notification on insertion and removal of what port the -	device is/was connected to (and what kind of device it was). - - version 0.2.2 (12/16/99) gkh -	Changed major number to the new allocated number. We're legal now! - - version 0.2.1 (12/14/99) gkh -	Fixed bug that happens when device node is opened when there isn't a -	device attached to it. Thanks to marek@webdesign.no for noticing this. - - version 0.2.0 (11/10/99) gkh -	Split up internals to make it easier to add different types of serial -	converters to the code. -	Added a "generic" driver that gets it's vendor and product id -	from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net) -	for the idea and sample code (from the usb scanner driver.) -	Cleared up any licensing questions by releasing it under the GNU GPL. - - version 0.1.2 (10/25/99) gkh - 	Fixed bug in detecting device. - - version 0.1.1 (10/05/99) gkh - 	Changed the major number to not conflict with anything else. - - version 0.1 (09/28/99) gkh - 	Can recognize the two different devices and start up a read from -	device when asked to. Writes also work. No control signals yet, this -	all is vendor specific data (i.e. no spec), also no control for -	different baud rates or other bit settings. -	Currently we are using the same devid as the acm driver. This needs -	to change. - ------------------------------------------------------------------------ -visor.c Change Log comments: - - (06/03/2003) Judd Montgomery <judd at jpilot.org> -     Added support for module parameter options for untested/unknown -     devices. - - (03/09/2003) gkh -	Added support for the Sony Clie NZ90V device.  Thanks to Martin Brachtl -	<brachtl@redgrep.cz> for the information. - - (03/05/2003) gkh -	Think Treo support is now working. - - (04/03/2002) gkh -	Added support for the Sony OS 4.1 devices.  Thanks to Hiroyuki ARAKI -	<hiro@zob.ne.jp> for the information. - - (03/27/2002) gkh -	Removed assumptions that port->tty was always valid (is not true -	for usb serial console devices.) - - (03/23/2002) gkh -	Added support for the Palm i705 device, thanks to Thomas Riemer -	<tom@netmech.com> for the information. - - (03/21/2002) gkh -	Added support for the Palm m130 device, thanks to Udo Eisenbarth -	<udo.eisenbarth@web.de> for the information. - - (02/27/2002) gkh -	Reworked the urb handling logic.  We have no more pool, but dynamically -	allocate the urb and the transfer buffer on the fly.  In testing this -	does not incure any measurable overhead.  This also relies on the fact -	that we have proper reference counting logic for urbs. - - (02/21/2002) SilaS -  Added initial support for the Palm m515 devices. - - (02/14/2002) gkh -	Added support for the Clie S-360 device. - - (12/18/2001) gkh -	Added better Clie support for 3.5 devices.  Thanks to Geoffrey Levand -	for the patch. - - (11/11/2001) gkh -	Added support for the m125 devices, and added check to prevent oopses -	for Clié devices that lie about the number of ports they have. - - (08/30/2001) gkh -	Added support for the Clie devices, both the 3.5 and 4.0 os versions. -	Many thanks to Daniel Burke, and Bryan Payne for helping with this. - - (08/23/2001) gkh -	fixed a few potential bugs pointed out by Oliver Neukum. - - (05/30/2001) gkh -	switched from using spinlock to a semaphore, which fixes lots of problems. - - (05/28/2000) gkh -	Added initial support for the Palm m500 and Palm m505 devices. - - (04/08/2001) gb -	Identify version on module load. - - (01/21/2000) gkh -	Added write_room and chars_in_buffer, as they were previously using the -	generic driver versions which is all wrong now that we are using an urb -	pool.  Thanks to Wolfgang Grandegger for pointing this out to me. -	Removed count assignment in the write function, which was not needed anymore -	either.  Thanks to Al Borchers for pointing this out. - - (12/12/2000) gkh -	Moved MOD_DEC to end of visor_close to be nicer, as the final write -	message can sleep. - - (11/12/2000) gkh -	Fixed bug with data being dropped on the floor by forcing tty->low_latency -	to be on.  Hopefully this fixes the OHCI issue! - - (11/01/2000) Adam J. Richter -	usb_device_id table support - - (10/05/2000) gkh -	Fixed bug with urb->dev not being set properly, now that the usb -	core needs it. - - (09/11/2000) gkh -	Got rid of always calling kmalloc for every urb we wrote out to the -	device. -	Added visor_read_callback so we can keep track of bytes in and out for -	those people who like to know the speed of their device. -	Removed DEBUG #ifdefs with call to usb_serial_debug_data - - (09/06/2000) gkh -	Fixed oops in visor_exit.  Need to uncomment usb_unlink_urb call _after_ -	the host controller drivers set urb->dev = NULL when the urb is finished. - - (08/28/2000) gkh -	Added locks for SMP safeness. - - (08/08/2000) gkh -	Fixed endian problem in visor_startup. -	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more -	than once. - - (07/23/2000) gkh -	Added pool of write urbs to speed up transfers to the visor. - - (07/19/2000) gkh -	Added module_init and module_exit functions to handle the fact that this -	driver is a loadable module now. - - (07/03/2000) gkh -	Added visor_set_ioctl and visor_set_termios functions (they don't do much -	of anything, but are good for debugging.) - - (06/25/2000) gkh -	Fixed bug in visor_unthrottle that should help with the disconnect in PPP -	bug that people have been reporting. - - (06/23/2000) gkh -	Cleaned up debugging statements in a quest to find UHCI timeout bug. - - (04/27/2000) Ryan VanderBijl - 	Fixed memory leak in visor_close - - (03/26/2000) gkh -	Split driver up into device specific pieces. - ------------------------------------------------------------------------ -pl2303.c Change Log comments: - - 2002_Mar_26 gkh -	allowed driver to work properly if there is no tty assigned to a port -	(this happens for serial console devices.) - - 2001_Oct_06 gkh -	Added RTS and DTR line control.  Thanks to joe@bndlg.de for parts of it. - - 2001_Sep_19 gkh -	Added break support. - - 2001_Aug_30 gkh -	fixed oops in write_bulk_callback. - - 2001_Aug_28 gkh -	reworked buffer logic to be like other usb-serial drivers.  Hopefully -	removing some reported problems. - - 2001_Jun_06 gkh -	finished porting to 2.4 format. - - ------------------------------------------------------------------------ -io_edgeport.c Change Log comments: - - 2003_04_03 al borchers -  - fixed a bug (that shows up with dosemu) where the tty struct is -    used in a callback after it has been freed - - 2.3 2002_03_08 greg kroah-hartman -	- fixed bug when multiple devices were attached at the same time. - - 2.2 2001_11_14 greg kroah-hartman -	- fixed bug in edge_close that kept the port from being used more -	  than once. -	- fixed memory leak on device removal. -	- fixed potential double free of memory when command urb submitting -	  failed. -	- other small cleanups when the device is removed - - 2.1 2001_07_09 greg kroah-hartman -	- added support for TIOCMBIS and TIOCMBIC. - -     (04/08/2001) gb -	- Identify version on module load. - - 2.0 2001_03_05 greg kroah-hartman -	- reworked entire driver to fit properly in with the other usb-serial -	  drivers.  Occasional oopses still happen, but it's a good start. - - 1.2.3 (02/23/2001) greg kroah-hartman -	- changed device table to work properly for 2.4.x final format. -	- fixed problem with dropping data at high data rates. - - 1.2.2 (11/27/2000) greg kroah-hartman -	- cleaned up more NTisms. -	- Added device table for 2.4.0-test11 - - 1.2.1 (11/08/2000) greg kroah-hartman -	- Started to clean up NTisms. -	- Fixed problem with dev field of urb for kernels >= 2.4.0-test9 - - 1.2 (10/17/2000) David Iacovelli - 	Remove all EPIC code and GPL source -  Fix RELEVANT_IFLAG macro to include flow control -  changes port configuration changes. -  Fix redefinition of SERIAL_MAGIC -  Change all timeout values to 5 seconds -  Tried to fix the UHCI multiple urb submission, but failed miserably. -  it seems to work fine with OHCI. -  ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must -    find a way to work arount this UHCI bug ) - - 1.1 (10/11/2000) David Iacovelli -  Fix XON/XOFF flow control to support both IXON and IXOFF - - 0.9.27 (06/30/2000) David Iacovelli -  Added transmit queue and now allocate urb for command writes. - - 0.9.26 (06/29/2000) David Iacovelli -  Add support for 80251 based edgeport - - 0.9.25 (06/27/2000) David Iacovelli -  Do not close the port if it has multiple opens. - - 0.9.24 (05/26/2000) David Iacovelli -  Add IOCTLs to support RXTX and JAVA POS -  and first cut at running BlackBox Demo - - 0.9.23 (05/24/2000) David Iacovelli -  Add IOCTLs to support RXTX and JAVA POS - - 0.9.22 (05/23/2000) David Iacovelli -  fixed bug in enumeration.  If epconfig turns on mapping by -  path after a device is already plugged in, we now update -  the mapping correctly - - 0.9.21 (05/16/2000) David Iacovelli -  Added BlockUntilChaseResp() to also wait for txcredits -  Updated the way we allocate and handle write URBs -	Add debug code to dump buffers - - 0.9.20 (05/01/2000) David Iacovelli -	change driver to use usb/tts/ - - 0.9.19 (05/01/2000) David Iacovelli -  Update code to compile if DEBUG is off - - 0.9.18 (04/28/2000) David Iacovelli -  cleanup and test tty_register with devfs - - 0.9.17 (04/27/2000) greg kroah-hartman - 	changed tty_register around to be like the way it - 	was before, but now it works properly with devfs. - - 0.9.16 (04/26/2000) david iacovelli -  Fixed bug in GetProductInfo() - - 0.9.15 (04/25/2000) david iacovelli -	Updated enumeration - - 0.9.14 (04/24/2000) david iacovelli -  Removed all config/status IOCTLS and -  converted to using /proc/edgeport -  still playing with devfs - - 0.9.13 (04/24/2000) david iacovelli -  Removed configuration based on ttyUSB0 -  Added support for configuration using /prod/edgeport -  first attempt at using devfs (not working yet!) -  Added IOCTL to GetProductInfo() -  Added support for custom baud rates -	Add support for random port numbers - - 0.9.12 (04/18/2000) david iacovelli -	added additional configuration IOCTLs -  use ttyUSB0 for configuration - - 0.9.11 (04/17/2000) greg kroah-hartman -	fixed module initialization race conditions. -	made all urbs dynamically allocated. -	made driver devfs compatible. now it only registers the tty device -	when the device is actually plugged in. - - 0.9.10 (04/13/2000) greg kroah-hartman -	added proc interface framework. - - 0.9.9 (04/13/2000) david iacovelli -	added enumeration code and ioctls to configure the device - - 0.9.8 (04/12/2000) david iacovelli -  Change interrupt read start when device is plugged in -  and stop when device is removed -	process interrupt reads when all ports are closed -  (keep value of rxBytesAvail consistent with the edgeport) -  set the USB_BULK_QUEUE flag so that we can shove a bunch -  of urbs at once down the pipe - - 0.9.7 (04/10/2000) david iacovelli - 	start to add enumeration code. -  generate serial number for epic devices -  add support for kdb - - 0.9.6 (03/30/2000) david iacovelli -  add IOCTL to get string, manufacture, and boot descriptors - - 0.9.5 (03/14/2000) greg kroah-hartman -	more error checking added to SerialOpen to try to fix UHCI open problem - - 0.9.4 (03/09/2000) greg kroah-hartman -	added more error checking to handle oops when data is hanging -	around and tty is abruptly closed. - - 0.9.3 (03/09/2000) david iacovelli -	Add epic support for xon/xoff chars -	play with performance - - 0.9.2 (03/08/2000) greg kroah-hartman -	changed most "info" calls to "dbg" -	implemented flow control properly in the termios call - - 0.9.1 (03/08/2000) david iacovelli -	added EPIC support -	enabled bootloader update - - 0.9 (03/08/2000) greg kroah-hartman -	Release to IO networks. -	Integrated changes that David made -  made getting urbs for writing SMP safe - - 0.8 (03/07/2000) greg kroah-hartman -	Release to IO networks. -	Fixed problems that were seen in code by David. -  Now both Edgeport/4 and Edgeport/2 works properly. -  Changed most of the functions to use port instead of serial. - - 0.7 (02/27/2000) greg kroah-hartman -	Milestone 3 release. -	Release to IO Networks -	ioctl for waiting on line change implemented. -	ioctl for getting statistics implemented. -	multiport support working. -	lsr and msr registers are now handled properly. -	change break now hooked up and working. -	support for all known Edgeport devices. - - 0.6 (02/22/2000) greg kroah-hartman -	Release to IO networks. -	CHASE is implemented correctly when port is closed. -	SerialOpen now blocks correctly until port is fully opened. - - 0.5 (02/20/2000) greg kroah-hartman -	Release to IO networks. -	Known problems: -		modem status register changes are not sent on to the user -		CHASE is not implemented when the port is closed. - - 0.4 (02/16/2000) greg kroah-hartman -	Second cut at the CeBit demo. -	Doesn't leak memory on every write to the port -	Still small leaks on startup. -	Added support for Edgeport/2 and Edgeport/8 - - 0.3 (02/15/2000) greg kroah-hartman -	CeBit demo release. -	Force the line settings to 4800, 8, 1, e for the demo. -	Warning! This version leaks memory like crazy! - - 0.2 (01/30/2000) greg kroah-hartman -	Milestone 1 release. -	Device is found by USB subsystem, enumerated, firmware is downloaded -	and the descriptors are printed to the debug log, config is set, and -	green light starts to blink. Open port works, and data can be sent -	and received at the default settings of the UART. Loopback connector -	and debug log confirms this. - - 0.1 (01/23/2000) greg kroah-hartman -	Initial release to help IO Networks try to set up their test system. -	Edgeport4 is recognized, firmware is downloaded, config is set so -	device blinks green light every 3 sec. Port is bound, but opening, -	closing, and sending data do not work properly. - - diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index d6921fa1403..f9f29b289f2 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -20,50 +20,7 @@   * TODO:   * -- Add true modem contol line query capability.  Currently we track the   *    states reported by the interrupt and the states we request. - * -- Add error reporting back to application for UART error conditions. - *    Just point me at how to implement this and I'll do it. I've put the - *    framework in, but haven't analyzed the "tty_flip" interface yet.   * -- Add support for flush commands - * -- Add everything that is missing :) - * - * 27-Nov-2001 gkh - * 	compressed all the differnent device entries into 1. - * - * 30-May-2001 gkh - *	switched from using spinlock to a semaphore, which fixes lots of - *	problems. - * - * 08-Apr-2001 gb - *	- Identify version on module load. - * - * 12-Mar-2001 gkh - *	- Added support for the GoHubs GO-COM232 device which is the same as the - *	  Peracom device. - * - * 06-Nov-2000 gkh - *	- Added support for the old Belkin and Peracom devices. - *	- Made the port able to be opened multiple times. - *	- Added some defaults incase the line settings are things these devices - *	  can't support. - * - * 18-Oct-2000 William Greathouse - *    Released into the wild (linux-usb-devel) - * - * 17-Oct-2000 William Greathouse - *    Add code to recognize firmware version and set hardware flow control - *    appropriately.  Belkin states that firmware prior to 3.05 does not - *    operate correctly in hardware handshake mode.  I have verified this - *    on firmware 2.05 -- for both RTS and DTR input flow control, the control - *    line is not reset.  The test performed by the Belkin Win* driver is - *    to enable hardware flow control for firmware 2.06 or greater and - *    for 1.00 or prior.  I am only enabling for 2.06 or greater. - * - * 12-Oct-2000 William Greathouse - *    First cut at supporting Belkin USB Serial Adapter F5U103 - *    I did not have a copy of the original work to support this - *    adapter, so pardon any stupid mistakes.  All of the information - *    I am using to write this driver was acquired by using a modified - *    UsbSnoop on Windows2000 and from examining the other USB drivers.   */  #include <linux/kernel.h> diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 6ae1c0688b5..0e77511060c 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -335,13 +335,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)  		goto out;  	dbg("%s - submitting interrupt urb", __func__); -	port->interrupt_in_urb->dev = serial->dev;  	r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  	if (r) {  		dev_err(&port->dev, "%s - failed submitting interrupt urb,"  			" error %d\n", __func__, r);  		ch341_close(port); -		return -EPROTO; +		goto out;  	}  	r = usb_serial_generic_open(tty, port); diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index fd67cc53545..adfe660ed00 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -92,6 +92,7 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */  	{ USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */  	{ USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ +	{ USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */  	{ USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */  	{ USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */  	{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ @@ -280,7 +281,10 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,  		dbg("%s - Unable to send config request, "  				"request=0x%x size=%d result=%d\n",  				__func__, request, size, result); -		return -EPROTO; +		if (result > 0) +			result = -EPROTO; + +		return result;  	}  	return 0; @@ -331,7 +335,10 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,  		dbg("%s - Unable to send request, "  				"request=0x%x size=%d result=%d\n",  				__func__, request, size, result); -		return -EPROTO; +		if (result > 0) +			result = -EPROTO; + +		return result;  	}  	return 0; @@ -395,10 +402,11 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)  	dbg("%s - port %d", __func__, port->number); -	if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) { -		dev_err(&port->dev, "%s - Unable to enable UART\n", -				__func__); -		return -EPROTO; +	result = cp210x_set_config_single(port, CP210X_IFC_ENABLE, +								UART_ENABLE); +	if (result) { +		dev_err(&port->dev, "%s - Unable to enable UART\n", __func__); +		return result;  	}  	result = usb_serial_generic_open(tty, port); @@ -520,18 +528,13 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,  		cflag |= PARENB;  		break;  	case BITS_PARITY_MARK: -		dbg("%s - parity = MARK (not supported, disabling parity)", -				__func__); -		cflag &= ~PARENB; -		bits &= ~BITS_PARITY_MASK; -		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); +		dbg("%s - parity = MARK", __func__); +		cflag |= (PARENB|PARODD|CMSPAR);  		break;  	case BITS_PARITY_SPACE: -		dbg("%s - parity = SPACE (not supported, disabling parity)", -				__func__); -		cflag &= ~PARENB; -		bits &= ~BITS_PARITY_MASK; -		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); +		dbg("%s - parity = SPACE", __func__); +		cflag &= ~PARODD; +		cflag |= (PARENB|CMSPAR);  		break;  	default:  		dbg("%s - Unknown parity mode, disabling parity", __func__); @@ -588,7 +591,6 @@ static void cp210x_set_termios(struct tty_struct *tty,  	if (!tty)  		return; -	tty->termios->c_cflag &= ~CMSPAR;  	cflag = tty->termios->c_cflag;  	old_cflag = old_termios->c_cflag;  	baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty)); @@ -643,16 +645,27 @@ static void cp210x_set_termios(struct tty_struct *tty,  					"not supported by device\n");  	} -	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) { +	if ((cflag     & (PARENB|PARODD|CMSPAR)) != +	    (old_cflag & (PARENB|PARODD|CMSPAR))) {  		cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);  		bits &= ~BITS_PARITY_MASK;  		if (cflag & PARENB) { -			if (cflag & PARODD) { -				bits |= BITS_PARITY_ODD; -				dbg("%s - parity = ODD", __func__); +			if (cflag & CMSPAR) { +			    if (cflag & PARODD) { +				    bits |= BITS_PARITY_MARK; +				    dbg("%s - parity = MARK", __func__); +			    } else { +				    bits |= BITS_PARITY_SPACE; +				    dbg("%s - parity = SPACE", __func__); +			    }  			} else { -				bits |= BITS_PARITY_EVEN; -				dbg("%s - parity = EVEN", __func__); +			    if (cflag & PARODD) { +				    bits |= BITS_PARITY_ODD; +				    dbg("%s - parity = ODD", __func__); +			    } else { +				    bits |= BITS_PARITY_EVEN; +				    dbg("%s - parity = EVEN", __func__); +			    }  			}  		}  		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index f744ab7a3b1..98bf8334983 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -138,7 +138,6 @@ static int cyberjack_startup(struct usb_serial *serial)  	for (i = 0; i < serial->num_ports; ++i) {  		int result; -		serial->port[i]->interrupt_in_urb->dev = serial->dev;  		result = usb_submit_urb(serial->port[i]->interrupt_in_urb,  					GFP_KERNEL);  		if (result) @@ -208,7 +207,6 @@ static void cyberjack_close(struct usb_serial_port *port)  static int cyberjack_write(struct tty_struct *tty,  	struct usb_serial_port *port, const unsigned char *buf, int count)  { -	struct usb_serial *serial = port->serial;  	struct cyberjack_private *priv = usb_get_serial_port_data(port);  	unsigned long flags;  	int result; @@ -221,22 +219,18 @@ static int cyberjack_write(struct tty_struct *tty,  		return 0;  	} -	spin_lock_bh(&port->lock); -	if (port->write_urb_busy) { -		spin_unlock_bh(&port->lock); +	if (!test_and_clear_bit(0, &port->write_urbs_free)) {  		dbg("%s - already writing", __func__);  		return 0;  	} -	port->write_urb_busy = 1; -	spin_unlock_bh(&port->lock);  	spin_lock_irqsave(&priv->lock, flags);  	if (count+priv->wrfilled > sizeof(priv->wrbuf)) {  		/* To much data for buffer. Reset buffer. */  		priv->wrfilled = 0; -		port->write_urb_busy = 0;  		spin_unlock_irqrestore(&priv->lock, flags); +		set_bit(0, &port->write_urbs_free);  		return 0;  	} @@ -265,13 +259,7 @@ static int cyberjack_write(struct tty_struct *tty,  		priv->wrsent = length;  		/* set up our urb */ -		usb_fill_bulk_urb(port->write_urb, serial->dev, -			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), -			      port->write_urb->transfer_buffer, length, -			      ((serial->type->write_bulk_callback) ? -			       serial->type->write_bulk_callback : -			       cyberjack_write_bulk_callback), -			      port); +		port->write_urb->transfer_buffer_length = length;  		/* send the data out the bulk port */  		result = usb_submit_urb(port->write_urb, GFP_ATOMIC); @@ -283,7 +271,7 @@ static int cyberjack_write(struct tty_struct *tty,  			priv->wrfilled = 0;  			priv->wrsent = 0;  			spin_unlock_irqrestore(&priv->lock, flags); -			port->write_urb_busy = 0; +			set_bit(0, &port->write_urbs_free);  			return 0;  		} @@ -351,7 +339,6 @@ static void cyberjack_read_int_callback(struct urb *urb)  		spin_unlock(&priv->lock);  		if (!old_rdtodo) { -			port->read_urb->dev = port->serial->dev;  			result = usb_submit_urb(port->read_urb, GFP_ATOMIC);  			if (result)  				dev_err(&port->dev, "%s - failed resubmitting " @@ -362,7 +349,6 @@ static void cyberjack_read_int_callback(struct urb *urb)  	}  resubmit: -	port->interrupt_in_urb->dev = port->serial->dev;  	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);  	if (result)  		dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); @@ -415,7 +401,6 @@ static void cyberjack_read_bulk_callback(struct urb *urb)  	/* Continue to read if we have still urbs to do. */  	if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) { -		port->read_urb->dev = port->serial->dev;  		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);  		if (result)  			dev_err(&port->dev, "%s - failed resubmitting read " @@ -432,7 +417,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb)  	dbg("%s - port %d", __func__, port->number); -	port->write_urb_busy = 0; +	set_bit(0, &port->write_urbs_free);  	if (status) {  		dbg("%s - nonzero write bulk status received: %d",  		    __func__, status); @@ -455,13 +440,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb)  		priv->wrsent += length;  		/* set up our urb */ -		usb_fill_bulk_urb(port->write_urb, port->serial->dev, -			      usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), -			      port->write_urb->transfer_buffer, length, -			      ((port->serial->type->write_bulk_callback) ? -			       port->serial->type->write_bulk_callback : -			       cyberjack_write_bulk_callback), -			      port); +		port->write_urb->transfer_buffer_length = length;  		/* send the data out the bulk port */  		result = usb_submit_urb(port->write_urb, GFP_ATOMIC); diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index d9906eb9d16..07680d6b792 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -16,32 +16,6 @@   *   * See http://geocities.com/i0xox0i for information on this driver and the   * earthmate usb device. - * - *  Lonnie Mendez <dignome@gmail.com> - *  4-29-2005 - *	Fixed problem where setting or retreiving the serial config would fail - *	with EPIPE.  Removed CRTS toggling so the driver behaves more like - *	other usbserial adapters.  Issued new interval of 1ms instead of the - *	default 10ms.  As a result, transfer speed has been substantially - *	increased from avg. 850bps to avg. 3300bps.  initial termios has also - *	been modified.  Cleaned up code and formatting issues so it is more - *	readable.  Replaced the C++ style comments. - * - *  Lonnie Mendez <dignome@gmail.com> - *  12-15-2004 - *	Incorporated write buffering from pl2303 driver.  Fixed bug with line - *	handling so both lines are raised in cypress_open. (was dropping rts) - *      Various code cleanups made as well along with other misc bug fixes. - * - *  Lonnie Mendez <dignome@gmail.com> - *  04-10-2004 - *	Driver modified to support dynamic line settings.  Various improvements - *      and features. - * - *  Neil Whelchel - *  10-2003 - *	Driver first released. - *   */  /* Thanks to Neil Whelchel for writing the first cypress m8 implementation @@ -1162,8 +1136,6 @@ static void cypress_unthrottle(struct tty_struct *tty)  		return;  	if (actually_throttled) { -		port->interrupt_in_urb->dev = port->serial->dev; -  		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  		if (result) {  			dev_err(&port->dev, "%s - failed submitting read urb, " @@ -1352,7 +1324,6 @@ static void cypress_write_int_callback(struct urb *urb)  		dbg("%s - nonzero write bulk status received: %d",  			__func__, status);  		port->interrupt_out_urb->transfer_buffer_length = 1; -		port->interrupt_out_urb->dev = port->serial->dev;  		result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);  		if (!result)  			return; diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index e92cbefc0f8..6d26a77d0f2 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -13,222 +13,6 @@  *  *  Peter Berger (pberger@brimson.com)  *  Al Borchers (borchers@steinerpoint.com) -*  -* (12/03/2001) gkh -*	switched to using port->port.count instead of private version. -*	Removed port->active -* -* (04/08/2001) gb -*	Identify version on module load. -* -* (11/01/2000) Adam J. Richter -*	usb_device_id table support -*  -* (11/01/2000) pberger and borchers -*    -- Turned off the USB_DISABLE_SPD flag for write bulk urbs--it caused -*       USB 4 ports to hang on startup. -*    -- Serialized access to write urbs by adding the dp_write_urb_in_use -*       flag; otherwise, the driver caused SMP system hangs.  Watching the -*       urb status is not sufficient. -* -* (10/05/2000) gkh -*    -- Fixed bug with urb->dev not being set properly, now that the usb -*	core needs it. -*  -*  (8/8/2000) pberger and borchers -*    -- Fixed close so that  -*       - it can timeout while waiting for transmit idle, if needed; -*       - it ignores interrupts when flushing the port, turning -*         of modem signalling, and so on; -*       - it waits for the flush to really complete before returning. -*    -- Read_bulk_callback and write_bulk_callback check for a closed -*       port before using the tty struct or writing to the port. -*    -- The two changes above fix the oops caused by interrupted closes. -*    -- Added interruptible args to write_oob_command and set_modem_signals -*       and added a timeout arg to transmit_idle; needed for fixes to -*       close. -*    -- Added code for rx_throttle and rx_unthrottle so that input flow -*       control works. -*    -- Added code to set overrun, parity, framing, and break errors -*       (untested). -*    -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length -*       bulk writes are done.  These hung the Digi USB device.  The -*       0 length bulk writes were a new feature of usb-uhci added in -*       the 2.4.0-test6 kernels. -*    -- Fixed mod inc race in open; do mod inc before sleeping to wait -*       for a close to finish. -* -*  (7/31/2000) pberger -*    -- Fixed bugs with hardware handshaking: -*       - Added code to set/clear tty->hw_stopped in digi_read_oob_callback() -*         and digi_set_termios() -*    -- Added code in digi_set_termios() to -*       - add conditional in code handling transition from B0 to only -*         set RTS if RTS/CTS flow control is either not in use or if -*         the port is not currently throttled. -*       - handle turning off CRTSCTS. -* -*  (7/30/2000) borchers -*    -- Added support for more than one Digi USB device by moving -*       globals to a private structure in the pointed to from the -*       usb_serial structure. -*    -- Moved the modem change and transmit idle wait queues into -*       the port private structure, so each port has its own queue -*       rather than sharing global queues. -*    -- Added support for break signals. -* -*  (7/25/2000) pberger -*    -- Added USB-2 support.  Note: the USB-2 supports 3 devices: two -*       serial and a parallel port.  The parallel port is implemented -*       as a serial-to-parallel converter.  That is, the driver actually -*       presents all three USB-2 interfaces as serial ports, but the third -*       one physically connects to a parallel device.  Thus, for example, -*       one could plug a parallel printer into the USB-2's third port, -*       but from the kernel's (and userland's) point of view what's -*       actually out there is a serial device. -* -*  (7/15/2000) borchers -*    -- Fixed race in open when a close is in progress. -*    -- Keep count of opens and dec the module use count for each -*       outstanding open when shutdown is called (on disconnect). -*    -- Fixed sanity checks in read_bulk_callback and write_bulk_callback -*       so pointers are checked before use. -*    -- Split read bulk callback into in band and out of band -*       callbacks, and no longer restart read chains if there is -*       a status error or a sanity error.  This fixed the seg -*       faults and other errors we used to get on disconnect. -*    -- Port->active is once again a flag as usb-serial intended it -*       to be, not a count.  Since it was only a char it would -*       have been limited to 256 simultaneous opens.  Now the open -*       count is kept in the port private structure in dp_open_count. -*    -- Added code for modularization of the digi_acceleport driver. -* -*  (6/27/2000) pberger and borchers -*    -- Zeroed out sync field in the wakeup_task before first use; -*       otherwise the uninitialized value might prevent the task from -*       being scheduled. -*    -- Initialized ret value to 0 in write_bulk_callback, otherwise -*       the uninitialized value could cause a spurious debugging message. -* -*  (6/22/2000) pberger and borchers -*    -- Made cond_wait_... inline--apparently on SPARC the flags arg -*       to spin_lock_irqsave cannot be passed to another function -*       to call spin_unlock_irqrestore.  Thanks to Pauline Middelink. -*    -- In digi_set_modem_signals the inner nested spin locks use just -*       spin_lock() rather than spin_lock_irqsave().  The old code -*       mistakenly left interrupts off.  Thanks to Pauline Middelink. -*    -- copy_from_user (which can sleep) is no longer called while a -*       spinlock is held.  We copy to a local buffer before getting -*       the spinlock--don't like the extra copy but the code is simpler. -*    -- Printk and dbg are no longer called while a spin lock is held. -* -*  (6/4/2000) pberger and borchers -*    -- Replaced separate calls to spin_unlock_irqrestore and -*       interruptible_sleep_on_timeout with a new function -*       cond_wait_interruptible_timeout_irqrestore.  This eliminates -*       the race condition where the wake up could happen after -*       the unlock and before the sleep. -*    -- Close now waits for output to drain. -*    -- Open waits until any close in progress is finished. -*    -- All out of band responses are now processed, not just the -*       first in a USB packet. -*    -- Fixed a bug that prevented the driver from working when the -*       first Digi port was not the first USB serial port--the driver -*       was mistakenly using the external USB serial port number to -*       try to index into its internal ports. -*    -- Fixed an SMP bug -- write_bulk_callback is called directly from -*       an interrupt, so spin_lock_irqsave/spin_unlock_irqrestore are -*       needed for locks outside write_bulk_callback that are also -*       acquired by write_bulk_callback to prevent deadlocks. -*    -- Fixed support for select() by making digi_chars_in_buffer() -*       return 256 when -EINPROGRESS is set, as the line discipline -*       code in n_tty.c expects. -*    -- Fixed an include file ordering problem that prevented debugging -*       messages from working. -*    -- Fixed an intermittent timeout problem that caused writes to -*       sometimes get stuck on some machines on some kernels.  It turns -*       out in these circumstances write_chan() (in n_tty.c) was -*       asleep waiting for our wakeup call.  Even though we call -*       wake_up_interruptible() in digi_write_bulk_callback(), there is -*       a race condition that could cause the wakeup to fail: if our -*       wake_up_interruptible() call occurs between the time that our -*       driver write routine finishes and write_chan() sets current->state -*       to TASK_INTERRUPTIBLE, the effect of our wakeup setting the state -*       to TASK_RUNNING will be lost and write_chan's subsequent call to -*       schedule() will never return (unless it catches a signal). -*       This race condition occurs because write_bulk_callback() (and thus -*       the wakeup) are called asynchronously from an interrupt, rather than -*       from the scheduler.  We can avoid the race by calling the wakeup -*       from the scheduler queue and that's our fix:  Now, at the end of -*       write_bulk_callback() we queue up a wakeup call on the scheduler -*       task queue.  We still also invoke the wakeup directly since that -*       squeezes a bit more performance out of the driver, and any lost -*       race conditions will get cleaned up at the next scheduler run. -* -*       NOTE:  The problem also goes away if you comment out -*       the two code lines in write_chan() where current->state -*       is set to TASK_RUNNING just before calling driver.write() and to -*       TASK_INTERRUPTIBLE immediately afterwards.  This is why the -*       problem did not show up with the 2.2 kernels -- they do not -*       include that code. -* -*  (5/16/2000) pberger and borchers -*    -- Added timeouts to sleeps, to defend against lost wake ups. -*    -- Handle transition to/from B0 baud rate in digi_set_termios. -* -*  (5/13/2000) pberger and borchers -*    -- All commands now sent on out of band port, using -*       digi_write_oob_command. -*    -- Get modem control signals whenever they change, support TIOCMGET/ -*       SET/BIS/BIC ioctls. -*    -- digi_set_termios now supports parity, word size, stop bits, and -*       receive enable. -*    -- Cleaned up open and close, use digi_set_termios and -*       digi_write_oob_command to set port parameters. -*    -- Added digi_startup_device to start read chains on all ports. -*    -- Write buffer is only used when count==1, to be sure put_char can -*       write a char (unless the buffer is full). -* -*  (5/10/2000) pberger and borchers -*    -- Added MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT calls on open/close. -*    -- Fixed problem where the first incoming character is lost on -*       port opens after the first close on that port.  Now we keep -*       the read_urb chain open until shutdown. -*    -- Added more port conditioning calls in digi_open and digi_close. -*    -- Convert port->active to a use count so that we can deal with multiple -*       opens and closes properly. -*    -- Fixed some problems with the locking code. -* -*  (5/3/2000) pberger and borchers -*    -- First alpha version of the driver--many known limitations and bugs. -* -* -*  Locking and SMP -* -*  - Each port, including the out-of-band port, has a lock used to -*    serialize all access to the port's private structure. -*  - The port lock is also used to serialize all writes and access to -*    the port's URB. -*  - The port lock is also used for the port write_wait condition -*    variable.  Holding the port lock will prevent a wake up on the -*    port's write_wait; this can be used with cond_wait_... to be sure -*    the wake up is not lost in a race when dropping the lock and -*    sleeping waiting for the wakeup. -*  - digi_write() does not sleep, since it is sometimes called on -*    interrupt time. -*  - digi_write_bulk_callback() and digi_read_bulk_callback() are -*    called directly from interrupts.  Hence spin_lock_irqsave() -*    and spin_unlock_irqrestore() are used in the rest of the code -*    for any locks they acquire. -*  - digi_write_bulk_callback() gets the port lock before waking up -*    processes sleeping on the port write_wait.  It also schedules -*    wake ups so they happen from the scheduler, because the tty -*    system can miss wake ups from interrupts. -*  - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to -*    recheck the condition they are sleeping on.  This is defensive, -*    in case a wake up is lost. -*  - Following Documentation/DocBook/kernel-locking.tmpl no spin locks -*    are held when calling copy_to/from_user or printk.  */  #include <linux/kernel.h> @@ -654,7 +438,6 @@ static int digi_write_oob_command(struct usb_serial_port *port,  			len &= ~3;  		memcpy(oob_port->write_urb->transfer_buffer, buf, len);  		oob_port->write_urb->transfer_buffer_length = len; -		oob_port->write_urb->dev = port->serial->dev;  		ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC);  		if (ret == 0) {  			oob_priv->dp_write_urb_in_use = 1; @@ -732,7 +515,6 @@ static int digi_write_inb_command(struct usb_serial_port *port,  			memcpy(data, buf, len);  			port->write_urb->transfer_buffer_length = len;  		} -		port->write_urb->dev = port->serial->dev;  		ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);  		if (ret == 0) { @@ -803,7 +585,6 @@ static int digi_set_modem_signals(struct usb_serial_port *port,  	data[7] = 0;  	oob_port->write_urb->transfer_buffer_length = 8; -	oob_port->write_urb->dev = port->serial->dev;  	ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC);  	if (ret == 0) { @@ -899,10 +680,8 @@ static void digi_rx_unthrottle(struct tty_struct *tty)  	spin_lock_irqsave(&priv->dp_port_lock, flags);  	/* restart read chain */ -	if (priv->dp_throttle_restart) { -		port->read_urb->dev = port->serial->dev; +	if (priv->dp_throttle_restart)  		ret = usb_submit_urb(port->read_urb, GFP_ATOMIC); -	}  	/* turn throttle off */  	priv->dp_throttled = 0; @@ -1195,7 +974,6 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,  	}  	port->write_urb->transfer_buffer_length = data_len+2; -	port->write_urb->dev = port->serial->dev;  	*data++ = DIGI_CMD_SEND_DATA;  	*data++ = data_len; @@ -1271,7 +1049,6 @@ static void digi_write_bulk_callback(struct urb *urb)  			= (unsigned char)priv->dp_out_buf_len;  		port->write_urb->transfer_buffer_length =  						priv->dp_out_buf_len + 2; -		port->write_urb->dev = serial->dev;  		memcpy(port->write_urb->transfer_buffer + 2, priv->dp_out_buf,  			priv->dp_out_buf_len);  		ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); @@ -1473,7 +1250,6 @@ static int digi_startup_device(struct usb_serial *serial)  	/* set USB_DISABLE_SPD flag for write bulk urbs */  	for (i = 0; i < serial->type->num_ports + 1; i++) {  		port = serial->port[i]; -		port->write_urb->dev = port->serial->dev;  		ret = usb_submit_urb(port->read_urb, GFP_KERNEL);  		if (ret != 0) {  			dev_err(&port->dev, @@ -1616,7 +1392,6 @@ static void digi_read_bulk_callback(struct urb *urb)  	}  	/* continue read */ -	urb->dev = port->serial->dev;  	ret = usb_submit_urb(urb, GFP_ATOMIC);  	if (ret != 0 && ret != -EPERM) {  		dev_err(&port->dev, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ff3db5d056a..c290df97108 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2105,6 +2105,9 @@ static void ftdi_set_termios(struct tty_struct *tty,  	cflag = termios->c_cflag; +	if (old_termios == 0) +		goto no_skip; +  	if (old_termios->c_cflag == termios->c_cflag  	    && old_termios->c_ispeed == termios->c_ispeed  	    && old_termios->c_ospeed == termios->c_ospeed) @@ -2118,6 +2121,7 @@ static void ftdi_set_termios(struct tty_struct *tty,  	    (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)))  		goto no_data_parity_stop_changes; +no_skip:  	/* Set number of data bits, parity, stop bits */  	urb_value = 0; diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 1a49ca9c8ea..bf12565f8e8 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -901,7 +901,6 @@ static int garmin_init_session(struct usb_serial_port *port)  		usb_kill_urb(port->interrupt_in_urb);  		dbg("%s - adding interrupt input", __func__); -		port->interrupt_in_urb->dev = serial->dev;  		status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  		if (status)  			dev_err(&serial->dev->dev, @@ -1277,7 +1276,6 @@ static void garmin_read_int_callback(struct urb *urb)  	unsigned long flags;  	int retval;  	struct usb_serial_port *port = urb->context; -	struct usb_serial *serial = port->serial;  	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);  	unsigned char *data = urb->transfer_buffer;  	int status = urb->status; @@ -1311,12 +1309,6 @@ static void garmin_read_int_callback(struct urb *urb)  		if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {  			/* bulk data available */ -			usb_fill_bulk_urb(port->read_urb, serial->dev, -					usb_rcvbulkpipe(serial->dev, -						port->bulk_in_endpointAddress), -					port->read_urb->transfer_buffer, -					port->read_urb->transfer_buffer_length, -					garmin_read_bulk_callback, port);  			retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);  			if (retval) {  				dev_err(&port->dev, @@ -1353,7 +1345,6 @@ static void garmin_read_int_callback(struct urb *urb)  	garmin_read_process(garmin_data_p, data, urb->actual_length, 0); -	port->interrupt_in_urb->dev = port->serial->dev;  	retval = usb_submit_urb(urb, GFP_ATOMIC);  	if (retval)  		dev_err(&urb->dev->dev, diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index e4db5ad2bc5..f7403576f99 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -1,7 +1,7 @@  /*   * USB Serial Converter Generic functions   * - * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) + * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com)   * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)   *   *	This program is free software; you can redistribute it and/or @@ -132,7 +132,7 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port  	/* if we have a bulk endpoint, start reading from it */  	if (port->bulk_in_size) -		result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL); +		result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);  	return result;  } @@ -157,8 +157,10 @@ static void generic_cleanup(struct usb_serial_port *port)  			kfifo_reset_out(&port->write_fifo);  			spin_unlock_irqrestore(&port->lock, flags);  		} -		if (port->bulk_in_size) -			usb_kill_urb(port->read_urb); +		if (port->bulk_in_size) { +			for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) +				usb_kill_urb(port->read_urbs[i]); +		}  	}  } @@ -308,19 +310,52 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)  	return chars;  } -int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, +static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, +						int index, gfp_t mem_flags) +{ +	int res; + +	if (!test_and_clear_bit(index, &port->read_urbs_free)) +		return 0; + +	dbg("%s - port %d, urb %d\n", __func__, port->number, index); + +	res = usb_submit_urb(port->read_urbs[index], mem_flags); +	if (res) { +		if (res != -EPERM) { +			dev_err(&port->dev, +					"%s - usb_submit_urb failed: %d\n", +					__func__, res); +		} +		set_bit(index, &port->read_urbs_free); +		return res; +	} + +	return 0; +} + +int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,  					gfp_t mem_flags)  { -	int result; +	int res; +	int i; -	result = usb_submit_urb(port->read_urb, mem_flags); -	if (result && result != -EPERM) { -		dev_err(&port->dev, "%s - error submitting urb: %d\n", -							__func__, result); +	dbg("%s - port %d", __func__, port->number); + +	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { +		res = usb_serial_generic_submit_read_urb(port, i, mem_flags); +		if (res) +			goto err;  	} -	return result; + +	return 0; +err: +	for (; i >= 0; --i) +		usb_kill_urb(port->read_urbs[i]); + +	return res;  } -EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb); +EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs);  void usb_serial_generic_process_read_urb(struct urb *urb)  { @@ -356,14 +391,19 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)  {  	struct usb_serial_port *port = urb->context;  	unsigned char *data = urb->transfer_buffer; -	int status = urb->status;  	unsigned long flags; +	int i; -	dbg("%s - port %d", __func__, port->number); +	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { +		if (urb == port->read_urbs[i]) +			break; +	} +	set_bit(i, &port->read_urbs_free); -	if (unlikely(status != 0)) { -		dbg("%s - nonzero read bulk status received: %d", -		    __func__, status); +	dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i, +							urb->actual_length); +	if (urb->status) { +		dbg("%s - non-zero urb status: %d\n", __func__, urb->status);  		return;  	} @@ -376,7 +416,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)  	port->throttled = port->throttle_req;  	if (!port->throttled) {  		spin_unlock_irqrestore(&port->lock, flags); -		usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); +		usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);  	} else  		spin_unlock_irqrestore(&port->lock, flags);  } @@ -443,7 +483,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)  	spin_unlock_irq(&port->lock);  	if (was_throttled) -		usb_serial_generic_submit_read_urb(port, GFP_KERNEL); +		usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);  }  EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); @@ -509,8 +549,9 @@ int usb_serial_generic_resume(struct usb_serial *serial)  		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))  			continue; -		if (port->read_urb) { -			r = usb_submit_urb(port->read_urb, GFP_NOIO); +		if (port->bulk_in_size) { +			r = usb_serial_generic_submit_read_urbs(port, +								GFP_NOIO);  			if (r < 0)  				c++;  		} diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 2ee807523f5..abd2ee2b2f9 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -610,7 +610,6 @@ static void edge_interrupt_callback(struct urb *urb)  					/* we have pending bytes on the  					   bulk in pipe, send a request */ -					edge_serial->read_urb->dev = edge_serial->serial->dev;  					result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);  					if (result) {  						dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __func__, result); @@ -711,7 +710,6 @@ static void edge_bulk_in_callback(struct urb *urb)  	/* check to see if there's any more data for us to read */  	if (edge_serial->rxBytesAvail > 0) {  		dbg("%s - posting a read", __func__); -		edge_serial->read_urb->dev = edge_serial->serial->dev;  		retval = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);  		if (retval) {  			dev_err(&urb->dev->dev, @@ -1330,7 +1328,6 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,  	edge_port->txCredits -= count;  	edge_port->icount.tx += count; -	urb->dev = edge_serial->serial->dev;  	status = usb_submit_urb(urb, GFP_ATOMIC);  	if (status) {  		/* something went wrong */ diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 0aac00afb5c..e44d375edaa 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -15,13 +15,6 @@   * For questions or problems with this driver, contact Inside Out   * Networks technical support, or Peter Berger <pberger@brimson.com>,   * or Al Borchers <alborchers@steinerpoint.com>. - * - * Version history: - * - *	July 11, 2002 	Removed 4 port device structure since all TI UMP - *			chips have only 2 ports - *			David Iacovelli (davidi@ionetworks.com) - *   */  #include <linux/kernel.h> @@ -1777,12 +1770,11 @@ static void edge_bulk_in_callback(struct urb *urb)  exit:  	/* continue read unless stopped */  	spin_lock(&edge_port->ep_lock); -	if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) { -		urb->dev = edge_port->port->serial->dev; +	if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING)  		retval = usb_submit_urb(urb, GFP_ATOMIC); -	} else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) { +	else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING)  		edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED; -	} +  	spin_unlock(&edge_port->ep_lock);  	if (retval)  		dev_err(&urb->dev->dev, @@ -1959,9 +1951,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)  			status = -EINVAL;  			goto release_es_lock;  		} -		urb->complete = edge_interrupt_callback;  		urb->context = edge_serial; -		urb->dev = dev;  		status = usb_submit_urb(urb, GFP_KERNEL);  		if (status) {  			dev_err(&port->dev, @@ -1987,9 +1977,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)  		goto unlink_int_urb;  	}  	edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING; -	urb->complete = edge_bulk_in_callback;  	urb->context = edge_port; -	urb->dev = dev;  	status = usb_submit_urb(urb, GFP_KERNEL);  	if (status) {  		dev_err(&port->dev, @@ -2118,12 +2106,7 @@ static void edge_send(struct tty_struct *tty)  				port->write_urb->transfer_buffer);  	/* set up our urb */ -	usb_fill_bulk_urb(port->write_urb, port->serial->dev, -			   usb_sndbulkpipe(port->serial->dev, -					    port->bulk_out_endpointAddress), -			   port->write_urb->transfer_buffer, count, -			   edge_bulk_out_callback, -			   port); +	port->write_urb->transfer_buffer_length = count;  	/* send the data out the bulk port */  	result = usb_submit_urb(port->write_urb, GFP_ATOMIC); @@ -2267,9 +2250,6 @@ static int restart_read(struct edgeport_port *edge_port)  	if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPED) {  		urb = edge_port->port->read_urb; -		urb->complete = edge_bulk_in_callback; -		urb->context = edge_port; -		urb->dev = edge_port->port->serial->dev;  		status = usb_submit_urb(urb, GFP_ATOMIC);  	}  	edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING; diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 4735931b4c7..36f5cbe9048 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -8,40 +8,6 @@   *	it under the terms of the GNU General Public License as published by   *	the Free Software Foundation; either version 2 of the License, or   *	(at your option) any later version. - * - * (12/12/2002) ganesh - * 	Added support for practically all devices supported by ActiveSync - * 	on Windows. Thanks to Wes Cilldhaire <billybobjoehenrybob@hotmail.com>. - * - * (26/11/2002) ganesh - * 	Added insmod options to specify product and vendor id. - * 	Use modprobe ipaq vendor=0xfoo product=0xbar - * - * (26/7/2002) ganesh - * 	Fixed up broken error handling in ipaq_open. Retry the "kickstart" - * 	packet much harder - this drastically reduces connection failures. - * - * (30/4/2002) ganesh - * 	Added support for the Casio EM500. Completely untested. Thanks - * 	to info from Nathan <wfilardo@fuse.net> - * - * (19/3/2002) ganesh - *	Don't submit urbs while holding spinlocks. Not strictly necessary - *	in 2.5.x. - * - * (8/3/2002) ganesh - * 	The ipaq sometimes emits a '\0' before the CLIENT string. At this - * 	point of time, the ppp ldisc is not yet attached to the tty, so - * 	n_tty echoes "^ " to the ipaq, which messes up the chat. In 2.5.6-pre2 - * 	this causes a panic because echo_char() tries to sleep in interrupt - * 	context. - * 	The fix is to tell the upper layers that this is a raw device so that - * 	echoing is suppressed. Thanks to Lyle Lindholm for a detailed bug - * 	report. - * - * (25/2/2002) ganesh - * 	Added support for the HP Jornada 548 and 568. Completely untested. - * 	Thanks to info from Heath Robinson and Arieh Davidoff.   */  #include <linux/kernel.h> diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index ccbce4066d0..0c537da0d3c 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -22,38 +22,6 @@   *   * See Documentation/usb/usb-serial.txt for more information on using this   * driver - * - * 2008_Jun_02  Felipe Balbi <me@felipebalbi.com> - *	Introduced common header to be used also in USB Gadget Framework. - *	Still needs some other style fixes. - * - * 2007_Jun_21  Alan Cox <alan@lxorguk.ukuu.org.uk> - *	Minimal cleanups for some of the driver problens and tty layer abuse. - *	Still needs fixing to allow multiple dongles. - * - * 2002_Mar_07	greg kh - *	moved some needed structures and #define values from the - *	net/irda/irda-usb.h file into our file, as we don't want to depend on - *	that codebase compiling correctly :) - * - * 2002_Jan_14  gb - *	Added module parameter to force specific number of XBOFs. - *	Added ir_xbof_change(). - *	Reorganized read_bulk_callback error handling. - *	Switched from FILL_BULK_URB() to usb_fill_bulk_urb(). - * - * 2001_Nov_08  greg kh - *	Changed the irda_usb_find_class_desc() function based on comments and - *	code from Martin Diehl. - * - * 2001_Nov_01	greg kh - *	Added support for more IrDA USB devices. - *	Added support for zero packet.  Added buffer override paramater, so - *	users can transfer larger packets at once if they wish.  Both patches - *	came from Dag Brattli <dag@obexcode.com>. - * - * 2001_Oct_07	greg kh - *	initial version released.   */  #include <linux/kernel.h> diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 6aca631a407..64d0ffd4440 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -1168,15 +1168,14 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)  			  port->write_urb->transfer_buffer, 1,  			  read_rxcmd_callback, port);  	result = usb_submit_urb(port->write_urb, GFP_KERNEL); -  	if (result) {  		dev_err(&port->dev, "%s - failed submitting read urb,"  			" error %d\n", __func__, result);  		iuu_close(port); -		return -EPROTO;  	} else {  		dbg("%s - rxcmd OK", __func__);  	} +  	return result;  } diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index a442352d7b6..bc8dc203e81 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -25,73 +25,6 @@    Tip 'o the hat to IBM (and previously Linuxcare :) for supporting    staff in their work on open source projects. - -  Change History - -    2003sep04	LPM (Keyspan) add support for new single port product USA19HS. -				Improve setup message handling for all devices. - -    Wed Feb 19 22:00:00 PST 2003 (Jeffrey S. Laing <keyspan@jsl.com>) -      Merged the current (1/31/03) Keyspan code with the current (2.4.21-pre4) -      Linux source tree.  The Linux tree lacked support for the 49WLC and -      others.  The Keyspan patches didn't work with the current kernel. - -    2003jan30	LPM	add support for the 49WLC and MPR - -    Wed Apr 25 12:00:00 PST 2002 (Keyspan) -      Started with Hugh Blemings' code dated Jan 17, 2002.  All adapters -      now supported (including QI and QW).  Modified port open, port -      close, and send setup() logic to fix various data and endpoint -      synchronization bugs and device LED status bugs.  Changed keyspan_ -      write_room() to accurately return transmit buffer availability. -      Changed forwardingLength from 1 to 16 for all adapters. - -    Fri Oct 12 16:45:00 EST 2001 -      Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV) - -    Wed Apr 25 12:00:00 PST 2002 (Keyspan) -      Started with Hugh Blemings' code dated Jan 17, 2002.  All adapters -      now supported (including QI and QW).  Modified port open, port -      close, and send setup() logic to fix various data and endpoint -      synchronization bugs and device LED status bugs.  Changed keyspan_ -      write_room() to accurately return transmit buffer availability. -      Changed forwardingLength from 1 to 16 for all adapters. - -    Fri Oct 12 16:45:00 EST 2001 -      Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV) - -    Mon Oct  8 14:29:00 EST 2001 hugh -      Fixed bug that prevented mulitport devices operating correctly -      if they weren't the first unit attached. - -    Sat Oct  6 12:31:21 EST 2001 hugh -      Added support for USA-28XA and -28XB, misc cleanups, break support -      for usa26 based models thanks to David Gibson. - -    Thu May 31 11:56:42 PDT 2001 gkh -      switched from using spinlock to a semaphore - -    (04/08/2001) gb -	Identify version on module load. - -    (11/01/2000) Adam J. Richter -	usb_device_id table support. - -    Tue Oct 10 23:15:33 EST 2000 Hugh -      Merged Paul's changes with my USA-49W mods.  Work in progress -      still... - -    Wed Jul 19 14:00:42 EST 2000 gkh -      Added module_init and module_exit functions to handle the fact that -      this driver is a loadable module now. - -    Tue Jul 18 16:14:52 EST 2000 Hugh -      Basic character input/output for USA-19 now mostly works, -      fixed at 9600 baud for the moment. - -    Sat Jul  8 11:11:48 EST 2000 Hugh -      First public release - nothing works except the firmware upload. -      Tested on PPC and x86 architectures, seems to behave...  */ @@ -397,7 +330,6 @@ static int keyspan_write(struct tty_struct *tty,  		/* send the data out the bulk port */  		this_urb->transfer_buffer_length = todo + dataOffset; -		this_urb->dev = port->serial->dev;  		err = usb_submit_urb(this_urb, GFP_ATOMIC);  		if (err != 0)  			dbg("usb_submit_urb(write bulk) failed (%d)", err); @@ -463,7 +395,6 @@ static void	usa26_indat_callback(struct urb *urb)  	tty_kref_put(tty);  	/* Resubmit urb so we continue receiving */ -	urb->dev = port->serial->dev;  	err = usb_submit_urb(urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - resubmit read urb failed. (%d)", __func__, err); @@ -559,7 +490,6 @@ static void	usa26_instat_callback(struct urb *urb)  	}  	/* Resubmit urb so we continue receiving */ -	urb->dev = serial->dev;  	err = usb_submit_urb(urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - resubmit read urb failed. (%d)", __func__, err); @@ -609,7 +539,6 @@ static void usa28_indat_callback(struct urb *urb)  		tty_kref_put(tty);  		/* Resubmit urb so we continue receiving */ -		urb->dev = port->serial->dev;  		err = usb_submit_urb(urb, GFP_ATOMIC);  		if (err != 0)  			dbg("%s - resubmit read urb failed. (%d)", @@ -694,7 +623,6 @@ static void	usa28_instat_callback(struct urb *urb)  	}  		/* Resubmit urb so we continue receiving */ -	urb->dev = serial->dev;  	err = usb_submit_urb(urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - resubmit read urb failed. (%d)", __func__, err); @@ -789,8 +717,6 @@ static void	usa49_instat_callback(struct urb *urb)  	}  	/* Resubmit urb so we continue receiving */ -	urb->dev = serial->dev; -  	err = usb_submit_urb(urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - resubmit read urb failed. (%d)", __func__, err); @@ -848,7 +774,6 @@ static void	usa49_indat_callback(struct urb *urb)  	tty_kref_put(tty);  	/* Resubmit urb so we continue receiving */ -	urb->dev = port->serial->dev;  	err = usb_submit_urb(urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - resubmit read urb failed. (%d)", __func__, err); @@ -919,8 +844,6 @@ static void usa49wg_indat_callback(struct urb *urb)  	}  	/* Resubmit urb so we continue receiving */ -	urb->dev = serial->dev; -  	err = usb_submit_urb(urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - resubmit read urb failed. (%d)", __func__, err); @@ -996,7 +919,6 @@ static void usa90_indat_callback(struct urb *urb)  	}  	/* Resubmit urb so we continue receiving */ -	urb->dev = port->serial->dev;  	err = usb_submit_urb(urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - resubmit read urb failed. (%d)", __func__, err); @@ -1047,7 +969,6 @@ static void	usa90_instat_callback(struct urb *urb)  	}  	/* Resubmit urb so we continue receiving */ -	urb->dev = serial->dev;  	err = usb_submit_urb(urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - resubmit read urb failed. (%d)", __func__, err); @@ -1123,7 +1044,6 @@ static void	usa67_instat_callback(struct urb *urb)  	}  	/* Resubmit urb so we continue receiving */ -	urb->dev = serial->dev;  	err = usb_submit_urb(urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - resubmit read urb failed. (%d)", __func__, err); @@ -1223,7 +1143,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)  		urb = p_priv->in_urbs[i];  		if (urb == NULL)  			continue; -		urb->dev = serial->dev;  		/* make sure endpoint data toggle is synchronized  		   with the device */ @@ -1239,7 +1158,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)  		urb = p_priv->out_urbs[i];  		if (urb == NULL)  			continue; -		urb->dev = serial->dev;  		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),  						usb_pipeout(urb->pipe), 0); */  	} @@ -1956,7 +1874,6 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,  	/* send the data out the device on control endpoint */  	this_urb->transfer_buffer_length = sizeof(msg); -	this_urb->dev = serial->dev;  	err = usb_submit_urb(this_urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); @@ -2084,7 +2001,6 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,  	/* send the data out the device on control endpoint */  	this_urb->transfer_buffer_length = sizeof(msg); -	this_urb->dev = serial->dev;  	err = usb_submit_urb(this_urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - usb_submit_urb(setup) failed", __func__); @@ -2271,8 +2187,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,  		/* send the data out the device on control endpoint */  		this_urb->transfer_buffer_length = sizeof(msg); - -		this_urb->dev = serial->dev;  	}  	err = usb_submit_urb(this_urb, GFP_ATOMIC);  	if (err != 0) @@ -2415,7 +2329,6 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,  	/* send the data out the device on control endpoint */  	this_urb->transfer_buffer_length = sizeof(msg); -	this_urb->dev = serial->dev;  	err = usb_submit_urb(this_urb, GFP_ATOMIC);  	if (err != 0)  		dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); @@ -2561,7 +2474,6 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial,  	/* send the data out the device on control endpoint */  	this_urb->transfer_buffer_length = sizeof(msg); -	this_urb->dev = serial->dev;  	err = usb_submit_urb(this_urb, GFP_ATOMIC);  	if (err != 0) @@ -2650,14 +2562,12 @@ static int keyspan_startup(struct usb_serial *serial)  	keyspan_setup_urbs(serial);  	if (s_priv->instat_urb != NULL) { -		s_priv->instat_urb->dev = serial->dev;  		err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);  		if (err != 0)  			dbg("%s - submit instat urb failed %d", __func__,  				err);  	}  	if (s_priv->indat_urb != NULL) { -		s_priv->indat_urb->dev = serial->dev;  		err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);  		if (err != 0)  			dbg("%s - submit indat urb failed %d", __func__, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index d5c0c6ab496..a40615674a6 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -12,59 +12,6 @@   *   * See Documentation/usb/usb-serial.txt for more information on using this   * driver - * - * (09/07/2001) gkh - *	cleaned up the Xircom support.  Added ids for Entregra device which is - *	the same as the Xircom device.  Enabled the code to be compiled for - *	either Xircom or Keyspan devices. - * - * (08/11/2001) Cristian M. Craciunescu - *	support for Xircom PGSDB9 - * - * (05/31/2001) gkh - *	switched from using spinlock to a semaphore, which fixes lots of - *	problems. - * - * (04/08/2001) gb - *	Identify version on module load. - * - * (11/01/2000) Adam J. Richter - *	usb_device_id table support - * - * (10/05/2000) gkh - *	Fixed bug with urb->dev not being set properly, now that the usb - *	core needs it. - * - * (08/28/2000) gkh - *	Added locks for SMP safeness. - *	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more - *	than once. - * - * (07/20/2000) borchers - *	- keyspan_pda_write no longer sleeps if it is called on interrupt time; - *	  PPP and the line discipline with stty echo on can call write on - *	  interrupt time and this would cause an oops if write slept - *	- if keyspan_pda_write is in an interrupt, it will not call - *	  usb_control_msg (which sleeps) to query the room in the device - *	  buffer, it simply uses the current room value it has - *	- if the urb is busy or if it is throttled keyspan_pda_write just - *	  returns 0, rather than sleeping to wait for this to change; the - *	  write_chan code in n_tty.c will sleep if needed before calling - *	  keyspan_pda_write again - *	- if the device needs to be unthrottled, write now queues up the - *	  call to usb_control_msg (which sleeps) to unthrottle the device - *	- the wakeups from keyspan_pda_write_bulk_callback are queued rather - *	  than done directly from the callback to avoid the race in write_chan - *	- keyspan_pda_chars_in_buffer also indicates its buffer is full if the - *	  urb status is -EINPROGRESS, meaning it cannot write at the moment - * - * (07/19/2000) gkh - *	Added module_init and module_exit functions to handle the fact that this - *	driver is a loadable module now. - * - * (03/26/2000) gkh - *	Split driver up into device specific pieces. - *   */ @@ -290,7 +237,6 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)  	struct usb_serial_port *port = tty->driver_data;  	/* just restart the receive interrupt URB */  	dbg("keyspan_pda_rx_unthrottle port %d", port->number); -	port->interrupt_in_urb->dev = port->serial->dev;  	if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))  		dbg(" usb_submit_urb(read urb) failed");  } @@ -532,11 +478,11 @@ static int keyspan_pda_write(struct tty_struct *tty,  	   the device is full (wait until it says there is room)  	*/  	spin_lock_bh(&port->lock); -	if (port->write_urb_busy || priv->tx_throttled) { +	if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) {  		spin_unlock_bh(&port->lock);  		return 0;  	} -	port->write_urb_busy = 1; +	clear_bit(0, &port->write_urbs_free);  	spin_unlock_bh(&port->lock);  	/* At this point the URB is in our control, nobody else can submit it @@ -598,7 +544,6 @@ static int keyspan_pda_write(struct tty_struct *tty,  		priv->tx_room -= count; -		port->write_urb->dev = port->serial->dev;  		rc = usb_submit_urb(port->write_urb, GFP_ATOMIC);  		if (rc) {  			dbg(" usb_submit_urb(write bulk) failed"); @@ -618,7 +563,7 @@ static int keyspan_pda_write(struct tty_struct *tty,  	rc = count;  exit:  	if (rc < 0) -		port->write_urb_busy = 0; +		set_bit(0, &port->write_urbs_free);  	return rc;  } @@ -628,7 +573,7 @@ static void keyspan_pda_write_bulk_callback(struct urb *urb)  	struct usb_serial_port *port = urb->context;  	struct keyspan_pda_private *priv; -	port->write_urb_busy = 0; +	set_bit(0, &port->write_urbs_free);  	priv = usb_get_serial_port_data(port);  	/* queue up a wakeup at scheduler time */ @@ -661,7 +606,7 @@ static int keyspan_pda_chars_in_buffer(struct tty_struct *tty)  	   n_tty.c:normal_poll() ) that we're not writeable. */  	spin_lock_irqsave(&port->lock, flags); -	if (port->write_urb_busy || priv->tx_throttled) +	if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled)  		ret = 256;  	spin_unlock_irqrestore(&port->lock, flags);  	return ret; @@ -717,7 +662,6 @@ static int keyspan_pda_open(struct tty_struct *tty,  	priv->tx_throttled = *room ? 0 : 1;  	/*Start reading from the device*/ -	port->interrupt_in_urb->dev = serial->dev;  	rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  	if (rc) {  		dbg("%s - usb_submit_urb(read int) failed", __func__); diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index ddd146300dd..5d3beeeb5fd 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -20,18 +20,6 @@   *   * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus   * (Adapter K), B1 Professional and KAAN Professional (Adapter B) - * - * (21/05/2004) tw - *      Fix bug with P'n'P readers - * - * (28/05/2003) tw - *      Add support for KAAN SIM - * - * (12/09/2002) tw - *      Adapted to 2.5. - * - * (11/08/2002) tw - *      Initial version.   */ @@ -231,9 +219,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)  	dbg("%s - port %d", __func__, port->number);  	priv = usb_get_serial_port_data(port); -	/* someone sets the dev to 0 if the close method has been called */ -	port->interrupt_in_urb->dev = port->serial->dev; -  	/* allocate memory for transfer buffer */  	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);  	if (!transfer_buffer) @@ -393,8 +378,6 @@ static void kobil_read_int_callback(struct urb *urb)  		tty_flip_buffer_push(tty);  	}  	tty_kref_put(tty); -	/* someone sets the dev to 0 if the close method has been called */ -	port->interrupt_in_urb->dev = port->serial->dev;  	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);  	dbg("%s - port %d Send read URB returns: %i", @@ -475,17 +458,9 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,  		priv->filled = 0;  		priv->cur_pos = 0; -		/* someone sets the dev to 0 if the close method -		   has been called */ -		port->interrupt_in_urb->dev = port->serial->dev; -  		/* start reading (except TWIN and KAAN SIM) */  		if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||  			priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) { -			/* someone sets the dev to 0 if the close method has -			   been called */ -			port->interrupt_in_urb->dev = port->serial->dev; -  			result = usb_submit_urb(port->interrupt_in_urb,  								GFP_NOIO);  			dbg("%s - port %d Send read URB returns: %i", diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index ba0d28727cc..a975bb80303 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -19,50 +19,6 @@   *   DTR/RTS signal handling may be incomplete or incorrect. I have mainly   *   implemented what I have seen with SniffUSB or found in belkin_sa.c.   *   For further TODOs check also belkin_sa.c. - * - * TEST STATUS: - *   Basic tests have been performed with minicom/zmodem transfers and - *   modem dialing under Linux 2.4.0-test10 (for me it works fine). - * - * 04-Nov-2003 Bill Marr <marr at flex dot com> - *   - Mimic Windows driver by sending 2 USB 'device request' messages - *     following normal 'baud rate change' message.  This allows data to be - *     transmitted to RS-232 devices which don't assert the 'CTS' signal. - * - * 10-Nov-2001 Wolfgang Grandegger - *   - Fixed an endianess problem with the baudrate selection for PowerPC. - * - * 06-Dec-2001 Martin Hamilton <martinh@gnu.org> - *   - Added support for the Belkin F5U109 DB9 adaptor - * - * 30-May-2001 Greg Kroah-Hartman - *   - switched from using spinlock to a semaphore, which fixes lots of - *     problems. - * - * 04-May-2001 Stelian Pop - *   - Set the maximum bulk output size for Sitecom U232-P25 model to 16 bytes - *     instead of the device reported 32 (using 32 bytes causes many data - *     loss, Windows driver uses 16 too). - * - * 02-May-2001 Stelian Pop - *   - Fixed the baud calculation for Sitecom U232-P25 model - * - * 08-Apr-2001 gb - *   - Identify version on module load. - * - * 06-Jan-2001 Cornel Ciocirlan - *   - Added support for Sitecom U232-P25 model (Product Id 0x0230) - *   - Added support for D-Link DU-H3SP USB BAY (Product Id 0x0200) - * - * 29-Nov-2000 Greg Kroah-Hartman - *   - Added device id table to fit with 2.4.0-test11 structure. - *   - took out DEAL_WITH_TWO_INT_IN_ENDPOINTS #define as it's not needed - *     (lots of things will change if/when the usb-serial core changes to - *     handle these issues. - * - * 27-Nov-2000 Wolfgang Grandegge - *   A version for kernel 2.4.0-test10 released to the Linux community - *   (via linux-usb-devel).   */  #include <linux/kernel.h> @@ -526,7 +482,6 @@ static int  mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)  	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);  	spin_unlock_irqrestore(&priv->lock, flags); -	port->read_urb->dev = port->serial->dev;  	retval = usb_submit_urb(port->read_urb, GFP_KERNEL);  	if (retval) {  		dev_err(&port->dev, @@ -535,7 +490,6 @@ static int  mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)  		goto error;  	} -	port->interrupt_in_urb->dev = port->serial->dev;  	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  	if (retval) {  		usb_kill_urb(port->read_urb); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 3524a105d04..19d112f51b9 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -939,14 +939,7 @@ static void mos7720_bulk_in_callback(struct urb *urb)  	}  	tty_kref_put(tty); -	if (!port->read_urb) { -		dbg("URB KILLED !!!"); -		return; -	} -  	if (port->read_urb->status != -EINPROGRESS) { -		port->read_urb->dev = port->serial->dev; -  		retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);  		if (retval)  			dbg("usb_submit_urb(read bulk) failed, retval = %d", @@ -1014,7 +1007,6 @@ static int mos77xx_calc_num_ports(struct usb_serial *serial)  static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)  {  	struct usb_serial *serial; -	struct usb_serial_port *port0;  	struct urb *urb;  	struct moschip_port *mos7720_port;  	int response; @@ -1029,8 +1021,6 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)  	if (mos7720_port == NULL)  		return -ENODEV; -	port0 = serial->port[0]; -  	usb_clear_halt(serial->dev, port->write_urb->pipe);  	usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -1735,8 +1725,6 @@ static void change_port_settings(struct tty_struct *tty,  	write_mos_reg(serial, port_number, IER, 0x0c);  	if (port->read_urb->status != -EINPROGRESS) { -		port->read_urb->dev = serial->dev; -  		status = usb_submit_urb(port->read_urb, GFP_ATOMIC);  		if (status)  			dbg("usb_submit_urb(read bulk) failed, status = %d", @@ -1786,13 +1774,7 @@ static void mos7720_set_termios(struct tty_struct *tty,  	/* change the port settings to the new ones specified */  	change_port_settings(tty, mos7720_port, old_termios); -	if (!port->read_urb) { -		dbg("%s", "URB KILLED !!!!!"); -		return; -	} -  	if (port->read_urb->status != -EINPROGRESS) { -		port->read_urb->dev = serial->dev;  		status = usb_submit_urb(port->read_urb, GFP_ATOMIC);  		if (status)  			dbg("usb_submit_urb(read bulk) failed, status = %d", diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c72abd52498..55cfd6265b9 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -792,8 +792,6 @@ static void mos7840_bulk_in_callback(struct urb *urb)  	} -	mos7840_port->read_urb->dev = serial->dev; -  	mos7840_port->read_urb_busy = true;  	retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); @@ -2058,7 +2056,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty,  	mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);  	if (mos7840_port->read_urb_busy == false) { -		mos7840_port->read_urb->dev = serial->dev;  		mos7840_port->read_urb_busy = true;  		status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);  		if (status) { @@ -2130,7 +2127,6 @@ static void mos7840_set_termios(struct tty_struct *tty,  	}  	if (mos7840_port->read_urb_busy == false) { -		mos7840_port->read_urb->dev = serial->dev;  		mos7840_port->read_urb_busy = true;  		status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);  		if (status) { diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 60f38d5e64f..45a8c55881d 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -9,31 +9,6 @@   * driver   *   * Please report both successes and troubles to the author at omninet@kroah.com - * - * (05/30/2001) gkh - *	switched from using spinlock to a semaphore, which fixes lots of - *	problems. - * - * (04/08/2001) gb - *	Identify version on module load. - * - * (11/01/2000) Adam J. Richter - *	usb_device_id table support - * - * (10/05/2000) gkh - *	Fixed bug with urb->dev not being set properly, now that the usb - *	core needs it. - * - * (08/28/2000) gkh - *	Added locks for SMP safeness. - *	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more - *	than once. - *	Fixed potential race in omninet_write_bulk_callback - * - * (07/19/2000) gkh - *	Added module_init and module_exit functions to handle the fact that this - *	driver is a loadable module now. - *   */  #include <linux/kernel.h> @@ -44,7 +19,6 @@  #include <linux/tty_driver.h>  #include <linux/tty_flip.h>  #include <linux/module.h> -#include <linux/spinlock.h>  #include <linux/uaccess.h>  #include <linux/usb.h>  #include <linux/usb/serial.h> @@ -174,12 +148,6 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)  	tty_port_tty_set(&wport->port, tty);  	/* Start reading from the device */ -	usb_fill_bulk_urb(port->read_urb, serial->dev, -			usb_rcvbulkpipe(serial->dev, -				port->bulk_in_endpointAddress), -			port->read_urb->transfer_buffer, -			port->read_urb->transfer_buffer_length, -			omninet_read_bulk_callback, port);  	result = usb_submit_urb(port->read_urb, GFP_KERNEL);  	if (result)  		dev_err(&port->dev, @@ -236,11 +204,6 @@ static void omninet_read_bulk_callback(struct urb *urb)  	}  	/* Continue trying to always read  */ -	usb_fill_bulk_urb(urb, port->serial->dev, -			usb_rcvbulkpipe(port->serial->dev, -					port->bulk_in_endpointAddress), -			urb->transfer_buffer, urb->transfer_buffer_length, -			omninet_read_bulk_callback, port);  	result = usb_submit_urb(urb, GFP_ATOMIC);  	if (result)  		dev_err(&port->dev, @@ -267,14 +230,10 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,  		return 0;  	} -	spin_lock_bh(&wport->lock); -	if (wport->write_urb_busy) { -		spin_unlock_bh(&wport->lock); +	if (!test_and_clear_bit(0, &port->write_urbs_free)) {  		dbg("%s - already writing", __func__);  		return 0;  	} -	wport->write_urb_busy = 1; -	spin_unlock_bh(&wport->lock);  	count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; @@ -292,10 +251,9 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,  	/* send the data out the bulk port, always 64 bytes */  	wport->write_urb->transfer_buffer_length = 64; -	wport->write_urb->dev = serial->dev;  	result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);  	if (result) { -		wport->write_urb_busy = 0; +		set_bit(0, &wport->write_urbs_free);  		dev_err(&port->dev,  			"%s - failed submitting write urb, error %d\n",  			__func__, result); @@ -314,8 +272,7 @@ static int omninet_write_room(struct tty_struct *tty)  	int room = 0; /* Default: no room */ -	/* FIXME: no consistent locking for write_urb_busy */ -	if (wport->write_urb_busy) +	if (test_bit(0, &wport->write_urbs_free))  		room = wport->bulk_out_size - OMNINET_HEADERLEN;  	dbg("%s - returns %d", __func__, room); @@ -332,7 +289,7 @@ static void omninet_write_bulk_callback(struct urb *urb)  	dbg("%s - port %0x", __func__, port->number); -	port->write_urb_busy = 0; +	set_bit(0, &port->write_urbs_free);  	if (status) {  		dbg("%s - nonzero write bulk status received: %d",  		    __func__, status); diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index c248a914743..691f57a9d71 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -384,7 +384,6 @@ static void opticon_unthrottle(struct tty_struct *tty)  	priv->actually_throttled = false;  	spin_unlock_irqrestore(&priv->lock, flags); -	priv->bulk_read_urb->dev = port->serial->dev;  	if (was_throttled) {  		result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC);  		if (result) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 6dd64534fad..c96b6b6509f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -476,6 +476,10 @@ static void option_instat_callback(struct urb *urb);  #define VIETTEL_VENDOR_ID			0x2262  #define VIETTEL_PRODUCT_VT1000			0x0002 +/* ZD Incorporated */ +#define ZD_VENDOR_ID				0x0685 +#define ZD_PRODUCT_7000				0x7000 +  /* some devices interfaces need special handling due to a number of reasons */  enum option_blacklist_reason {  		OPTION_BLACKLIST_NONE = 0, @@ -1178,6 +1182,7 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) },  	{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) },  	{ USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) },  	{ } /* Terminating entry */  };  MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 4c29e6c2bda..2161d1c3c08 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -264,7 +264,6 @@ static void setup_line(struct work_struct *work)  	spin_unlock_irqrestore(&priv->lock, flags);  	dbg("%s(): submitting interrupt urb", __func__); -	port->interrupt_in_urb->dev = port->serial->dev;  	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  	if (result != 0) {  		dev_err(&port->dev, "%s(): usb_submit_urb() failed" @@ -321,7 +320,6 @@ static void send_data(struct work_struct *work)  		priv->flags.write_urb_in_use = 0;  		dbg("%s(): submitting interrupt urb", __func__); -		port->interrupt_in_urb->dev = port->serial->dev;  		result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);  		if (result != 0) {  			dev_err(&port->dev, "%s(): usb_submit_urb() failed" @@ -334,7 +332,6 @@ static void send_data(struct work_struct *work)  					port->write_urb->transfer_buffer,  					count, &port->lock);  	port->write_urb->transfer_buffer_length = count; -	port->write_urb->dev = port->serial->dev;  	result = usb_submit_urb(port->write_urb, GFP_NOIO);  	if (result != 0) {  		dev_err(&port->dev, "%s(): usb_submit_urb() failed" @@ -583,13 +580,12 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)  	kfree(buf);  	dbg("%s(): submitting interrupt urb", __func__); -	port->interrupt_in_urb->dev = serial->dev;  	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  	if (result != 0) {  		dev_err(&port->dev, "%s(): usb_submit_urb() failed"  			       " with error %d\n", __func__, result);  		oti6858_close(port); -		return -EPROTO; +		return result;  	}  	/* setup termios */ @@ -837,7 +833,6 @@ static void oti6858_read_int_callback(struct urb *urb)  	if (can_recv) {  		int result; -		port->read_urb->dev = port->serial->dev;  		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);  		if (result != 0) {  			priv->flags.read_urb_in_use = 0; @@ -866,7 +861,6 @@ static void oti6858_read_int_callback(struct urb *urb)  		int result;  /*		dbg("%s(): submitting interrupt urb", __func__); */ -		urb->dev = port->serial->dev;  		result = usb_submit_urb(urb, GFP_ATOMIC);  		if (result != 0) {  			dev_err(&urb->dev->dev, @@ -894,18 +888,6 @@ static void oti6858_read_bulk_callback(struct urb *urb)  	spin_unlock_irqrestore(&priv->lock, flags);  	if (status != 0) { -		/* -		if (status == -EPROTO) { -			* PL2303 mysteriously fails with -EPROTO reschedule -			   the read * -			dbg("%s - caught -EPROTO, resubmitting the urb", -								__func__); -			result = usb_submit_urb(urb, GFP_ATOMIC); -			if (result) -				dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result); -			return; -		} -		*/  		dbg("%s(): unable to handle the error, exiting", __func__);  		return;  	} @@ -918,7 +900,6 @@ static void oti6858_read_bulk_callback(struct urb *urb)  	tty_kref_put(tty);  	/* schedule the interrupt urb */ -	port->interrupt_in_urb->dev = port->serial->dev;  	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);  	if (result != 0 && result != -EPERM) {  		dev_err(&port->dev, "%s(): usb_submit_urb() failed," @@ -955,7 +936,6 @@ static void oti6858_write_bulk_callback(struct urb *urb)  		dbg("%s(): overflow in write", __func__);  		port->write_urb->transfer_buffer_length = 1; -		port->write_urb->dev = port->serial->dev;  		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);  		if (result) {  			dev_err(&port->dev, "%s(): usb_submit_urb() failed," @@ -968,7 +948,6 @@ static void oti6858_write_bulk_callback(struct urb *urb)  	priv->flags.write_urb_in_use = 0;  	/* schedule the interrupt urb if we are still open */ -	port->interrupt_in_urb->dev = port->serial->dev;  	dbg("%s(): submitting interrupt urb", __func__);  	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);  	if (result != 0) { diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index fc2d66f7f4e..329295615d0 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -502,21 +502,20 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)  	if (tty)  		pl2303_set_termios(tty, port, &tmp_termios); -	dbg("%s - submitting read urb", __func__); -	result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL); -	if (result) { -		pl2303_close(port); -		return -EPROTO; -	} -  	dbg("%s - submitting interrupt urb", __func__);  	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  	if (result) {  		dev_err(&port->dev, "%s - failed submitting interrupt urb,"  			" error %d\n", __func__, result); -		pl2303_close(port); -		return -EPROTO; +		return result;  	} + +	result = usb_serial_generic_open(tty, port); +	if (result) { +		usb_kill_urb(port->interrupt_in_urb); +		return result; +	} +  	port->port.drain_delay = 256;  	return 0;  } diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index b18179bda0d..f2485429172 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -681,7 +681,6 @@ static void sierra_instat_callback(struct urb *urb)  	/* Resubmit urb so we continue receiving IRQ data */  	if (status != -ESHUTDOWN && status != -ENOENT) {  		usb_mark_last_busy(serial->dev); -		urb->dev = serial->dev;  		err = usb_submit_urb(urb, GFP_ATOMIC);  		if (err && err != -EPERM)  			dev_err(&port->dev, "%s: resubmit intr urb " diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index 7096f799b07..c70cc012d03 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -182,7 +182,6 @@ static void symbol_unthrottle(struct tty_struct *tty)  	priv->actually_throttled = false;  	spin_unlock_irq(&priv->lock); -	priv->int_urb->dev = port->serial->dev;  	if (was_throttled) {  		result = usb_submit_urb(priv->int_urb, GFP_KERNEL);  		if (result) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index ea8445689c8..4af21f46096 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -535,9 +535,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)  			status = -EINVAL;  			goto release_lock;  		} -		urb->complete = ti_interrupt_callback;  		urb->context = tdev; -		urb->dev = dev;  		status = usb_submit_urb(urb, GFP_KERNEL);  		if (status) {  			dev_err(&port->dev, @@ -619,9 +617,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)  		goto unlink_int_urb;  	}  	tport->tp_read_urb_state = TI_READ_URB_RUNNING; -	urb->complete = ti_bulk_in_callback;  	urb->context = tport; -	urb->dev = dev;  	status = usb_submit_urb(urb, GFP_KERNEL);  	if (status) {  		dev_err(&port->dev, "%s - submit read urb failed, %d\n", @@ -1236,12 +1232,11 @@ static void ti_bulk_in_callback(struct urb *urb)  exit:  	/* continue to read unless stopping */  	spin_lock(&tport->tp_lock); -	if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) { -		urb->dev = port->serial->dev; +	if (tport->tp_read_urb_state == TI_READ_URB_RUNNING)  		retval = usb_submit_urb(urb, GFP_ATOMIC); -	} else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING) { +	else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING)  		tport->tp_read_urb_state = TI_READ_URB_STOPPED; -	} +  	spin_unlock(&tport->tp_lock);  	if (retval)  		dev_err(dev, "%s - resubmit read urb failed, %d\n", @@ -1574,9 +1569,7 @@ static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty)  		tport->tp_read_urb_state = TI_READ_URB_RUNNING;  		urb = tport->tp_port->read_urb;  		spin_unlock_irqrestore(&tport->tp_lock, flags); -		urb->complete = ti_bulk_in_callback;  		urb->context = tport; -		urb->dev = tport->tp_port->serial->dev;  		status = usb_submit_urb(urb, GFP_KERNEL);  	} else  {  		tport->tp_read_urb_state = TI_READ_URB_RUNNING; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index cc274fdf262..ce6c1a65a54 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -50,7 +50,7 @@ static struct usb_driver usb_serial_driver = {  	.disconnect =	usb_serial_disconnect,  	.suspend =	usb_serial_suspend,  	.resume =	usb_serial_resume, -	.no_dynamic_id = 	1, +	.no_dynamic_id =	1,  	.supports_autosuspend =	1,  }; @@ -260,6 +260,10 @@ static int serial_activate(struct tty_port *tport, struct tty_struct *tty)  	else  		retval = port->serial->type->open(tty, port);  	mutex_unlock(&serial->disc_mutex); + +	if (retval < 0) +		retval = usb_translate_errors(retval); +  	return retval;  } @@ -360,7 +364,8 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf,  	/* pass on to the driver specific version of this function */  	retval = port->serial->type->write(tty, port, buf, count); - +	if (retval < 0) +		retval = usb_translate_errors(retval);  exit:  	return retval;  } @@ -562,8 +567,8 @@ static void kill_traffic(struct usb_serial_port *port)  {  	int i; -	usb_kill_urb(port->read_urb); -	usb_kill_urb(port->write_urb); +	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) +		usb_kill_urb(port->read_urbs[i]);  	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)  		usb_kill_urb(port->write_urbs[i]);  	/* @@ -595,17 +600,17 @@ static void port_release(struct device *dev)  	kill_traffic(port);  	cancel_work_sync(&port->work); -	usb_free_urb(port->read_urb); -	usb_free_urb(port->write_urb);  	usb_free_urb(port->interrupt_in_urb);  	usb_free_urb(port->interrupt_out_urb); +	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { +		usb_free_urb(port->read_urbs[i]); +		kfree(port->bulk_in_buffers[i]); +	}  	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {  		usb_free_urb(port->write_urbs[i]);  		kfree(port->bulk_out_buffers[i]);  	}  	kfifo_free(&port->write_fifo); -	kfree(port->bulk_in_buffer); -	kfree(port->bulk_out_buffer);  	kfree(port->interrupt_in_buffer);  	kfree(port->interrupt_out_buffer);  	kfree(port); @@ -686,16 +691,18 @@ static int serial_carrier_raised(struct tty_port *port)  {  	struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);  	struct usb_serial_driver *drv = p->serial->type; +  	if (drv->carrier_raised)  		return drv->carrier_raised(p);  	/* No carrier control - don't block */ -	return 1;	 +	return 1;  }  static void serial_dtr_rts(struct tty_port *port, int on)  {  	struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);  	struct usb_serial_driver *drv = p->serial->type; +  	if (drv->dtr_rts)  		drv->dtr_rts(p, on);  } @@ -724,6 +731,7 @@ int usb_serial_probe(struct usb_interface *interface,  	unsigned int minor;  	int buffer_size;  	int i; +	int j;  	int num_interrupt_in = 0;  	int num_interrupt_out = 0;  	int num_bulk_in = 0; @@ -906,38 +914,41 @@ int usb_serial_probe(struct usb_interface *interface,  	for (i = 0; i < num_bulk_in; ++i) {  		endpoint = bulk_in_endpoint[i];  		port = serial->port[i]; -		port->read_urb = usb_alloc_urb(0, GFP_KERNEL); -		if (!port->read_urb) { -			dev_err(&interface->dev, "No free urbs available\n"); -			goto probe_error; -		}  		buffer_size = max_t(int, serial->type->bulk_in_size,  				usb_endpoint_maxp(endpoint));  		port->bulk_in_size = buffer_size;  		port->bulk_in_endpointAddress = endpoint->bEndpointAddress; -		port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); -		if (!port->bulk_in_buffer) { -			dev_err(&interface->dev, + +		for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) { +			set_bit(j, &port->read_urbs_free); +			port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); +			if (!port->read_urbs[j]) { +				dev_err(&interface->dev, +						"No free urbs available\n"); +				goto probe_error; +			} +			port->bulk_in_buffers[j] = kmalloc(buffer_size, +								GFP_KERNEL); +			if (!port->bulk_in_buffers[j]) { +				dev_err(&interface->dev,  					"Couldn't allocate bulk_in_buffer\n"); -			goto probe_error; -		} -		usb_fill_bulk_urb(port->read_urb, dev, -				usb_rcvbulkpipe(dev, +				goto probe_error; +			} +			usb_fill_bulk_urb(port->read_urbs[j], dev, +					usb_rcvbulkpipe(dev,  						endpoint->bEndpointAddress), -				port->bulk_in_buffer, buffer_size, -				serial->type->read_bulk_callback, port); +					port->bulk_in_buffers[j], buffer_size, +					serial->type->read_bulk_callback, +					port); +		} + +		port->read_urb = port->read_urbs[0]; +		port->bulk_in_buffer = port->bulk_in_buffers[0];  	}  	for (i = 0; i < num_bulk_out; ++i) { -		int j; -  		endpoint = bulk_out_endpoint[i];  		port = serial->port[i]; -		port->write_urb = usb_alloc_urb(0, GFP_KERNEL); -		if (!port->write_urb) { -			dev_err(&interface->dev, "No free urbs available\n"); -			goto probe_error; -		}  		if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))  			goto probe_error;  		buffer_size = serial->type->bulk_out_size; @@ -945,17 +956,7 @@ int usb_serial_probe(struct usb_interface *interface,  			buffer_size = usb_endpoint_maxp(endpoint);  		port->bulk_out_size = buffer_size;  		port->bulk_out_endpointAddress = endpoint->bEndpointAddress; -		port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); -		if (!port->bulk_out_buffer) { -			dev_err(&interface->dev, -					"Couldn't allocate bulk_out_buffer\n"); -			goto probe_error; -		} -		usb_fill_bulk_urb(port->write_urb, dev, -				usb_sndbulkpipe(dev, -					endpoint->bEndpointAddress), -				port->bulk_out_buffer, buffer_size, -				serial->type->write_bulk_callback, port); +  		for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {  			set_bit(j, &port->write_urbs_free);  			port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); @@ -978,6 +979,9 @@ int usb_serial_probe(struct usb_interface *interface,  					serial->type->write_bulk_callback,  					port);  		} + +		port->write_urb = port->write_urbs[0]; +		port->bulk_out_buffer = port->bulk_out_buffers[0];  	}  	if (serial->type->read_int_callback) { @@ -1196,7 +1200,7 @@ static const struct tty_operations serial_ops = {  	.open =			serial_open,  	.close =		serial_close,  	.write =		serial_write, -	.hangup = 		serial_hangup, +	.hangup =		serial_hangup,  	.write_room =		serial_write_room,  	.ioctl =		serial_ioctl,  	.set_termios =		serial_set_termios, @@ -1206,9 +1210,9 @@ static const struct tty_operations serial_ops = {  	.chars_in_buffer =	serial_chars_in_buffer,  	.tiocmget =		serial_tiocmget,  	.tiocmset =		serial_tiocmset, -	.get_icount = 		serial_get_icount, -	.cleanup = 		serial_cleanup, -	.install = 		serial_install, +	.get_icount =		serial_get_icount, +	.cleanup =		serial_cleanup, +	.install =		serial_install,  	.proc_fops =		&serial_proc_fops,  }; @@ -1237,7 +1241,7 @@ static int __init usb_serial_init(void)  	usb_serial_tty_driver->owner = THIS_MODULE;  	usb_serial_tty_driver->driver_name = "usbserial"; -	usb_serial_tty_driver->name = 	"ttyUSB"; +	usb_serial_tty_driver->name = "ttyUSB";  	usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;  	usb_serial_tty_driver->minor_start = 0;  	usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; @@ -1336,7 +1340,6 @@ static void fixup_generic(struct usb_serial_driver *device)  int usb_serial_register(struct usb_serial_driver *driver)  { -	/* must be called with BKL held */  	int retval;  	if (usb_disabled()) @@ -1374,7 +1377,6 @@ EXPORT_SYMBOL_GPL(usb_serial_register);  void usb_serial_deregister(struct usb_serial_driver *device)  { -	/* must be called with BKL held */  	printk(KERN_INFO "USB Serial deregistering driver %s\n",  	       device->description);  	mutex_lock(&table_lock); diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c index 95a82148ee8..9b632e75321 100644 --- a/drivers/usb/serial/usb_debug.c +++ b/drivers/usb/serial/usb_debug.c @@ -40,7 +40,7 @@ static struct usb_driver debug_driver = {  	.probe =	usb_serial_probe,  	.disconnect =	usb_serial_disconnect,  	.id_table =	id_table, -	.no_dynamic_id = 	1, +	.no_dynamic_id =	1,  };  /* This HW really does not support a serial break, so one will be @@ -54,19 +54,18 @@ static void usb_debug_break_ctl(struct tty_struct *tty, int break_state)  	usb_serial_generic_write(tty, port, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE);  } -static void usb_debug_read_bulk_callback(struct urb *urb) +static void usb_debug_process_read_urb(struct urb *urb)  {  	struct usb_serial_port *port = urb->context;  	if (urb->actual_length == USB_DEBUG_BRK_SIZE && -	    memcmp(urb->transfer_buffer, USB_DEBUG_BRK, -		   USB_DEBUG_BRK_SIZE) == 0) { +		memcmp(urb->transfer_buffer, USB_DEBUG_BRK, +						USB_DEBUG_BRK_SIZE) == 0) {  		usb_serial_handle_break(port); -		usb_serial_generic_submit_read_urb(port, GFP_ATOMIC);  		return;  	} -	usb_serial_generic_read_bulk_callback(urb); +	usb_serial_generic_process_read_urb(urb);  }  static struct usb_serial_driver debug_device = { @@ -79,7 +78,7 @@ static struct usb_serial_driver debug_device = {  	.num_ports =		1,  	.bulk_out_size =	USB_DEBUG_MAX_PACKET_SIZE,  	.break_ctl =		usb_debug_break_ctl, -	.read_bulk_callback =	usb_debug_read_bulk_callback, +	.process_read_urb =	usb_debug_process_read_urb,  };  static int __init debug_init(void) diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 5b073bcc807..11af903cb09 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -14,57 +14,6 @@   *   * See Documentation/usb/usb-serial.txt for more information on using this   * driver - * - * (10/09/2002) Stuart MacDonald (stuartm@connecttech.com) - *	Upgrade to full working driver - * - * (05/30/2001) gkh - *	switched from using spinlock to a semaphore, which fixes lots of - *	problems. - * - * (04/08/2001) gb - *	Identify version on module load. - * - * 2001_Mar_19 gkh - *	Fixed MOD_INC and MOD_DEC logic, the ability to open a port more - *	than once, and the got the proper usb_device_id table entries so - *	the driver works again. - * - * (11/01/2000) Adam J. Richter - *	usb_device_id table support - * - * (10/05/2000) gkh - *	Fixed bug with urb->dev not being set properly, now that the usb - *	core needs it. - * - * (10/03/2000) smd - *	firmware is improved to guard against crap sent to device - *	firmware now replies CMD_FAILURE on bad things - *	read_callback fix you provided for private info struct - *	command_finished now indicates success or fail - *	setup_port struct now packed to avoid gcc padding - *	firmware uses 1 based port numbering, driver now handles that - * - * (09/11/2000) gkh - *	Removed DEBUG #ifdefs with call to usb_serial_debug_data - * - * (07/19/2000) gkh - *	Added module_init and module_exit functions to handle the fact that this - *	driver is a loadable module now. - *	Fixed bug with port->minor that was found by Al Borchers - * - * (07/04/2000) gkh - *	Added support for port settings. Baud rate can now be changed. Line - *	signals are not transferred to and from the tty layer yet, but things - *	seem to be working well now. - * - * (05/04/2000) gkh - *	First cut at open and close commands. Data can flow through the ports at - *	default speeds now. - * - * (03/26/2000) gkh - *	Split driver up into device specific pieces. - *   */  #include <linux/kernel.h> @@ -753,7 +702,6 @@ static void whiteheat_close(struct usb_serial_port *port)  static int whiteheat_write(struct tty_struct *tty,  	struct usb_serial_port *port, const unsigned char *buf, int count)  { -	struct usb_serial *serial = port->serial;  	struct whiteheat_private *info = usb_get_serial_port_data(port);  	struct whiteheat_urb_wrap *wrap;  	struct urb *urb; @@ -789,7 +737,6 @@ static int whiteheat_write(struct tty_struct *tty,  		usb_serial_debug_data(debug, &port->dev,  				__func__, bytes, urb->transfer_buffer); -		urb->dev = serial->dev;  		urb->transfer_buffer_length = bytes;  		result = usb_submit_urb(urb, GFP_ATOMIC);  		if (result) { @@ -1035,7 +982,6 @@ static void command_port_read_callback(struct urb *urb)  		dbg("%s - bad reply from firmware", __func__);  	/* Continue trying to always read */ -	command_port->read_urb->dev = command_port->serial->dev;  	result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC);  	if (result)  		dbg("%s - failed resubmitting read urb, error %d", @@ -1141,7 +1087,6 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command,  	transfer_buffer[0] = command;  	memcpy(&transfer_buffer[1], data, datasize);  	command_port->write_urb->transfer_buffer_length = datasize + 1; -	command_port->write_urb->dev = port->serial->dev;  	retval = usb_submit_urb(command_port->write_urb, GFP_NOIO);  	if (retval) {  		dbg("%s - submit urb failed", __func__); @@ -1362,7 +1307,6 @@ static int start_command_port(struct usb_serial *serial)  		/* Work around HCD bugs */  		usb_clear_halt(serial->dev, command_port->read_urb->pipe); -		command_port->read_urb->dev = serial->dev;  		retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL);  		if (retval) {  			dev_err(&serial->dev->dev, @@ -1410,7 +1354,6 @@ static int start_port_read(struct usb_serial_port *port)  		list_del(tmp);  		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);  		urb = wrap->urb; -		urb->dev = port->serial->dev;  		spin_unlock_irqrestore(&info->lock, flags);  		retval = usb_submit_urb(urb, GFP_KERNEL);  		if (retval) { @@ -1490,7 +1433,6 @@ static void rx_data_softint(struct work_struct *work)  			sent += tty_insert_flip_string(tty,  				urb->transfer_buffer, urb->actual_length); -		urb->dev = port->serial->dev;  		result = usb_submit_urb(urb, GFP_ATOMIC);  		if (result) {  			dev_err(&port->dev, diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index 3ca87a82334..51af2fee2ef 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -139,7 +139,7 @@ static int init_alauda(struct us_data *us);  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id alauda_usb_ids[] = { +static struct usb_device_id alauda_usb_ids[] = {  #	include "unusual_alauda.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c index c7909dfa243..387cbd47acc 100644 --- a/drivers/usb/storage/cypress_atacb.c +++ b/drivers/usb/storage/cypress_atacb.c @@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id cypress_usb_ids[] = { +static struct usb_device_id cypress_usb_ids[] = {  #	include "unusual_cypress.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index a99be857b79..15d41f2b3d6 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -88,7 +88,7 @@ static int datafab_determine_lun(struct us_data *us,  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id datafab_usb_ids[] = { +static struct usb_device_id datafab_usb_ids[] = {  #	include "unusual_datafab.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index b0a1687ca94..a6ade4071a9 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -42,7 +42,7 @@ MODULE_LICENSE("GPL");  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \  	.driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id ene_ub6250_usb_ids[] = { +static struct usb_device_id ene_ub6250_usb_ids[] = {  #	include "unusual_ene_ub6250.h"  	{ }		/* Terminating entry */  }; @@ -607,8 +607,8 @@ static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)  static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)  { -	u32   bl_num; -	u16    bl_len; +	u32	bl_num; +	u32	bl_len;  	unsigned int offset = 0;  	unsigned char    buf[8];  	struct scatterlist *sg = NULL; @@ -622,7 +622,7 @@ static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)  		else  			bl_num = (info->HC_C_SIZE + 1) * 1024 - 1;  	} else { -		bl_len = 1<<(info->SD_READ_BL_LEN); +		bl_len = 1 << (info->SD_READ_BL_LEN);  		bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1)  				* (1 << (info->SD_C_SIZE_MULT + 2)) - 1;  	} @@ -777,7 +777,7 @@ static int ms_lib_free_logicalmap(struct us_data *us)  	return 0;  } -int ms_lib_alloc_logicalmap(struct us_data *us) +static int ms_lib_alloc_logicalmap(struct us_data *us)  {  	u32  i;  	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; @@ -2248,7 +2248,7 @@ static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)  /*   * ms_scsi_irp()   */ -int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb) +static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)  {  	int result;  	struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra; diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index 03d4a873748..fa161574847 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -119,7 +119,7 @@ static int init_freecom(struct us_data *us);  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id freecom_usb_ids[] = { +static struct usb_device_id freecom_usb_ids[] = {  #	include "unusual_freecom.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 93d359f4d6a..bd550270083 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -76,7 +76,7 @@ static int isd200_Initialization(struct us_data *us);  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id isd200_usb_ids[] = { +static struct usb_device_id isd200_usb_ids[] = {  #	include "unusual_isd200.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index 54b71650b69..a19211b5c26 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -71,7 +71,7 @@ MODULE_LICENSE("GPL");  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id jumpshot_usb_ids[] = { +static struct usb_device_id jumpshot_usb_ids[] = {  #	include "unusual_jumpshot.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c index 35181e29124..e720f8ebdf9 100644 --- a/drivers/usb/storage/karma.c +++ b/drivers/usb/storage/karma.c @@ -59,7 +59,7 @@ static int rio_karma_init(struct us_data *us);  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id karma_usb_ids[] = { +static struct usb_device_id karma_usb_ids[] = {  #	include "unusual_karma.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 721c8c58730..d75155c3820 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -69,7 +69,7 @@ struct usb_onetouch {  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id onetouch_usb_ids[] = { +static struct usb_device_id onetouch_usb_ids[] = {  #	include "unusual_onetouch.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index c41cd30d2c0..1f62723ef1a 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -398,10 +398,9 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)  	u8 cmnd[12] = { 0 };  	u8 *buf; -	buf = kmalloc(len, GFP_NOIO); +	buf = kmemdup(data, len, GFP_NOIO);  	if (buf == NULL)  		return USB_STOR_TRANSPORT_ERROR; -	memcpy(buf, data, len);  	US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len); @@ -507,15 +506,14 @@ static int enable_oscillator(struct us_data *us)  static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)  {  	int retval; -	u16 addr = 0xFE47;  	u8 cmnd[12] = {0}; -	US_DEBUGP("%s, addr = 0x%x, len = %d\n", __FUNCTION__, addr, len); +	US_DEBUGP("%s, addr = 0xfe47, len = %d\n", __FUNCTION__, len);  	cmnd[0] = 0xF0;  	cmnd[1] = 0x0E; -	cmnd[2] = (u8)(addr >> 8); -	cmnd[3] = (u8)addr; +	cmnd[2] = 0xfe; +	cmnd[3] = 0x47;  	cmnd[4] = (u8)(len >> 8);  	cmnd[5] = (u8)len; @@ -818,7 +816,7 @@ static inline int working_scsi(struct scsi_cmnd *srb)  	return 1;  } -void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) +static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)  {  	struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);  	static int card_first_show = 1; @@ -977,7 +975,7 @@ static void realtek_cr_destructor(void *extra)  }  #ifdef CONFIG_PM -int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message) +static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message)  {  	struct us_data *us = usb_get_intfdata(iface); diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 83ee49e737b..425df7df2e5 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -71,7 +71,7 @@ static int usb_stor_sddr09_init(struct us_data *us);  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id sddr09_usb_ids[] = { +static struct usb_device_id sddr09_usb_ids[] = {  #	include "unusual_sddr09.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index 8983ec2ffb5..e4ca5fcb7cc 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -48,7 +48,7 @@ MODULE_LICENSE("GPL");  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id sddr55_usb_ids[] = { +static struct usb_device_id sddr55_usb_ids[] = {  #	include "unusual_sddr55.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index a4c02751af4..1369d259061 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -170,7 +170,7 @@ static int init_usbat_flash(struct us_data *us);  { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \    .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -struct usb_device_id usbat_usb_ids[] = { +static struct usb_device_id usbat_usb_ids[] = {  #	include "unusual_usbat.h"  	{ }		/* Terminating entry */  }; diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index aa84b3d7727..3dd7da9fd50 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1074,6 +1074,7 @@ static struct usb_driver usb_storage_driver = {  	.id_table =	usb_storage_usb_ids,  	.supports_autosuspend = 1,  	.soft_unbind =	1, +	.no_dynamic_id = 1,  };  static int __init usb_stor_init(void) diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 5c6c1bdbd45..8efeae24764 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -27,6 +27,8 @@  #define USB_SKEL_VENDOR_ID	0xfff0  #define USB_SKEL_PRODUCT_ID	0xfff0 +static DEFINE_MUTEX(skel_mutex); +  /* table of devices that work with this driver */  static const struct usb_device_id skel_table[] = {  	{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, @@ -60,7 +62,6 @@ struct usb_skel {  	__u8			bulk_in_endpointAddr;	/* the address of the bulk in endpoint */  	__u8			bulk_out_endpointAddr;	/* the address of the bulk out endpoint */  	int			errors;			/* the last request tanked */ -	int			open_count;		/* count the number of openers */  	bool			ongoing_read;		/* a read is going on */  	bool			processed_urb;		/* indicates we haven't processed the urb */  	spinlock_t		err_lock;		/* lock for errors */ @@ -100,39 +101,37 @@ static int skel_open(struct inode *inode, struct file *file)  		goto exit;  	} +	mutex_lock(&skel_mutex);  	dev = usb_get_intfdata(interface);  	if (!dev) { +		mutex_unlock(&skel_mutex);  		retval = -ENODEV;  		goto exit;  	}  	/* increment our usage count for the device */  	kref_get(&dev->kref); +	mutex_unlock(&skel_mutex);  	/* lock the device to allow correctly handling errors  	 * in resumption */  	mutex_lock(&dev->io_mutex); +	if (!dev->interface) { +		retval = -ENODEV; +		goto out_err; +	} -	if (!dev->open_count++) { -		retval = usb_autopm_get_interface(interface); -			if (retval) { -				dev->open_count--; -				mutex_unlock(&dev->io_mutex); -				kref_put(&dev->kref, skel_delete); -				goto exit; -			} -	} /* else { //uncomment this block if you want exclusive open -		retval = -EBUSY; -		dev->open_count--; -		mutex_unlock(&dev->io_mutex); -		kref_put(&dev->kref, skel_delete); -		goto exit; -	} */ -	/* prevent the device from being autosuspended */ +	retval = usb_autopm_get_interface(interface); +	if (retval) +		goto out_err;  	/* save our object in the file's private structure */  	file->private_data = dev; + +out_err:  	mutex_unlock(&dev->io_mutex); +	if (retval) +		kref_put(&dev->kref, skel_delete);  exit:  	return retval; @@ -148,7 +147,7 @@ static int skel_release(struct inode *inode, struct file *file)  	/* allow the device to be autosuspended */  	mutex_lock(&dev->io_mutex); -	if (!--dev->open_count && dev->interface) +	if (dev->interface)  		usb_autopm_put_interface(dev->interface);  	mutex_unlock(&dev->io_mutex); @@ -612,7 +611,6 @@ static void skel_disconnect(struct usb_interface *interface)  	int minor = interface->minor;  	dev = usb_get_intfdata(interface); -	usb_set_intfdata(interface, NULL);  	/* give back our minor */  	usb_deregister_dev(interface, &skel_class); @@ -624,8 +622,12 @@ static void skel_disconnect(struct usb_interface *interface)  	usb_kill_anchored_urbs(&dev->submitted); +	mutex_lock(&skel_mutex); +	usb_set_intfdata(interface, NULL); +  	/* decrement our usage count */  	kref_put(&dev->kref, skel_delete); +	mutex_unlock(&skel_mutex);  	dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);  } diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig index eb09a0a14a8..0ead8826ec7 100644 --- a/drivers/usb/wusbcore/Kconfig +++ b/drivers/usb/wusbcore/Kconfig @@ -5,6 +5,7 @@ config USB_WUSB  	tristate "Enable Wireless USB extensions (EXPERIMENTAL)"  	depends on EXPERIMENTAL  	depends on USB +	depends on PCI          select UWB          select CRYPTO          select CRYPTO_BLKCIPHER diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c index 371f61733f0..fa810a83e83 100644 --- a/drivers/usb/wusbcore/security.c +++ b/drivers/usb/wusbcore/security.c @@ -354,7 +354,7 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,  	struct wusb_keydvt_in keydvt_in;  	struct wusb_keydvt_out keydvt_out; -	hs = kzalloc(3*sizeof(hs[0]), GFP_KERNEL); +	hs = kcalloc(3, sizeof(hs[0]), GFP_KERNEL);  	if (hs == NULL) {  		dev_err(dev, "can't allocate handshake data\n");  		goto error_kzalloc;  |