diff options
Diffstat (limited to 'drivers/usb')
77 files changed, 1727 insertions, 2714 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3f104599347..2bfc41ece0e 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -462,11 +462,18 @@ urbs:  		rcv->buffer = buf; -		usb_fill_bulk_urb(rcv->urb, acm->dev, -				  acm->rx_endpoint, -				  buf->base, -				  acm->readsize, -				  acm_read_bulk, rcv); +		if (acm->is_int_ep) +			usb_fill_int_urb(rcv->urb, acm->dev, +					 acm->rx_endpoint, +					 buf->base, +					 acm->readsize, +					 acm_read_bulk, rcv, acm->bInterval); +		else +			usb_fill_bulk_urb(rcv->urb, acm->dev, +					  acm->rx_endpoint, +					  buf->base, +					  acm->readsize, +					  acm_read_bulk, rcv);  		rcv->urb->transfer_dma = buf->dma;  		rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -740,7 +747,7 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)  {  	struct acm *acm = tty->driver_data;  	if (!ACM_READY(acm)) -		return -EINVAL; +		return 0;  	/*  	 * This is inaccurate (overcounts), but it works.  	 */ @@ -1173,6 +1180,9 @@ made_compressed_probe:  	spin_lock_init(&acm->read_lock);  	mutex_init(&acm->mutex);  	acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); +	acm->is_int_ep = usb_endpoint_xfer_int(epread); +	if (acm->is_int_ep) +		acm->bInterval = epread->bInterval;  	tty_port_init(&acm->port);  	acm->port.ops = &acm_port_ops; @@ -1227,9 +1237,14 @@ made_compressed_probe:  			goto alloc_fail7;  		} -		usb_fill_bulk_urb(snd->urb, usb_dev, -			usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), -			NULL, acm->writesize, acm_write_bulk, snd); +		if (usb_endpoint_xfer_int(epwrite)) +			usb_fill_int_urb(snd->urb, usb_dev, +				usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), +				NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval); +		else +			usb_fill_bulk_urb(snd->urb, usb_dev, +				usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), +				NULL, acm->writesize, acm_write_bulk, snd);  		snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;  		snd->instance = acm;  	} diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 1602324808b..c4a0ee8ffcc 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -126,6 +126,8 @@ struct acm {  	unsigned int ctrl_caps;				/* control capabilities from the class specific header */  	unsigned int susp_count;			/* number of suspended interfaces */  	int combined_interfaces:1;			/* control and data collapsed */ +	int is_int_ep:1;				/* interrupt endpoints contrary to spec used */ +	u8 bInterval;  	struct acm_wb *delayed_wb;			/* write queued for a device about to be woken */  }; diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 0fe434505ac..ba589d4ca8b 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -15,7 +15,6 @@  #include <linux/errno.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/smp_lock.h>  #include <linux/mutex.h>  #include <linux/uaccess.h>  #include <linux/bitops.h> diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 3703789d0d2..b09a527f734 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -751,7 +751,7 @@ static int get_capabilities(struct usbtmc_device_data *data)  {  	struct device *dev = &data->usb_dev->dev;  	char *buffer; -	int rv; +	int rv = 0;  	buffer = kmalloc(0x18, GFP_KERNEL);  	if (!buffer) @@ -763,7 +763,7 @@ static int get_capabilities(struct usbtmc_device_data *data)  			     0, 0, buffer, 0x18, USBTMC_TIMEOUT);  	if (rv < 0) {  		dev_err(dev, "usb_control_msg returned %d\n", rv); -		return rv; +		goto err_out;  	}  	dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); @@ -773,7 +773,8 @@ static int get_capabilities(struct usbtmc_device_data *data)  	dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]);  	if (buffer[0] != USBTMC_STATUS_SUCCESS) {  		dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); -		return -EPERM; +		rv = -EPERM; +		goto err_out;  	}  	data->capabilities.interface_capabilities = buffer[4]; @@ -781,8 +782,9 @@ static int get_capabilities(struct usbtmc_device_data *data)  	data->capabilities.usb488_interface_capabilities = buffer[14];  	data->capabilities.usb488_device_capabilities = buffer[15]; +err_out:  	kfree(buffer); -	return 0; +	return rv;  }  #define capability_attribute(name)					\ diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 69280c35b5c..ad925946f86 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -28,7 +28,7 @@ comment "Miscellaneous USB options"  	depends on USB  config USB_DEVICEFS -	bool "USB device filesystem (DEPRECATED)" if EMBEDDED +	bool "USB device filesystem (DEPRECATED)"  	depends on USB  	---help---  	  If you say Y here (and to "/proc file system support" in the "File diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 24dfb33f90c..a16c538d013 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -80,38 +80,18 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,  	int max_tx;  	int i; -	/* Allocate space for the SS endpoint companion descriptor */ -	ep->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp), -			GFP_KERNEL); -	if (!ep->ss_ep_comp) -		return -ENOMEM;  	desc = (struct usb_ss_ep_comp_descriptor *) buffer;  	if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {  		dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "  				" interface %d altsetting %d ep %d: "  				"using minimum values\n",  				cfgno, inum, asnum, ep->desc.bEndpointAddress); -		ep->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE; -		ep->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; -		ep->ss_ep_comp->desc.bMaxBurst = 0; -		/* -		 * Leave bmAttributes as zero, which will mean no streams for -		 * bulk, and isoc won't support multiple bursts of packets. -		 * With bursts of only one packet, and a Mult of 1, the max -		 * amount of data moved per endpoint service interval is one -		 * packet. -		 */ -		if (usb_endpoint_xfer_isoc(&ep->desc) || -				usb_endpoint_xfer_int(&ep->desc)) -			ep->ss_ep_comp->desc.wBytesPerInterval = -				ep->desc.wMaxPacketSize;  		/*  		 * The next descriptor is for an Endpoint or Interface,  		 * no extra descriptors to copy into the companion structure,  		 * and we didn't eat up any of the buffer.  		 */ -		retval = 0; -		goto valid; +		return 0;  	}  	memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE);  	desc = &ep->ss_ep_comp->desc; @@ -320,6 +300,28 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,  		buffer += i;  		size -= i; +		/* Allocate space for the SS endpoint companion descriptor */ +		endpoint->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp), +				GFP_KERNEL); +		if (!endpoint->ss_ep_comp) +			return -ENOMEM; + +		/* Fill in some default values (may be overwritten later) */ +		endpoint->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE; +		endpoint->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; +		endpoint->ss_ep_comp->desc.bMaxBurst = 0; +		/* +		 * Leave bmAttributes as zero, which will mean no streams for +		 * bulk, and isoc won't support multiple bursts of packets. +		 * With bursts of only one packet, and a Mult of 1, the max +		 * amount of data moved per endpoint service interval is one +		 * packet. +		 */ +		if (usb_endpoint_xfer_isoc(&endpoint->desc) || +				usb_endpoint_xfer_int(&endpoint->desc)) +			endpoint->ss_ep_comp->desc.wBytesPerInterval = +				endpoint->desc.wMaxPacketSize; +  		if (size > 0) {  			retval = usb_parse_ss_endpoint_companion(ddev, cfgno,  					inum, asnum, endpoint, num_ep, buffer, @@ -329,6 +331,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,  				retval = buffer - buffer0;  			}  		} else { +			dev_warn(ddev, "config %d interface %d altsetting %d " +				"endpoint 0x%X has no " +				"SuperSpeed companion descriptor\n", +				cfgno, inum, asnum, d->bEndpointAddress);  			retval = buffer - buffer0;  		}  	} else { diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 73c108d117b..96f11715cd2 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -136,17 +136,19 @@ static const struct class_info clas_info[] =  	{USB_CLASS_AUDIO,		"audio"},  	{USB_CLASS_COMM,		"comm."},  	{USB_CLASS_HID,			"HID"}, -	{USB_CLASS_HUB,			"hub"},  	{USB_CLASS_PHYSICAL,		"PID"}, +	{USB_CLASS_STILL_IMAGE,		"still"},  	{USB_CLASS_PRINTER,		"print"},  	{USB_CLASS_MASS_STORAGE,	"stor."}, +	{USB_CLASS_HUB,			"hub"},  	{USB_CLASS_CDC_DATA,		"data"}, -	{USB_CLASS_APP_SPEC,		"app."}, -	{USB_CLASS_VENDOR_SPEC,		"vend."}, -	{USB_CLASS_STILL_IMAGE,		"still"},  	{USB_CLASS_CSCID,		"scard"},  	{USB_CLASS_CONTENT_SEC,		"c-sec"},  	{USB_CLASS_VIDEO,		"video"}, +	{USB_CLASS_WIRELESS_CONTROLLER,	"wlcon"}, +	{USB_CLASS_MISC,		"misc"}, +	{USB_CLASS_APP_SPEC,		"app."}, +	{USB_CLASS_VENDOR_SPEC,		"vend."},  	{-1,				"unk."}		/* leave as last */  }; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 308609039c7..4247eccf858 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -325,21 +325,34 @@ static void async_completed(struct urb *urb)  	struct async *as = urb->context;  	struct dev_state *ps = as->ps;  	struct siginfo sinfo; +	struct pid *pid = NULL; +	uid_t uid = 0; +	uid_t euid = 0; +	u32 secid = 0; +	int signr;  	spin_lock(&ps->lock);  	list_move_tail(&as->asynclist, &ps->async_completed); -	spin_unlock(&ps->lock);  	as->status = urb->status; -	if (as->signr) { +	signr = as->signr; +	if (signr) {  		sinfo.si_signo = as->signr;  		sinfo.si_errno = as->status;  		sinfo.si_code = SI_ASYNCIO;  		sinfo.si_addr = as->userurb; -		kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, -				      as->euid, as->secid); +		pid = as->pid; +		uid = as->uid; +		euid = as->euid; +		secid = as->secid;  	}  	snoop(&urb->dev->dev, "urb complete\n");  	snoop_urb(urb, as->userurb); +	spin_unlock(&ps->lock); + +	if (signr) +		kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid, +				      euid, secid); +  	wake_up(&ps->wait);  } @@ -582,7 +595,7 @@ static int usbdev_open(struct inode *inode, struct file *file)  	if (!ps)  		goto out; -	ret = -ENOENT; +	ret = -ENODEV;  	/* usbdev device-node */  	if (imajor(inode) == USB_DEVICE_MAJOR) @@ -982,7 +995,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  				USBDEVFS_URB_ZERO_PACKET |  				USBDEVFS_URB_NO_INTERRUPT))  		return -EINVAL; -	if (!uurb->buffer) +	if (uurb->buffer_length > 0 && !uurb->buffer)  		return -EINVAL;  	if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&  	    (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { @@ -1038,11 +1051,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  			is_in = 0;  			uurb->endpoint &= ~USB_DIR_IN;  		} -		if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, -				uurb->buffer, uurb->buffer_length)) { -			kfree(dr); -			return -EFAULT; -		}  		snoop(&ps->dev->dev, "control urb: bRequest=%02x "  			"bRrequestType=%02x wValue=%04x "  			"wIndex=%04x wLength=%04x\n", @@ -1062,9 +1070,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  		uurb->number_of_packets = 0;  		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)  			return -EINVAL; -		if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, -				uurb->buffer, uurb->buffer_length)) -			return -EFAULT;  		snoop(&ps->dev->dev, "bulk urb\n");  		break; @@ -1106,28 +1111,35 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  			return -EINVAL;  		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)  			return -EINVAL; -		if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, -				uurb->buffer, uurb->buffer_length)) -			return -EFAULT;  		snoop(&ps->dev->dev, "interrupt urb\n");  		break;  	default:  		return -EINVAL;  	} -	as = alloc_async(uurb->number_of_packets); -	if (!as) { +	if (uurb->buffer_length > 0 && +			!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, +				uurb->buffer, uurb->buffer_length)) {  		kfree(isopkt);  		kfree(dr); -		return -ENOMEM; +		return -EFAULT;  	} -	as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); -	if (!as->urb->transfer_buffer) { +	as = alloc_async(uurb->number_of_packets); +	if (!as) {  		kfree(isopkt);  		kfree(dr); -		free_async(as);  		return -ENOMEM;  	} +	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; +		} +	}  	as->urb->dev = ps->dev;  	as->urb->pipe = (uurb->type << 30) |  			__create_pipe(ps->dev, uurb->endpoint & 0xf) | @@ -1169,7 +1181,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	kfree(isopkt);  	as->ps = ps;  	as->userurb = arg; -	if (uurb->endpoint & USB_DIR_IN) +	if (is_in && uurb->buffer_length > 0)  		as->userbuffer = uurb->buffer;  	else  		as->userbuffer = NULL; @@ -1179,9 +1191,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	as->uid = cred->uid;  	as->euid = cred->euid;  	security_task_getsecid(current, &as->secid); -	if (!is_in) { +	if (!is_in && uurb->buffer_length > 0) {  		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, -				as->urb->transfer_buffer_length)) { +				uurb->buffer_length)) {  			free_async(as);  			return -EFAULT;  		} @@ -1231,22 +1243,22 @@ static int processcompl(struct async *as, void __user * __user *arg)  	if (as->userbuffer)  		if (copy_to_user(as->userbuffer, urb->transfer_buffer,  				 urb->transfer_buffer_length)) -			return -EFAULT; +			goto err_out;  	if (put_user(as->status, &userurb->status)) -		return -EFAULT; +		goto err_out;  	if (put_user(urb->actual_length, &userurb->actual_length)) -		return -EFAULT; +		goto err_out;  	if (put_user(urb->error_count, &userurb->error_count)) -		return -EFAULT; +		goto err_out;  	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {  		for (i = 0; i < urb->number_of_packets; i++) {  			if (put_user(urb->iso_frame_desc[i].actual_length,  				     &userurb->iso_frame_desc[i].actual_length)) -				return -EFAULT; +				goto err_out;  			if (put_user(urb->iso_frame_desc[i].status,  				     &userurb->iso_frame_desc[i].status)) -				return -EFAULT; +				goto err_out;  		}  	} @@ -1255,6 +1267,10 @@ static int processcompl(struct async *as, void __user * __user *arg)  	if (put_user(addr, (void __user * __user *)arg))  		return -EFAULT;  	return 0; + +err_out: +	free_async(as); +	return -EFAULT;  }  static struct async *reap_as(struct dev_state *ps) @@ -1305,7 +1321,8 @@ static int get_urb32(struct usbdevfs_urb *kurb,  		     struct usbdevfs_urb32 __user *uurb)  {  	__u32  uptr; -	if (get_user(kurb->type, &uurb->type) || +	if (!access_ok(VERIFY_READ, uurb, sizeof(*uurb)) || +	    __get_user(kurb->type, &uurb->type) ||  	    __get_user(kurb->endpoint, &uurb->endpoint) ||  	    __get_user(kurb->status, &uurb->status) ||  	    __get_user(kurb->flags, &uurb->flags) || @@ -1520,8 +1537,9 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)  	u32 udata;  	uioc = compat_ptr((long)arg); -	if (get_user(ctrl.ifno, &uioc->ifno) || -	    get_user(ctrl.ioctl_code, &uioc->ioctl_code) || +	if (!access_ok(VERIFY_READ, uioc, sizeof(*uioc)) || +	    __get_user(ctrl.ifno, &uioc->ifno) || +	    __get_user(ctrl.ioctl_code, &uioc->ioctl_code) ||  	    __get_user(udata, &uioc->data))  		return -EFAULT;  	ctrl.data = compat_ptr(udata); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index ce3f453f02e..95ccfa0b9fc 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -648,7 +648,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)  	struct urb	*urb;  	int		length;  	unsigned long	flags; -	char		buffer[4];	/* Any root hubs with > 31 ports? */ +	char		buffer[6];	/* Any root hubs with > 31 ports? */  	if (unlikely(!hcd->rh_registered))  		return; diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index d397ecfd5b1..ec5c67ea07b 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -227,6 +227,10 @@ struct hc_driver {  		/* has a port been handed over to a companion? */  	int	(*port_handed_over)(struct usb_hcd *, int); +		/* CLEAR_TT_BUFFER completion callback */ +	void	(*clear_tt_buffer_complete)(struct usb_hcd *, +				struct usb_host_endpoint *); +  	/* xHCI specific functions */  		/* Called by usb_alloc_dev to alloc HC device structures */  	int	(*alloc_dev)(struct usb_hcd *, struct usb_device *); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2af3b4f0605..71f86c60d83 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -450,10 +450,10 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)   * talking to TTs must queue control transfers (not just bulk and iso), so   * both can talk to the same hub concurrently.   */ -static void hub_tt_kevent (struct work_struct *work) +static void hub_tt_work(struct work_struct *work)  {  	struct usb_hub		*hub = -		container_of(work, struct usb_hub, tt.kevent); +		container_of(work, struct usb_hub, tt.clear_work);  	unsigned long		flags;  	int			limit = 100; @@ -462,6 +462,7 @@ static void hub_tt_kevent (struct work_struct *work)  		struct list_head	*next;  		struct usb_tt_clear	*clear;  		struct usb_device	*hdev = hub->hdev; +		const struct hc_driver	*drv;  		int			status;  		next = hub->tt.clear_list.next; @@ -471,21 +472,25 @@ static void hub_tt_kevent (struct work_struct *work)  		/* drop lock so HCD can concurrently report other TT errors */  		spin_unlock_irqrestore (&hub->tt.lock, flags);  		status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); -		spin_lock_irqsave (&hub->tt.lock, flags); -  		if (status)  			dev_err (&hdev->dev,  				"clear tt %d (%04x) error %d\n",  				clear->tt, clear->devinfo, status); + +		/* Tell the HCD, even if the operation failed */ +		drv = clear->hcd->driver; +		if (drv->clear_tt_buffer_complete) +			(drv->clear_tt_buffer_complete)(clear->hcd, clear->ep); +  		kfree(clear); +		spin_lock_irqsave(&hub->tt.lock, flags);  	}  	spin_unlock_irqrestore (&hub->tt.lock, flags);  }  /** - * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub - * @udev: the device whose split transaction failed - * @pipe: identifies the endpoint of the failed transaction + * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub + * @urb: an URB associated with the failed or incomplete split transaction   *   * High speed HCDs use this to tell the hub driver that some split control or   * bulk transaction failed in a way that requires clearing internal state of @@ -495,8 +500,10 @@ static void hub_tt_kevent (struct work_struct *work)   * It may not be possible for that hub to handle additional full (or low)   * speed transactions until that state is fully cleared out.   */ -void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) +int usb_hub_clear_tt_buffer(struct urb *urb)  { +	struct usb_device	*udev = urb->dev; +	int			pipe = urb->pipe;  	struct usb_tt		*tt = udev->tt;  	unsigned long		flags;  	struct usb_tt_clear	*clear; @@ -508,7 +515,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)  	if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) {  		dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n");  		/* FIXME recover somehow ... RESET_TT? */ -		return; +		return -ENOMEM;  	}  	/* info that CLEAR_TT_BUFFER needs */ @@ -520,14 +527,19 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)  			: (USB_ENDPOINT_XFER_BULK << 11);  	if (usb_pipein (pipe))  		clear->devinfo |= 1 << 15; -	 + +	/* info for completion callback */ +	clear->hcd = bus_to_hcd(udev->bus); +	clear->ep = urb->ep; +  	/* tell keventd to clear state for this TT */  	spin_lock_irqsave (&tt->lock, flags);  	list_add_tail (&clear->clear_list, &tt->clear_list); -	schedule_work (&tt->kevent); +	schedule_work(&tt->clear_work);  	spin_unlock_irqrestore (&tt->lock, flags); +	return 0;  } -EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer); +EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer);  /* If do_delay is false, return the number of milliseconds the caller   * needs to delay. @@ -818,7 +830,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)  	if (hub->has_indicators)  		cancel_delayed_work_sync(&hub->leds);  	if (hub->tt.hub) -		cancel_work_sync(&hub->tt.kevent); +		cancel_work_sync(&hub->tt.clear_work);  }  /* caller has locked the hub device */ @@ -935,7 +947,7 @@ static int hub_configure(struct usb_hub *hub,  	spin_lock_init (&hub->tt.lock);  	INIT_LIST_HEAD (&hub->tt.clear_list); -	INIT_WORK (&hub->tt.kevent, hub_tt_kevent); +	INIT_WORK(&hub->tt.clear_work, hub_tt_work);  	switch (hdev->descriptor.bDeviceProtocol) {  		case 0:  			break; diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 889c0f32a40..de8081f065e 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -188,16 +188,18 @@ struct usb_tt {  	/* for control/bulk error recovery (CLEAR_TT_BUFFER) */  	spinlock_t		lock;  	struct list_head	clear_list;	/* of usb_tt_clear */ -	struct work_struct			kevent; +	struct work_struct	clear_work;  };  struct usb_tt_clear {  	struct list_head	clear_list;  	unsigned		tt;  	u16			devinfo; +	struct usb_hcd		*hcd; +	struct usb_host_endpoint	*ep;  }; -extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe); +extern int usb_hub_clear_tt_buffer(struct urb *urb);  extern void usb_ep0_reinit(struct usb_device *);  #endif /* __LINUX_HUB_H */ diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 2bed83caacb..9720e699f47 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -806,6 +806,48 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,  	return rc;  } +static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf) +{ +	int err; + +	if (dev->have_langid) +		return 0; + +	if (dev->string_langid < 0) +		return -EPIPE; + +	err = usb_string_sub(dev, 0, 0, tbuf); + +	/* If the string was reported but is malformed, default to english +	 * (0x0409) */ +	if (err == -ENODATA || (err > 0 && err < 4)) { +		dev->string_langid = 0x0409; +		dev->have_langid = 1; +		dev_err(&dev->dev, +			"string descriptor 0 malformed (err = %d), " +			"defaulting to 0x%04x\n", +				err, dev->string_langid); +		return 0; +	} + +	/* In case of all other errors, we assume the device is not able to +	 * deal with strings at all. Set string_langid to -1 in order to +	 * prevent any string to be retrieved from the device */ +	if (err < 0) { +		dev_err(&dev->dev, "string descriptor 0 read error: %d\n", +					err); +		dev->string_langid = -1; +		return -EPIPE; +	} + +	/* always use the first langid listed */ +	dev->string_langid = tbuf[2] | (tbuf[3] << 8); +	dev->have_langid = 1; +	dev_dbg(&dev->dev, "default language 0x%04x\n", +				dev->string_langid); +	return 0; +} +  /**   * usb_string - returns UTF-8 version of a string descriptor   * @dev: the device whose string descriptor is being retrieved @@ -837,24 +879,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)  	if (!tbuf)  		return -ENOMEM; -	/* get langid for strings if it's not yet known */ -	if (!dev->have_langid) { -		err = usb_string_sub(dev, 0, 0, tbuf); -		if (err < 0) { -			dev_err(&dev->dev, -				"string descriptor 0 read error: %d\n", -				err); -		} else if (err < 4) { -			dev_err(&dev->dev, "string descriptor 0 too short\n"); -		} else { -			dev->string_langid = tbuf[2] | (tbuf[3] << 8); -			/* always use the first langid listed */ -			dev_dbg(&dev->dev, "default language 0x%04x\n", -				dev->string_langid); -		} - -		dev->have_langid = 1; -	} +	err = usb_get_langid(dev, tbuf); +	if (err < 0) +		goto errout;  	err = usb_string_sub(dev, dev->string_langid, index, tbuf);  	if (err < 0) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5d1ddf485d1..7f8e83a954a 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -286,6 +286,27 @@ config USB_S3C_HSOTG  	default USB_GADGET  	select USB_GADGET_SELECTED +config USB_GADGET_IMX +	boolean "Freescale IMX USB Peripheral Controller" +	depends on ARCH_MX1 +	help +	   Freescale's IMX series include an integrated full speed +	   USB 1.1 device controller.  The controller in the IMX series +	   is register-compatible. + +	   It has Six fixed-function endpoints, as well as endpoint +	   zero (for control transfers). + +	   Say "y" to link the driver statically, or "m" to build a +	   dynamically linked module called "imx_udc" and force all +	   gadget drivers to also be dynamically linked. + +config USB_IMX +	tristate +	depends on USB_GADGET_IMX +	default USB_GADGET +	select USB_GADGET_SELECTED +  config USB_GADGET_S3C2410  	boolean "S3C2410 USB Device Controller"  	depends on ARCH_S3C2410 @@ -321,27 +342,6 @@ config USB_GADGET_MUSB_HDRC  	  This OTG-capable silicon IP is used in dual designs including  	  the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin -config USB_GADGET_IMX -	boolean "Freescale IMX USB Peripheral Controller" -	depends on ARCH_MX1 -	help -	   Freescale's IMX series include an integrated full speed -	   USB 1.1 device controller.  The controller in the IMX series -	   is register-compatible. - -	   It has Six fixed-function endpoints, as well as endpoint -	   zero (for control transfers). - -	   Say "y" to link the driver statically, or "m" to build a -	   dynamically linked module called "imx_udc" and force all -	   gadget drivers to also be dynamically linked. - -config USB_IMX -	tristate -	depends on USB_GADGET_IMX -	default USB_GADGET -	select USB_GADGET_SELECTED -  config USB_GADGET_M66592  	boolean "Renesas M66592 USB Peripheral Controller"  	select USB_GADGET_DUALSPEED @@ -604,6 +604,7 @@ config USB_ZERO_HNPTEST  config USB_AUDIO  	tristate "Audio Gadget (EXPERIMENTAL)"  	depends on SND +	select SND_PCM  	help  	  Gadget Audio is compatible with USB Audio Class specification 1.0.  	  It will include at least one AudioControl interface, zero or more diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 826f3adde5d..77352ccc245 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -48,7 +48,6 @@  #include <linux/ioport.h>  #include <linux/sched.h>  #include <linux/slab.h> -#include <linux/smp_lock.h>  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/timer.h> diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c index 94de7e86461..9f80f4e970b 100644 --- a/drivers/usb/gadget/audio.c +++ b/drivers/usb/gadget/audio.c @@ -42,9 +42,9 @@   * Instead:  allocate your own, using normal USB-IF procedures.   */ -/* Thanks to NetChip Technologies for donating this product ID. */ -#define AUDIO_VENDOR_NUM		0x0525	/* NetChip */ -#define AUDIO_PRODUCT_NUM		0xa4a1	/* Linux-USB Audio Gadget */ +/* Thanks to Linux Foundation for donating this product ID. */ +#define AUDIO_VENDOR_NUM		0x1d6b	/* Linux Foundation */ +#define AUDIO_PRODUCT_NUM		0x0101	/* Linux-USB Audio Gadget */  /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index d006dc652e0..bd102f5052b 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -293,15 +293,16 @@ static int __init eth_bind(struct usb_composite_dev *cdev)  		/* CDC Subset */  		eth_config_driver.label = "CDC Subset/SAFE"; -		device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM), -		device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM), -		device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; +		device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM); +		device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM); +		if (!has_rndis()) +			device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;  	}  	if (has_rndis()) {  		/* RNDIS plus ECM-or-Subset */ -		device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM), -		device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM), +		device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM); +		device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM);  		device_desc.bNumConfigurations = 2;  	} diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index 6829d596135..a3913519fd5 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -34,7 +34,6 @@  #include <linux/ioport.h>  #include <linux/sched.h>  #include <linux/slab.h> -#include <linux/smp_lock.h>  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/timer.h> diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 0ce4e281984..ed21e263f83 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -139,7 +139,7 @@ static int is_vbus_present(void)  {  	struct pxa2xx_udc_mach_info		*mach = the_controller->mach; -	if (mach->gpio_vbus) { +	if (gpio_is_valid(mach->gpio_vbus)) {  		int value = gpio_get_value(mach->gpio_vbus);  		if (mach->gpio_vbus_inverted) @@ -158,7 +158,7 @@ static void pullup_off(void)  	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;  	int off_level = mach->gpio_pullup_inverted; -	if (mach->gpio_pullup) +	if (gpio_is_valid(mach->gpio_pullup))  		gpio_set_value(mach->gpio_pullup, off_level);  	else if (mach->udc_command)  		mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); @@ -169,7 +169,7 @@ static void pullup_on(void)  	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;  	int on_level = !mach->gpio_pullup_inverted; -	if (mach->gpio_pullup) +	if (gpio_is_valid(mach->gpio_pullup))  		gpio_set_value(mach->gpio_pullup, on_level);  	else if (mach->udc_command)  		mach->udc_command(PXA2XX_UDC_CMD_CONNECT); @@ -1000,7 +1000,7 @@ static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active)  	udc = container_of(_gadget, struct pxa25x_udc, gadget);  	/* not all boards support pullup control */ -	if (!udc->mach->gpio_pullup && !udc->mach->udc_command) +	if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command)  		return -EOPNOTSUPP;  	udc->pullup = (is_active != 0); @@ -1802,11 +1802,13 @@ pxa25x_udc_irq(int irq, void *_dev)  					USIR0 |= tmp;  					handled = 1;  				} +#ifndef	CONFIG_USB_PXA25X_SMALL  				if (usir1 & tmp) {  					handle_ep(&dev->ep[i+8]);  					USIR1 |= tmp;  					handled = 1;  				} +#endif  			}  		} @@ -2160,7 +2162,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)  	dev->dev = &pdev->dev;  	dev->mach = pdev->dev.platform_data; -	if (dev->mach->gpio_vbus) { +	if (gpio_is_valid(dev->mach->gpio_vbus)) {  		if ((retval = gpio_request(dev->mach->gpio_vbus,  				"pxa25x_udc GPIO VBUS"))) {  			dev_dbg(&pdev->dev, @@ -2173,7 +2175,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)  	} else  		vbus_irq = 0; -	if (dev->mach->gpio_pullup) { +	if (gpio_is_valid(dev->mach->gpio_pullup)) {  		if ((retval = gpio_request(dev->mach->gpio_pullup,  				"pca25x_udc GPIO PULLUP"))) {  			dev_dbg(&pdev->dev, @@ -2256,10 +2258,10 @@ lubbock_fail0:  #endif  	free_irq(irq, dev);   err_irq1: -	if (dev->mach->gpio_pullup) +	if (gpio_is_valid(dev->mach->gpio_pullup))  		gpio_free(dev->mach->gpio_pullup);   err_gpio_pullup: -	if (dev->mach->gpio_vbus) +	if (gpio_is_valid(dev->mach->gpio_vbus))  		gpio_free(dev->mach->gpio_vbus);   err_gpio_vbus:  	clk_put(dev->clk); @@ -2294,11 +2296,11 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)  		free_irq(LUBBOCK_USB_IRQ, dev);  	}  #endif -	if (dev->mach->gpio_vbus) { +	if (gpio_is_valid(dev->mach->gpio_vbus)) {  		free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);  		gpio_free(dev->mach->gpio_vbus);  	} -	if (dev->mach->gpio_pullup) +	if (gpio_is_valid(dev->mach->gpio_pullup))  		gpio_free(dev->mach->gpio_pullup);  	clk_put(dev->clk); @@ -2329,7 +2331,7 @@ static int pxa25x_udc_suspend(struct platform_device *dev, pm_message_t state)  	struct pxa25x_udc	*udc = platform_get_drvdata(dev);  	unsigned long flags; -	if (!udc->mach->gpio_pullup && !udc->mach->udc_command) +	if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command)  		WARNING("USB host won't detect disconnect!\n");  	udc->suspended = 1; diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 2b4660e08c4..ca41b0b5afb 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -442,6 +442,8 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,  	case OID_802_3_MAC_OPTIONS:  		pr_debug("%s: OID_802_3_MAC_OPTIONS\n", __func__); +		*outbuf = cpu_to_le32(0); +		retval = 0;  		break;  	/* ieee802.3 statistics OIDs (table 4-4) */ diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 9a2b8920532..a9b452fe622 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -28,7 +28,6 @@  #include <linux/ioport.h>  #include <linux/sched.h>  #include <linux/slab.h> -#include <linux/smp_lock.h>  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/timer.h> diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 1576a0520ad..1a920c70b5a 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -181,26 +181,27 @@ config USB_OHCI_HCD_PPC_SOC  	  Enables support for the USB controller on the MPC52xx or  	  STB03xxx processor chip.  If unsure, say Y. -config USB_OHCI_HCD_PPC_OF -	bool "OHCI support for PPC USB controller on OF platform bus" -	depends on USB_OHCI_HCD && PPC_OF -	default y -	---help--- -	  Enables support for the USB controller PowerPC present on the -	  OpenFirmware platform bus. -  config USB_OHCI_HCD_PPC_OF_BE -	bool "Support big endian HC" -	depends on USB_OHCI_HCD_PPC_OF -	default y +	bool "OHCI support for OF platform bus (big endian)" +	depends on USB_OHCI_HCD && PPC_OF  	select USB_OHCI_BIG_ENDIAN_DESC  	select USB_OHCI_BIG_ENDIAN_MMIO +	---help--- +	  Enables support for big-endian USB controllers present on the +	  OpenFirmware platform bus.  config USB_OHCI_HCD_PPC_OF_LE -	bool "Support little endian HC" -	depends on USB_OHCI_HCD_PPC_OF -	default n +	bool "OHCI support for OF platform bus (little endian)" +	depends on USB_OHCI_HCD && PPC_OF  	select USB_OHCI_LITTLE_ENDIAN +	---help--- +	  Enables support for little-endian USB controllers present on the +	  OpenFirmware platform bus. + +config USB_OHCI_HCD_PPC_OF +	bool +	depends on USB_OHCI_HCD && PPC_OF +	default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE  config USB_OHCI_HCD_PCI  	bool "OHCI support for PCI-bus USB controllers" @@ -337,10 +338,10 @@ config USB_R8A66597_HCD  config SUPERH_ON_CHIP_R8A66597  	boolean "Enable SuperH on-chip R8A66597 USB" -	depends on USB_R8A66597_HCD && (CPU_SUBTYPE_SH7366 || CPU_SUBTYPE_SH7723) +	depends on USB_R8A66597_HCD && (CPU_SUBTYPE_SH7366 || CPU_SUBTYPE_SH7723 || CPU_SUBTYPE_SH7724)  	help  	   This driver enables support for the on-chip R8A66597 in the -	   SH7366 and SH7723 processors. +	   SH7366, SH7723 and SH7724 processors.  config USB_WHCI_HCD  	tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)" diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index c3a778bd359..59d208d94d4 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -113,6 +113,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {  	.bus_resume		= ehci_bus_resume,  	.relinquish_port	= ehci_relinquish_port,  	.port_handed_over	= ehci_port_handed_over, + +	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,  };  static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index bf86809c512..991174937db 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -325,6 +325,8 @@ static const struct hc_driver ehci_fsl_hc_driver = {  	.bus_resume = ehci_bus_resume,  	.relinquish_port = ehci_relinquish_port,  	.port_handed_over = ehci_port_handed_over, + +	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,  };  static int ehci_fsl_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 2b72473544d..11c627ce602 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -903,7 +903,8 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  			/* already started */  			break;  		case QH_STATE_IDLE: -			WARN_ON(1); +			/* QH might be waiting for a Clear-TT-Buffer */ +			qh_completions(ehci, qh);  			break;  		}  		break; @@ -1003,6 +1004,8 @@ idle_timeout:  		schedule_timeout_uninterruptible(1);  		goto rescan;  	case QH_STATE_IDLE:		/* fully unlinked */ +		if (qh->clearing_tt) +			goto idle_timeout;  		if (list_empty (&qh->qtd_list)) {  			qh_put (qh);  			break; @@ -1030,12 +1033,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)  	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);  	struct ehci_qh		*qh;  	int			eptype = usb_endpoint_type(&ep->desc); +	int			epnum = usb_endpoint_num(&ep->desc); +	int			is_out = usb_endpoint_dir_out(&ep->desc); +	unsigned long		flags;  	if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)  		return; - rescan: -	spin_lock_irq(&ehci->lock); +	spin_lock_irqsave(&ehci->lock, flags);  	qh = ep->hcpriv;  	/* For Bulk and Interrupt endpoints we maintain the toggle state @@ -1044,29 +1049,24 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)  	 * the toggle bit in the QH.  	 */  	if (qh) { +		usb_settoggle(qh->dev, epnum, is_out, 0);  		if (!list_empty(&qh->qtd_list)) {  			WARN_ONCE(1, "clear_halt for a busy endpoint\n"); -		} else if (qh->qh_state == QH_STATE_IDLE) { -			qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); -		} else { -			/* It's not safe to write into the overlay area -			 * while the QH is active.  Unlink it first and -			 * wait for the unlink to complete. +		} else if (qh->qh_state == QH_STATE_LINKED) { + +			/* The toggle value in the QH can't be updated +			 * while the QH is active.  Unlink it now; +			 * re-linking will call qh_refresh().  			 */ -			if (qh->qh_state == QH_STATE_LINKED) { -				if (eptype == USB_ENDPOINT_XFER_BULK) { -					unlink_async(ehci, qh); -				} else { -					intr_deschedule(ehci, qh); -					(void) qh_schedule(ehci, qh); -				} +			if (eptype == USB_ENDPOINT_XFER_BULK) { +				unlink_async(ehci, qh); +			} else { +				intr_deschedule(ehci, qh); +				(void) qh_schedule(ehci, qh);  			} -			spin_unlock_irq(&ehci->lock); -			schedule_timeout_uninterruptible(1); -			goto rescan;  		}  	} -	spin_unlock_irq(&ehci->lock); +	spin_unlock_irqrestore(&ehci->lock, flags);  }  static int ehci_get_frame (struct usb_hcd *hcd) diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c index a44bb4a9495..89b7c70c6ed 100644 --- a/drivers/usb/host/ehci-ixp4xx.c +++ b/drivers/usb/host/ehci-ixp4xx.c @@ -61,6 +61,8 @@ static const struct hc_driver ixp4xx_ehci_hc_driver = {  #endif  	.relinquish_port	= ehci_relinquish_port,  	.port_handed_over	= ehci_port_handed_over, + +	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,  };  static int ixp4xx_ehci_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 770dd9aba62..1d283e1b2b8 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -105,6 +105,7 @@ static int ehci_orion_setup(struct usb_hcd *hcd)  	struct ehci_hcd *ehci = hcd_to_ehci(hcd);  	int retval; +	ehci_reset(ehci);  	retval = ehci_halt(ehci);  	if (retval)  		return retval; @@ -118,7 +119,6 @@ static int ehci_orion_setup(struct usb_hcd *hcd)  	hcd->has_tt = 1; -	ehci_reset(ehci);  	ehci_port_power(ehci, 0);  	return retval; @@ -165,6 +165,8 @@ static const struct hc_driver ehci_orion_hc_driver = {  	.bus_resume = ehci_bus_resume,  	.relinquish_port = ehci_relinquish_port,  	.port_handed_over = ehci_port_handed_over, + +	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,  };  static void __init diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index f3683e1da16..c2f1b7df918 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -404,6 +404,8 @@ static const struct hc_driver ehci_pci_hc_driver = {  	.bus_resume =		ehci_bus_resume,  	.relinquish_port =	ehci_relinquish_port,  	.port_handed_over =	ehci_port_handed_over, + +	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,  };  /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index fbd272288fc..36f96da129f 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -79,6 +79,8 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {  #endif  	.relinquish_port	= ehci_relinquish_port,  	.port_handed_over	= ehci_port_handed_over, + +	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,  }; diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 93f7035d00a..1dee33b9139 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -75,6 +75,8 @@ static const struct hc_driver ps3_ehci_hc_driver = {  #endif  	.relinquish_port	= ehci_relinquish_port,  	.port_handed_over	= ehci_port_handed_over, + +	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,  };  static int __devinit ps3_ehci_probe(struct ps3_system_bus_device *dev) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 3192f683f80..7673554fa64 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -93,6 +93,22 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)  	qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);  	qh->hw_alt_next = EHCI_LIST_END(ehci); +	/* Except for control endpoints, we make hardware maintain data +	 * toggle (like OHCI) ... here (re)initialize the toggle in the QH, +	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will +	 * ever clear it. +	 */ +	if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { +		unsigned	is_out, epnum; + +		is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); +		epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f; +		if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { +			qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); +			usb_settoggle (qh->dev, epnum, is_out, 1); +		} +	} +  	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */  	wmb ();  	qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING); @@ -123,6 +139,55 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)  /*-------------------------------------------------------------------------*/ +static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh); + +static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd, +		struct usb_host_endpoint *ep) +{ +	struct ehci_hcd		*ehci = hcd_to_ehci(hcd); +	struct ehci_qh		*qh = ep->hcpriv; +	unsigned long		flags; + +	spin_lock_irqsave(&ehci->lock, flags); +	qh->clearing_tt = 0; +	if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list) +			&& HC_IS_RUNNING(hcd->state)) +		qh_link_async(ehci, qh); +	spin_unlock_irqrestore(&ehci->lock, flags); +} + +static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh, +		struct urb *urb, u32 token) +{ + +	/* If an async split transaction gets an error or is unlinked, +	 * the TT buffer may be left in an indeterminate state.  We +	 * have to clear the TT buffer. +	 * +	 * Note: this routine is never called for Isochronous transfers. +	 */ +	if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { +#ifdef DEBUG +		struct usb_device *tt = urb->dev->tt->hub; +		dev_dbg(&tt->dev, +			"clear tt buffer port %d, a%d ep%d t%08x\n", +			urb->dev->ttport, urb->dev->devnum, +			usb_pipeendpoint(urb->pipe), token); +#endif /* DEBUG */ +		if (!ehci_is_TDI(ehci) +				|| urb->dev->tt->hub != +				   ehci_to_hcd(ehci)->self.root_hub) { +			if (usb_hub_clear_tt_buffer(urb) == 0) +				qh->clearing_tt = 1; +		} else { + +			/* REVISIT ARC-derived cores don't clear the root +			 * hub TT buffer in this way... +			 */ +		} +	} +} +  static int qtd_copy_status (  	struct ehci_hcd *ehci,  	struct urb *urb, @@ -149,6 +214,14 @@ static int qtd_copy_status (  		if (token & QTD_STS_BABBLE) {  			/* FIXME "must" disable babbling device's port too */  			status = -EOVERFLOW; +		/* CERR nonzero + halt --> stall */ +		} else if (QTD_CERR(token)) { +			status = -EPIPE; + +		/* In theory, more than one of the following bits can be set +		 * since they are sticky and the transaction is retried. +		 * Which to test first is rather arbitrary. +		 */  		} else if (token & QTD_STS_MMF) {  			/* fs/ls interrupt xfer missed the complete-split */  			status = -EPROTO; @@ -157,21 +230,15 @@ static int qtd_copy_status (  				? -ENOSR  /* hc couldn't read data */  				: -ECOMM; /* hc couldn't write data */  		} else if (token & QTD_STS_XACT) { -			/* timeout, bad crc, wrong PID, etc; retried */ -			if (QTD_CERR (token)) -				status = -EPIPE; -			else { -				ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n", -					urb->dev->devpath, -					usb_pipeendpoint (urb->pipe), -					usb_pipein (urb->pipe) ? "in" : "out"); -				status = -EPROTO; -			} -		/* CERR nonzero + no errors + halt --> stall */ -		} else if (QTD_CERR (token)) -			status = -EPIPE; -		else	/* unknown */ +			/* timeout, bad CRC, wrong PID, etc */ +			ehci_dbg(ehci, "devpath %s ep%d%s 3strikes\n", +				urb->dev->devpath, +				usb_pipeendpoint(urb->pipe), +				usb_pipein(urb->pipe) ? "in" : "out"); +			status = -EPROTO; +		} else {	/* unknown */  			status = -EPROTO; +		}  		ehci_vdbg (ehci,  			"dev%d ep%d%s qtd token %08x --> status %d\n", @@ -179,28 +246,6 @@ static int qtd_copy_status (  			usb_pipeendpoint (urb->pipe),  			usb_pipein (urb->pipe) ? "in" : "out",  			token, status); - -		/* if async CSPLIT failed, try cleaning out the TT buffer */ -		if (status != -EPIPE -				&& urb->dev->tt -				&& !usb_pipeint(urb->pipe) -				&& ((token & QTD_STS_MMF) != 0 -					|| QTD_CERR(token) == 0) -				&& (!ehci_is_TDI(ehci) -			                || urb->dev->tt->hub != -					   ehci_to_hcd(ehci)->self.root_hub)) { -#ifdef DEBUG -			struct usb_device *tt = urb->dev->tt->hub; -			dev_dbg (&tt->dev, -				"clear tt buffer port %d, a%d ep%d t%08x\n", -				urb->dev->ttport, urb->dev->devnum, -				usb_pipeendpoint (urb->pipe), token); -#endif /* DEBUG */ -			/* REVISIT ARC-derived cores don't clear the root -			 * hub TT buffer in this way... -			 */ -			usb_hub_tt_clear_buffer (urb->dev, urb->pipe); -		}  	}  	return status; @@ -330,12 +375,11 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)  				 */  				if ((token & QTD_STS_XACT) &&  						QTD_CERR(token) == 0 && -						--qh->xacterrs > 0 && +						++qh->xacterrs < QH_XACTERR_MAX &&  						!urb->unlinked) {  					ehci_dbg(ehci,  	"detected XactErr len %zu/%zu retry %d\n", -	qtd->length - QTD_LENGTH(token), qtd->length, -	QH_XACTERR_MAX - qh->xacterrs); +	qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs);  					/* reset the token in the qtd and the  					 * qh overlay (which still contains @@ -391,9 +435,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)  			/* qh unlinked; token in overlay may be most current */  			if (state == QH_STATE_IDLE  					&& cpu_to_hc32(ehci, qtd->qtd_dma) -						== qh->hw_current) +						== qh->hw_current) {  				token = hc32_to_cpu(ehci, qh->hw_token); +				/* An unlink may leave an incomplete +				 * async transaction in the TT buffer. +				 * We have to clear it. +				 */ +				ehci_clear_tt_buffer(ehci, qh, urb, token); +			} +  			/* force halt for unlinked or blocked qh, so we'll  			 * patch the qh later and so that completions can't  			 * activate it while we "know" it's stopped. @@ -419,6 +470,13 @@ halt:  					&& (qtd->hw_alt_next  						& EHCI_LIST_END(ehci)))  				last_status = -EINPROGRESS; + +			/* As part of low/full-speed endpoint-halt processing +			 * we must clear the TT buffer (11.17.5). +			 */ +			if (unlikely(last_status != -EINPROGRESS && +					last_status != -EREMOTEIO)) +				ehci_clear_tt_buffer(ehci, qh, urb, token);  		}  		/* if we're removing something not at the queue head, @@ -435,7 +493,7 @@ halt:  		last = qtd;  		/* reinit the xacterr counter for the next qtd */ -		qh->xacterrs = QH_XACTERR_MAX; +		qh->xacterrs = 0;  	}  	/* last urb's completion might still need calling */ @@ -834,6 +892,7 @@ done:  	qh->qh_state = QH_STATE_IDLE;  	qh->hw_info1 = cpu_to_hc32(ehci, info1);  	qh->hw_info2 = cpu_to_hc32(ehci, info2); +	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);  	qh_refresh (ehci, qh);  	return qh;  } @@ -847,6 +906,10 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)  	__hc32		dma = QH_NEXT(ehci, qh->qh_dma);  	struct ehci_qh	*head; +	/* Don't link a QH if there's a Clear-TT-Buffer pending */ +	if (unlikely(qh->clearing_tt)) +		return; +  	/* (re)start the async schedule? */  	head = ehci->async;  	timer_action_done (ehci, TIMER_ASYNC_OFF); @@ -864,7 +927,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)  		}  	} -	/* clear halt and maybe recover from silicon quirk */ +	/* clear halt and/or toggle; and maybe recover from silicon quirk */  	if (qh->qh_state == QH_STATE_IDLE)  		qh_refresh (ehci, qh); @@ -876,7 +939,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)  	head->qh_next.qh = qh;  	head->hw_next = dma; -	qh->xacterrs = QH_XACTERR_MAX; +	qh_get(qh); +	qh->xacterrs = 0;  	qh->qh_state = QH_STATE_LINKED;  	/* qtd completions reported later by interrupt */  } @@ -1016,7 +1080,7 @@ submit_async (  	 * the HC and TT handle it when the TT has a buffer ready.  	 */  	if (likely (qh->qh_state == QH_STATE_IDLE)) -		qh_link_async (ehci, qh_get (qh)); +		qh_link_async(ehci, qh);   done:  	spin_unlock_irqrestore (&ehci->lock, flags);  	if (unlikely (qh == NULL)) @@ -1051,8 +1115,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)  			&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))  		qh_link_async (ehci, qh);  	else { -		qh_put (qh);		// refcount from async list -  		/* it's not free to turn the async schedule on/off; leave it  		 * active but idle for a while once it empties.  		 */ @@ -1060,6 +1122,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)  				&& ehci->async->qh_next.qh == NULL)  			timer_action (ehci, TIMER_ASYNC_OFF);  	} +	qh_put(qh);			/* refcount from async list */  	if (next) {  		ehci->reclaim = NULL; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 9d1babc7ff6..edd61ee9032 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -542,6 +542,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)  		}  	}  	qh->qh_state = QH_STATE_LINKED; +	qh->xacterrs = 0;  	qh_get (qh);  	/* update per-qh bandwidth for usbfs */ @@ -1619,11 +1620,14 @@ itd_complete (  				desc->status = -EPROTO;  			/* HC need not update length with this error */ -			if (!(t & EHCI_ISOC_BABBLE)) -				desc->actual_length = EHCI_ITD_LENGTH (t); +			if (!(t & EHCI_ISOC_BABBLE)) { +				desc->actual_length = EHCI_ITD_LENGTH(t); +				urb->actual_length += desc->actual_length; +			}  		} else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) {  			desc->status = 0; -			desc->actual_length = EHCI_ITD_LENGTH (t); +			desc->actual_length = EHCI_ITD_LENGTH(t); +			urb->actual_length += desc->actual_length;  		} else {  			/* URB was too late */  			desc->status = -EXDEV; @@ -2014,7 +2018,8 @@ sitd_complete (  			desc->status = -EPROTO;  	} else {  		desc->status = 0; -		desc->actual_length = desc->length - SITD_LENGTH (t); +		desc->actual_length = desc->length - SITD_LENGTH(t); +		urb->actual_length += desc->actual_length;  	}  	stream->depth -= stream->interval << 3; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 90ad3395bb2..2bfff30f470 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -354,7 +354,9 @@ struct ehci_qh {  	unsigned short		period;		/* polling interval */  	unsigned short		start;		/* where polling starts */  #define NO_FRAME ((unsigned short)~0)			/* pick new start */ +  	struct usb_device	*dev;		/* access to TT */ +	unsigned		clearing_tt:1;	/* Clear-TT-Buf in progress */  } __attribute__ ((aligned (32)));  /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c index bb63b68ddb7..62a226b6167 100644 --- a/drivers/usb/host/fhci-sched.c +++ b/drivers/usb/host/fhci-sched.c @@ -576,9 +576,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)  			out_be16(&usb->fhci->regs->usb_event,  				 usb->saved_msk);  		} else if (usb->port_status == FHCI_PORT_DISABLED) { -			if (fhci_ioports_check_bus_state(fhci) == 1 && -					usb->port_status != FHCI_PORT_LOW && -					usb->port_status != FHCI_PORT_FULL) +			if (fhci_ioports_check_bus_state(fhci) == 1)  				fhci_device_connected_interrupt(fhci);  		}  		usb_er &= ~USB_E_RESET_MASK; @@ -605,9 +603,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)  	}  	if (usb_er & USB_E_IDLE_MASK) { -		if (usb->port_status == FHCI_PORT_DISABLED && -				usb->port_status != FHCI_PORT_LOW && -				usb->port_status != FHCI_PORT_FULL) { +		if (usb->port_status == FHCI_PORT_DISABLED) {  			usb_er &= ~USB_E_RESET_MASK;  			fhci_device_connected_interrupt(fhci);  		} else if (usb->port_status == diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 3fa3a170279..d4feebfc63b 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -361,7 +361,7 @@ static int __devexit isp1760_plat_remove(struct platform_device *pdev)  static struct platform_driver isp1760_plat_driver = {  	.probe	= isp1760_plat_probe, -	.remove	= isp1760_plat_remove, +	.remove	= __devexit_p(isp1760_plat_remove),  	.driver	= {  		.name	= "isp1760",  	}, diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index f3aaba35e91..83cbecd2a1e 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -282,6 +282,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)  static void ohci_omap_stop(struct usb_hcd *hcd)  {  	dev_dbg(hcd->self.controller, "stopping USB Controller\n"); +	ohci_stop(hcd);  	omap_ohci_clock_power(0);  } diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 56976cc0352..e18f74946e6 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -26,7 +26,6 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/smp_lock.h>  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/timer.h> diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 2501c571f85..705e3432415 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -173,6 +173,7 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int  {  	void *addr;  	u32 temp; +	u64 temp_64;  	addr = &ir_set->irq_pending;  	temp = xhci_readl(xhci, addr); @@ -200,25 +201,15 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int  		xhci_dbg(xhci, "  WARN: %p: ir_set.rsvd = 0x%x\n",  				addr, (unsigned int)temp); -	addr = &ir_set->erst_base[0]; -	temp = xhci_readl(xhci, addr); -	xhci_dbg(xhci, "  %p: ir_set.erst_base[0] = 0x%x\n", -			addr, (unsigned int) temp); - -	addr = &ir_set->erst_base[1]; -	temp = xhci_readl(xhci, addr); -	xhci_dbg(xhci, "  %p: ir_set.erst_base[1] = 0x%x\n", -			addr, (unsigned int) temp); +	addr = &ir_set->erst_base; +	temp_64 = xhci_read_64(xhci, addr); +	xhci_dbg(xhci, "  %p: ir_set.erst_base = @%08llx\n", +			addr, temp_64); -	addr = &ir_set->erst_dequeue[0]; -	temp = xhci_readl(xhci, addr); -	xhci_dbg(xhci, "  %p: ir_set.erst_dequeue[0] = 0x%x\n", -			addr, (unsigned int) temp); - -	addr = &ir_set->erst_dequeue[1]; -	temp = xhci_readl(xhci, addr); -	xhci_dbg(xhci, "  %p: ir_set.erst_dequeue[1] = 0x%x\n", -			addr, (unsigned int) temp); +	addr = &ir_set->erst_dequeue; +	temp_64 = xhci_read_64(xhci, addr); +	xhci_dbg(xhci, "  %p: ir_set.erst_dequeue = @%08llx\n", +			addr, temp_64);  }  void xhci_print_run_regs(struct xhci_hcd *xhci) @@ -268,8 +259,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)  		xhci_dbg(xhci, "Link TRB:\n");  		xhci_print_trb_offsets(xhci, trb); -		address = trb->link.segment_ptr[0] + -			(((u64) trb->link.segment_ptr[1]) << 32); +		address = trb->link.segment_ptr;  		xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address);  		xhci_dbg(xhci, "Interrupter target = 0x%x\n", @@ -282,8 +272,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)  				(unsigned int) (trb->link.control & TRB_NO_SNOOP));  		break;  	case TRB_TYPE(TRB_TRANSFER): -		address = trb->trans_event.buffer[0] + -			(((u64) trb->trans_event.buffer[1]) << 32); +		address = trb->trans_event.buffer;  		/*  		 * FIXME: look at flags to figure out if it's an address or if  		 * the data is directly in the buffer field. @@ -291,8 +280,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)  		xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address);  		break;  	case TRB_TYPE(TRB_COMPLETION): -		address = trb->event_cmd.cmd_trb[0] + -			(((u64) trb->event_cmd.cmd_trb[1]) << 32); +		address = trb->event_cmd.cmd_trb;  		xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);  		xhci_dbg(xhci, "Completion status = %u\n",  				(unsigned int) GET_COMP_CODE(trb->event_cmd.status)); @@ -328,8 +316,8 @@ void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)  	for (i = 0; i < TRBS_PER_SEGMENT; ++i) {  		trb = &seg->trbs[i];  		xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr, -				(unsigned int) trb->link.segment_ptr[0], -				(unsigned int) trb->link.segment_ptr[1], +				lower_32_bits(trb->link.segment_ptr), +				upper_32_bits(trb->link.segment_ptr),  				(unsigned int) trb->link.intr_target,  				(unsigned int) trb->link.control);  		addr += sizeof(*trb); @@ -386,8 +374,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)  		entry = &erst->entries[i];  		xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n",  				(unsigned int) addr, -				(unsigned int) entry->seg_addr[0], -				(unsigned int) entry->seg_addr[1], +				lower_32_bits(entry->seg_addr), +				upper_32_bits(entry->seg_addr),  				(unsigned int) entry->seg_size,  				(unsigned int) entry->rsvd);  		addr += sizeof(*entry); @@ -396,90 +384,147 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)  void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)  { -	u32 val; +	u64 val; -	val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]); -	xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = 0x%x\n", val); -	val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]); -	xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val); +	val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); +	xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = @%08x\n", +			lower_32_bits(val)); +	xhci_dbg(xhci, "// xHC command ring deq ptr high bits = @%08x\n", +			upper_32_bits(val));  } -void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) +/* Print the last 32 bytes for 64-byte contexts */ +static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma) +{ +	int i; +	for (i = 0; i < 4; ++i) { +		xhci_dbg(xhci, "@%p (virt) @%08llx " +			 "(dma) %#08llx - rsvd64[%d]\n", +			 &ctx[4 + i], (unsigned long long)dma, +			 ctx[4 + i], i); +		dma += 8; +	} +} + +void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)  { -	int i, j; -	int last_ep_ctx = 31;  	/* Fields are 32 bits wide, DMA addresses are in bytes */  	int field_size = 32 / 8; +	int i; -	xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", -			&ctx->drop_flags, (unsigned long long)dma, -			ctx->drop_flags); -	dma += field_size; -	xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", -			&ctx->add_flags, (unsigned long long)dma, -			ctx->add_flags); -	dma += field_size; -	for (i = 0; i > 6; ++i) { -		xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", -				&ctx->rsvd[i], (unsigned long long)dma, -				ctx->rsvd[i], i); -		dma += field_size; -	} +	struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx); +	dma_addr_t dma = ctx->dma + ((unsigned long)slot_ctx - (unsigned long)ctx); +	int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);  	xhci_dbg(xhci, "Slot Context:\n");  	xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n", -			&ctx->slot.dev_info, -			(unsigned long long)dma, ctx->slot.dev_info); +			&slot_ctx->dev_info, +			(unsigned long long)dma, slot_ctx->dev_info);  	dma += field_size;  	xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n", -			&ctx->slot.dev_info2, -			(unsigned long long)dma, ctx->slot.dev_info2); +			&slot_ctx->dev_info2, +			(unsigned long long)dma, slot_ctx->dev_info2);  	dma += field_size;  	xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n", -			&ctx->slot.tt_info, -			(unsigned long long)dma, ctx->slot.tt_info); +			&slot_ctx->tt_info, +			(unsigned long long)dma, slot_ctx->tt_info);  	dma += field_size;  	xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n", -			&ctx->slot.dev_state, -			(unsigned long long)dma, ctx->slot.dev_state); +			&slot_ctx->dev_state, +			(unsigned long long)dma, slot_ctx->dev_state);  	dma += field_size; -	for (i = 0; i > 4; ++i) { +	for (i = 0; i < 4; ++i) {  		xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", -				&ctx->slot.reserved[i], (unsigned long long)dma, -				ctx->slot.reserved[i], i); +				&slot_ctx->reserved[i], (unsigned long long)dma, +				slot_ctx->reserved[i], i);  		dma += field_size;  	} +	if (csz) +		dbg_rsvd64(xhci, (u64 *)slot_ctx, dma); +} + +void xhci_dbg_ep_ctx(struct xhci_hcd *xhci, +		     struct xhci_container_ctx *ctx, +		     unsigned int last_ep) +{ +	int i, j; +	int last_ep_ctx = 31; +	/* Fields are 32 bits wide, DMA addresses are in bytes */ +	int field_size = 32 / 8; +	int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); +  	if (last_ep < 31)  		last_ep_ctx = last_ep + 1;  	for (i = 0; i < last_ep_ctx; ++i) { +		struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i); +		dma_addr_t dma = ctx->dma + +			((unsigned long)ep_ctx - (unsigned long)ctx); +  		xhci_dbg(xhci, "Endpoint %02d Context:\n", i);  		xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", -				&ctx->ep[i].ep_info, -				(unsigned long long)dma, ctx->ep[i].ep_info); +				&ep_ctx->ep_info, +				(unsigned long long)dma, ep_ctx->ep_info);  		dma += field_size;  		xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n", -				&ctx->ep[i].ep_info2, -				(unsigned long long)dma, ctx->ep[i].ep_info2); -		dma += field_size; -		xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[0]\n", -				&ctx->ep[i].deq[0], -				(unsigned long long)dma, ctx->ep[i].deq[0]); -		dma += field_size; -		xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[1]\n", -				&ctx->ep[i].deq[1], -				(unsigned long long)dma, ctx->ep[i].deq[1]); +				&ep_ctx->ep_info2, +				(unsigned long long)dma, ep_ctx->ep_info2);  		dma += field_size; +		xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", +				&ep_ctx->deq, +				(unsigned long long)dma, ep_ctx->deq); +		dma += 2*field_size;  		xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", -				&ctx->ep[i].tx_info, -				(unsigned long long)dma, ctx->ep[i].tx_info); +				&ep_ctx->tx_info, +				(unsigned long long)dma, ep_ctx->tx_info);  		dma += field_size;  		for (j = 0; j < 3; ++j) {  			xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", -					&ctx->ep[i].reserved[j], +					&ep_ctx->reserved[j],  					(unsigned long long)dma, -					ctx->ep[i].reserved[j], j); +					ep_ctx->reserved[j], j); +			dma += field_size; +		} + +		if (csz) +			dbg_rsvd64(xhci, (u64 *)ep_ctx, dma); +	} +} + +void xhci_dbg_ctx(struct xhci_hcd *xhci, +		  struct xhci_container_ctx *ctx, +		  unsigned int last_ep) +{ +	int i; +	/* Fields are 32 bits wide, DMA addresses are in bytes */ +	int field_size = 32 / 8; +	struct xhci_slot_ctx *slot_ctx; +	dma_addr_t dma = ctx->dma; +	int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); + +	if (ctx->type == XHCI_CTX_TYPE_INPUT) { +		struct xhci_input_control_ctx *ctrl_ctx = +			xhci_get_input_control_ctx(xhci, ctx); +		xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", +			 &ctrl_ctx->drop_flags, (unsigned long long)dma, +			 ctrl_ctx->drop_flags); +		dma += field_size; +		xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", +			 &ctrl_ctx->add_flags, (unsigned long long)dma, +			 ctrl_ctx->add_flags); +		dma += field_size; +		for (i = 0; i < 6; ++i) { +			xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd2[%d]\n", +				 &ctrl_ctx->rsvd2[i], (unsigned long long)dma, +				 ctrl_ctx->rsvd2[i], i);  			dma += field_size;  		} + +		if (csz) +			dbg_rsvd64(xhci, (u64 *)ctrl_ctx, dma);  	} + +	slot_ctx = xhci_get_slot_ctx(xhci, ctx); +	xhci_dbg_slot_ctx(xhci, ctx); +	xhci_dbg_ep_ctx(xhci, ctx, last_ep);  } diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index dba3e07ccd0..816c39caca1 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -103,7 +103,10 @@ int xhci_reset(struct xhci_hcd *xhci)  	u32 state;  	state = xhci_readl(xhci, &xhci->op_regs->status); -	BUG_ON((state & STS_HALT) == 0); +	if ((state & STS_HALT) == 0) { +		xhci_warn(xhci, "Host controller not halted, aborting reset.\n"); +		return 0; +	}  	xhci_dbg(xhci, "// Reset the HC\n");  	command = xhci_readl(xhci, &xhci->op_regs->command); @@ -226,6 +229,7 @@ int xhci_init(struct usb_hcd *hcd)  static void xhci_work(struct xhci_hcd *xhci)  {  	u32 temp; +	u64 temp_64;  	/*  	 * Clear the op reg interrupt status first, @@ -248,9 +252,9 @@ static void xhci_work(struct xhci_hcd *xhci)  	/* FIXME this should be a delayed service routine that clears the EHB */  	xhci_handle_event(xhci); -	/* Clear the event handler busy flag; the event ring should be empty. */ -	temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); -	xhci_writel(xhci, temp & ~ERST_EHB, &xhci->ir_set->erst_dequeue[0]); +	/* Clear the event handler busy flag (RW1C); the event ring should be empty. */ +	temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); +	xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);  	/* Flush posted writes -- FIXME is this necessary? */  	xhci_readl(xhci, &xhci->ir_set->irq_pending);  } @@ -266,19 +270,34 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)  {  	struct xhci_hcd *xhci = hcd_to_xhci(hcd);  	u32 temp, temp2; +	union xhci_trb *trb;  	spin_lock(&xhci->lock); +	trb = xhci->event_ring->dequeue;  	/* Check if the xHC generated the interrupt, or the irq is shared */  	temp = xhci_readl(xhci, &xhci->op_regs->status);  	temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending); +	if (temp == 0xffffffff && temp2 == 0xffffffff) +		goto hw_died; +  	if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) {  		spin_unlock(&xhci->lock);  		return IRQ_NONE;  	} +	xhci_dbg(xhci, "op reg status = %08x\n", temp); +	xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2); +	xhci_dbg(xhci, "Event ring dequeue ptr:\n"); +	xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n", +			(unsigned long long)xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb), +			lower_32_bits(trb->link.segment_ptr), +			upper_32_bits(trb->link.segment_ptr), +			(unsigned int) trb->link.intr_target, +			(unsigned int) trb->link.control);  	if (temp & STS_FATAL) {  		xhci_warn(xhci, "WARNING: Host System Error\n");  		xhci_halt(xhci); +hw_died:  		xhci_to_hcd(xhci)->state = HC_STATE_HALT;  		spin_unlock(&xhci->lock);  		return -ESHUTDOWN; @@ -295,6 +314,7 @@ void xhci_event_ring_work(unsigned long arg)  {  	unsigned long flags;  	int temp; +	u64 temp_64;  	struct xhci_hcd *xhci = (struct xhci_hcd *) arg;  	int i, j; @@ -311,9 +331,9 @@ void xhci_event_ring_work(unsigned long arg)  	xhci_dbg(xhci, "Event ring:\n");  	xhci_debug_segment(xhci, xhci->event_ring->deq_seg);  	xhci_dbg_ring_ptrs(xhci, xhci->event_ring); -	temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); -	temp &= ERST_PTR_MASK; -	xhci_dbg(xhci, "ERST deq = 0x%x\n", temp); +	temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); +	temp_64 &= ~ERST_PTR_MASK; +	xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);  	xhci_dbg(xhci, "Command ring:\n");  	xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg);  	xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); @@ -356,6 +376,7 @@ void xhci_event_ring_work(unsigned long arg)  int xhci_run(struct usb_hcd *hcd)  {  	u32 temp; +	u64 temp_64;  	struct xhci_hcd *xhci = hcd_to_xhci(hcd);  	void (*doorbell)(struct xhci_hcd *) = NULL; @@ -382,6 +403,20 @@ int xhci_run(struct usb_hcd *hcd)  	add_timer(&xhci->event_ring_timer);  #endif +	xhci_dbg(xhci, "Command ring memory map follows:\n"); +	xhci_debug_ring(xhci, xhci->cmd_ring); +	xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); +	xhci_dbg_cmd_ptrs(xhci); + +	xhci_dbg(xhci, "ERST memory map follows:\n"); +	xhci_dbg_erst(xhci, &xhci->erst); +	xhci_dbg(xhci, "Event ring:\n"); +	xhci_debug_ring(xhci, xhci->event_ring); +	xhci_dbg_ring_ptrs(xhci, xhci->event_ring); +	temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); +	temp_64 &= ~ERST_PTR_MASK; +	xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); +  	xhci_dbg(xhci, "// Set the interrupt modulation register\n");  	temp = xhci_readl(xhci, &xhci->ir_set->irq_control);  	temp &= ~ER_IRQ_INTERVAL_MASK; @@ -406,22 +441,6 @@ int xhci_run(struct usb_hcd *hcd)  	if (NUM_TEST_NOOPS > 0)  		doorbell = xhci_setup_one_noop(xhci); -	xhci_dbg(xhci, "Command ring memory map follows:\n"); -	xhci_debug_ring(xhci, xhci->cmd_ring); -	xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); -	xhci_dbg_cmd_ptrs(xhci); - -	xhci_dbg(xhci, "ERST memory map follows:\n"); -	xhci_dbg_erst(xhci, &xhci->erst); -	xhci_dbg(xhci, "Event ring:\n"); -	xhci_debug_ring(xhci, xhci->event_ring); -	xhci_dbg_ring_ptrs(xhci, xhci->event_ring); -	temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); -	temp &= ERST_PTR_MASK; -	xhci_dbg(xhci, "ERST deq = 0x%x\n", temp); -	temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[1]); -	xhci_dbg(xhci, "ERST deq upper = 0x%x\n", temp); -  	temp = xhci_readl(xhci, &xhci->op_regs->command);  	temp |= (CMD_RUN);  	xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", @@ -601,10 +620,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  		goto exit;  	}  	if (usb_endpoint_xfer_control(&urb->ep->desc)) -		ret = xhci_queue_ctrl_tx(xhci, mem_flags, urb, +		/* We have a spinlock and interrupts disabled, so we must pass +		 * atomic context to this function, which may allocate memory. +		 */ +		ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,  				slot_id, ep_index);  	else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) -		ret = xhci_queue_bulk_tx(xhci, mem_flags, urb, +		ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,  				slot_id, ep_index);  	else  		ret = -EINVAL; @@ -661,8 +683,12 @@ 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_ring = xhci->devs[urb->dev->slot_id]->ep_rings[ep_index]; +	xhci_dbg(xhci, "Endpoint ring:\n"); +	xhci_debug_ring(xhci, ep_ring);  	td = (struct xhci_td *) urb->hcpriv;  	ep_ring->cancels_pending++; @@ -696,7 +722,9 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,  		struct usb_host_endpoint *ep)  {  	struct xhci_hcd *xhci; -	struct xhci_device_control *in_ctx; +	struct xhci_container_ctx *in_ctx, *out_ctx; +	struct xhci_input_control_ctx *ctrl_ctx; +	struct xhci_slot_ctx *slot_ctx;  	unsigned int last_ctx;  	unsigned int ep_index;  	struct xhci_ep_ctx *ep_ctx; @@ -724,31 +752,34 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,  	}  	in_ctx = xhci->devs[udev->slot_id]->in_ctx; +	out_ctx = xhci->devs[udev->slot_id]->out_ctx; +	ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);  	ep_index = xhci_get_endpoint_index(&ep->desc); -	ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index]; +	ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);  	/* If the HC already knows the endpoint is disabled,  	 * or the HCD has noted it is disabled, ignore this request  	 */  	if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED || -			in_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) { +			ctrl_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) {  		xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",  				__func__, ep);  		return 0;  	} -	in_ctx->drop_flags |= drop_flag; -	new_drop_flags = in_ctx->drop_flags; +	ctrl_ctx->drop_flags |= drop_flag; +	new_drop_flags = ctrl_ctx->drop_flags; -	in_ctx->add_flags = ~drop_flag; -	new_add_flags = in_ctx->add_flags; +	ctrl_ctx->add_flags = ~drop_flag; +	new_add_flags = ctrl_ctx->add_flags; -	last_ctx = xhci_last_valid_endpoint(in_ctx->add_flags); +	last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags); +	slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);  	/* Update the last valid endpoint context, if we deleted the last one */ -	if ((in_ctx->slot.dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) { -		in_ctx->slot.dev_info &= ~LAST_CTX_MASK; -		in_ctx->slot.dev_info |= LAST_CTX(last_ctx); +	if ((slot_ctx->dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) { +		slot_ctx->dev_info &= ~LAST_CTX_MASK; +		slot_ctx->dev_info |= LAST_CTX(last_ctx);  	} -	new_slot_info = in_ctx->slot.dev_info; +	new_slot_info = slot_ctx->dev_info;  	xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep); @@ -778,17 +809,22 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,  		struct usb_host_endpoint *ep)  {  	struct xhci_hcd *xhci; -	struct xhci_device_control *in_ctx; +	struct xhci_container_ctx *in_ctx, *out_ctx;  	unsigned int ep_index;  	struct xhci_ep_ctx *ep_ctx; +	struct xhci_slot_ctx *slot_ctx; +	struct xhci_input_control_ctx *ctrl_ctx;  	u32 added_ctxs;  	unsigned int last_ctx;  	u32 new_add_flags, new_drop_flags, new_slot_info;  	int ret = 0;  	ret = xhci_check_args(hcd, udev, ep, 1, __func__); -	if (ret <= 0) +	if (ret <= 0) { +		/* So we won't queue a reset ep command for a root hub */ +		ep->hcpriv = NULL;  		return ret; +	}  	xhci = hcd_to_xhci(hcd);  	added_ctxs = xhci_get_endpoint_flag(&ep->desc); @@ -810,12 +846,14 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,  	}  	in_ctx = xhci->devs[udev->slot_id]->in_ctx; +	out_ctx = xhci->devs[udev->slot_id]->out_ctx; +	ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);  	ep_index = xhci_get_endpoint_index(&ep->desc); -	ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index]; +	ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);  	/* If the HCD has already noted the endpoint is enabled,  	 * ignore this request.  	 */ -	if (in_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) { +	if (ctrl_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) {  		xhci_warn(xhci, "xHCI %s called with enabled ep %p\n",  				__func__, ep);  		return 0; @@ -833,8 +871,8 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,  		return -ENOMEM;  	} -	in_ctx->add_flags |= added_ctxs; -	new_add_flags = in_ctx->add_flags; +	ctrl_ctx->add_flags |= added_ctxs; +	new_add_flags = ctrl_ctx->add_flags;  	/* If xhci_endpoint_disable() was called for this endpoint, but the  	 * xHC hasn't been notified yet through the check_bandwidth() call, @@ -842,14 +880,18 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,  	 * descriptors.  We must drop and re-add this endpoint, so we leave the  	 * drop flags alone.  	 */ -	new_drop_flags = in_ctx->drop_flags; +	new_drop_flags = ctrl_ctx->drop_flags; +	slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);  	/* Update the last valid endpoint context, if we just added one past */ -	if ((in_ctx->slot.dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) { -		in_ctx->slot.dev_info &= ~LAST_CTX_MASK; -		in_ctx->slot.dev_info |= LAST_CTX(last_ctx); +	if ((slot_ctx->dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) { +		slot_ctx->dev_info &= ~LAST_CTX_MASK; +		slot_ctx->dev_info |= LAST_CTX(last_ctx);  	} -	new_slot_info = in_ctx->slot.dev_info; +	new_slot_info = slot_ctx->dev_info; + +	/* Store the usb_device pointer for later use */ +	ep->hcpriv = udev;  	xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n",  			(unsigned int) ep->desc.bEndpointAddress, @@ -860,9 +902,11 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,  	return 0;  } -static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev) +static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev)  { +	struct xhci_input_control_ctx *ctrl_ctx;  	struct xhci_ep_ctx *ep_ctx; +	struct xhci_slot_ctx *slot_ctx;  	int i;  	/* When a device's add flag and drop flag are zero, any subsequent @@ -870,17 +914,18 @@ static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev)  	 * untouched.  Make sure we don't leave any old state in the input  	 * endpoint contexts.  	 */ -	virt_dev->in_ctx->drop_flags = 0; -	virt_dev->in_ctx->add_flags = 0; -	virt_dev->in_ctx->slot.dev_info &= ~LAST_CTX_MASK; +	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); +	ctrl_ctx->drop_flags = 0; +	ctrl_ctx->add_flags = 0; +	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); +	slot_ctx->dev_info &= ~LAST_CTX_MASK;  	/* Endpoint 0 is always valid */ -	virt_dev->in_ctx->slot.dev_info |= LAST_CTX(1); +	slot_ctx->dev_info |= LAST_CTX(1);  	for (i = 1; i < 31; ++i) { -		ep_ctx = &virt_dev->in_ctx->ep[i]; +		ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, i);  		ep_ctx->ep_info = 0;  		ep_ctx->ep_info2 = 0; -		ep_ctx->deq[0] = 0; -		ep_ctx->deq[1] = 0; +		ep_ctx->deq = 0;  		ep_ctx->tx_info = 0;  	}  } @@ -903,6 +948,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)  	unsigned long flags;  	struct xhci_hcd *xhci;  	struct xhci_virt_device	*virt_dev; +	struct xhci_input_control_ctx *ctrl_ctx; +	struct xhci_slot_ctx *slot_ctx;  	ret = xhci_check_args(hcd, udev, NULL, 0, __func__);  	if (ret <= 0) @@ -918,16 +965,18 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)  	virt_dev = xhci->devs[udev->slot_id];  	/* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */ -	virt_dev->in_ctx->add_flags |= SLOT_FLAG; -	virt_dev->in_ctx->add_flags &= ~EP0_FLAG; -	virt_dev->in_ctx->drop_flags &= ~SLOT_FLAG; -	virt_dev->in_ctx->drop_flags &= ~EP0_FLAG; +	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); +	ctrl_ctx->add_flags |= SLOT_FLAG; +	ctrl_ctx->add_flags &= ~EP0_FLAG; +	ctrl_ctx->drop_flags &= ~SLOT_FLAG; +	ctrl_ctx->drop_flags &= ~EP0_FLAG;  	xhci_dbg(xhci, "New Input Control Context:\n"); -	xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, -			LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); +	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); +	xhci_dbg_ctx(xhci, virt_dev->in_ctx, +			LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));  	spin_lock_irqsave(&xhci->lock, flags); -	ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx_dma, +	ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma,  			udev->slot_id);  	if (ret < 0) {  		spin_unlock_irqrestore(&xhci->lock, flags); @@ -982,10 +1031,10 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)  	}  	xhci_dbg(xhci, "Output context after successful config ep cmd:\n"); -	xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, -			LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); +	xhci_dbg_ctx(xhci, virt_dev->out_ctx, +			LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); -	xhci_zero_in_ctx(virt_dev); +	xhci_zero_in_ctx(xhci, virt_dev);  	/* Free any old rings */  	for (i = 1; i < 31; ++i) {  		if (virt_dev->new_ep_rings[i]) { @@ -1023,7 +1072,67 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)  			virt_dev->new_ep_rings[i] = NULL;  		}  	} -	xhci_zero_in_ctx(virt_dev); +	xhci_zero_in_ctx(xhci, virt_dev); +} + +/* Deal with stalled endpoints.  The core should have sent the control message + * to clear the halt condition.  However, we need to make the xHCI hardware + * reset its sequence number, since a device will expect a sequence number of + * zero after the halt condition is cleared. + * Context: in_interrupt + */ +void xhci_endpoint_reset(struct usb_hcd *hcd, +		struct usb_host_endpoint *ep) +{ +	struct xhci_hcd *xhci; +	struct usb_device *udev; +	unsigned int ep_index; +	unsigned long flags; +	int ret; +	struct xhci_dequeue_state deq_state; +	struct xhci_ring *ep_ring; + +	xhci = hcd_to_xhci(hcd); +	udev = (struct usb_device *) ep->hcpriv; +	/* Called with a root hub endpoint (or an endpoint that wasn't added +	 * with xhci_add_endpoint() +	 */ +	if (!ep->hcpriv) +		return; +	ep_index = xhci_get_endpoint_index(&ep->desc); +	ep_ring = xhci->devs[udev->slot_id]->ep_rings[ep_index]; +	if (!ep_ring->stopped_td) { +		xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n", +				ep->desc.bEndpointAddress); +		return; +	} + +	xhci_dbg(xhci, "Queueing reset endpoint command\n"); +	spin_lock_irqsave(&xhci->lock, flags); +	ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index); +	/* +	 * Can't change the ring dequeue pointer until it's transitioned to the +	 * stopped state, which is only upon a successful reset endpoint +	 * command.  Better hope that last command worked! +	 */ +	if (!ret) { +		xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n"); +		/* We need to move the HW's dequeue pointer past this TD, +		 * or it will attempt to resend it on the next doorbell ring. +		 */ +		xhci_find_new_dequeue_state(xhci, udev->slot_id, +				ep_index, ep_ring->stopped_td, &deq_state); +		xhci_dbg(xhci, "Queueing new dequeue state\n"); +		xhci_queue_new_dequeue_state(xhci, ep_ring, +				udev->slot_id, +				ep_index, &deq_state); +		kfree(ep_ring->stopped_td); +		xhci_ring_cmd_db(xhci); +	} +	spin_unlock_irqrestore(&xhci->lock, flags); + +	if (ret) +		xhci_warn(xhci, "FIXME allocate a new ring segment\n");  }  /* @@ -1120,7 +1229,9 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  	struct xhci_virt_device *virt_dev;  	int ret = 0;  	struct xhci_hcd *xhci = hcd_to_xhci(hcd); -	u32 temp; +	struct xhci_slot_ctx *slot_ctx; +	struct xhci_input_control_ctx *ctrl_ctx; +	u64 temp_64;  	if (!udev->slot_id) {  		xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id); @@ -1133,10 +1244,12 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  	if (!udev->config)  		xhci_setup_addressable_virt_dev(xhci, udev);  	/* Otherwise, assume the core has the device configured how it wants */ +	xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); +	xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);  	spin_lock_irqsave(&xhci->lock, flags); -	ret = xhci_queue_address_device(xhci, virt_dev->in_ctx_dma, -			udev->slot_id); +	ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, +					udev->slot_id);  	if (ret) {  		spin_unlock_irqrestore(&xhci->lock, flags);  		xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); @@ -1176,41 +1289,37 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  	default:  		xhci_err(xhci, "ERROR: unexpected command completion "  				"code 0x%x.\n", virt_dev->cmd_status); +		xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); +		xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);  		ret = -EINVAL;  		break;  	}  	if (ret) {  		return ret;  	} -	temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[0]); -	xhci_dbg(xhci, "Op regs DCBAA ptr[0] = %#08x\n", temp); -	temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[1]); -	xhci_dbg(xhci, "Op regs DCBAA ptr[1] = %#08x\n", temp); -	xhci_dbg(xhci, "Slot ID %d dcbaa entry[0] @%p = %#08x\n", -			udev->slot_id, -			&xhci->dcbaa->dev_context_ptrs[2*udev->slot_id], -			xhci->dcbaa->dev_context_ptrs[2*udev->slot_id]); -	xhci_dbg(xhci, "Slot ID %d dcbaa entry[1] @%p = %#08x\n", +	temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); +	xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64); +	xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n",  			udev->slot_id, -			&xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1], -			xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1]); +			&xhci->dcbaa->dev_context_ptrs[udev->slot_id], +			(unsigned long long) +				xhci->dcbaa->dev_context_ptrs[udev->slot_id]);  	xhci_dbg(xhci, "Output Context DMA address = %#08llx\n", -			(unsigned long long)virt_dev->out_ctx_dma); +			(unsigned long long)virt_dev->out_ctx->dma);  	xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); -	xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2); +	xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);  	xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); -	xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); +	xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);  	/*  	 * USB core uses address 1 for the roothubs, so we add one to the  	 * address given back to us by the HC.  	 */ -	udev->devnum = (virt_dev->out_ctx->slot.dev_state & DEV_ADDR_MASK) + 1; +	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); +	udev->devnum = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1;  	/* Zero the input context control for later use */ -	virt_dev->in_ctx->add_flags = 0; -	virt_dev->in_ctx->drop_flags = 0; -	/* Mirror flags in the output context for future ep enable/disable */ -	virt_dev->out_ctx->add_flags = SLOT_FLAG | EP0_FLAG; -	virt_dev->out_ctx->drop_flags = 0; +	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); +	ctrl_ctx->add_flags = 0; +	ctrl_ctx->drop_flags = 0;  	xhci_dbg(xhci, "Device address = %d\n", udev->devnum);  	/* XXX Meh, not sure if anyone else but choose_address uses this. */ @@ -1252,7 +1361,6 @@ static int __init xhci_hcd_init(void)  	/* xhci_device_control has eight fields, and also  	 * embeds one xhci_slot_ctx and 31 xhci_ep_ctx  	 */ -	BUILD_BUG_ON(sizeof(struct xhci_device_control) != (8+8+8*31)*32/8);  	BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8);  	BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8);  	BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index c8a72de1c50..e6b9a1c6002 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -88,7 +88,7 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,  		return;  	prev->next = next;  	if (link_trbs) { -		prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr[0] = next->dma; +		prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = next->dma;  		/* Set the last TRB in the segment to have a TRB type ID of Link TRB */  		val = prev->trbs[TRBS_PER_SEGMENT-1].link.control; @@ -189,6 +189,63 @@ fail:  	return 0;  } +#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32) + +struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, +						    int type, gfp_t flags) +{ +	struct xhci_container_ctx *ctx = kzalloc(sizeof(*ctx), flags); +	if (!ctx) +		return NULL; + +	BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT)); +	ctx->type = type; +	ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024; +	if (type == XHCI_CTX_TYPE_INPUT) +		ctx->size += CTX_SIZE(xhci->hcc_params); + +	ctx->bytes = dma_pool_alloc(xhci->device_pool, flags, &ctx->dma); +	memset(ctx->bytes, 0, ctx->size); +	return ctx; +} + +void xhci_free_container_ctx(struct xhci_hcd *xhci, +			     struct xhci_container_ctx *ctx) +{ +	dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma); +	kfree(ctx); +} + +struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, +					      struct xhci_container_ctx *ctx) +{ +	BUG_ON(ctx->type != XHCI_CTX_TYPE_INPUT); +	return (struct xhci_input_control_ctx *)ctx->bytes; +} + +struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, +					struct xhci_container_ctx *ctx) +{ +	if (ctx->type == XHCI_CTX_TYPE_DEVICE) +		return (struct xhci_slot_ctx *)ctx->bytes; + +	return (struct xhci_slot_ctx *) +		(ctx->bytes + CTX_SIZE(xhci->hcc_params)); +} + +struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, +				    struct xhci_container_ctx *ctx, +				    unsigned int ep_index) +{ +	/* increment ep index by offset of start of ep ctx array */ +	ep_index++; +	if (ctx->type == XHCI_CTX_TYPE_INPUT) +		ep_index++; + +	return (struct xhci_ep_ctx *) +		(ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params))); +} +  /* All the xhci_tds in the ring's TD list should be freed at this point */  void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)  { @@ -200,8 +257,7 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)  		return;  	dev = xhci->devs[slot_id]; -	xhci->dcbaa->dev_context_ptrs[2*slot_id] = 0; -	xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0; +	xhci->dcbaa->dev_context_ptrs[slot_id] = 0;  	if (!dev)  		return; @@ -210,11 +266,10 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)  			xhci_ring_free(xhci, dev->ep_rings[i]);  	if (dev->in_ctx) -		dma_pool_free(xhci->device_pool, -				dev->in_ctx, dev->in_ctx_dma); +		xhci_free_container_ctx(xhci, dev->in_ctx);  	if (dev->out_ctx) -		dma_pool_free(xhci->device_pool, -				dev->out_ctx, dev->out_ctx_dma); +		xhci_free_container_ctx(xhci, dev->out_ctx); +  	kfree(xhci->devs[slot_id]);  	xhci->devs[slot_id] = 0;  } @@ -222,7 +277,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)  int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,  		struct usb_device *udev, gfp_t flags)  { -	dma_addr_t	dma;  	struct xhci_virt_device *dev;  	/* Slot ID 0 is reserved */ @@ -236,23 +290,21 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,  		return 0;  	dev = xhci->devs[slot_id]; -	/* Allocate the (output) device context that will be used in the HC */ -	dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); +	/* Allocate the (output) device context that will be used in the HC. */ +	dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags);  	if (!dev->out_ctx)  		goto fail; -	dev->out_ctx_dma = dma; +  	xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, -			(unsigned long long)dma); -	memset(dev->out_ctx, 0, sizeof(*dev->out_ctx)); +			(unsigned long long)dev->out_ctx->dma);  	/* Allocate the (input) device context for address device command */ -	dev->in_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); +	dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags);  	if (!dev->in_ctx)  		goto fail; -	dev->in_ctx_dma = dma; +  	xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, -			(unsigned long long)dma); -	memset(dev->in_ctx, 0, sizeof(*dev->in_ctx)); +			(unsigned long long)dev->in_ctx->dma);  	/* Allocate endpoint 0 ring */  	dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags); @@ -261,17 +313,12 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,  	init_completion(&dev->cmd_completion); -	/* -	 * Point to output device context in dcbaa; skip the output control -	 * context, which is eight 32 bit fields (or 32 bytes long) -	 */ -	xhci->dcbaa->dev_context_ptrs[2*slot_id] = -		(u32) dev->out_ctx_dma + (32); +	/* Point to output device context in dcbaa. */ +	xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma;  	xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",  			slot_id, -			&xhci->dcbaa->dev_context_ptrs[2*slot_id], -			(unsigned long long)dev->out_ctx_dma); -	xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0; +			&xhci->dcbaa->dev_context_ptrs[slot_id], +			(unsigned long long) xhci->dcbaa->dev_context_ptrs[slot_id]);  	return 1;  fail: @@ -285,6 +332,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud  	struct xhci_virt_device *dev;  	struct xhci_ep_ctx	*ep0_ctx;  	struct usb_device	*top_dev; +	struct xhci_slot_ctx    *slot_ctx; +	struct xhci_input_control_ctx *ctrl_ctx;  	dev = xhci->devs[udev->slot_id];  	/* Slot ID 0 is reserved */ @@ -293,27 +342,29 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud  				udev->slot_id);  		return -EINVAL;  	} -	ep0_ctx = &dev->in_ctx->ep[0]; +	ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0); +	ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx); +	slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx);  	/* 2) New slot context and endpoint 0 context are valid*/ -	dev->in_ctx->add_flags = SLOT_FLAG | EP0_FLAG; +	ctrl_ctx->add_flags = SLOT_FLAG | EP0_FLAG;  	/* 3) Only the control endpoint is valid - one endpoint context */ -	dev->in_ctx->slot.dev_info |= LAST_CTX(1); +	slot_ctx->dev_info |= LAST_CTX(1);  	switch (udev->speed) {  	case USB_SPEED_SUPER: -		dev->in_ctx->slot.dev_info |= (u32) udev->route; -		dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_SS; +		slot_ctx->dev_info |= (u32) udev->route; +		slot_ctx->dev_info |= (u32) SLOT_SPEED_SS;  		break;  	case USB_SPEED_HIGH: -		dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_HS; +		slot_ctx->dev_info |= (u32) SLOT_SPEED_HS;  		break;  	case USB_SPEED_FULL: -		dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_FS; +		slot_ctx->dev_info |= (u32) SLOT_SPEED_FS;  		break;  	case USB_SPEED_LOW: -		dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_LS; +		slot_ctx->dev_info |= (u32) SLOT_SPEED_LS;  		break;  	case USB_SPEED_VARIABLE:  		xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); @@ -327,7 +378,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud  	for (top_dev = udev; top_dev->parent && top_dev->parent->parent;  			top_dev = top_dev->parent)  		/* Found device below root hub */; -	dev->in_ctx->slot.dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum); +	slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);  	xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum);  	/* Is this a LS/FS device under a HS hub? */ @@ -337,8 +388,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud  	 */  	if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) &&  			udev->tt) { -		dev->in_ctx->slot.tt_info = udev->tt->hub->slot_id; -		dev->in_ctx->slot.tt_info |= udev->ttport << 8; +		slot_ctx->tt_info = udev->tt->hub->slot_id; +		slot_ctx->tt_info |= udev->ttport << 8;  	}  	xhci_dbg(xhci, "udev->tt = %p\n", udev->tt);  	xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport); @@ -360,10 +411,9 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud  	ep0_ctx->ep_info2 |= MAX_BURST(0);  	ep0_ctx->ep_info2 |= ERROR_COUNT(3); -	ep0_ctx->deq[0] = +	ep0_ctx->deq =  		dev->ep_rings[0]->first_seg->dma; -	ep0_ctx->deq[0] |= dev->ep_rings[0]->cycle_state; -	ep0_ctx->deq[1] = 0; +	ep0_ctx->deq |= dev->ep_rings[0]->cycle_state;  	/* Steps 7 and 8 were done in xhci_alloc_virt_device() */ @@ -470,25 +520,26 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,  	unsigned int max_burst;  	ep_index = xhci_get_endpoint_index(&ep->desc); -	ep_ctx = &virt_dev->in_ctx->ep[ep_index]; +	ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);  	/* Set up the endpoint ring */  	virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags);  	if (!virt_dev->new_ep_rings[ep_index])  		return -ENOMEM;  	ep_ring = virt_dev->new_ep_rings[ep_index]; -	ep_ctx->deq[0] = ep_ring->first_seg->dma | ep_ring->cycle_state; -	ep_ctx->deq[1] = 0; +	ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state;  	ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep);  	/* FIXME dig Mult and streams info out of ep companion desc */ -	/* Allow 3 retries for everything but isoc */ +	/* Allow 3 retries for everything but isoc; +	 * error count = 0 means infinite retries. +	 */  	if (!usb_endpoint_xfer_isoc(&ep->desc))  		ep_ctx->ep_info2 = ERROR_COUNT(3);  	else -		ep_ctx->ep_info2 = ERROR_COUNT(0); +		ep_ctx->ep_info2 = ERROR_COUNT(1);  	ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep); @@ -498,7 +549,12 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,  		max_packet = ep->desc.wMaxPacketSize;  		ep_ctx->ep_info2 |= MAX_PACKET(max_packet);  		/* dig out max burst from ep companion desc */ -		max_packet = ep->ss_ep_comp->desc.bMaxBurst; +		if (!ep->ss_ep_comp) { +			xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n"); +			max_packet = 0; +		} else { +			max_packet = ep->ss_ep_comp->desc.bMaxBurst; +		}  		ep_ctx->ep_info2 |= MAX_BURST(max_packet);  		break;  	case USB_SPEED_HIGH: @@ -531,18 +587,114 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci,  	struct xhci_ep_ctx *ep_ctx;  	ep_index = xhci_get_endpoint_index(&ep->desc); -	ep_ctx = &virt_dev->in_ctx->ep[ep_index]; +	ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);  	ep_ctx->ep_info = 0;  	ep_ctx->ep_info2 = 0; -	ep_ctx->deq[0] = 0; -	ep_ctx->deq[1] = 0; +	ep_ctx->deq = 0;  	ep_ctx->tx_info = 0;  	/* Don't free the endpoint ring until the set interface or configuration  	 * request succeeds.  	 */  } +/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */ +static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) +{ +	int i; +	struct device *dev = xhci_to_hcd(xhci)->self.controller; +	int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); + +	xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp); + +	if (!num_sp) +		return 0; + +	xhci->scratchpad = kzalloc(sizeof(*xhci->scratchpad), flags); +	if (!xhci->scratchpad) +		goto fail_sp; + +	xhci->scratchpad->sp_array = +		pci_alloc_consistent(to_pci_dev(dev), +				     num_sp * sizeof(u64), +				     &xhci->scratchpad->sp_dma); +	if (!xhci->scratchpad->sp_array) +		goto fail_sp2; + +	xhci->scratchpad->sp_buffers = kzalloc(sizeof(void *) * num_sp, flags); +	if (!xhci->scratchpad->sp_buffers) +		goto fail_sp3; + +	xhci->scratchpad->sp_dma_buffers = +		kzalloc(sizeof(dma_addr_t) * num_sp, flags); + +	if (!xhci->scratchpad->sp_dma_buffers) +		goto fail_sp4; + +	xhci->dcbaa->dev_context_ptrs[0] = xhci->scratchpad->sp_dma; +	for (i = 0; i < num_sp; i++) { +		dma_addr_t dma; +		void *buf = pci_alloc_consistent(to_pci_dev(dev), +						 xhci->page_size, &dma); +		if (!buf) +			goto fail_sp5; + +		xhci->scratchpad->sp_array[i] = dma; +		xhci->scratchpad->sp_buffers[i] = buf; +		xhci->scratchpad->sp_dma_buffers[i] = dma; +	} + +	return 0; + + fail_sp5: +	for (i = i - 1; i >= 0; i--) { +		pci_free_consistent(to_pci_dev(dev), xhci->page_size, +				    xhci->scratchpad->sp_buffers[i], +				    xhci->scratchpad->sp_dma_buffers[i]); +	} +	kfree(xhci->scratchpad->sp_dma_buffers); + + fail_sp4: +	kfree(xhci->scratchpad->sp_buffers); + + fail_sp3: +	pci_free_consistent(to_pci_dev(dev), num_sp * sizeof(u64), +			    xhci->scratchpad->sp_array, +			    xhci->scratchpad->sp_dma); + + fail_sp2: +	kfree(xhci->scratchpad); +	xhci->scratchpad = NULL; + + fail_sp: +	return -ENOMEM; +} + +static void scratchpad_free(struct xhci_hcd *xhci) +{ +	int num_sp; +	int i; +	struct pci_dev	*pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + +	if (!xhci->scratchpad) +		return; + +	num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); + +	for (i = 0; i < num_sp; i++) { +		pci_free_consistent(pdev, xhci->page_size, +				    xhci->scratchpad->sp_buffers[i], +				    xhci->scratchpad->sp_dma_buffers[i]); +	} +	kfree(xhci->scratchpad->sp_dma_buffers); +	kfree(xhci->scratchpad->sp_buffers); +	pci_free_consistent(pdev, num_sp * sizeof(u64), +			    xhci->scratchpad->sp_array, +			    xhci->scratchpad->sp_dma); +	kfree(xhci->scratchpad); +	xhci->scratchpad = NULL; +} +  void xhci_mem_cleanup(struct xhci_hcd *xhci)  {  	struct pci_dev	*pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); @@ -551,10 +703,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)  	/* Free the Event Ring Segment Table and the actual Event Ring */  	xhci_writel(xhci, 0, &xhci->ir_set->erst_size); -	xhci_writel(xhci, 0, &xhci->ir_set->erst_base[0]); -	xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]); -	xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[0]); -	xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]); +	xhci_write_64(xhci, 0, &xhci->ir_set->erst_base); +	xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);  	size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);  	if (xhci->erst.entries)  		pci_free_consistent(pdev, size, @@ -566,8 +716,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)  	xhci->event_ring = NULL;  	xhci_dbg(xhci, "Freed event ring\n"); -	xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[0]); -	xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[1]); +	xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring);  	if (xhci->cmd_ring)  		xhci_ring_free(xhci, xhci->cmd_ring);  	xhci->cmd_ring = NULL; @@ -586,8 +735,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)  	xhci->device_pool = NULL;  	xhci_dbg(xhci, "Freed device context pool\n"); -	xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[0]); -	xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[1]); +	xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);  	if (xhci->dcbaa)  		pci_free_consistent(pdev, sizeof(*xhci->dcbaa),  				xhci->dcbaa, xhci->dcbaa->dma); @@ -595,6 +743,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)  	xhci->page_size = 0;  	xhci->page_shift = 0; +	scratchpad_free(xhci);  }  int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) @@ -602,6 +751,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	dma_addr_t	dma;  	struct device	*dev = xhci_to_hcd(xhci)->self.controller;  	unsigned int	val, val2; +	u64		val_64;  	struct xhci_segment	*seg;  	u32 page_size;  	int i; @@ -647,8 +797,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	xhci->dcbaa->dma = dma;  	xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n",  			(unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); -	xhci_writel(xhci, dma, &xhci->op_regs->dcbaa_ptr[0]); -	xhci_writel(xhci, (u32) 0, &xhci->op_regs->dcbaa_ptr[1]); +	xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr);  	/*  	 * Initialize the ring segment pool.  The ring must be a contiguous @@ -658,11 +807,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	 */  	xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,  			SEGMENT_SIZE, 64, xhci->page_size); +  	/* See Table 46 and Note on Figure 55 */ -	/* FIXME support 64-byte contexts */  	xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, -			sizeof(struct xhci_device_control), -			64, xhci->page_size); +			2112, 64, xhci->page_size);  	if (!xhci->segment_pool || !xhci->device_pool)  		goto fail; @@ -675,14 +823,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  			(unsigned long long)xhci->cmd_ring->first_seg->dma);  	/* Set the address in the Command Ring Control register */ -	val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]); -	val = (val & ~CMD_RING_ADDR_MASK) | -		(xhci->cmd_ring->first_seg->dma & CMD_RING_ADDR_MASK) | +	val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); +	val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | +		(xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |  		xhci->cmd_ring->cycle_state; -	xhci_dbg(xhci, "// Setting command ring address low bits to 0x%x\n", val); -	xhci_writel(xhci, val, &xhci->op_regs->cmd_ring[0]); -	xhci_dbg(xhci, "// Setting command ring address high bits to 0x0\n"); -	xhci_writel(xhci, (u32) 0, &xhci->op_regs->cmd_ring[1]); +	xhci_dbg(xhci, "// Setting command ring address to 0x%x\n", val); +	xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);  	xhci_dbg_cmd_ptrs(xhci);  	val = xhci_readl(xhci, &xhci->cap_regs->db_off); @@ -722,8 +868,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	/* set ring base address and size for each segment table entry */  	for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) {  		struct xhci_erst_entry *entry = &xhci->erst.entries[val]; -		entry->seg_addr[0] = seg->dma; -		entry->seg_addr[1] = 0; +		entry->seg_addr = seg->dma;  		entry->seg_size = TRBS_PER_SEGMENT;  		entry->rsvd = 0;  		seg = seg->next; @@ -741,11 +886,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	/* set the segment table base address */  	xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n",  			(unsigned long long)xhci->erst.erst_dma_addr); -	val = xhci_readl(xhci, &xhci->ir_set->erst_base[0]); -	val &= ERST_PTR_MASK; -	val |= (xhci->erst.erst_dma_addr & ~ERST_PTR_MASK); -	xhci_writel(xhci, val, &xhci->ir_set->erst_base[0]); -	xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]); +	val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base); +	val_64 &= ERST_PTR_MASK; +	val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK); +	xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);  	/* Set the event ring dequeue address */  	xhci_set_hc_event_deq(xhci); @@ -761,7 +905,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	for (i = 0; i < MAX_HC_SLOTS; ++i)  		xhci->devs[i] = 0; +	if (scratchpad_alloc(xhci, flags)) +		goto fail; +  	return 0; +  fail:  	xhci_warn(xhci, "Couldn't initialize memory\n");  	xhci_mem_cleanup(xhci); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 1462709e26c..592fe7e623f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -117,6 +117,7 @@ static const struct hc_driver xhci_pci_hc_driver = {  	.free_dev =		xhci_free_dev,  	.add_endpoint =		xhci_add_endpoint,  	.drop_endpoint =	xhci_drop_endpoint, +	.endpoint_reset =	xhci_endpoint_reset,  	.check_bandwidth =	xhci_check_bandwidth,  	.reset_bandwidth =	xhci_reset_bandwidth,  	.address_device =	xhci_address_device, diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 02d81985c45..aa88a067148 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -135,6 +135,7 @@ static void next_trb(struct xhci_hcd *xhci,  static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)  {  	union xhci_trb *next = ++(ring->dequeue); +	unsigned long long addr;  	ring->deq_updates++;  	/* Update the dequeue pointer further if that was a link TRB or we're at @@ -152,6 +153,13 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer  		ring->dequeue = ring->deq_seg->trbs;  		next = ring->dequeue;  	} +	addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue); +	if (ring == xhci->event_ring) +		xhci_dbg(xhci, "Event ring deq = 0x%llx (DMA)\n", addr); +	else if (ring == xhci->cmd_ring) +		xhci_dbg(xhci, "Command ring deq = 0x%llx (DMA)\n", addr); +	else +		xhci_dbg(xhci, "Ring deq = 0x%llx (DMA)\n", addr);  }  /* @@ -171,6 +179,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer  {  	u32 chain;  	union xhci_trb *next; +	unsigned long long addr;  	chain = ring->enqueue->generic.field[3] & TRB_CHAIN;  	next = ++(ring->enqueue); @@ -204,6 +213,13 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer  		ring->enqueue = ring->enq_seg->trbs;  		next = ring->enqueue;  	} +	addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue); +	if (ring == xhci->event_ring) +		xhci_dbg(xhci, "Event ring enq = 0x%llx (DMA)\n", addr); +	else if (ring == xhci->cmd_ring) +		xhci_dbg(xhci, "Command ring enq = 0x%llx (DMA)\n", addr); +	else +		xhci_dbg(xhci, "Ring enq = 0x%llx (DMA)\n", addr);  }  /* @@ -237,7 +253,7 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,  void xhci_set_hc_event_deq(struct xhci_hcd *xhci)  { -	u32 temp; +	u64 temp;  	dma_addr_t deq;  	deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, @@ -246,13 +262,15 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci)  		xhci_warn(xhci, "WARN something wrong with SW event ring "  				"dequeue ptr.\n");  	/* Update HC event ring dequeue pointer */ -	temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); +	temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);  	temp &= ERST_PTR_MASK; -	if (!in_interrupt()) -		xhci_dbg(xhci, "// Write event ring dequeue pointer\n"); -	xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]); -	xhci_writel(xhci, (deq & ~ERST_PTR_MASK) | temp, -			&xhci->ir_set->erst_dequeue[0]); +	/* Don't clear the EHB bit (which is RW1C) because +	 * there might be more events to service. +	 */ +	temp &= ~ERST_EHB; +	xhci_dbg(xhci, "// Write event ring dequeue pointer, preserving EHB bit\n"); +	xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, +			&xhci->ir_set->erst_dequeue);  }  /* Ring the host controller doorbell after placing a command on the ring */ @@ -279,7 +297,8 @@ static void ring_ep_doorbell(struct xhci_hcd *xhci,  	/* Don't ring the doorbell for this endpoint if there are pending  	 * cancellations because the we don't want to interrupt processing.  	 */ -	if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING)) { +	if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING) +			&& !(ep_ring->state & EP_HALTED)) {  		field = xhci_readl(xhci, db_addr) & DB_MASK;  		xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr);  		/* Flush PCI posted writes - FIXME Matthew Wilcox says this @@ -316,12 +335,6 @@ static struct xhci_segment *find_trb_seg(  	return cur_seg;  } -struct dequeue_state { -	struct xhci_segment *new_deq_seg; -	union xhci_trb *new_deq_ptr; -	int new_cycle_state; -}; -  /*   * Move the xHC's endpoint ring dequeue pointer past cur_td.   * Record the new state of the xHC's endpoint ring dequeue segment, @@ -336,24 +349,30 @@ struct dequeue_state {   *  - Finally we move the dequeue state one TRB further, toggling the cycle bit   *    if we've moved it past a link TRB with the toggle cycle bit set.   */ -static void find_new_dequeue_state(struct xhci_hcd *xhci, +void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,  		unsigned int slot_id, unsigned int ep_index, -		struct xhci_td *cur_td, struct dequeue_state *state) +		struct xhci_td *cur_td, struct xhci_dequeue_state *state)  {  	struct xhci_virt_device *dev = xhci->devs[slot_id];  	struct xhci_ring *ep_ring = dev->ep_rings[ep_index];  	struct xhci_generic_trb *trb; +	struct xhci_ep_ctx *ep_ctx; +	dma_addr_t addr;  	state->new_cycle_state = 0; +	xhci_dbg(xhci, "Finding segment containing stopped TRB.\n");  	state->new_deq_seg = find_trb_seg(cur_td->start_seg,  			ep_ring->stopped_trb,  			&state->new_cycle_state);  	if (!state->new_deq_seg)  		BUG();  	/* Dig out the cycle state saved by the xHC during the stop ep cmd */ -	state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq[0]; +	xhci_dbg(xhci, "Finding endpoint context\n"); +	ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); +	state->new_cycle_state = 0x1 & ep_ctx->deq;  	state->new_deq_ptr = cur_td->last_trb; +	xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n");  	state->new_deq_seg = find_trb_seg(state->new_deq_seg,  			state->new_deq_ptr,  			&state->new_cycle_state); @@ -367,6 +386,12 @@ static void find_new_dequeue_state(struct xhci_hcd *xhci,  	next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);  	/* Don't update the ring cycle state for the producer (us). */ +	xhci_dbg(xhci, "New dequeue segment = %p (virtual)\n", +			state->new_deq_seg); +	addr = xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr); +	xhci_dbg(xhci, "New dequeue pointer = 0x%llx (DMA)\n", +			(unsigned long long) addr); +	xhci_dbg(xhci, "Setting dequeue pointer in internal ring state.\n");  	ep_ring->dequeue = state->new_deq_ptr;  	ep_ring->deq_seg = state->new_deq_seg;  } @@ -416,6 +441,30 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,  		unsigned int ep_index, struct xhci_segment *deq_seg,  		union xhci_trb *deq_ptr, u32 cycle_state); +void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, +		struct xhci_ring *ep_ring, unsigned int slot_id, +		unsigned int ep_index, struct xhci_dequeue_state *deq_state) +{ +	xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " +			"new deq ptr = %p (0x%llx dma), new cycle = %u\n", +			deq_state->new_deq_seg, +			(unsigned long long)deq_state->new_deq_seg->dma, +			deq_state->new_deq_ptr, +			(unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr), +			deq_state->new_cycle_state); +	queue_set_tr_deq(xhci, slot_id, ep_index, +			deq_state->new_deq_seg, +			deq_state->new_deq_ptr, +			(u32) deq_state->new_cycle_state); +	/* Stop the TD queueing code from ringing the doorbell until +	 * this command completes.  The HC won't set the dequeue pointer +	 * if the ring is running, and ringing the doorbell starts the +	 * ring running. +	 */ +	ep_ring->state |= SET_DEQ_PENDING; +	xhci_ring_cmd_db(xhci); +} +  /*   * When we get a command completion for a Stop Endpoint Command, we need to   * unlink any cancelled TDs from the ring.  There are two ways to do that: @@ -436,7 +485,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,  	struct xhci_td *cur_td = 0;  	struct xhci_td *last_unlinked_td; -	struct dequeue_state deq_state; +	struct xhci_dequeue_state deq_state;  #ifdef CONFIG_USB_HCD_STAT  	ktime_t stop_time = ktime_get();  #endif @@ -464,7 +513,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,  		 * move the xHC endpoint ring dequeue pointer past this TD.  		 */  		if (cur_td == ep_ring->stopped_td) -			find_new_dequeue_state(xhci, slot_id, ep_index, cur_td, +			xhci_find_new_dequeue_state(xhci, slot_id, ep_index, cur_td,  					&deq_state);  		else  			td_to_noop(xhci, ep_ring, cur_td); @@ -480,24 +529,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,  	/* If necessary, queue a Set Transfer Ring Dequeue Pointer command */  	if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { -		xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " -				"new deq ptr = %p (0x%llx dma), new cycle = %u\n", -				deq_state.new_deq_seg, -				(unsigned long long)deq_state.new_deq_seg->dma, -				deq_state.new_deq_ptr, -				(unsigned long long)xhci_trb_virt_to_dma(deq_state.new_deq_seg, deq_state.new_deq_ptr), -				deq_state.new_cycle_state); -		queue_set_tr_deq(xhci, slot_id, ep_index, -				deq_state.new_deq_seg, -				deq_state.new_deq_ptr, -				(u32) deq_state.new_cycle_state); -		/* Stop the TD queueing code from ringing the doorbell until -		 * this command completes.  The HC won't set the dequeue pointer -		 * if the ring is running, and ringing the doorbell starts the -		 * ring running. -		 */ -		ep_ring->state |= SET_DEQ_PENDING; -		xhci_ring_cmd_db(xhci); +		xhci_queue_new_dequeue_state(xhci, ep_ring, +				slot_id, ep_index, &deq_state);  	} else {  		/* Otherwise just ring the doorbell to restart the ring */  		ring_ep_doorbell(xhci, slot_id, ep_index); @@ -551,11 +584,15 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,  	unsigned int ep_index;  	struct xhci_ring *ep_ring;  	struct xhci_virt_device *dev; +	struct xhci_ep_ctx *ep_ctx; +	struct xhci_slot_ctx *slot_ctx;  	slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);  	ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);  	dev = xhci->devs[slot_id];  	ep_ring = dev->ep_rings[ep_index]; +	ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); +	slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx);  	if (GET_COMP_CODE(event->status) != COMP_SUCCESS) {  		unsigned int ep_state; @@ -569,9 +606,9 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,  		case COMP_CTX_STATE:  			xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due "  					"to incorrect slot or ep state.\n"); -			ep_state = dev->out_ctx->ep[ep_index].ep_info; +			ep_state = ep_ctx->ep_info;  			ep_state &= EP_STATE_MASK; -			slot_state = dev->out_ctx->slot.dev_state; +			slot_state = slot_ctx->dev_state;  			slot_state = GET_SLOT_STATE(slot_state);  			xhci_dbg(xhci, "Slot state = %u, EP state = %u\n",  					slot_state, ep_state); @@ -593,16 +630,33 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,  		 * cancelling URBs, which might not be an error...  		 */  	} else { -		xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq[0] = 0x%x, " -				"deq[1] = 0x%x.\n", -				dev->out_ctx->ep[ep_index].deq[0], -				dev->out_ctx->ep[ep_index].deq[1]); +		xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n", +				ep_ctx->deq);  	}  	ep_ring->state &= ~SET_DEQ_PENDING;  	ring_ep_doorbell(xhci, slot_id, ep_index);  } +static void handle_reset_ep_completion(struct xhci_hcd *xhci, +		struct xhci_event_cmd *event, +		union xhci_trb *trb) +{ +	int slot_id; +	unsigned int ep_index; + +	slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); +	ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); +	/* This command will only fail if the endpoint wasn't halted, +	 * but we don't care. +	 */ +	xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n", +			(unsigned int) GET_COMP_CODE(event->status)); + +	/* Clear our internal halted state and restart the ring */ +	xhci->devs[slot_id]->ep_rings[ep_index]->state &= ~EP_HALTED; +	ring_ep_doorbell(xhci, slot_id, ep_index); +}  static void handle_cmd_completion(struct xhci_hcd *xhci,  		struct xhci_event_cmd *event) @@ -611,7 +665,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,  	u64 cmd_dma;  	dma_addr_t cmd_dequeue_dma; -	cmd_dma = (((u64) event->cmd_trb[1]) << 32) + event->cmd_trb[0]; +	cmd_dma = event->cmd_trb;  	cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,  			xhci->cmd_ring->dequeue);  	/* Is the command ring deq ptr out of sync with the deq seg ptr? */ @@ -653,6 +707,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,  	case TRB_TYPE(TRB_CMD_NOOP):  		++xhci->noops_handled;  		break; +	case TRB_TYPE(TRB_RESET_EP): +		handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue); +		break;  	default:  		/* Skip over unknown commands on the event ring */  		xhci->error_bitmask |= 1 << 6; @@ -756,7 +813,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,  	union xhci_trb *event_trb;  	struct urb *urb = 0;  	int status = -EINPROGRESS; +	struct xhci_ep_ctx *ep_ctx; +	xhci_dbg(xhci, "In %s\n", __func__);  	xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)];  	if (!xdev) {  		xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n"); @@ -765,17 +824,17 @@ static int handle_tx_event(struct xhci_hcd *xhci,  	/* Endpoint ID is 1 based, our index is zero based */  	ep_index = TRB_TO_EP_ID(event->flags) - 1; +	xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index);  	ep_ring = xdev->ep_rings[ep_index]; -	if (!ep_ring || (xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) { +	ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); +	if (!ep_ring || (ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) {  		xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n");  		return -ENODEV;  	} -	event_dma = event->buffer[0]; -	if (event->buffer[1] != 0) -		xhci_warn(xhci, "WARN ignoring upper 32-bits of 64-bit TRB dma address\n"); - +	event_dma = event->buffer;  	/* This TRB should be in the TD at the head of this ring's TD list */ +	xhci_dbg(xhci, "%s - checking for list empty\n", __func__);  	if (list_empty(&ep_ring->td_list)) {  		xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n",  				TRB_TO_SLOT_ID(event->flags), ep_index); @@ -785,11 +844,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,  		urb = NULL;  		goto cleanup;  	} +	xhci_dbg(xhci, "%s - getting list entry\n", __func__);  	td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);  	/* Is this a TRB in the currently executing TD? */ +	xhci_dbg(xhci, "%s - looking for TD\n", __func__);  	event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,  			td->last_trb, event_dma); +	xhci_dbg(xhci, "%s - found event_seg = %p\n", __func__, event_seg);  	if (!event_seg) {  		/* HC is busted, give up! */  		xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not part of current TD\n"); @@ -798,10 +860,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,  	event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / sizeof(*event_trb)];  	xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",  			(unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10); -	xhci_dbg(xhci, "Offset 0x00 (buffer[0]) = 0x%x\n", -			(unsigned int) event->buffer[0]); -	xhci_dbg(xhci, "Offset 0x04 (buffer[0]) = 0x%x\n", -			(unsigned int) event->buffer[1]); +	xhci_dbg(xhci, "Offset 0x00 (buffer lo) = 0x%x\n", +			lower_32_bits(event->buffer)); +	xhci_dbg(xhci, "Offset 0x04 (buffer hi) = 0x%x\n", +			upper_32_bits(event->buffer));  	xhci_dbg(xhci, "Offset 0x08 (transfer length) = 0x%x\n",  			(unsigned int) event->transfer_len);  	xhci_dbg(xhci, "Offset 0x0C (flags) = 0x%x\n", @@ -823,6 +885,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,  		break;  	case COMP_STALL:  		xhci_warn(xhci, "WARN: Stalled endpoint\n"); +		ep_ring->state |= EP_HALTED;  		status = -EPIPE;  		break;  	case COMP_TRB_ERR: @@ -833,6 +896,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,  		xhci_warn(xhci, "WARN: transfer error on endpoint\n");  		status = -EPROTO;  		break; +	case COMP_BABBLE: +		xhci_warn(xhci, "WARN: babble error on endpoint\n"); +		status = -EOVERFLOW; +		break;  	case COMP_DB_ERR:  		xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n");  		status = -ENOSR; @@ -874,15 +941,26 @@ static int handle_tx_event(struct xhci_hcd *xhci,  		if (event_trb != ep_ring->dequeue) {  			/* The event was for the status stage */  			if (event_trb == td->last_trb) { -				td->urb->actual_length = -					td->urb->transfer_buffer_length; +				if (td->urb->actual_length != 0) { +					/* Don't overwrite a previously set error code */ +					if (status == -EINPROGRESS || status == 0) +						/* Did we already see a short data stage? */ +						status = -EREMOTEIO; +				} else { +					td->urb->actual_length = +						td->urb->transfer_buffer_length; +				}  			} else {  			/* Maybe the event was for the data stage? */ -				if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) +				if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) {  					/* We didn't stop on a link TRB in the middle */  					td->urb->actual_length =  						td->urb->transfer_buffer_length -  						TRB_LEN(event->transfer_len); +					xhci_dbg(xhci, "Waiting for status stage event\n"); +					urb = NULL; +					goto cleanup; +				}  			}  		}  	} else { @@ -929,16 +1007,20 @@ static int handle_tx_event(struct xhci_hcd *xhci,  							TRB_LEN(event->transfer_len));  					td->urb->actual_length = 0;  				} -				if (td->urb->transfer_flags & URB_SHORT_NOT_OK) -					status = -EREMOTEIO; -				else -					status = 0; +				/* Don't overwrite a previously set error code */ +				if (status == -EINPROGRESS) { +					if (td->urb->transfer_flags & URB_SHORT_NOT_OK) +						status = -EREMOTEIO; +					else +						status = 0; +				}  			} else {  				td->urb->actual_length = td->urb->transfer_buffer_length;  				/* Ignore a short packet completion if the  				 * untransferred length was zero.  				 */ -				status = 0; +				if (status == -EREMOTEIO) +					status = 0;  			}  		} else {  			/* Slow path - walk the list, starting from the dequeue @@ -965,19 +1047,30 @@ static int handle_tx_event(struct xhci_hcd *xhci,  					TRB_LEN(event->transfer_len);  		}  	} -	/* The Endpoint Stop Command completion will take care of -	 * any stopped TDs.  A stopped TD may be restarted, so don't update the -	 * ring dequeue pointer or take this TD off any lists yet. -	 */  	if (GET_COMP_CODE(event->transfer_len) == COMP_STOP_INVAL ||  			GET_COMP_CODE(event->transfer_len) == COMP_STOP) { +		/* The Endpoint Stop Command completion will take care of any +		 * stopped TDs.  A stopped TD may be restarted, so don't update +		 * the ring dequeue pointer or take this TD off any lists yet. +		 */  		ep_ring->stopped_td = td;  		ep_ring->stopped_trb = event_trb;  	} else { -		/* Update ring dequeue pointer */ -		while (ep_ring->dequeue != td->last_trb) +		if (GET_COMP_CODE(event->transfer_len) == COMP_STALL) { +			/* The transfer is completed from the driver's +			 * perspective, but we need to issue a set dequeue +			 * command for this stalled endpoint to move the dequeue +			 * pointer past the TD.  We can't do that here because +			 * the halt condition must be cleared first. +			 */ +			ep_ring->stopped_td = td; +			ep_ring->stopped_trb = event_trb; +		} else { +			/* Update ring dequeue pointer */ +			while (ep_ring->dequeue != td->last_trb) +				inc_deq(xhci, ep_ring, false);  			inc_deq(xhci, ep_ring, false); -		inc_deq(xhci, ep_ring, false); +		}  		/* Clean up the endpoint's TD list */  		urb = td->urb; @@ -987,7 +1080,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,  			list_del(&td->cancelled_td_list);  			ep_ring->cancels_pending--;  		} -		kfree(td); +		/* Leave the TD around for the reset endpoint function to use */ +		if (GET_COMP_CODE(event->transfer_len) != COMP_STALL) { +			kfree(td); +		}  		urb->hcpriv = NULL;  	}  cleanup: @@ -997,6 +1093,8 @@ cleanup:  	/* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */  	if (urb) {  		usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb); +		xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n", +				urb, td->urb->actual_length, status);  		spin_unlock(&xhci->lock);  		usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status);  		spin_lock(&xhci->lock); @@ -1014,6 +1112,7 @@ void xhci_handle_event(struct xhci_hcd *xhci)  	int update_ptrs = 1;  	int ret; +	xhci_dbg(xhci, "In %s\n", __func__);  	if (!xhci->event_ring || !xhci->event_ring->dequeue) {  		xhci->error_bitmask |= 1 << 1;  		return; @@ -1026,18 +1125,25 @@ void xhci_handle_event(struct xhci_hcd *xhci)  		xhci->error_bitmask |= 1 << 2;  		return;  	} +	xhci_dbg(xhci, "%s - OS owns TRB\n", __func__);  	/* FIXME: Handle more event types. */  	switch ((event->event_cmd.flags & TRB_TYPE_BITMASK)) {  	case TRB_TYPE(TRB_COMPLETION): +		xhci_dbg(xhci, "%s - calling handle_cmd_completion\n", __func__);  		handle_cmd_completion(xhci, &event->event_cmd); +		xhci_dbg(xhci, "%s - returned from handle_cmd_completion\n", __func__);  		break;  	case TRB_TYPE(TRB_PORT_STATUS): +		xhci_dbg(xhci, "%s - calling handle_port_status\n", __func__);  		handle_port_status(xhci, event); +		xhci_dbg(xhci, "%s - returned from handle_port_status\n", __func__);  		update_ptrs = 0;  		break;  	case TRB_TYPE(TRB_TRANSFER): +		xhci_dbg(xhci, "%s - calling handle_tx_event\n", __func__);  		ret = handle_tx_event(xhci, &event->trans_event); +		xhci_dbg(xhci, "%s - returned from handle_tx_event\n", __func__);  		if (ret < 0)  			xhci->error_bitmask |= 1 << 9;  		else @@ -1093,13 +1199,13 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,  		 */  		xhci_warn(xhci, "WARN urb submitted to disabled ep\n");  		return -ENOENT; -	case EP_STATE_HALTED:  	case EP_STATE_ERROR: -		xhci_warn(xhci, "WARN waiting for halt or error on ep " -				"to be cleared\n"); +		xhci_warn(xhci, "WARN waiting for error on ep to be cleared\n");  		/* FIXME event handling code for error needs to clear it */  		/* XXX not sure if this should be -ENOENT or not */  		return -EINVAL; +	case EP_STATE_HALTED: +		xhci_dbg(xhci, "WARN halted endpoint, queueing URB anyway.\n");  	case EP_STATE_STOPPED:  	case EP_STATE_RUNNING:  		break; @@ -1128,9 +1234,9 @@ static int prepare_transfer(struct xhci_hcd *xhci,  		gfp_t mem_flags)  {  	int ret; - +	struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);  	ret = prepare_ring(xhci, xdev->ep_rings[ep_index], -			xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK, +			ep_ctx->ep_info & EP_STATE_MASK,  			num_trbs, mem_flags);  	if (ret)  		return ret; @@ -1285,6 +1391,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  	/* Queue the first TRB, even if it's zero-length */  	do {  		u32 field = 0; +		u32 length_field = 0;  		/* Don't change the cycle bit of the first TRB until later */  		if (first_trb) @@ -1314,10 +1421,13 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  					(unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),  					(unsigned int) addr + trb_buff_len);  		} +		length_field = TRB_LEN(trb_buff_len) | +			TD_REMAINDER(urb->transfer_buffer_length - running_total) | +			TRB_INTR_TARGET(0);  		queue_trb(xhci, ep_ring, false, -				(u32) addr, -				(u32) ((u64) addr >> 32), -				TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0), +				lower_32_bits(addr), +				upper_32_bits(addr), +				length_field,  				/* We always want to know if the TRB was short,  				 * or we won't get an event when it completes.  				 * (Unless we use event data TRBs, which are a @@ -1365,7 +1475,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  	struct xhci_generic_trb *start_trb;  	bool first_trb;  	int start_cycle; -	u32 field; +	u32 field, length_field;  	int running_total, trb_buff_len, ret;  	u64 addr; @@ -1443,10 +1553,13 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  			td->last_trb = ep_ring->enqueue;  			field |= TRB_IOC;  		} +		length_field = TRB_LEN(trb_buff_len) | +			TD_REMAINDER(urb->transfer_buffer_length - running_total) | +			TRB_INTR_TARGET(0);  		queue_trb(xhci, ep_ring, false, -				(u32) addr, -				(u32) ((u64) addr >> 32), -				TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0), +				lower_32_bits(addr), +				upper_32_bits(addr), +				length_field,  				/* We always want to know if the TRB was short,  				 * or we won't get an event when it completes.  				 * (Unless we use event data TRBs, which are a @@ -1478,7 +1591,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  	struct usb_ctrlrequest *setup;  	struct xhci_generic_trb *start_trb;  	int start_cycle; -	u32 field; +	u32 field, length_field;  	struct xhci_td *td;  	ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; @@ -1528,13 +1641,16 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  	/* If there's data, queue data TRBs */  	field = 0; +	length_field = TRB_LEN(urb->transfer_buffer_length) | +		TD_REMAINDER(urb->transfer_buffer_length) | +		TRB_INTR_TARGET(0);  	if (urb->transfer_buffer_length > 0) {  		if (setup->bRequestType & USB_DIR_IN)  			field |= TRB_DIR_IN;  		queue_trb(xhci, ep_ring, false,  				lower_32_bits(urb->transfer_dma),  				upper_32_bits(urb->transfer_dma), -				TRB_LEN(urb->transfer_buffer_length) | TRB_INTR_TARGET(0), +				length_field,  				/* Event on short tx */  				field | TRB_ISP | TRB_TYPE(TRB_DATA) | ep_ring->cycle_state);  	} @@ -1603,7 +1719,8 @@ int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id)  int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,  		u32 slot_id)  { -	return queue_command(xhci, in_ctx_ptr, 0, 0, +	return queue_command(xhci, lower_32_bits(in_ctx_ptr), +			upper_32_bits(in_ctx_ptr), 0,  			TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id));  } @@ -1611,7 +1728,8 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,  int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,  		u32 slot_id)  { -	return queue_command(xhci, in_ctx_ptr, 0, 0, +	return queue_command(xhci, lower_32_bits(in_ctx_ptr), +			upper_32_bits(in_ctx_ptr), 0,  			TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id));  } @@ -1639,10 +1757,23 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,  	u32 type = TRB_TYPE(TRB_SET_DEQ);  	addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr); -	if (addr == 0) +	if (addr == 0) {  		xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n");  		xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n",  				deq_seg, deq_ptr); -	return queue_command(xhci, (u32) addr | cycle_state, 0, 0, +		return 0; +	} +	return queue_command(xhci, lower_32_bits(addr) | cycle_state, +			upper_32_bits(addr), 0,  			trb_slot_id | trb_ep_index | type);  } + +int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, +		unsigned int ep_index) +{ +	u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); +	u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); +	u32 type = TRB_TYPE(TRB_RESET_EP); + +	return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type); +} diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8936eeb5588..d31d32206ba 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -25,6 +25,7 @@  #include <linux/usb.h>  #include <linux/timer.h> +#include <linux/kernel.h>  #include "../core/hcd.h"  /* Code sharing between pci-quirks and xhci hcd */ @@ -42,14 +43,6 @@   * xHCI register interface.   * This corresponds to the eXtensible Host Controller Interface (xHCI)   * Revision 0.95 specification - * - * Registers should always be accessed with double word or quad word accesses. - * - * Some xHCI implementations may support 64-bit address pointers.  Registers - * with 64-bit address pointers should be written to with dword accesses by - * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. - * xHCI implementations that do not support 64-bit address pointers will ignore - * the high dword, and write order is irrelevant.   */  /** @@ -96,6 +89,7 @@ struct xhci_cap_regs {  #define HCS_ERST_MAX(p)		(((p) >> 4) & 0xf)  /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */  /* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ +#define HCS_MAX_SCRATCHPAD(p)   (((p) >> 27) & 0x1f)  /* HCSPARAMS3 - hcs_params3 - bitmasks */  /* bits 0:7, Max U1 to U0 latency for the roothub ports */ @@ -166,10 +160,10 @@ struct xhci_op_regs {  	u32	reserved1;  	u32	reserved2;  	u32	dev_notification; -	u32	cmd_ring[2]; +	u64	cmd_ring;  	/* rsvd: offset 0x20-2F */  	u32	reserved3[4]; -	u32	dcbaa_ptr[2]; +	u64	dcbaa_ptr;  	u32	config_reg;  	/* rsvd: offset 0x3C-3FF */  	u32	reserved4[241]; @@ -254,7 +248,7 @@ struct xhci_op_regs {  #define CMD_RING_RUNNING	(1 << 3)  /* bits 4:5 reserved and should be preserved */  /* Command Ring pointer - bit mask for the lower 32 bits. */ -#define CMD_RING_ADDR_MASK	(0xffffffc0) +#define CMD_RING_RSVD_BITS	(0x3f)  /* CONFIG - Configure Register - config_reg bitmasks */  /* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */ @@ -382,8 +376,8 @@ struct xhci_intr_reg {  	u32	irq_control;  	u32	erst_size;  	u32	rsvd; -	u32	erst_base[2]; -	u32	erst_dequeue[2]; +	u64	erst_base; +	u64	erst_dequeue;  };  /* irq_pending bitmasks */ @@ -453,6 +447,27 @@ struct xhci_doorbell_array {  /** + * struct xhci_container_ctx + * @type: Type of context.  Used to calculated offsets to contained contexts. + * @size: Size of the context data + * @bytes: The raw context data given to HW + * @dma: dma address of the bytes + * + * Represents either a Device or Input context.  Holds a pointer to the raw + * memory used for the context (bytes) and dma address of it (dma). + */ +struct xhci_container_ctx { +	unsigned type; +#define XHCI_CTX_TYPE_DEVICE  0x1 +#define XHCI_CTX_TYPE_INPUT   0x2 + +	int size; + +	u8 *bytes; +	dma_addr_t dma; +}; + +/**   * struct xhci_slot_ctx   * @dev_info:	Route string, device speed, hub info, and last valid endpoint   * @dev_info2:	Max exit latency for device number, root hub port number @@ -538,7 +553,7 @@ struct xhci_slot_ctx {  struct xhci_ep_ctx {  	u32	ep_info;  	u32	ep_info2; -	u32	deq[2]; +	u64	deq;  	u32	tx_info;  	/* offset 0x14 - 0x1f reserved for HC internal use */  	u32	reserved[3]; @@ -589,18 +604,16 @@ struct xhci_ep_ctx {  /** - * struct xhci_device_control - * Input/Output context; see section 6.2.5. + * struct xhci_input_control_context + * Input control context; see section 6.2.5.   *   * @drop_context:	set the bit of the endpoint context you want to disable   * @add_context:	set the bit of the endpoint context you want to enable   */ -struct xhci_device_control { +struct xhci_input_control_ctx {  	u32	drop_flags;  	u32	add_flags; -	u32	rsvd[6]; -	struct xhci_slot_ctx	slot; -	struct xhci_ep_ctx	ep[31]; +	u32	rsvd2[6];  };  /* drop context bitmasks */ @@ -608,7 +621,6 @@ struct xhci_device_control {  /* add context bitmasks */  #define	ADD_EP(x)	(0x1 << x) -  struct xhci_virt_device {  	/*  	 * Commands to the hardware are passed an "input context" that @@ -618,11 +630,10 @@ struct xhci_virt_device {  	 * track of input and output contexts separately because  	 * these commands might fail and we don't trust the hardware.  	 */ -	struct xhci_device_control	*out_ctx; -	dma_addr_t			out_ctx_dma; +	struct xhci_container_ctx       *out_ctx;  	/* Used for addressing devices and configuration changes */ -	struct xhci_device_control	*in_ctx; -	dma_addr_t			in_ctx_dma; +	struct xhci_container_ctx       *in_ctx; +  	/* FIXME when stream support is added */  	struct xhci_ring		*ep_rings[31];  	/* Temporary storage in case the configure endpoint command fails and we @@ -641,7 +652,7 @@ struct xhci_virt_device {   */  struct xhci_device_context_array {  	/* 64-bit device addresses; we only write 32-bit addresses */ -	u32			dev_context_ptrs[2*MAX_HC_SLOTS]; +	u64			dev_context_ptrs[MAX_HC_SLOTS];  	/* private xHCD pointers */  	dma_addr_t	dma;  }; @@ -654,7 +665,7 @@ struct xhci_device_context_array {  struct xhci_stream_ctx {  	/* 64-bit stream ring address, cycle state, and stream type */ -	u32	stream_ring[2]; +	u64	stream_ring;  	/* offset 0x14 - 0x1f reserved for HC internal use */  	u32	reserved[2];  }; @@ -662,7 +673,7 @@ struct xhci_stream_ctx {  struct xhci_transfer_event {  	/* 64-bit buffer address, or immediate data */ -	u32	buffer[2]; +	u64	buffer;  	u32	transfer_len;  	/* This field is interpreted differently based on the type of TRB */  	u32	flags; @@ -744,7 +755,7 @@ struct xhci_transfer_event {  struct xhci_link_trb {  	/* 64-bit segment pointer*/ -	u32 segment_ptr[2]; +	u64 segment_ptr;  	u32 intr_target;  	u32 control;  }; @@ -755,7 +766,7 @@ struct xhci_link_trb {  /* Command completion event TRB */  struct xhci_event_cmd {  	/* Pointer to command TRB, or the value passed by the event data trb */ -	u32 cmd_trb[2]; +	u64 cmd_trb;  	u32 status;  	u32 flags;  }; @@ -848,8 +859,8 @@ union xhci_trb {  #define TRB_CONFIG_EP		12  /* Evaluate Context Command */  #define TRB_EVAL_CONTEXT	13 -/* Reset Transfer Ring Command */ -#define TRB_RESET_RING		14 +/* Reset Endpoint Command */ +#define TRB_RESET_EP		14  /* Stop Transfer Ring Command */  #define TRB_STOP_RING		15  /* Set Transfer Ring Dequeue Pointer Command */ @@ -929,6 +940,7 @@ struct xhci_ring {  	unsigned int		cancels_pending;  	unsigned int		state;  #define SET_DEQ_PENDING		(1 << 0) +#define EP_HALTED		(1 << 1)  	/* The TRB that was last reported in a stopped endpoint ring */  	union xhci_trb		*stopped_trb;  	struct xhci_td		*stopped_td; @@ -940,9 +952,15 @@ struct xhci_ring {  	u32			cycle_state;  }; +struct xhci_dequeue_state { +	struct xhci_segment *new_deq_seg; +	union xhci_trb *new_deq_ptr; +	int new_cycle_state; +}; +  struct xhci_erst_entry {  	/* 64-bit event ring segment address */ -	u32	seg_addr[2]; +	u64	seg_addr;  	u32	seg_size;  	/* Set to zero */  	u32	rsvd; @@ -957,6 +975,13 @@ struct xhci_erst {  	unsigned int		erst_size;  }; +struct xhci_scratchpad { +	u64 *sp_array; +	dma_addr_t sp_dma; +	void **sp_buffers; +	dma_addr_t *sp_dma_buffers; +}; +  /*   * Each segment table entry is 4*32bits long.  1K seems like an ok size:   * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, @@ -1011,6 +1036,9 @@ struct xhci_hcd {  	struct xhci_ring	*cmd_ring;  	struct xhci_ring	*event_ring;  	struct xhci_erst	erst; +	/* Scratchpad */ +	struct xhci_scratchpad  *scratchpad; +  	/* slot enabling and address device helpers */  	struct completion	addr_dev;  	int slot_id; @@ -1071,13 +1099,43 @@ static inline unsigned int xhci_readl(const struct xhci_hcd *xhci,  static inline void xhci_writel(struct xhci_hcd *xhci,  		const unsigned int val, __u32 __iomem *regs)  { -	if (!in_interrupt()) -		xhci_dbg(xhci, -			 "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n", -			 regs, val); +	xhci_dbg(xhci, +			"`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n", +			regs, val);  	writel(val, regs);  } +/* + * Registers should always be accessed with double word or quad word accesses. + * + * Some xHCI implementations may support 64-bit address pointers.  Registers + * with 64-bit address pointers should be written to with dword accesses by + * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. + * xHCI implementations that do not support 64-bit address pointers will ignore + * the high dword, and write order is irrelevant. + */ +static inline u64 xhci_read_64(const struct xhci_hcd *xhci, +		__u64 __iomem *regs) +{ +	__u32 __iomem *ptr = (__u32 __iomem *) regs; +	u64 val_lo = readl(ptr); +	u64 val_hi = readl(ptr + 1); +	return val_lo + (val_hi << 32); +} +static inline void xhci_write_64(struct xhci_hcd *xhci, +		const u64 val, __u64 __iomem *regs) +{ +	__u32 __iomem *ptr = (__u32 __iomem *) regs; +	u32 val_lo = lower_32_bits(val); +	u32 val_hi = upper_32_bits(val); + +	xhci_dbg(xhci, +			"`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n", +			regs, (long unsigned int) val); +	writel(val_lo, ptr); +	writel(val_hi, ptr + 1); +} +  /* xHCI debugging */  void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num);  void xhci_print_registers(struct xhci_hcd *xhci); @@ -1090,7 +1148,7 @@ void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring);  void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);  void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci);  void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); -void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep); +void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep);  /* xHCI memory managment */  void xhci_mem_cleanup(struct xhci_hcd *xhci); @@ -1128,6 +1186,7 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);  int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);  int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);  int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); +void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);  int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);  void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); @@ -1148,10 +1207,23 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,  		int slot_id, unsigned int ep_index);  int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,  		u32 slot_id); +int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, +		unsigned int ep_index); +void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, +		unsigned int slot_id, unsigned int ep_index, +		struct xhci_td *cur_td, struct xhci_dequeue_state *state); +void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, +		struct xhci_ring *ep_ring, unsigned int slot_id, +		unsigned int ep_index, struct xhci_dequeue_state *deq_state);  /* xHCI roothub code */  int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,  		char *buf, u16 wLength);  int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); +/* xHCI contexts */ +struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); +struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); +struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index); +  #endif /* __LINUX_XHCI_HCD_H */ diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a68d91a11be..abe3aa67ed0 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -220,7 +220,7 @@ config USB_IOWARRIOR  config USB_TEST  	tristate "USB testing driver" -	depends on USB && USB_DEVICEFS +	depends on USB  	help  	  This driver is for testing host controller software.  It is used  	  with specialized device firmware for regression and stress testing, diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 3c5fe5cee05..90e1a8dedfa 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -18,6 +18,7 @@  #include <linux/init.h>  #include <linux/slab.h>  #include <linux/sched.h> +#include <linux/smp_lock.h>  #include <linux/poll.h>  #include <linux/usb/iowarrior.h> diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index deb95bb49fd..d645f3899fe 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -32,6 +32,7 @@  #include <linux/kernel.h>  #include <linux/signal.h>  #include <linux/sched.h> +#include <linux/smp_lock.h>  #include <linux/errno.h>  #include <linux/random.h>  #include <linux/poll.h> diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index e0ff9ccd866..29092b8e59c 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -16,6 +16,7 @@  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/slab.h> +#include <linux/smp_lock.h>  #include <linux/errno.h>  #include <linux/mutex.h>  #include <asm/uaccess.h> diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index f8d9045d668..0f7a30b7d2d 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1261,7 +1261,7 @@ static int mon_alloc_buff(struct mon_pgmap *map, int npages)  			return -ENOMEM;  		}  		map[n].ptr = (unsigned char *) vaddr; -		map[n].pg = virt_to_page(vaddr); +		map[n].pg = virt_to_page((void *) vaddr);  	}  	return 0;  } diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 70073b157f0..803adcb5ac1 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -12,6 +12,7 @@ config USB_MUSB_HDRC  	depends on !SUPERH  	select NOP_USB_XCEIV if ARCH_DAVINCI  	select TWL4030_USB if MACH_OMAP_3430SDP +	select NOP_USB_XCEIV if MACH_OMAP3EVM  	select USB_OTG_UTILS  	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'  	help diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h index 8a39de3e6e4..59bf949e589 100644 --- a/drivers/usb/musb/cppi_dma.h +++ b/drivers/usb/musb/cppi_dma.h @@ -5,7 +5,6 @@  #include <linux/slab.h>  #include <linux/list.h> -#include <linux/smp_lock.h>  #include <linux/errno.h>  #include <linux/dmapool.h> diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 180d7daa409..e16ff605c45 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -35,13 +35,14 @@  #include <mach/hardware.h>  #include <mach/memory.h>  #include <mach/gpio.h> +#include <mach/cputype.h>  #include <asm/mach-types.h>  #include "musb_core.h"  #ifdef CONFIG_MACH_DAVINCI_EVM -#define GPIO_nVBUS_DRV		87 +#define GPIO_nVBUS_DRV		144  #endif  #include "davinci.h" @@ -329,7 +330,6 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)  			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);  			WARNING("VBUS error workaround (delay coming)\n");  		} else if (is_host_enabled(musb) && drvvbus) { -			musb->is_active = 1;  			MUSB_HST_MODE(musb);  			musb->xceiv->default_a = 1;  			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; @@ -343,7 +343,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)  			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);  		} -		/* NOTE:  this must complete poweron within 100 msec */ +		/* NOTE:  this must complete poweron within 100 msec +		 * (OTG_TIME_A_WAIT_VRISE) but we don't check for that. +		 */  		davinci_source_power(musb, drvvbus, 0);  		DBG(2, "VBUS %s (%s)%s, devctl %02x\n",  				drvvbus ? "on" : "off", @@ -411,6 +413,21 @@ int __init musb_platform_init(struct musb *musb)  		__raw_writel(phy_ctrl, USB_PHY_CTRL);  	} +	/* On dm355, the default-A state machine needs DRVVBUS control. +	 * If we won't be a host, there's no need to turn it on. +	 */ +	if (cpu_is_davinci_dm355()) { +		u32	deepsleep = __raw_readl(DM355_DEEPSLEEP); + +		if (is_host_enabled(musb)) { +			deepsleep &= ~DRVVBUS_OVERRIDE; +		} else { +			deepsleep &= ~DRVVBUS_FORCE; +			deepsleep |= DRVVBUS_OVERRIDE; +		} +		__raw_writel(deepsleep, DM355_DEEPSLEEP); +	} +  	/* reset the controller */  	musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1); @@ -437,6 +454,15 @@ int musb_platform_exit(struct musb *musb)  	if (is_host_enabled(musb))  		del_timer_sync(&otg_workaround); +	/* force VBUS off */ +	if (cpu_is_davinci_dm355()) { +		u32	deepsleep = __raw_readl(DM355_DEEPSLEEP); + +		deepsleep &= ~DRVVBUS_FORCE; +		deepsleep |= DRVVBUS_OVERRIDE; +		__raw_writel(deepsleep, DM355_DEEPSLEEP); +	} +  	davinci_source_power(musb, 0 /*off*/, 1);  	/* delay, to avoid problems with module reload */ diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 554a414f65d..c7c1ca0494c 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1326,7 +1326,6 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)  	int		i;  	/* log core options (read using indexed model) */ -	musb_ep_select(mbase, 0);  	reg = musb_read_configdata(mbase);  	strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8"); @@ -1990,7 +1989,7 @@ bad_config:  	if (status < 0)  		goto fail2; -#ifdef CONFIG_USB_OTG +#ifdef CONFIG_USB_MUSB_OTG  	setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);  #endif diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index f3772ca3b2c..381d648a36b 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -38,7 +38,6 @@  #include <linux/slab.h>  #include <linux/list.h>  #include <linux/interrupt.h> -#include <linux/smp_lock.h>  #include <linux/errno.h>  #include <linux/timer.h>  #include <linux/clk.h> diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 40ed50ecedf..7a6778675ad 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -407,7 +407,7 @@ stall:  					csr |= MUSB_RXCSR_P_SENDSTALL  						| MUSB_RXCSR_FLUSHFIFO  						| MUSB_RXCSR_CLRDATATOG -						| MUSB_TXCSR_P_WZC_BITS; +						| MUSB_RXCSR_P_WZC_BITS;  					musb_writew(regs, MUSB_RXCSR,  							csr);  				} diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 94a2a350a41..cf94511485f 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -373,7 +373,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,  		musb_save_toggle(qh, is_in, urb);  		break;  	case USB_ENDPOINT_XFER_ISOC: -		if (urb->error_count) +		if (status == 0 && urb->error_count)  			status = -EXDEV;  		break;  	} @@ -2235,13 +2235,30 @@ static void musb_h_stop(struct usb_hcd *hcd)  static int musb_bus_suspend(struct usb_hcd *hcd)  {  	struct musb	*musb = hcd_to_musb(hcd); +	u8		devctl; -	if (musb->xceiv->state == OTG_STATE_A_SUSPEND) +	if (!is_host_active(musb))  		return 0; -	if (is_host_active(musb) && musb->is_active) { -		WARNING("trying to suspend as %s is_active=%i\n", -			otg_state_string(musb), musb->is_active); +	switch (musb->xceiv->state) { +	case OTG_STATE_A_SUSPEND: +		return 0; +	case OTG_STATE_A_WAIT_VRISE: +		/* ID could be grounded even if there's no device +		 * on the other end of the cable.  NOTE that the +		 * A_WAIT_VRISE timers are messy with MUSB... +		 */ +		devctl = musb_readb(musb->mregs, MUSB_DEVCTL); +		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) +			musb->xceiv->state = OTG_STATE_A_WAIT_BCON; +		break; +	default: +		break; +	} + +	if (musb->is_active) { +		WARNING("trying to suspend as %s while active\n", +				otg_state_string(musb));  		return -EBUSY;  	} else  		return 0; diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index de3b2f18db4..fbfd3fd9ce1 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -323,6 +323,7 @@ static inline void  musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)  static inline u8 musb_read_configdata(void __iomem *mbase)  { +	musb_writeb(mbase, MUSB_INDEX, 0);  	return musb_readb(mbase, 0x10 + MUSB_CONFIGDATA);  } diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 69feeec1628..aa884d072f0 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -59,18 +59,4 @@ config NOP_USB_XCEIV  	 built-in with usb ip or which are autonomous and doesn't require any  	 phy programming such as ISP1x04 etc. -config USB_LANGWELL_OTG -	tristate "Intel Langwell USB OTG dual-role support" -	depends on USB && MRST -	select USB_OTG -	select USB_OTG_UTILS -	help -	  Say Y here if you want to build Intel Langwell USB OTG -	  transciever driver in kernel. This driver implements role -	  switch between EHCI host driver and Langwell USB OTG -	  client driver. - -	  To compile this driver as a module, choose M here: the -	  module will be called langwell_otg. -  endif # USB || OTG diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 6d1abdd3c0a..20816785652 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_USB_OTG_UTILS)	+= otg.o  obj-$(CONFIG_USB_GPIO_VBUS)	+= gpio_vbus.o  obj-$(CONFIG_ISP1301_OMAP)	+= isp1301_omap.o  obj-$(CONFIG_TWL4030_USB)	+= twl4030-usb.o -obj-$(CONFIG_USB_LANGWELL_OTG)	+= langwell_otg.o  obj-$(CONFIG_NOP_USB_XCEIV)	+= nop-usb-xceiv.o  ccflags-$(CONFIG_USB_DEBUG)	+= -DDEBUG diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c deleted file mode 100644 index 6f628d0e9f3..00000000000 --- a/drivers/usb/otg/langwell_otg.c +++ /dev/null @@ -1,1915 +0,0 @@ -/* - * Intel Langwell USB OTG transceiver driver - * Copyright (C) 2008 - 2009, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -/* This driver helps to switch Langwell OTG controller function between host - * and peripheral. It works with EHCI driver and Langwell client controller - * driver together. - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/moduleparam.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb.h> -#include <linux/usb/otg.h> -#include <linux/notifier.h> -#include <asm/ipc_defs.h> -#include <linux/delay.h> -#include "../core/hcd.h" - -#include <linux/usb/langwell_otg.h> - -#define	DRIVER_DESC		"Intel Langwell USB OTG transceiver driver" -#define	DRIVER_VERSION		"3.0.0.32L.0002" - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Henry Yuan <hang.yuan@intel.com>, Hao Wu <hao.wu@intel.com>"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -static const char driver_name[] = "langwell_otg"; - -static int langwell_otg_probe(struct pci_dev *pdev, -			const struct pci_device_id *id); -static void langwell_otg_remove(struct pci_dev *pdev); -static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message); -static int langwell_otg_resume(struct pci_dev *pdev); - -static int langwell_otg_set_host(struct otg_transceiver *otg, -				struct usb_bus *host); -static int langwell_otg_set_peripheral(struct otg_transceiver *otg, -				struct usb_gadget *gadget); -static int langwell_otg_start_srp(struct otg_transceiver *otg); - -static const struct pci_device_id pci_ids[] = {{ -	.class =        ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), -	.class_mask =   ~0, -	.vendor =	0x8086, -	.device =	0x0811, -	.subvendor =	PCI_ANY_ID, -	.subdevice =	PCI_ANY_ID, -}, { /* end: all zeroes */ } -}; - -static struct pci_driver otg_pci_driver = { -	.name =		(char *) driver_name, -	.id_table =	pci_ids, - -	.probe =	langwell_otg_probe, -	.remove =	langwell_otg_remove, - -	.suspend =	langwell_otg_suspend, -	.resume =	langwell_otg_resume, -}; - -static const char *state_string(enum usb_otg_state state) -{ -	switch (state) { -	case OTG_STATE_A_IDLE: -		return "a_idle"; -	case OTG_STATE_A_WAIT_VRISE: -		return "a_wait_vrise"; -	case OTG_STATE_A_WAIT_BCON: -		return "a_wait_bcon"; -	case OTG_STATE_A_HOST: -		return "a_host"; -	case OTG_STATE_A_SUSPEND: -		return "a_suspend"; -	case OTG_STATE_A_PERIPHERAL: -		return "a_peripheral"; -	case OTG_STATE_A_WAIT_VFALL: -		return "a_wait_vfall"; -	case OTG_STATE_A_VBUS_ERR: -		return "a_vbus_err"; -	case OTG_STATE_B_IDLE: -		return "b_idle"; -	case OTG_STATE_B_SRP_INIT: -		return "b_srp_init"; -	case OTG_STATE_B_PERIPHERAL: -		return "b_peripheral"; -	case OTG_STATE_B_WAIT_ACON: -		return "b_wait_acon"; -	case OTG_STATE_B_HOST: -		return "b_host"; -	default: -		return "UNDEFINED"; -	} -} - -/* HSM timers */ -static inline struct langwell_otg_timer *otg_timer_initializer -(void (*function)(unsigned long), unsigned long expires, unsigned long data) -{ -	struct langwell_otg_timer *timer; -	timer = kmalloc(sizeof(struct langwell_otg_timer), GFP_KERNEL); -	timer->function = function; -	timer->expires = expires; -	timer->data = data; -	return timer; -} - -static struct langwell_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, -	*a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_res_tmr, -	*b_bus_suspend_tmr; - -static struct list_head active_timers; - -static struct langwell_otg *the_transceiver; - -/* host/client notify transceiver when event affects HNP state */ -void langwell_update_transceiver() -{ -	otg_dbg("transceiver driver is notified\n"); -	queue_work(the_transceiver->qwork, &the_transceiver->work); -} -EXPORT_SYMBOL(langwell_update_transceiver); - -static int langwell_otg_set_host(struct otg_transceiver *otg, -					struct usb_bus *host) -{ -	otg->host = host; - -	return 0; -} - -static int langwell_otg_set_peripheral(struct otg_transceiver *otg, -					struct usb_gadget *gadget) -{ -	otg->gadget = gadget; - -	return 0; -} - -static int langwell_otg_set_power(struct otg_transceiver *otg, -				unsigned mA) -{ -	return 0; -} - -/* A-device drives vbus, controlled through PMIC CHRGCNTL register*/ -static void langwell_otg_drv_vbus(int on) -{ -	struct ipc_pmic_reg_data	pmic_data = {0}; -	struct ipc_pmic_reg_data	battery_data; - -	/* Check if battery is attached or not */ -	battery_data.pmic_reg_data[0].register_address = 0xd2; -	battery_data.ioc = 0; -	battery_data.num_entries = 1; -	if (ipc_pmic_register_read(&battery_data)) { -		otg_dbg("Failed to read PMIC register 0xd2.\n"); -		return; -	} - -	if ((battery_data.pmic_reg_data[0].value & 0x20) == 0) { -		otg_dbg("no battery attached\n"); -		return; -	} - -	/* Workaround for battery attachment issue */ -	if (battery_data.pmic_reg_data[0].value == 0x34) { -		otg_dbg("battery \n"); -		return; -	} - -	otg_dbg("battery attached\n"); - -	pmic_data.ioc = 0; -	pmic_data.pmic_reg_data[0].register_address = 0xD4; -	pmic_data.num_entries = 1; -	if (on) -		pmic_data.pmic_reg_data[0].value = 0x20; -	else -		pmic_data.pmic_reg_data[0].value = 0xc0; - -	if (ipc_pmic_register_write(&pmic_data, TRUE)) -		otg_dbg("Failed to write PMIC.\n"); - -} - -/* charge vbus or discharge vbus through a resistor to ground */ -static void langwell_otg_chrg_vbus(int on) -{ - -	u32	val; - -	val = readl(the_transceiver->regs + CI_OTGSC); - -	if (on) -		writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VC, -				the_transceiver->regs + CI_OTGSC); -	else -		writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VD, -				the_transceiver->regs + CI_OTGSC); - -} - -/* Start SRP */ -static int langwell_otg_start_srp(struct otg_transceiver *otg) -{ -	u32	val; - -	otg_dbg("Start SRP ->\n"); - -	val = readl(the_transceiver->regs + CI_OTGSC); - -	writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, -		the_transceiver->regs + CI_OTGSC); - -	/* Check if the data plus is finished or not */ -	msleep(8); -	val = readl(the_transceiver->regs + CI_OTGSC); -	if (val & (OTGSC_HADP | OTGSC_DP)) -		otg_dbg("DataLine SRP Error\n"); - -	/* FIXME: VBus SRP */ - -	return 0; -} - - -/* stop SOF via bus_suspend */ -static void langwell_otg_loc_sof(int on) -{ -	struct usb_hcd	*hcd; -	int		err; - -	otg_dbg("loc_sof -> %d\n", on); - -	hcd = bus_to_hcd(the_transceiver->otg.host); -	if (on) -		err = hcd->driver->bus_resume(hcd); -	else -		err = hcd->driver->bus_suspend(hcd); - -	if (err) -		otg_dbg("Failed to resume/suspend bus - %d\n", err); -} - -static void langwell_otg_phy_low_power(int on) -{ -	u32	val; - -	otg_dbg("phy low power mode-> %d\n", on); - -	val = readl(the_transceiver->regs + CI_HOSTPC1); -	if (on) -		writel(val | HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1); -	else -		writel(val & ~HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1); -} - -/* Enable/Disable OTG interrupt */ -static void langwell_otg_intr(int on) -{ -	u32 val; - -	otg_dbg("interrupt -> %d\n", on); - -	val = readl(the_transceiver->regs + CI_OTGSC); -	if (on) { -		val = val | (OTGSC_INTEN_MASK | OTGSC_IDPU); -		writel(val, the_transceiver->regs + CI_OTGSC); -	} else { -		val = val & ~(OTGSC_INTEN_MASK | OTGSC_IDPU); -		writel(val, the_transceiver->regs + CI_OTGSC); -	} -} - -/* set HAAR: Hardware Assist Auto-Reset */ -static void langwell_otg_HAAR(int on) -{ -	u32	val; - -	otg_dbg("HAAR -> %d\n", on); - -	val = readl(the_transceiver->regs + CI_OTGSC); -	if (on) -		writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HAAR, -				the_transceiver->regs + CI_OTGSC); -	else -		writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HAAR, -				the_transceiver->regs + CI_OTGSC); -} - -/* set HABA: Hardware Assist B-Disconnect to A-Connect */ -static void langwell_otg_HABA(int on) -{ -	u32	val; - -	otg_dbg("HABA -> %d\n", on); - -	val = readl(the_transceiver->regs + CI_OTGSC); -	if (on) -		writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA, -				the_transceiver->regs + CI_OTGSC); -	else -		writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA, -				the_transceiver->regs + CI_OTGSC); -} - -static int langwell_otg_check_se0_srp(int on) -{ -	u32 val; - -	int delay_time = TB_SE0_SRP * 10; /* step is 100us */ - -	otg_dbg("check_se0_srp -> \n"); - -	do { -		udelay(100); -		if (!delay_time--) -			break; -		val = readl(the_transceiver->regs + CI_PORTSC1); -		val &= PORTSC_LS; -	} while (!val); - -	otg_dbg("check_se0_srp <- \n"); -	return val; -} - -/* The timeout callback function to set time out bit */ -static void set_tmout(unsigned long indicator) -{ -	*(int *)indicator = 1; -} - -void langwell_otg_nsf_msg(unsigned long indicator) -{ -	switch (indicator) { -	case 2: -	case 4: -	case 6: -	case 7: -		printk(KERN_ERR "OTG:NSF-%lu - deivce not responding\n", -				indicator); -		break; -	case 3: -		printk(KERN_ERR "OTG:NSF-%lu - deivce not supported\n", -				indicator); -		break; -	default: -		printk(KERN_ERR "Do not have this kind of NSF\n"); -		break; -	} -} - -/* Initialize timers */ -static void langwell_otg_init_timers(struct otg_hsm *hsm) -{ -	/* HSM used timers */ -	a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE, -				(unsigned long)&hsm->a_wait_vrise_tmout); -	a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON, -				(unsigned long)&hsm->a_wait_bcon_tmout); -	a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS, -				(unsigned long)&hsm->a_aidl_bdis_tmout); -	b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST, -				(unsigned long)&hsm->b_ase0_brst_tmout); -	b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP, -				(unsigned long)&hsm->b_se0_srp); -	b_srp_res_tmr = otg_timer_initializer(&set_tmout, TB_SRP_RES, -				(unsigned long)&hsm->b_srp_res_tmout); -	b_bus_suspend_tmr = otg_timer_initializer(&set_tmout, TB_BUS_SUSPEND, -				(unsigned long)&hsm->b_bus_suspend_tmout); -} - -/* Free timers */ -static void langwell_otg_free_timers(void) -{ -	kfree(a_wait_vrise_tmr); -	kfree(a_wait_bcon_tmr); -	kfree(a_aidl_bdis_tmr); -	kfree(b_ase0_brst_tmr); -	kfree(b_se0_srp_tmr); -	kfree(b_srp_res_tmr); -	kfree(b_bus_suspend_tmr); -} - -/* Add timer to timer list */ -static void langwell_otg_add_timer(void *gtimer) -{ -	struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer; -	struct langwell_otg_timer *tmp_timer; -	u32	val32; - -	/* Check if the timer is already in the active list, -	 * if so update timer count -	 */ -	list_for_each_entry(tmp_timer, &active_timers, list) -		if (tmp_timer == timer) { -			timer->count = timer->expires; -			return; -		} -	timer->count = timer->expires; - -	if (list_empty(&active_timers)) { -		val32 = readl(the_transceiver->regs + CI_OTGSC); -		writel(val32 | OTGSC_1MSE, the_transceiver->regs + CI_OTGSC); -	} - -	list_add_tail(&timer->list, &active_timers); -} - -/* Remove timer from the timer list; clear timeout status */ -static void langwell_otg_del_timer(void *gtimer) -{ -	struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer; -	struct langwell_otg_timer *tmp_timer, *del_tmp; -	u32 val32; - -	list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) -		if (tmp_timer == timer) -			list_del(&timer->list); - -	if (list_empty(&active_timers)) { -		val32 = readl(the_transceiver->regs + CI_OTGSC); -		writel(val32 & ~OTGSC_1MSE, the_transceiver->regs + CI_OTGSC); -	} -} - -/* Reduce timer count by 1, and find timeout conditions.*/ -static int langwell_otg_tick_timer(u32 *int_sts) -{ -	struct langwell_otg_timer *tmp_timer, *del_tmp; -	int expired = 0; - -	list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) { -		tmp_timer->count--; -		/* check if timer expires */ -		if (!tmp_timer->count) { -			list_del(&tmp_timer->list); -			tmp_timer->function(tmp_timer->data); -			expired = 1; -		} -	} - -	if (list_empty(&active_timers)) { -		otg_dbg("tick timer: disable 1ms int\n"); -		*int_sts = *int_sts & ~OTGSC_1MSE; -	} -	return expired; -} - -static void reset_otg(void) -{ -	u32	val; -	int	delay_time = 1000; - -	otg_dbg("reseting OTG controller ...\n"); -	val = readl(the_transceiver->regs + CI_USBCMD); -	writel(val | USBCMD_RST, the_transceiver->regs + CI_USBCMD); -	do { -		udelay(100); -		if (!delay_time--) -			otg_dbg("reset timeout\n"); -		val = readl(the_transceiver->regs + CI_USBCMD); -		val &= USBCMD_RST; -	} while (val != 0); -	otg_dbg("reset done.\n"); -} - -static void set_host_mode(void) -{ -	u32 	val; - -	reset_otg(); -	val = readl(the_transceiver->regs + CI_USBMODE); -	val = (val & (~USBMODE_CM)) | USBMODE_HOST; -	writel(val, the_transceiver->regs + CI_USBMODE); -} - -static void set_client_mode(void) -{ -	u32 	val; - -	reset_otg(); -	val = readl(the_transceiver->regs + CI_USBMODE); -	val = (val & (~USBMODE_CM)) | USBMODE_DEVICE; -	writel(val, the_transceiver->regs + CI_USBMODE); -} - -static void init_hsm(void) -{ -	struct langwell_otg	*langwell = the_transceiver; -	u32			val32; - -	/* read OTGSC after reset */ -	val32 = readl(langwell->regs + CI_OTGSC); -	otg_dbg("%s: OTGSC init value = 0x%x\n", __func__, val32); - -	/* set init state */ -	if (val32 & OTGSC_ID) { -		langwell->hsm.id = 1; -		langwell->otg.default_a = 0; -		set_client_mode(); -		langwell->otg.state = OTG_STATE_B_IDLE; -		langwell_otg_drv_vbus(0); -	} else { -		langwell->hsm.id = 0; -		langwell->otg.default_a = 1; -		set_host_mode(); -		langwell->otg.state = OTG_STATE_A_IDLE; -	} - -	/* set session indicator */ -	if (val32 & OTGSC_BSE) -		langwell->hsm.b_sess_end = 1; -	if (val32 & OTGSC_BSV) -		langwell->hsm.b_sess_vld = 1; -	if (val32 & OTGSC_ASV) -		langwell->hsm.a_sess_vld = 1; -	if (val32 & OTGSC_AVV) -		langwell->hsm.a_vbus_vld = 1; - -	/* defautly power the bus */ -	langwell->hsm.a_bus_req = 1; -	langwell->hsm.a_bus_drop = 0; -	/* defautly don't request bus as B device */ -	langwell->hsm.b_bus_req = 0; -	/* no system error */ -	langwell->hsm.a_clr_err = 0; -} - -static irqreturn_t otg_dummy_irq(int irq, void *_dev) -{ -	void __iomem	*reg_base = _dev; -	u32	val; -	u32	int_mask = 0; - -	val = readl(reg_base + CI_USBMODE); -	if ((val & USBMODE_CM) != USBMODE_DEVICE) -		return IRQ_NONE; - -	val = readl(reg_base + CI_USBSTS); -	int_mask = val & INTR_DUMMY_MASK; - -	if (int_mask == 0) -		return IRQ_NONE; - -	/* clear hsm.b_conn here since host driver can't detect it -	*  otg_dummy_irq called means B-disconnect happened. -	*/ -	if (the_transceiver->hsm.b_conn) { -		the_transceiver->hsm.b_conn = 0; -		if (spin_trylock(&the_transceiver->wq_lock)) { -			queue_work(the_transceiver->qwork, -				&the_transceiver->work); -			spin_unlock(&the_transceiver->wq_lock); -		} -	} -	/* Clear interrupts */ -	writel(int_mask, reg_base + CI_USBSTS); -	return IRQ_HANDLED; -} - -static irqreturn_t otg_irq(int irq, void *_dev) -{ -	struct	langwell_otg *langwell = _dev; -	u32	int_sts, int_en; -	u32	int_mask = 0; -	int	flag = 0; - -	int_sts = readl(langwell->regs + CI_OTGSC); -	int_en = (int_sts & OTGSC_INTEN_MASK) >> 8; -	int_mask = int_sts & int_en; -	if (int_mask == 0) -		return IRQ_NONE; - -	if (int_mask & OTGSC_IDIS) { -		otg_dbg("%s: id change int\n", __func__); -		langwell->hsm.id = (int_sts & OTGSC_ID) ? 1 : 0; -		flag = 1; -	} -	if (int_mask & OTGSC_DPIS) { -		otg_dbg("%s: data pulse int\n", __func__); -		langwell->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0; -		flag = 1; -	} -	if (int_mask & OTGSC_BSEIS) { -		otg_dbg("%s: b session end int\n", __func__); -		langwell->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0; -		flag = 1; -	} -	if (int_mask & OTGSC_BSVIS) { -		otg_dbg("%s: b session valid int\n", __func__); -		langwell->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0; -		flag = 1; -	} -	if (int_mask & OTGSC_ASVIS) { -		otg_dbg("%s: a session valid int\n", __func__); -		langwell->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0; -		flag = 1; -	} -	if (int_mask & OTGSC_AVVIS) { -		otg_dbg("%s: a vbus valid int\n", __func__); -		langwell->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0; -		flag = 1; -	} - -	if (int_mask & OTGSC_1MSS) { -		/* need to schedule otg_work if any timer is expired */ -		if (langwell_otg_tick_timer(&int_sts)) -			flag = 1; -	} - -	writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask, -			langwell->regs + CI_OTGSC); -	if (flag) -		queue_work(langwell->qwork, &langwell->work); - -	return IRQ_HANDLED; -} - -static void langwell_otg_work(struct work_struct *work) -{ -	struct langwell_otg *langwell = container_of(work, -					struct langwell_otg, work); -	int	retval; - -	otg_dbg("%s: old state = %s\n", __func__, -			state_string(langwell->otg.state)); - -	switch (langwell->otg.state) { -	case OTG_STATE_UNDEFINED: -	case OTG_STATE_B_IDLE: -		if (!langwell->hsm.id) { -			langwell_otg_del_timer(b_srp_res_tmr); -			langwell->otg.default_a = 1; -			langwell->hsm.a_srp_det = 0; - -			langwell_otg_chrg_vbus(0); -			langwell_otg_drv_vbus(0); - -			set_host_mode(); -			langwell->otg.state = OTG_STATE_A_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (langwell->hsm.b_srp_res_tmout) { -			langwell->hsm.b_srp_res_tmout = 0; -			langwell->hsm.b_bus_req = 0; -			langwell_otg_nsf_msg(6); -		} else if (langwell->hsm.b_sess_vld) { -			langwell_otg_del_timer(b_srp_res_tmr); -			langwell->hsm.b_sess_end = 0; -			langwell->hsm.a_bus_suspend = 0; - -			langwell_otg_chrg_vbus(0); -			if (langwell->client_ops) { -				langwell->client_ops->resume(langwell->pdev); -				langwell->otg.state = OTG_STATE_B_PERIPHERAL; -			} else -				otg_dbg("client driver not loaded.\n"); - -		} else if (langwell->hsm.b_bus_req && -				(langwell->hsm.b_sess_end)) { -			/* workaround for b_se0_srp detection */ -			retval = langwell_otg_check_se0_srp(0); -			if (retval) { -				langwell->hsm.b_bus_req = 0; -				otg_dbg("LS is not SE0, try again later\n"); -			} else { -				/* Start SRP */ -				langwell_otg_start_srp(&langwell->otg); -				langwell_otg_add_timer(b_srp_res_tmr); -			} -		} -		break; -	case OTG_STATE_B_SRP_INIT: -		if (!langwell->hsm.id) { -			langwell->otg.default_a = 1; -			langwell->hsm.a_srp_det = 0; - -			langwell_otg_drv_vbus(0); -			langwell_otg_chrg_vbus(0); - -			langwell->otg.state = OTG_STATE_A_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (langwell->hsm.b_sess_vld) { -			langwell_otg_chrg_vbus(0); -			if (langwell->client_ops) { -				langwell->client_ops->resume(langwell->pdev); -				langwell->otg.state = OTG_STATE_B_PERIPHERAL; -			} else -				otg_dbg("client driver not loaded.\n"); -		} -		break; -	case OTG_STATE_B_PERIPHERAL: -		if (!langwell->hsm.id) { -			langwell->otg.default_a = 1; -			langwell->hsm.a_srp_det = 0; - -			langwell_otg_drv_vbus(0); -			langwell_otg_chrg_vbus(0); -			set_host_mode(); - -			if (langwell->client_ops) { -				langwell->client_ops->suspend(langwell->pdev, -					PMSG_FREEZE); -			} else -				otg_dbg("client driver has been removed.\n"); - -			langwell->otg.state = OTG_STATE_A_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (!langwell->hsm.b_sess_vld) { -			langwell->hsm.b_hnp_enable = 0; - -			if (langwell->client_ops) { -				langwell->client_ops->suspend(langwell->pdev, -					PMSG_FREEZE); -			} else -				otg_dbg("client driver has been removed.\n"); - -			langwell->otg.state = OTG_STATE_B_IDLE; -		} else if (langwell->hsm.b_bus_req && langwell->hsm.b_hnp_enable -			&& langwell->hsm.a_bus_suspend) { - -			if (langwell->client_ops) { -				langwell->client_ops->suspend(langwell->pdev, -					PMSG_FREEZE); -			} else -				otg_dbg("client driver has been removed.\n"); - -			langwell_otg_HAAR(1); -			langwell->hsm.a_conn = 0; - -			if (langwell->host_ops) { -				langwell->host_ops->probe(langwell->pdev, -					langwell->host_ops->id_table); -				langwell->otg.state = OTG_STATE_B_WAIT_ACON; -			} else -				otg_dbg("host driver not loaded.\n"); - -			langwell->hsm.a_bus_resume = 0; -			langwell->hsm.b_ase0_brst_tmout = 0; -			langwell_otg_add_timer(b_ase0_brst_tmr); -		} -		break; - -	case OTG_STATE_B_WAIT_ACON: -		if (!langwell->hsm.id) { -			langwell_otg_del_timer(b_ase0_brst_tmr); -			langwell->otg.default_a = 1; -			langwell->hsm.a_srp_det = 0; - -			langwell_otg_drv_vbus(0); -			langwell_otg_chrg_vbus(0); -			set_host_mode(); - -			langwell_otg_HAAR(0); -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell->otg.state = OTG_STATE_A_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (!langwell->hsm.b_sess_vld) { -			langwell_otg_del_timer(b_ase0_brst_tmr); -			langwell->hsm.b_hnp_enable = 0; -			langwell->hsm.b_bus_req = 0; -			langwell_otg_chrg_vbus(0); -			langwell_otg_HAAR(0); - -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell->otg.state = OTG_STATE_B_IDLE; -		} else if (langwell->hsm.a_conn) { -			langwell_otg_del_timer(b_ase0_brst_tmr); -			langwell_otg_HAAR(0); -			langwell->otg.state = OTG_STATE_B_HOST; -			queue_work(langwell->qwork, &langwell->work); -		} else if (langwell->hsm.a_bus_resume || -				langwell->hsm.b_ase0_brst_tmout) { -			langwell_otg_del_timer(b_ase0_brst_tmr); -			langwell_otg_HAAR(0); -			langwell_otg_nsf_msg(7); - -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); - -			langwell->hsm.a_bus_suspend = 0; -			langwell->hsm.b_bus_req = 0; - -			if (langwell->client_ops) -				langwell->client_ops->resume(langwell->pdev); -			else -				otg_dbg("client driver not loaded.\n"); - -			langwell->otg.state = OTG_STATE_B_PERIPHERAL; -		} -		break; - -	case OTG_STATE_B_HOST: -		if (!langwell->hsm.id) { -			langwell->otg.default_a = 1; -			langwell->hsm.a_srp_det = 0; - -			langwell_otg_drv_vbus(0); -			langwell_otg_chrg_vbus(0); -			set_host_mode(); -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell->otg.state = OTG_STATE_A_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (!langwell->hsm.b_sess_vld) { -			langwell->hsm.b_hnp_enable = 0; -			langwell->hsm.b_bus_req = 0; -			langwell_otg_chrg_vbus(0); -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell->otg.state = OTG_STATE_B_IDLE; -		} else if ((!langwell->hsm.b_bus_req) || -				(!langwell->hsm.a_conn)) { -			langwell->hsm.b_bus_req = 0; -			langwell_otg_loc_sof(0); -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); - -			langwell->hsm.a_bus_suspend = 0; - -			if (langwell->client_ops) -				langwell->client_ops->resume(langwell->pdev); -			else -				otg_dbg("client driver not loaded.\n"); - -			langwell->otg.state = OTG_STATE_B_PERIPHERAL; -		} -		break; - -	case OTG_STATE_A_IDLE: -		langwell->otg.default_a = 1; -		if (langwell->hsm.id) { -			langwell->otg.default_a = 0; -			langwell->hsm.b_bus_req = 0; -			langwell_otg_drv_vbus(0); -			langwell_otg_chrg_vbus(0); - -			langwell->otg.state = OTG_STATE_B_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (langwell->hsm.a_sess_vld) { -			langwell_otg_drv_vbus(1); -			langwell->hsm.a_srp_det = 1; -			langwell->hsm.a_wait_vrise_tmout = 0; -			langwell_otg_add_timer(a_wait_vrise_tmr); -			langwell->otg.state = OTG_STATE_A_WAIT_VRISE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (!langwell->hsm.a_bus_drop && -			(langwell->hsm.a_srp_det || langwell->hsm.a_bus_req)) { -			langwell_otg_drv_vbus(1); -			langwell->hsm.a_wait_vrise_tmout = 0; -			langwell_otg_add_timer(a_wait_vrise_tmr); -			langwell->otg.state = OTG_STATE_A_WAIT_VRISE; -			queue_work(langwell->qwork, &langwell->work); -		} -		break; -	case OTG_STATE_A_WAIT_VRISE: -		if (langwell->hsm.id) { -			langwell_otg_del_timer(a_wait_vrise_tmr); -			langwell->hsm.b_bus_req = 0; -			langwell->otg.default_a = 0; -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_B_IDLE; -		} else if (langwell->hsm.a_vbus_vld) { -			langwell_otg_del_timer(a_wait_vrise_tmr); -			if (langwell->host_ops) -				langwell->host_ops->probe(langwell->pdev, -						langwell->host_ops->id_table); -			else -				otg_dbg("host driver not loaded.\n"); -			langwell->hsm.b_conn = 0; -			langwell->hsm.a_set_b_hnp_en = 0; -			langwell->hsm.a_wait_bcon_tmout = 0; -			langwell_otg_add_timer(a_wait_bcon_tmr); -			langwell->otg.state = OTG_STATE_A_WAIT_BCON; -		} else if (langwell->hsm.a_wait_vrise_tmout) { -			if (langwell->hsm.a_vbus_vld) { -				if (langwell->host_ops) -					langwell->host_ops->probe( -						langwell->pdev, -						langwell->host_ops->id_table); -				else -					otg_dbg("host driver not loaded.\n"); -				langwell->hsm.b_conn = 0; -				langwell->hsm.a_set_b_hnp_en = 0; -				langwell->hsm.a_wait_bcon_tmout = 0; -				langwell_otg_add_timer(a_wait_bcon_tmr); -				langwell->otg.state = OTG_STATE_A_WAIT_BCON; -			} else { -				langwell_otg_drv_vbus(0); -				langwell->otg.state = OTG_STATE_A_VBUS_ERR; -			} -		} -		break; -	case OTG_STATE_A_WAIT_BCON: -		if (langwell->hsm.id) { -			langwell_otg_del_timer(a_wait_bcon_tmr); - -			langwell->otg.default_a = 0; -			langwell->hsm.b_bus_req = 0; -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_B_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (!langwell->hsm.a_vbus_vld) { -			langwell_otg_del_timer(a_wait_bcon_tmr); - -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_A_VBUS_ERR; -		} else if (langwell->hsm.a_bus_drop || -				(langwell->hsm.a_wait_bcon_tmout && -				!langwell->hsm.a_bus_req)) { -			langwell_otg_del_timer(a_wait_bcon_tmr); - -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_A_WAIT_VFALL; -		} else if (langwell->hsm.b_conn) { -			langwell_otg_del_timer(a_wait_bcon_tmr); - -			langwell->hsm.a_suspend_req = 0; -			langwell->otg.state = OTG_STATE_A_HOST; -			if (!langwell->hsm.a_bus_req && -				langwell->hsm.a_set_b_hnp_en) { -				/* It is not safe enough to do a fast -				 * transistion from A_WAIT_BCON to -				 * A_SUSPEND */ -				msleep(10000); -				if (langwell->hsm.a_bus_req) -					break; - -				if (request_irq(langwell->pdev->irq, -					otg_dummy_irq, IRQF_SHARED, -					driver_name, langwell->regs) != 0) { -					otg_dbg("request interrupt %d fail\n", -					langwell->pdev->irq); -				} - -				langwell_otg_HABA(1); -				langwell->hsm.b_bus_resume = 0; -				langwell->hsm.a_aidl_bdis_tmout = 0; -				langwell_otg_add_timer(a_aidl_bdis_tmr); - -				langwell_otg_loc_sof(0); -				langwell->otg.state = OTG_STATE_A_SUSPEND; -			} else if (!langwell->hsm.a_bus_req && -				!langwell->hsm.a_set_b_hnp_en) { -				struct pci_dev *pdev = langwell->pdev; -				if (langwell->host_ops) -					langwell->host_ops->remove(pdev); -				else -					otg_dbg("host driver removed.\n"); -				langwell_otg_drv_vbus(0); -				langwell->otg.state = OTG_STATE_A_WAIT_VFALL; -			} -		} -		break; -	case OTG_STATE_A_HOST: -		if (langwell->hsm.id) { -			langwell->otg.default_a = 0; -			langwell->hsm.b_bus_req = 0; -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_B_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (langwell->hsm.a_bus_drop || -		(!langwell->hsm.a_set_b_hnp_en && !langwell->hsm.a_bus_req)) { -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_A_WAIT_VFALL; -		} else if (!langwell->hsm.a_vbus_vld) { -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_A_VBUS_ERR; -		} else if (langwell->hsm.a_set_b_hnp_en -				&& !langwell->hsm.a_bus_req) { -			/* Set HABA to enable hardware assistance to signal -			 *  A-connect after receiver B-disconnect. Hardware -			 *  will then set client mode and enable URE, SLE and -			 *  PCE after the assistance. otg_dummy_irq is used to -			 *  clean these ints when client driver is not resumed. -			 */ -			if (request_irq(langwell->pdev->irq, -				otg_dummy_irq, IRQF_SHARED, driver_name, -				langwell->regs) != 0) { -				otg_dbg("request interrupt %d failed\n", -						langwell->pdev->irq); -			} - -			/* set HABA */ -			langwell_otg_HABA(1); -			langwell->hsm.b_bus_resume = 0; -			langwell->hsm.a_aidl_bdis_tmout = 0; -			langwell_otg_add_timer(a_aidl_bdis_tmr); -			langwell_otg_loc_sof(0); -			langwell->otg.state = OTG_STATE_A_SUSPEND; -		} else if (!langwell->hsm.b_conn || !langwell->hsm.a_bus_req) { -			langwell->hsm.a_wait_bcon_tmout = 0; -			langwell->hsm.a_set_b_hnp_en = 0; -			langwell_otg_add_timer(a_wait_bcon_tmr); -			langwell->otg.state = OTG_STATE_A_WAIT_BCON; -		} -		break; -	case OTG_STATE_A_SUSPEND: -		if (langwell->hsm.id) { -			langwell_otg_del_timer(a_aidl_bdis_tmr); -			langwell_otg_HABA(0); -			free_irq(langwell->pdev->irq, langwell->regs); -			langwell->otg.default_a = 0; -			langwell->hsm.b_bus_req = 0; -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_B_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (langwell->hsm.a_bus_req || -				langwell->hsm.b_bus_resume) { -			langwell_otg_del_timer(a_aidl_bdis_tmr); -			langwell_otg_HABA(0); -			free_irq(langwell->pdev->irq, langwell->regs); -			langwell->hsm.a_suspend_req = 0; -			langwell_otg_loc_sof(1); -			langwell->otg.state = OTG_STATE_A_HOST; -		} else if (langwell->hsm.a_aidl_bdis_tmout || -				langwell->hsm.a_bus_drop) { -			langwell_otg_del_timer(a_aidl_bdis_tmr); -			langwell_otg_HABA(0); -			free_irq(langwell->pdev->irq, langwell->regs); -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_A_WAIT_VFALL; -		} else if (!langwell->hsm.b_conn && -				langwell->hsm.a_set_b_hnp_en) { -			langwell_otg_del_timer(a_aidl_bdis_tmr); -			langwell_otg_HABA(0); -			free_irq(langwell->pdev->irq, langwell->regs); - -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); - -			langwell->hsm.b_bus_suspend = 0; -			langwell->hsm.b_bus_suspend_vld = 0; -			langwell->hsm.b_bus_suspend_tmout = 0; - -			/* msleep(200); */ -			if (langwell->client_ops) -				langwell->client_ops->resume(langwell->pdev); -			else -				otg_dbg("client driver not loaded.\n"); - -			langwell_otg_add_timer(b_bus_suspend_tmr); -			langwell->otg.state = OTG_STATE_A_PERIPHERAL; -			break; -		} else if (!langwell->hsm.a_vbus_vld) { -			langwell_otg_del_timer(a_aidl_bdis_tmr); -			langwell_otg_HABA(0); -			free_irq(langwell->pdev->irq, langwell->regs); -			if (langwell->host_ops) -				langwell->host_ops->remove(langwell->pdev); -			else -				otg_dbg("host driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_A_VBUS_ERR; -		} -		break; -	case OTG_STATE_A_PERIPHERAL: -		if (langwell->hsm.id) { -			langwell_otg_del_timer(b_bus_suspend_tmr); -			langwell->otg.default_a = 0; -			langwell->hsm.b_bus_req = 0; -			if (langwell->client_ops) -				langwell->client_ops->suspend(langwell->pdev, -					PMSG_FREEZE); -			else -				otg_dbg("client driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_B_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (!langwell->hsm.a_vbus_vld) { -			langwell_otg_del_timer(b_bus_suspend_tmr); -			if (langwell->client_ops) -				langwell->client_ops->suspend(langwell->pdev, -					PMSG_FREEZE); -			else -				otg_dbg("client driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_A_VBUS_ERR; -		} else if (langwell->hsm.a_bus_drop) { -			langwell_otg_del_timer(b_bus_suspend_tmr); -			if (langwell->client_ops) -				langwell->client_ops->suspend(langwell->pdev, -					PMSG_FREEZE); -			else -				otg_dbg("client driver has been removed.\n"); -			langwell_otg_drv_vbus(0); -			langwell->otg.state = OTG_STATE_A_WAIT_VFALL; -		} else if (langwell->hsm.b_bus_suspend) { -			langwell_otg_del_timer(b_bus_suspend_tmr); -			if (langwell->client_ops) -				langwell->client_ops->suspend(langwell->pdev, -					PMSG_FREEZE); -			else -				otg_dbg("client driver has been removed.\n"); - -			if (langwell->host_ops) -				langwell->host_ops->probe(langwell->pdev, -						langwell->host_ops->id_table); -			else -				otg_dbg("host driver not loaded.\n"); -			langwell->hsm.a_set_b_hnp_en = 0; -			langwell->hsm.a_wait_bcon_tmout = 0; -			langwell_otg_add_timer(a_wait_bcon_tmr); -			langwell->otg.state = OTG_STATE_A_WAIT_BCON; -		} else if (langwell->hsm.b_bus_suspend_tmout) { -			u32	val; -			val = readl(langwell->regs + CI_PORTSC1); -			if (!(val & PORTSC_SUSP)) -				break; -			if (langwell->client_ops) -				langwell->client_ops->suspend(langwell->pdev, -						PMSG_FREEZE); -			else -				otg_dbg("client driver has been removed.\n"); -			if (langwell->host_ops) -				langwell->host_ops->probe(langwell->pdev, -						langwell->host_ops->id_table); -			else -				otg_dbg("host driver not loaded.\n"); -			langwell->hsm.a_set_b_hnp_en = 0; -			langwell->hsm.a_wait_bcon_tmout = 0; -			langwell_otg_add_timer(a_wait_bcon_tmr); -			langwell->otg.state = OTG_STATE_A_WAIT_BCON; -		} -		break; -	case OTG_STATE_A_VBUS_ERR: -		if (langwell->hsm.id) { -			langwell->otg.default_a = 0; -			langwell->hsm.a_clr_err = 0; -			langwell->hsm.a_srp_det = 0; -			langwell->otg.state = OTG_STATE_B_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (langwell->hsm.a_clr_err) { -			langwell->hsm.a_clr_err = 0; -			langwell->hsm.a_srp_det = 0; -			reset_otg(); -			init_hsm(); -			if (langwell->otg.state == OTG_STATE_A_IDLE) -				queue_work(langwell->qwork, &langwell->work); -		} -		break; -	case OTG_STATE_A_WAIT_VFALL: -		if (langwell->hsm.id) { -			langwell->otg.default_a = 0; -			langwell->otg.state = OTG_STATE_B_IDLE; -			queue_work(langwell->qwork, &langwell->work); -		} else if (langwell->hsm.a_bus_req) { -			langwell_otg_drv_vbus(1); -			langwell->hsm.a_wait_vrise_tmout = 0; -			langwell_otg_add_timer(a_wait_vrise_tmr); -			langwell->otg.state = OTG_STATE_A_WAIT_VRISE; -		} else if (!langwell->hsm.a_sess_vld) { -			langwell->hsm.a_srp_det = 0; -			langwell_otg_drv_vbus(0); -			set_host_mode(); -			langwell->otg.state = OTG_STATE_A_IDLE; -		} -		break; -	default: -		; -	} - -	otg_dbg("%s: new state = %s\n", __func__, -			state_string(langwell->otg.state)); -} - -	static ssize_t -show_registers(struct device *_dev, struct device_attribute *attr, char *buf) -{ -	struct langwell_otg *langwell; -	char *next; -	unsigned size; -	unsigned t; - -	langwell = the_transceiver; -	next = buf; -	size = PAGE_SIZE; - -	t = scnprintf(next, size, -		"\n" -		"USBCMD = 0x%08x \n" -		"USBSTS = 0x%08x \n" -		"USBINTR = 0x%08x \n" -		"ASYNCLISTADDR = 0x%08x \n" -		"PORTSC1 = 0x%08x \n" -		"HOSTPC1 = 0x%08x \n" -		"OTGSC = 0x%08x \n" -		"USBMODE = 0x%08x \n", -		readl(langwell->regs + 0x30), -		readl(langwell->regs + 0x34), -		readl(langwell->regs + 0x38), -		readl(langwell->regs + 0x48), -		readl(langwell->regs + 0x74), -		readl(langwell->regs + 0xb4), -		readl(langwell->regs + 0xf4), -		readl(langwell->regs + 0xf8) -		); -	size -= t; -	next += t; - -	return PAGE_SIZE - size; -} -static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); - -static ssize_t -show_hsm(struct device *_dev, struct device_attribute *attr, char *buf) -{ -	struct langwell_otg *langwell; -	char *next; -	unsigned size; -	unsigned t; - -	langwell = the_transceiver; -	next = buf; -	size = PAGE_SIZE; - -	t = scnprintf(next, size, -		"\n" -		"current state = %s\n" -		"a_bus_resume = \t%d\n" -		"a_bus_suspend = \t%d\n" -		"a_conn = \t%d\n" -		"a_sess_vld = \t%d\n" -		"a_srp_det = \t%d\n" -		"a_vbus_vld = \t%d\n" -		"b_bus_resume = \t%d\n" -		"b_bus_suspend = \t%d\n" -		"b_conn = \t%d\n" -		"b_se0_srp = \t%d\n" -		"b_sess_end = \t%d\n" -		"b_sess_vld = \t%d\n" -		"id = \t%d\n" -		"a_set_b_hnp_en = \t%d\n" -		"b_srp_done = \t%d\n" -		"b_hnp_enable = \t%d\n" -		"a_wait_vrise_tmout = \t%d\n" -		"a_wait_bcon_tmout = \t%d\n" -		"a_aidl_bdis_tmout = \t%d\n" -		"b_ase0_brst_tmout = \t%d\n" -		"a_bus_drop = \t%d\n" -		"a_bus_req = \t%d\n" -		"a_clr_err = \t%d\n" -		"a_suspend_req = \t%d\n" -		"b_bus_req = \t%d\n" -		"b_bus_suspend_tmout = \t%d\n" -		"b_bus_suspend_vld = \t%d\n", -		state_string(langwell->otg.state), -		langwell->hsm.a_bus_resume, -		langwell->hsm.a_bus_suspend, -		langwell->hsm.a_conn, -		langwell->hsm.a_sess_vld, -		langwell->hsm.a_srp_det, -		langwell->hsm.a_vbus_vld, -		langwell->hsm.b_bus_resume, -		langwell->hsm.b_bus_suspend, -		langwell->hsm.b_conn, -		langwell->hsm.b_se0_srp, -		langwell->hsm.b_sess_end, -		langwell->hsm.b_sess_vld, -		langwell->hsm.id, -		langwell->hsm.a_set_b_hnp_en, -		langwell->hsm.b_srp_done, -		langwell->hsm.b_hnp_enable, -		langwell->hsm.a_wait_vrise_tmout, -		langwell->hsm.a_wait_bcon_tmout, -		langwell->hsm.a_aidl_bdis_tmout, -		langwell->hsm.b_ase0_brst_tmout, -		langwell->hsm.a_bus_drop, -		langwell->hsm.a_bus_req, -		langwell->hsm.a_clr_err, -		langwell->hsm.a_suspend_req, -		langwell->hsm.b_bus_req, -		langwell->hsm.b_bus_suspend_tmout, -		langwell->hsm.b_bus_suspend_vld -		); -	size -= t; -	next += t; - -	return PAGE_SIZE - size; -} -static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL); - -static ssize_t -get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) -{ -	struct langwell_otg *langwell; -	char *next; -	unsigned size; -	unsigned t; - -	langwell =  the_transceiver; -	next = buf; -	size = PAGE_SIZE; - -	t = scnprintf(next, size, "%d", langwell->hsm.a_bus_req); -	size -= t; -	next += t; - -	return PAGE_SIZE - size; -} - -static ssize_t -set_a_bus_req(struct device *dev, struct device_attribute *attr, -		const char *buf, size_t count) -{ -	struct langwell_otg *langwell; -	langwell = the_transceiver; -	if (!langwell->otg.default_a) -		return -1; -	if (count > 2) -		return -1; - -	if (buf[0] == '0') { -		langwell->hsm.a_bus_req = 0; -		otg_dbg("a_bus_req = 0\n"); -	} else if (buf[0] == '1') { -		/* If a_bus_drop is TRUE, a_bus_req can't be set */ -		if (langwell->hsm.a_bus_drop) -			return -1; -		langwell->hsm.a_bus_req = 1; -		otg_dbg("a_bus_req = 1\n"); -	} -	if (spin_trylock(&langwell->wq_lock)) { -		queue_work(langwell->qwork, &langwell->work); -		spin_unlock(&langwell->wq_lock); -	} -	return count; -} -static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req); - -static ssize_t -get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf) -{ -	struct langwell_otg *langwell; -	char *next; -	unsigned size; -	unsigned t; - -	langwell =  the_transceiver; -	next = buf; -	size = PAGE_SIZE; - -	t = scnprintf(next, size, "%d", langwell->hsm.a_bus_drop); -	size -= t; -	next += t; - -	return PAGE_SIZE - size; -} - -static ssize_t -set_a_bus_drop(struct device *dev, struct device_attribute *attr, -		const char *buf, size_t count) -{ -	struct langwell_otg *langwell; -	langwell = the_transceiver; -	if (!langwell->otg.default_a) -		return -1; -	if (count > 2) -		return -1; - -	if (buf[0] == '0') { -		langwell->hsm.a_bus_drop = 0; -		otg_dbg("a_bus_drop = 0\n"); -	} else if (buf[0] == '1') { -		langwell->hsm.a_bus_drop = 1; -		langwell->hsm.a_bus_req = 0; -		otg_dbg("a_bus_drop = 1, then a_bus_req = 0\n"); -	} -	if (spin_trylock(&langwell->wq_lock)) { -		queue_work(langwell->qwork, &langwell->work); -		spin_unlock(&langwell->wq_lock); -	} -	return count; -} -static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO, -	get_a_bus_drop, set_a_bus_drop); - -static ssize_t -get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf) -{ -	struct langwell_otg *langwell; -	char *next; -	unsigned size; -	unsigned t; - -	langwell =  the_transceiver; -	next = buf; -	size = PAGE_SIZE; - -	t = scnprintf(next, size, "%d", langwell->hsm.b_bus_req); -	size -= t; -	next += t; - -	return PAGE_SIZE - size; -} - -static ssize_t -set_b_bus_req(struct device *dev, struct device_attribute *attr, -		const char *buf, size_t count) -{ -	struct langwell_otg *langwell; -	langwell = the_transceiver; - -	if (langwell->otg.default_a) -		return -1; - -	if (count > 2) -		return -1; - -	if (buf[0] == '0') { -		langwell->hsm.b_bus_req = 0; -		otg_dbg("b_bus_req = 0\n"); -	} else if (buf[0] == '1') { -		langwell->hsm.b_bus_req = 1; -		otg_dbg("b_bus_req = 1\n"); -	} -	if (spin_trylock(&langwell->wq_lock)) { -		queue_work(langwell->qwork, &langwell->work); -		spin_unlock(&langwell->wq_lock); -	} -	return count; -} -static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req); - -static ssize_t -set_a_clr_err(struct device *dev, struct device_attribute *attr, -		const char *buf, size_t count) -{ -	struct langwell_otg *langwell; -	langwell = the_transceiver; - -	if (!langwell->otg.default_a) -		return -1; -	if (count > 2) -		return -1; - -	if (buf[0] == '1') { -		langwell->hsm.a_clr_err = 1; -		otg_dbg("a_clr_err = 1\n"); -	} -	if (spin_trylock(&langwell->wq_lock)) { -		queue_work(langwell->qwork, &langwell->work); -		spin_unlock(&langwell->wq_lock); -	} -	return count; -} -static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err); - -static struct attribute *inputs_attrs[] = { -	&dev_attr_a_bus_req.attr, -	&dev_attr_a_bus_drop.attr, -	&dev_attr_b_bus_req.attr, -	&dev_attr_a_clr_err.attr, -	NULL, -}; - -static struct attribute_group debug_dev_attr_group = { -	.name = "inputs", -	.attrs = inputs_attrs, -}; - -int langwell_register_host(struct pci_driver *host_driver) -{ -	int	ret = 0; - -	the_transceiver->host_ops = host_driver; -	queue_work(the_transceiver->qwork, &the_transceiver->work); -	otg_dbg("host controller driver is registered\n"); - -	return ret; -} -EXPORT_SYMBOL(langwell_register_host); - -void langwell_unregister_host(struct pci_driver *host_driver) -{ -	if (the_transceiver->host_ops) -		the_transceiver->host_ops->remove(the_transceiver->pdev); -	the_transceiver->host_ops = NULL; -	the_transceiver->hsm.a_bus_drop = 1; -	queue_work(the_transceiver->qwork, &the_transceiver->work); -	otg_dbg("host controller driver is unregistered\n"); -} -EXPORT_SYMBOL(langwell_unregister_host); - -int langwell_register_peripheral(struct pci_driver *client_driver) -{ -	int	ret = 0; - -	if (client_driver) -		ret = client_driver->probe(the_transceiver->pdev, -				client_driver->id_table); -	if (!ret) { -		the_transceiver->client_ops = client_driver; -		queue_work(the_transceiver->qwork, &the_transceiver->work); -		otg_dbg("client controller driver is registered\n"); -	} - -	return ret; -} -EXPORT_SYMBOL(langwell_register_peripheral); - -void langwell_unregister_peripheral(struct pci_driver *client_driver) -{ -	if (the_transceiver->client_ops) -		the_transceiver->client_ops->remove(the_transceiver->pdev); -	the_transceiver->client_ops = NULL; -	the_transceiver->hsm.b_bus_req = 0; -	queue_work(the_transceiver->qwork, &the_transceiver->work); -	otg_dbg("client controller driver is unregistered\n"); -} -EXPORT_SYMBOL(langwell_unregister_peripheral); - -static int langwell_otg_probe(struct pci_dev *pdev, -		const struct pci_device_id *id) -{ -	unsigned long		resource, len; -	void __iomem 		*base = NULL; -	int			retval; -	u32			val32; -	struct langwell_otg	*langwell; -	char			qname[] = "langwell_otg_queue"; - -	retval = 0; -	otg_dbg("\notg controller is detected.\n"); -	if (pci_enable_device(pdev) < 0) { -		retval = -ENODEV; -		goto done; -	} - -	langwell = kzalloc(sizeof *langwell, GFP_KERNEL); -	if (langwell == NULL) { -		retval = -ENOMEM; -		goto done; -	} -	the_transceiver = langwell; - -	/* control register: BAR 0 */ -	resource = pci_resource_start(pdev, 0); -	len = pci_resource_len(pdev, 0); -	if (!request_mem_region(resource, len, driver_name)) { -		retval = -EBUSY; -		goto err; -	} -	langwell->region = 1; - -	base = ioremap_nocache(resource, len); -	if (base == NULL) { -		retval = -EFAULT; -		goto err; -	} -	langwell->regs = base; - -	if (!pdev->irq) { -		otg_dbg("No IRQ.\n"); -		retval = -ENODEV; -		goto err; -	} - -	langwell->qwork = create_workqueue(qname); -	if (!langwell->qwork) { -		otg_dbg("cannot create workqueue %s\n", qname); -		retval = -ENOMEM; -		goto err; -	} -	INIT_WORK(&langwell->work, langwell_otg_work); - -	/* OTG common part */ -	langwell->pdev = pdev; -	langwell->otg.dev = &pdev->dev; -	langwell->otg.label = driver_name; -	langwell->otg.set_host = langwell_otg_set_host; -	langwell->otg.set_peripheral = langwell_otg_set_peripheral; -	langwell->otg.set_power = langwell_otg_set_power; -	langwell->otg.start_srp = langwell_otg_start_srp; -	langwell->otg.state = OTG_STATE_UNDEFINED; -	if (otg_set_transceiver(&langwell->otg)) { -		otg_dbg("can't set transceiver\n"); -		retval = -EBUSY; -		goto err; -	} - -	reset_otg(); -	init_hsm(); - -	spin_lock_init(&langwell->lock); -	spin_lock_init(&langwell->wq_lock); -	INIT_LIST_HEAD(&active_timers); -	langwell_otg_init_timers(&langwell->hsm); - -	if (request_irq(pdev->irq, otg_irq, IRQF_SHARED, -				driver_name, langwell) != 0) { -		otg_dbg("request interrupt %d failed\n", pdev->irq); -		retval = -EBUSY; -		goto err; -	} - -	/* enable OTGSC int */ -	val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE | -		OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU; -	writel(val32, langwell->regs + CI_OTGSC); - -	retval = device_create_file(&pdev->dev, &dev_attr_registers); -	if (retval < 0) { -		otg_dbg("Can't register sysfs attribute: %d\n", retval); -		goto err; -	} - -	retval = device_create_file(&pdev->dev, &dev_attr_hsm); -	if (retval < 0) { -		otg_dbg("Can't hsm sysfs attribute: %d\n", retval); -		goto err; -	} - -	retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group); -	if (retval < 0) { -		otg_dbg("Can't register sysfs attr group: %d\n", retval); -		goto err; -	} - -	if (langwell->otg.state == OTG_STATE_A_IDLE) -		queue_work(langwell->qwork, &langwell->work); - -	return 0; - -err: -	if (the_transceiver) -		langwell_otg_remove(pdev); -done: -	return retval; -} - -static void langwell_otg_remove(struct pci_dev *pdev) -{ -	struct langwell_otg *langwell; - -	langwell = the_transceiver; - -	if (langwell->qwork) { -		flush_workqueue(langwell->qwork); -		destroy_workqueue(langwell->qwork); -	} -	langwell_otg_free_timers(); - -	/* disable OTGSC interrupt as OTGSC doesn't change in reset */ -	writel(0, langwell->regs + CI_OTGSC); - -	if (pdev->irq) -		free_irq(pdev->irq, langwell); -	if (langwell->regs) -		iounmap(langwell->regs); -	if (langwell->region) -		release_mem_region(pci_resource_start(pdev, 0), -				pci_resource_len(pdev, 0)); - -	otg_set_transceiver(NULL); -	pci_disable_device(pdev); -	sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group); -	device_remove_file(&pdev->dev, &dev_attr_hsm); -	device_remove_file(&pdev->dev, &dev_attr_registers); -	kfree(langwell); -	langwell = NULL; -} - -static void transceiver_suspend(struct pci_dev *pdev) -{ -	pci_save_state(pdev); -	pci_set_power_state(pdev, PCI_D3hot); -	langwell_otg_phy_low_power(1); -} - -static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message) -{ -	int 	ret = 0; -	struct langwell_otg *langwell; - -	langwell = the_transceiver; - -	/* Disbale OTG interrupts */ -	langwell_otg_intr(0); - -	if (pdev->irq) -		free_irq(pdev->irq, langwell); - -	/* Prevent more otg_work */ -	flush_workqueue(langwell->qwork); -	spin_lock(&langwell->wq_lock); - -	/* start actions */ -	switch (langwell->otg.state) { -	case OTG_STATE_A_IDLE: -	case OTG_STATE_B_IDLE: -	case OTG_STATE_A_WAIT_VFALL: -	case OTG_STATE_A_VBUS_ERR: -		transceiver_suspend(pdev); -		break; -	case OTG_STATE_A_WAIT_VRISE: -		langwell_otg_del_timer(a_wait_vrise_tmr); -		langwell->hsm.a_srp_det = 0; -		langwell_otg_drv_vbus(0); -		langwell->otg.state = OTG_STATE_A_IDLE; -		transceiver_suspend(pdev); -		break; -	case OTG_STATE_A_WAIT_BCON: -		langwell_otg_del_timer(a_wait_bcon_tmr); -		if (langwell->host_ops) -			ret = langwell->host_ops->suspend(pdev, message); -		langwell_otg_drv_vbus(0); -		break; -	case OTG_STATE_A_HOST: -		if (langwell->host_ops) -			ret = langwell->host_ops->suspend(pdev, message); -		langwell_otg_drv_vbus(0); -		langwell_otg_phy_low_power(1); -		break; -	case OTG_STATE_A_SUSPEND: -		langwell_otg_del_timer(a_aidl_bdis_tmr); -		langwell_otg_HABA(0); -		if (langwell->host_ops) -			langwell->host_ops->remove(pdev); -		else -			otg_dbg("host driver has been removed.\n"); -		langwell_otg_drv_vbus(0); -		transceiver_suspend(pdev); -		langwell->otg.state = OTG_STATE_A_WAIT_VFALL; -		break; -	case OTG_STATE_A_PERIPHERAL: -		if (langwell->client_ops) -			ret = langwell->client_ops->suspend(pdev, message); -		else -			otg_dbg("client driver has been removed.\n"); -		langwell_otg_drv_vbus(0); -		transceiver_suspend(pdev); -		langwell->otg.state = OTG_STATE_A_WAIT_VFALL; -		break; -	case OTG_STATE_B_HOST: -		if (langwell->host_ops) -			langwell->host_ops->remove(pdev); -		else -			otg_dbg("host driver has been removed.\n"); -		langwell->hsm.b_bus_req = 0; -		transceiver_suspend(pdev); -		langwell->otg.state = OTG_STATE_B_IDLE; -		break; -	case OTG_STATE_B_PERIPHERAL: -		if (langwell->client_ops) -			ret = langwell->client_ops->suspend(pdev, message); -		else -			otg_dbg("client driver has been removed.\n"); -		break; -	case OTG_STATE_B_WAIT_ACON: -		langwell_otg_del_timer(b_ase0_brst_tmr); -		langwell_otg_HAAR(0); -		if (langwell->host_ops) -			langwell->host_ops->remove(pdev); -		else -			otg_dbg("host driver has been removed.\n"); -		langwell->hsm.b_bus_req = 0; -		langwell->otg.state = OTG_STATE_B_IDLE; -		transceiver_suspend(pdev); -		break; -	default: -		otg_dbg("error state before suspend\n "); -		break; -	} -	spin_unlock(&langwell->wq_lock); - -	return ret; -} - -static void transceiver_resume(struct pci_dev *pdev) -{ -	pci_restore_state(pdev); -	pci_set_power_state(pdev, PCI_D0); -	langwell_otg_phy_low_power(0); -} - -static int langwell_otg_resume(struct pci_dev *pdev) -{ -	int 	ret = 0; -	struct langwell_otg *langwell; - -	langwell = the_transceiver; - -	spin_lock(&langwell->wq_lock); - -	switch (langwell->otg.state) { -	case OTG_STATE_A_IDLE: -	case OTG_STATE_B_IDLE: -	case OTG_STATE_A_WAIT_VFALL: -	case OTG_STATE_A_VBUS_ERR: -		transceiver_resume(pdev); -		break; -	case OTG_STATE_A_WAIT_BCON: -		langwell_otg_add_timer(a_wait_bcon_tmr); -		langwell_otg_drv_vbus(1); -		if (langwell->host_ops) -			ret = langwell->host_ops->resume(pdev); -		break; -	case OTG_STATE_A_HOST: -		langwell_otg_drv_vbus(1); -		langwell_otg_phy_low_power(0); -		if (langwell->host_ops) -			ret = langwell->host_ops->resume(pdev); -		break; -	case OTG_STATE_B_PERIPHERAL: -		if (langwell->client_ops) -			ret = langwell->client_ops->resume(pdev); -		else -			otg_dbg("client driver not loaded.\n"); -		break; -	default: -		otg_dbg("error state before suspend\n "); -		break; -	} - -	if (request_irq(pdev->irq, otg_irq, IRQF_SHARED, -				driver_name, the_transceiver) != 0) { -		otg_dbg("request interrupt %d failed\n", pdev->irq); -		ret = -EBUSY; -	} - -	/* enable OTG interrupts */ -	langwell_otg_intr(1); - -	spin_unlock(&langwell->wq_lock); - -	queue_work(langwell->qwork, &langwell->work); - - -	return ret; -} - -static int __init langwell_otg_init(void) -{ -	return pci_register_driver(&otg_pci_driver); -} -module_init(langwell_otg_init); - -static void __exit langwell_otg_cleanup(void) -{ -	pci_unregister_driver(&otg_pci_driver); -} -module_exit(langwell_otg_cleanup); diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c index 9ed5ea56867..af456b48985 100644 --- a/drivers/usb/otg/nop-usb-xceiv.c +++ b/drivers/usb/otg/nop-usb-xceiv.c @@ -53,6 +53,7 @@ EXPORT_SYMBOL(usb_nop_xceiv_register);  void usb_nop_xceiv_unregister(void)  {  	platform_device_unregister(pd); +	pd = NULL;  }  EXPORT_SYMBOL(usb_nop_xceiv_unregister); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 247b61bfb7f..0e4f2e41ace 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -169,9 +169,11 @@ static int usb_console_setup(struct console *co, char *options)  			kfree(tty);  		}  	} -	/* So we know not to kill the hardware on a hangup on this -	   port. We have also bumped the use count by one so it won't go -	   idle */ +	/* Now that any required fake tty operations are completed restore +	 * the tty port count */ +	--port->port.count; +	/* The console is special in terms of closing the device so +	 * indicate this port is now acting as a system console. */  	port->console = 1;  	retval = 0; @@ -204,7 +206,7 @@ static void usb_console_write(struct console *co,  	dbg("%s - port %d, %d byte(s)", __func__, port->number, count); -	if (!port->port.count) { +	if (!port->console) {  		dbg("%s - port not opened", __func__);  		return;  	} @@ -300,8 +302,7 @@ void usb_serial_console_exit(void)  {  	if (usbcons_info.port) {  		unregister_console(&usbcons); -		if (usbcons_info.port->port.count) -			usbcons_info.port->port.count--; +		usbcons_info.port->console = 0;  		usbcons_info.port = NULL;  	}  } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 2b9eeda62bf..985cbcf48bd 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -67,6 +67,8 @@ static struct usb_device_id id_table [] = {  	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */  	{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */  	{ USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */ +	{ USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */ +	{ USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */  	{ USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */  	{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */  	{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ @@ -78,6 +80,7 @@ static struct usb_device_id id_table [] = {  	{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */  	{ USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */  	{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ +	{ USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */  	{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */  	{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */  	{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ @@ -94,7 +97,9 @@ static struct usb_device_id id_table [] = {  	{ USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */  	{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */  	{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ +	{ USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */  	{ USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ +	{ USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */  	{ USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */  	{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */  	{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 9734085fd2f..59adfe12311 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -1228,8 +1228,8 @@ static void cypress_read_int_callback(struct urb *urb)  		/* precursor to disconnect so just go away */  		return;  	case -EPIPE: -		usb_clear_halt(port->serial->dev, 0x81); -		break; +		/* Can't call usb_clear_halt while in_interrupt */ +		/* FALLS THROUGH */  	default:  		/* something ugly is going on... */  		dev_err(&urb->dev->dev, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3dc3768ca71..8fec5d4455c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -33,6 +33,7 @@  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/slab.h> +#include <linux/smp_lock.h>  #include <linux/tty.h>  #include <linux/tty_driver.h>  #include <linux/tty_flip.h> @@ -107,6 +108,7 @@ struct ftdi_sio_quirk {  static int   ftdi_jtag_probe(struct usb_serial *serial);  static int   ftdi_mtxorb_hack_setup(struct usb_serial *serial); +static int   ftdi_NDI_device_setup(struct usb_serial *serial);  static void  ftdi_USB_UIRT_setup(struct ftdi_private *priv);  static void  ftdi_HE_TIRA1_setup(struct ftdi_private *priv); @@ -118,6 +120,10 @@ static struct ftdi_sio_quirk ftdi_mtxorb_hack_quirk = {  	.probe  = ftdi_mtxorb_hack_setup,  }; +static struct ftdi_sio_quirk ftdi_NDI_device_quirk = { +	.probe	= ftdi_NDI_device_setup, +}; +  static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {  	.port_probe = ftdi_USB_UIRT_setup,  }; @@ -191,6 +197,7 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, +	{ USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },  	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },  	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },  	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) }, @@ -579,6 +586,9 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) }, +	{ USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) }, +	{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) }, +	{ USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) },  	{ USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },  	{ USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },  	{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, @@ -644,6 +654,16 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },  	{ USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) }, +	{ USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID), +		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, +	{ USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID), +		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, +	{ USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID), +		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, +	{ USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID), +		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, +	{ USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID), +		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },  	{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, @@ -660,6 +680,8 @@ static struct usb_device_id id_table_combined [] = {  		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },  	{ USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID),  		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, +	{ USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), +		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },  	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },  	{ USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },  	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) }, @@ -667,7 +689,6 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },  	{ USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) },  	{ USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) }, -	{ USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID) },  	{ USB_DEVICE(ATMEL_VID, STK541_PID) },  	{ USB_DEVICE(DE_VID, STB_PID) },  	{ USB_DEVICE(DE_VID, WHT_PID) }, @@ -677,6 +698,10 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),  		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },  	{ USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, +	{ USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, +	{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, +	{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), +		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },  	{ },					/* Optional parameter entry */  	{ }					/* Terminating entry */  }; @@ -1023,6 +1048,16 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,  	case FT2232C: /* FT2232C chip */  	case FT232RL:  		if (baud <= 3000000) { +			__u16 product_id = le16_to_cpu( +				port->serial->dev->descriptor.idProduct); +			if (((FTDI_NDI_HUC_PID == product_id) || +			     (FTDI_NDI_SPECTRA_SCU_PID == product_id) || +			     (FTDI_NDI_FUTURE_2_PID == product_id) || +			     (FTDI_NDI_FUTURE_3_PID == product_id) || +			     (FTDI_NDI_AURORA_SCU_PID == product_id)) && +			    (baud == 19200)) { +				baud = 1200000; +			}  			div_value = ftdi_232bm_baud_to_divisor(baud);  		} else {  			dbg("%s - Baud rate too high!", __func__); @@ -1554,6 +1589,39 @@ static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)  } /* ftdi_HE_TIRA1_setup */  /* + * Module parameter to control latency timer for NDI FTDI-based USB devices. + * If this value is not set in modprobe.conf.local its value will be set to 1ms. + */ +static int ndi_latency_timer = 1; + +/* Setup for the NDI FTDI-based USB devices, which requires hardwired + * baudrate (19200 gets mapped to 1200000). + * + * Called from usbserial:serial_probe. + */ +static int ftdi_NDI_device_setup(struct usb_serial *serial) +{ +	struct usb_device *udev = serial->dev; +	int latency = ndi_latency_timer; +	int rv = 0; +	char buf[1]; + +	if (latency == 0) +		latency = 1; +	if (latency > 99) +		latency = 99; + +	dbg("%s setting NDI device latency to %d", __func__, latency); +	dev_info(&udev->dev, "NDI device with a latency value of %d", latency); + +	rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), +				FTDI_SIO_SET_LATENCY_TIMER_REQUEST, +				FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, +				latency, 0, buf, 0, WDR_TIMEOUT); +	return 0; +} + +/*   * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko   * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from   * userspace using openocd. @@ -2121,7 +2189,7 @@ static void ftdi_process_read(struct work_struct *work)  				/* Note that the error flag is duplicated for  				   every character received since we don't know  				   which character it applied to */ -				if (!usb_serial_handle_sysrq_char(port, +				if (!usb_serial_handle_sysrq_char(tty, port,  						data[packet_offset + i]))  					tty_insert_flip_char(tty,  						data[packet_offset + i], @@ -2622,3 +2690,5 @@ MODULE_PARM_DESC(vendor, "User specified vendor ID (default="  module_param(product, ushort, 0);  MODULE_PARM_DESC(product, "User specified product ID"); +module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override"); diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index f1d440a728a..8c92b88166a 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -506,6 +506,7 @@   *   * Armin Laeuger originally sent the PID for the UM 100 module.   */ +#define FTDI_R2000KU_TRUE_RNG	0xFB80  /* R2000KU TRUE RNG */  #define FTDI_ELV_UR100_PID	0xFB58	/* USB-RS232-Umsetzer (UR 100) */  #define FTDI_ELV_UM100_PID	0xFB5A	/* USB-Modul UM 100 */  #define FTDI_ELV_UO100_PID	0xFB5B	/* USB-Modul UO 100 */ @@ -614,6 +615,9 @@  #define FTDI_CCSICDU20_0_PID    0xF9D0  #define FTDI_CCSICDU40_1_PID    0xF9D1  #define FTDI_CCSMACHX_2_PID     0xF9D2 +#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3 +#define FTDI_CCSICDU64_4_PID    0xF9D4 +#define FTDI_CCSPRIME8_5_PID    0xF9D5  /* Inside Accesso contactless reader (http://www.insidefr.com) */  #define INSIDE_ACCESSO		0xFAD0 @@ -736,6 +740,15 @@  #define FTDI_PYRAMID_PID	0xE6C8	/* Pyramid Appliance Display */  /* + * NDI (www.ndigital.com) product ids + */ +#define FTDI_NDI_HUC_PID		0xDA70	/* NDI Host USB Converter */ +#define FTDI_NDI_SPECTRA_SCU_PID	0xDA71	/* NDI Spectra SCU */ +#define FTDI_NDI_FUTURE_2_PID		0xDA72	/* NDI future device #2 */ +#define FTDI_NDI_FUTURE_3_PID		0xDA73	/* NDI future device #3 */ +#define FTDI_NDI_AURORA_SCU_PID		0xDA74	/* NDI Aurora SCU */ + +/*   * Posiflex inc retail equipment (http://www.posiflex.com.tw)   */  #define POSIFLEX_VID		0x0d3a  /* Vendor ID */ @@ -848,9 +861,6 @@  #define TML_VID			0x1B91	/* Vendor ID */  #define TML_USB_SERIAL_PID	0x0064	/* USB - Serial Converter */ -/* NDI Polaris System */ -#define FTDI_NDI_HUC_PID        0xDA70 -  /* Propox devices */  #define FTDI_PROPOX_JTAGCABLEII_PID	0xD738 @@ -934,6 +944,29 @@  #define MARVELL_VID		0x9e88  #define MARVELL_SHEEVAPLUG_PID	0x9e8f +#define FTDI_TURTELIZER_PID	0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */ + +/* + * GN Otometrics (http://www.otometrics.com) + * Submitted by Ville Sundberg. + */ +#define GN_OTOMETRICS_VID	0x0c33	/* Vendor ID */ +#define AURICAL_USB_PID		0x0010	/* Aurical USB Audiometer */ + +/* + * Bayer Ascensia Contour blood glucose meter USB-converter cable. + * http://winglucofacts.com/cables/ + */ +#define BAYER_VID                      0x1A79 +#define BAYER_CONTOUR_CABLE_PID        0x6001 + +/* + * Marvell OpenRD Base, Client + * http://www.open-rd.org + * OpenRD Base, Client use VID 0x0403 + */ +#define MARVELL_OPENRD_PID	0x9e90 +  /*   *   BmRequestType:  1100 0000b   *   bRequest:       FTDI_E2_READ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 932d6241b78..ce57f6a32bd 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -424,10 +424,17 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port)  	if (!tty)  		goto done; -	/* Push data to tty */ -	for (i = 0; i < urb->actual_length; i++, ch++) { -		if (!usb_serial_handle_sysrq_char(port, *ch)) -			tty_insert_flip_char(tty, *ch, TTY_NORMAL); +	/* The per character mucking around with sysrq path it too slow for +	   stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases +	   where the USB serial is not a console anyway */ +	if (!port->console || !port->sysrq) +		tty_insert_flip_string(tty, ch, urb->actual_length); +	else { +		/* Push data to tty */ +		for (i = 0; i < urb->actual_length; i++, ch++) { +			if (!usb_serial_handle_sysrq_char(tty, port, *ch)) +				tty_insert_flip_char(tty, *ch, TTY_NORMAL); +		}  	}  	tty_flip_buffer_push(tty);  	tty_kref_put(tty); @@ -527,11 +534,12 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)  	}  } -int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) +int usb_serial_handle_sysrq_char(struct tty_struct *tty, +			struct usb_serial_port *port, unsigned int ch)  {  	if (port->sysrq && port->console) {  		if (ch && time_before(jiffies, port->sysrq)) { -			handle_sysrq(ch, tty_port_tty_get(&port->port)); +			handle_sysrq(ch, tty);  			port->sysrq = 0;  			return 1;  		} diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index bfc5ce000ef..ccd4dd340d2 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -521,7 +521,7 @@ static int mos7720_chars_in_buffer(struct tty_struct *tty)  	mos7720_port = usb_get_serial_port_data(port);  	if (mos7720_port == NULL) {  		dbg("%s:leaving ...........", __func__); -		return -ENODEV; +		return 0;  	}  	for (i = 0; i < NUM_URBS; ++i) { diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c40f95c1951..270009afdf7 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -26,6 +26,7 @@  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/slab.h> +#include <linux/smp_lock.h>  #include <linux/tty.h>  #include <linux/tty_driver.h>  #include <linux/tty_flip.h> @@ -123,10 +124,13 @@  #define BANDB_DEVICE_ID_USOPTL4_4       0xAC44  #define BANDB_DEVICE_ID_USOPTL4_2       0xAC42 -/* This driver also supports the ATEN UC2324 device since it is mos7840 based - *  - if I knew the device id it would also support the ATEN UC2322 */ +/* This driver also supports + * ATEN UC2324 device using Moschip MCS7840 + * ATEN UC2322 device using Moschip MCS7820 + */  #define USB_VENDOR_ID_ATENINTL		0x0557  #define ATENINTL_DEVICE_ID_UC2324	0x2011 +#define ATENINTL_DEVICE_ID_UC2322	0x7820  /* Interrupt Routine Defines    */ @@ -176,6 +180,7 @@ static struct usb_device_id moschip_port_id_table[] = {  	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},  	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},  	{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, +	{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},  	{}			/* terminating entry */  }; @@ -185,6 +190,7 @@ static __devinitdata struct usb_device_id moschip_id_table_combined[] = {  	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},  	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},  	{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, +	{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},  	{}			/* terminating entry */  }; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 575816e6ba3..c784ddbe7b6 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -66,8 +66,10 @@ static int  option_tiocmget(struct tty_struct *tty, struct file *file);  static int  option_tiocmset(struct tty_struct *tty, struct file *file,  				unsigned int set, unsigned int clear);  static int  option_send_setup(struct usb_serial_port *port); +#ifdef CONFIG_PM  static int  option_suspend(struct usb_serial *serial, pm_message_t message);  static int  option_resume(struct usb_serial *serial); +#endif  /* Vendor and product IDs */  #define OPTION_VENDOR_ID			0x0AF0 @@ -205,7 +207,9 @@ static int  option_resume(struct usb_serial *serial);  #define NOVATELWIRELESS_PRODUCT_MC727		0x4100  #define NOVATELWIRELESS_PRODUCT_MC950D		0x4400  #define NOVATELWIRELESS_PRODUCT_U727		0x5010 +#define NOVATELWIRELESS_PRODUCT_MC727_NEW	0x5100  #define NOVATELWIRELESS_PRODUCT_MC760		0x6000 +#define NOVATELWIRELESS_PRODUCT_OVMC760		0x6002  /* FUTURE NOVATEL PRODUCTS */  #define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED	0X6001 @@ -258,11 +262,6 @@ static int  option_resume(struct usb_serial *serial);  #define AXESSTEL_VENDOR_ID			0x1726  #define AXESSTEL_PRODUCT_MV110H			0x1000 -#define ONDA_VENDOR_ID				0x19d2 -#define ONDA_PRODUCT_MSA501HS			0x0001 -#define ONDA_PRODUCT_ET502HS			0x0002 -#define ONDA_PRODUCT_MT503HS			0x2000 -  #define BANDRICH_VENDOR_ID			0x1A8D  #define BANDRICH_PRODUCT_C100_1			0x1002  #define BANDRICH_PRODUCT_C100_2			0x1003 @@ -300,6 +299,7 @@ static int  option_resume(struct usb_serial *serial);  #define ZTE_PRODUCT_MF628			0x0015  #define ZTE_PRODUCT_MF626			0x0031  #define ZTE_PRODUCT_CDMA_TECH			0xfffe +#define ZTE_PRODUCT_AC8710			0xfff1  #define BENQ_VENDOR_ID				0x04a5  #define BENQ_PRODUCT_H10			0x4068 @@ -307,11 +307,25 @@ static int  option_resume(struct usb_serial *serial);  #define DLINK_VENDOR_ID				0x1186  #define DLINK_PRODUCT_DWM_652			0x3e04 +#define QISDA_VENDOR_ID				0x1da5 +#define QISDA_PRODUCT_H21_4512			0x4512 +#define QISDA_PRODUCT_H21_4523			0x4523 +#define QISDA_PRODUCT_H20_4515			0x4515 +#define QISDA_PRODUCT_H20_4519			0x4519 +  /* TOSHIBA PRODUCTS */  #define TOSHIBA_VENDOR_ID			0x0930  #define TOSHIBA_PRODUCT_HSDPA_MINICARD		0x1302 +#define ALINK_VENDOR_ID				0x1e0e +#define ALINK_PRODUCT_3GU			0x9200 + +/* ALCATEL PRODUCTS */ +#define ALCATEL_VENDOR_ID			0x1bbb +#define ALCATEL_PRODUCT_X060S			0x0000 + +  static struct usb_device_id option_ids[] = {  	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },  	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -428,8 +442,10 @@ static struct usb_device_id option_ids[] = {  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU870D) }, /* Novatel EU850D/EU860D/EU870D */  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */ +	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727_NEW) }, /* Novatel MC727/U727/USB727 refresh */  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC760) }, /* Novatel MC760/U760/USB760 */ +	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_OVMC760) }, /* Novatel Ovation MC760 */  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, /* Novatel HSPA product */  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, /* Novatel EVDO Embedded product */  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, /* Novatel HSPA Embedded product */ @@ -463,42 +479,6 @@ static struct usb_device_id option_ids[] = {  	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },  	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },  	{ USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MSA501HS) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_ET502HS) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0003) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0004) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0005) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0006) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0007) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0008) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0009) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x000a) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x000b) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x000c) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x000d) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x000e) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x000f) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0010) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0011) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0012) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0013) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0014) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0015) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0016) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0017) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0018) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0019) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0020) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0021) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0022) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0023) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0024) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0025) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0026) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0027) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0028) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, 0x0029) }, -	{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MT503HS) },  	{ USB_DEVICE(YISO_VENDOR_ID, YISO_PRODUCT_U893) },  	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },  	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) }, @@ -523,14 +503,85 @@ static struct usb_device_id option_ids[] = {  	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */  	{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, -	{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622) }, -	{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) }, -	{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) }, -	{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0006, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0007, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0008, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0009, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000a, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000b, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000c, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000d, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000e, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000f, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0026, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0069, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0076, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0078, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0082, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */ +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0060, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },  	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },  	{ USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, -	{ USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */ +	{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) }, +	{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) }, +	{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) }, +	{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) },  	{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ +	{ USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },  	{ } /* Terminating entry */  };  MODULE_DEVICE_TABLE(usb, option_ids); @@ -539,8 +590,10 @@ static struct usb_driver option_driver = {  	.name       = "option",  	.probe      = usb_serial_probe,  	.disconnect = usb_serial_disconnect, +#ifdef CONFIG_PM  	.suspend    = usb_serial_suspend,  	.resume     = usb_serial_resume, +#endif  	.id_table   = option_ids,  	.no_dynamic_id = 	1,  }; @@ -572,8 +625,10 @@ static struct usb_serial_driver option_1port_device = {  	.disconnect        = option_disconnect,  	.release           = option_release,  	.read_int_callback = option_instat_callback, +#ifdef CONFIG_PM  	.suspend           = option_suspend,  	.resume            = option_resume, +#endif  };  static int debug; @@ -732,7 +787,6 @@ static int option_write(struct tty_struct *tty, struct usb_serial_port *port,  		memcpy(this_urb->transfer_buffer, buf, todo);  		this_urb->transfer_buffer_length = todo; -		this_urb->dev = port->serial->dev;  		err = usb_submit_urb(this_urb, GFP_ATOMIC);  		if (err) {  			dbg("usb_submit_urb %p (write bulk) failed " @@ -816,7 +870,6 @@ static void option_instat_callback(struct urb *urb)  	int status = urb->status;  	struct usb_serial_port *port =  urb->context;  	struct option_port_private *portdata = usb_get_serial_port_data(port); -	struct usb_serial *serial = port->serial;  	dbg("%s", __func__);  	dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata); @@ -860,7 +913,6 @@ static void option_instat_callback(struct urb *urb)  	/* Resubmit urb so we continue receiving IRQ data */  	if (status != -ESHUTDOWN && status != -ENOENT) { -		urb->dev = serial->dev;  		err = usb_submit_urb(urb, GFP_ATOMIC);  		if (err)  			dbg("%s: resubmit intr urb failed. (%d)", @@ -913,7 +965,6 @@ static int option_open(struct tty_struct *tty,  			struct usb_serial_port *port, struct file *filp)  {  	struct option_port_private *portdata; -	struct usb_serial *serial = port->serial;  	int i, err;  	struct urb *urb; @@ -921,23 +972,11 @@ static int option_open(struct tty_struct *tty,  	dbg("%s", __func__); -	/* Reset low level data toggle and start reading from endpoints */ +	/* Start reading from the IN endpoint */  	for (i = 0; i < N_IN_URB; i++) {  		urb = portdata->in_urbs[i];  		if (!urb)  			continue; -		if (urb->dev != serial->dev) { -			dbg("%s: dev %p != %p", __func__, -				urb->dev, serial->dev); -			continue; -		} - -		/* -		 * make sure endpoint data toggle is synchronized with the -		 * device -		 */ -		usb_clear_halt(urb->dev, urb->pipe); -  		err = usb_submit_urb(urb, GFP_KERNEL);  		if (err) {  			dbg("%s: submit urb %d failed (%d) %d", @@ -946,16 +985,6 @@ static int option_open(struct tty_struct *tty,  		}  	} -	/* Reset low level data toggle on out endpoints */ -	for (i = 0; i < N_OUT_URB; i++) { -		urb = portdata->out_urbs[i]; -		if (!urb) -			continue; -		urb->dev = serial->dev; -		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), -				usb_pipeout(urb->pipe), 0); */ -	} -  	option_send_setup(port);  	return 0; @@ -1195,6 +1224,7 @@ static void option_release(struct usb_serial *serial)  	}  } +#ifdef CONFIG_PM  static int option_suspend(struct usb_serial *serial, pm_message_t message)  {  	dbg("%s entered", __func__); @@ -1218,7 +1248,6 @@ static int option_resume(struct usb_serial *serial)  			dbg("%s: No interrupt URB for port %d\n", __func__, i);  			continue;  		} -		port->interrupt_in_urb->dev = serial->dev;  		err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);  		dbg("Submitted interrupt URB for port %d (result %d)", i, err);  		if (err < 0) { @@ -1254,6 +1283,7 @@ static int option_resume(struct usb_serial *serial)  	}  	return 0;  } +#endif  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index ec6c132a25b..3e86815b270 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -94,6 +94,8 @@ static struct usb_device_id id_table [] = {  	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },  	{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },  	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, +	{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, +	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },  	{ }					/* Terminating entry */  }; @@ -971,18 +973,46 @@ exit:  			__func__, retval);  } +static void pl2303_push_data(struct tty_struct *tty, +		struct usb_serial_port *port, struct urb *urb, +		u8 line_status) +{ +	unsigned char *data = urb->transfer_buffer; +	/* get tty_flag from status */ +	char tty_flag = TTY_NORMAL; +	/* break takes precedence over parity, */ +	/* which takes precedence over framing errors */ +	if (line_status & UART_BREAK_ERROR) +		tty_flag = TTY_BREAK; +	else if (line_status & UART_PARITY_ERROR) +		tty_flag = TTY_PARITY; +	else if (line_status & UART_FRAME_ERROR) +		tty_flag = TTY_FRAME; +	dbg("%s - tty_flag = %d", __func__, tty_flag); + +	tty_buffer_request_room(tty, urb->actual_length + 1); +	/* overrun is special, not associated with a char */ +	if (line_status & UART_OVERRUN_ERROR) +		tty_insert_flip_char(tty, 0, TTY_OVERRUN); +	if (port->console && port->sysrq) { +		int i; +		for (i = 0; i < urb->actual_length; ++i) +			if (!usb_serial_handle_sysrq_char(tty, port, data[i])) +				tty_insert_flip_char(tty, data[i], tty_flag); +	} else +		tty_insert_flip_string(tty, data, urb->actual_length); +	tty_flip_buffer_push(tty); +} +  static void pl2303_read_bulk_callback(struct urb *urb)  {  	struct usb_serial_port *port =  urb->context;  	struct pl2303_private *priv = usb_get_serial_port_data(port);  	struct tty_struct *tty; -	unsigned char *data = urb->transfer_buffer;  	unsigned long flags; -	int i;  	int result;  	int status = urb->status;  	u8 line_status; -	char tty_flag;  	dbg("%s - port %d", __func__, port->number); @@ -1010,10 +1040,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)  	}  	usb_serial_debug_data(debug, &port->dev, __func__, -			      urb->actual_length, data); - -	/* get tty_flag from status */ -	tty_flag = TTY_NORMAL; +			      urb->actual_length, urb->transfer_buffer);  	spin_lock_irqsave(&priv->lock, flags);  	line_status = priv->line_status; @@ -1021,26 +1048,9 @@ static void pl2303_read_bulk_callback(struct urb *urb)  	spin_unlock_irqrestore(&priv->lock, flags);  	wake_up_interruptible(&priv->delta_msr_wait); -	/* break takes precedence over parity, */ -	/* which takes precedence over framing errors */ -	if (line_status & UART_BREAK_ERROR) -		tty_flag = TTY_BREAK; -	else if (line_status & UART_PARITY_ERROR) -		tty_flag = TTY_PARITY; -	else if (line_status & UART_FRAME_ERROR) -		tty_flag = TTY_FRAME; -	dbg("%s - tty_flag = %d", __func__, tty_flag); -  	tty = tty_port_tty_get(&port->port);  	if (tty && urb->actual_length) { -		tty_buffer_request_room(tty, urb->actual_length + 1); -		/* overrun is special, not associated with a char */ -		if (line_status & UART_OVERRUN_ERROR) -			tty_insert_flip_char(tty, 0, TTY_OVERRUN); -		for (i = 0; i < urb->actual_length; ++i) -			if (!usb_serial_handle_sysrq_char(port, data[i])) -				tty_insert_flip_char(tty, data[i], tty_flag); -		tty_flip_buffer_push(tty); +		pl2303_push_data(tty, port, urb, line_status);  	}  	tty_kref_put(tty);  	/* Schedule the next read _if_ we are still open */ diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 1d7a22e3a9f..ee9505e1dd9 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -122,3 +122,11 @@  /* Hewlett-Packard LD220-HP POS Pole Display */  #define HP_VENDOR_ID		0x03f0  #define HP_LD220_PRODUCT_ID	0x3524 + +/* Cressi Edy (diving computer) PC interface */ +#define CRESSI_VENDOR_ID	0x04b8 +#define CRESSI_EDY_PRODUCT_ID	0x0521 + +/* Sony, USB data cable for CMD-Jxx mobile phones */ +#define SONY_VENDOR_ID		0x054c +#define SONY_QN3USB_PRODUCT_ID	0x0437 diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 032f7aeb40a..f48d05e0acc 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -181,35 +181,50 @@ static const struct sierra_iface_info direct_ip_interface_blacklist = {  };  static struct usb_device_id id_table [] = { +	{ USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */ +	{ USB_DEVICE(0x03F0, 0x1B1D) },	/* HP ev2200 a.k.a MC5720 */ +	{ USB_DEVICE(0x03F0, 0x1E1D) },	/* HP hs2300 a.k.a MC8775 */ +  	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */  	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */  	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */ -	{ USB_DEVICE(0x03f0, 0x1b1d) }, /* HP ev2200 a.k.a MC5720 */  	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */ -	{ USB_DEVICE(0x1199, 0x0024) },	/* Sierra Wireless MC5727 */  	{ USB_DEVICE(0x1199, 0x0220) },	/* Sierra Wireless MC5725 */ +	{ USB_DEVICE(0x1199, 0x0022) },	/* Sierra Wireless EM5725 */ +	{ USB_DEVICE(0x1199, 0x0024) },	/* Sierra Wireless MC5727 */ +	{ USB_DEVICE(0x1199, 0x0224) },	/* Sierra Wireless MC5727 */  	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */  	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */ +	{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */  	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless USB Dongle 595U */ -	 /* Sierra Wireless C597 */ +	/* Sierra Wireless C597 */  	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) }, -	 /* Sierra Wireless Device */ +	/* Sierra Wireless T598 */  	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0025, 0xFF, 0xFF, 0xFF) }, -	{ USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless Device */ -	{ USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless Device */ -	{ USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless Device */ +	{ USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless T11 */ +	{ USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless AC402 */ +	{ USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless MC5728 */ +	{ USB_DEVICE(0x1199, 0x0029) }, /* Sierra Wireless Device */  	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */ -	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */  	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */ +	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */ +	{ USB_DEVICE(0x1199, 0x6805) },	/* Sierra Wireless MC8765 */ +	{ USB_DEVICE(0x1199, 0x6808) },	/* Sierra Wireless MC8755 */ +	{ USB_DEVICE(0x1199, 0x6809) },	/* Sierra Wireless MC8765 */  	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 & AC 875U */ -	{ USB_DEVICE(0x1199, 0x6813) },	/* Sierra Wireless MC8775 (Lenovo) */ +	{ USB_DEVICE(0x1199, 0x6813) },	/* Sierra Wireless MC8775 */  	{ USB_DEVICE(0x1199, 0x6815) },	/* Sierra Wireless MC8775 */ -	{ USB_DEVICE(0x03f0, 0x1e1d) },	/* HP hs2300 a.k.a MC8775 */ +	{ USB_DEVICE(0x1199, 0x6816) },	/* Sierra Wireless MC8775 */  	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */  	{ USB_DEVICE(0x1199, 0x6821) },	/* Sierra Wireless AirCard 875U */ +	{ USB_DEVICE(0x1199, 0x6822) },	/* Sierra Wireless AirCard 875E */  	{ USB_DEVICE(0x1199, 0x6832) },	/* Sierra Wireless MC8780 */  	{ USB_DEVICE(0x1199, 0x6833) },	/* Sierra Wireless MC8781 */ +	{ USB_DEVICE(0x1199, 0x6834) },	/* Sierra Wireless MC8780 */ +	{ USB_DEVICE(0x1199, 0x6835) },	/* Sierra Wireless MC8781 */ +	{ USB_DEVICE(0x1199, 0x6838) },	/* Sierra Wireless MC8780 */ +	{ USB_DEVICE(0x1199, 0x6839) },	/* Sierra Wireless MC8781 */  	{ USB_DEVICE(0x1199, 0x683A) },	/* Sierra Wireless MC8785 */  	{ USB_DEVICE(0x1199, 0x683B) },	/* Sierra Wireless MC8785 Composite */  	/* Sierra Wireless MC8790, MC8791, MC8792 Composite */ @@ -227,16 +242,13 @@ static struct usb_device_id id_table [] = {  	{ USB_DEVICE(0x1199, 0x685A) },	/* Sierra Wireless AirCard 885 E */  	/* Sierra Wireless C885 */  	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6880, 0xFF, 0xFF, 0xFF)}, -	/* Sierra Wireless Device */ +	/* Sierra Wireless C888, Air Card 501, USB 303, USB 304 */  	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6890, 0xFF, 0xFF, 0xFF)}, -	/* Sierra Wireless Device */ +	/* Sierra Wireless C22/C33 */  	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6891, 0xFF, 0xFF, 0xFF)}, -	/* Sierra Wireless Device */ +	/* Sierra Wireless HSPA Non-Composite Device */  	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)}, - -	{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ -	{ USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */ - +	{ USB_DEVICE(0x1199, 0x6893) },	/* Sierra Wireless Device */  	{ USB_DEVICE(0x1199, 0x68A3), 	/* Sierra Wireless Direct IP modems */  	  .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist  	}, @@ -814,7 +826,7 @@ static int sierra_startup(struct usb_serial *serial)  	return 0;  } -static void sierra_disconnect(struct usb_serial *serial) +static void sierra_release(struct usb_serial *serial)  {  	int i;  	struct usb_serial_port *port; @@ -830,7 +842,6 @@ static void sierra_disconnect(struct usb_serial *serial)  		if (!portdata)  			continue;  		kfree(portdata); -		usb_set_serial_port_data(port, NULL);  	}  } @@ -853,7 +864,7 @@ static struct usb_serial_driver sierra_device = {  	.tiocmget          = sierra_tiocmget,  	.tiocmset          = sierra_tiocmset,  	.attach            = sierra_startup, -	.disconnect        = sierra_disconnect, +	.release           = sierra_release,  	.read_int_callback = sierra_instat_callback,  }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 991d8232e37..3bc609fe224 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -191,7 +191,6 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {  	{ USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },  	{ USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) },  	{ USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, -	{ USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) },  };  static struct usb_device_id ti_id_table_combined[14+2*TI_EXTRA_VID_PID_COUNT+1] = { @@ -728,7 +727,7 @@ static int ti_write_room(struct tty_struct *tty)  	dbg("%s - port %d", __func__, port->number);  	if (tport == NULL) -		return -ENODEV; +		return 0;  	spin_lock_irqsave(&tport->tp_lock, flags);  	room = ti_buf_space_avail(tport->tp_write_buf); @@ -749,7 +748,7 @@ static int ti_chars_in_buffer(struct tty_struct *tty)  	dbg("%s - port %d", __func__, port->number);  	if (tport == NULL) -		return -ENODEV; +		return 0;  	spin_lock_irqsave(&tport->tp_lock, flags);  	chars = ti_buf_data_avail(tport->tp_write_buf); @@ -1658,7 +1657,7 @@ static int ti_do_download(struct usb_device *dev, int pipe,  	u8 cs = 0;  	int done;  	struct ti_firmware_header *header; -	int status; +	int status = 0;  	int len;  	for (pos = sizeof(struct ti_firmware_header); pos < size; pos++) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index a84216464ca..99188c92068 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -21,6 +21,7 @@  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/slab.h> +#include <linux/smp_lock.h>  #include <linux/tty.h>  #include <linux/tty_driver.h>  #include <linux/tty_flip.h> @@ -31,6 +32,7 @@  #include <linux/mutex.h>  #include <linux/list.h>  #include <linux/uaccess.h> +#include <linux/serial.h>  #include <linux/usb.h>  #include <linux/usb/serial.h>  #include "pl2303.h" @@ -183,6 +185,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp)  	struct usb_serial_port *port;  	unsigned int portNumber;  	int retval = 0; +	int first = 0;  	dbg("%s", __func__); @@ -220,8 +223,9 @@ static int serial_open (struct tty_struct *tty, struct file *filp)  	tty->driver_data = port;  	tty_port_tty_set(&port->port, tty); -	if (port->port.count == 1) { - +	/* If the console is attached, the device is already open */ +	if (port->port.count == 1 && !port->console) { +		first = 1;  		/* lock this module before we call it  		 * this may fail, which means we must bail out,  		 * safe because we are called with BKL held */ @@ -244,13 +248,21 @@ static int serial_open (struct tty_struct *tty, struct file *filp)  		if (retval)  			goto bailout_interface_put;  		mutex_unlock(&serial->disc_mutex); +		set_bit(ASYNCB_INITIALIZED, &port->port.flags);  	}  	mutex_unlock(&port->mutex);  	/* Now do the correct tty layer semantics */  	retval = tty_port_block_til_ready(&port->port, tty, filp); -	if (retval == 0) +	if (retval == 0) { +		if (!first) +			usb_serial_put(serial);  		return 0; - +	} +	mutex_lock(&port->mutex); +	if (first == 0) +		goto bailout_mutex_unlock; +	/* Undo the initial port actions */ +	mutex_lock(&serial->disc_mutex);  bailout_interface_put:  	usb_autopm_put_interface(serial->interface);  bailout_module_put: @@ -338,6 +350,22 @@ static void serial_close(struct tty_struct *tty, struct file *filp)  	dbg("%s - port %d", __func__, port->number); +	/* FIXME: +	   This leaves a very narrow race. Really we should do the +	   serial_do_free() on tty->shutdown(), but tty->shutdown can +	   be called from IRQ context and serial_do_free can sleep. + +	   The right fix is probably to make the tty free (which is rare) +	   and thus tty->shutdown() occur via a work queue and simplify all +	   the drivers that use it. +	*/ +	if (tty_hung_up_p(filp)) { +		/* serial_hangup already called serial_down at this point. +		   Another user may have already reopened the port but +		   serial_do_free is refcounted */ +		serial_do_free(port); +		return; +	}  	if (tty_port_close_start(&port->port, tty, filp) == 0)  		return; @@ -353,7 +381,8 @@ static void serial_hangup(struct tty_struct *tty)  	struct usb_serial_port *port = tty->driver_data;  	serial_do_down(port);  	tty_port_hangup(&port->port); -	serial_do_free(port); +	/* We must not free port yet - the USB serial layer depends on it's +	   continued existence */  }  static int serial_write(struct tty_struct *tty, const unsigned char *buf, @@ -392,7 +421,6 @@ static int serial_chars_in_buffer(struct tty_struct *tty)  	struct usb_serial_port *port = tty->driver_data;  	dbg("%s = port %d", __func__, port->number); -	WARN_ON(!port->port.count);  	/* if the device was unplugged then any remaining characters  	   fell out of the connector ;) */  	if (port->serial->disconnected) diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c index d41cc0a970f..773a5cd38c5 100644 --- a/drivers/usb/storage/option_ms.c +++ b/drivers/usb/storage/option_ms.c @@ -118,6 +118,9 @@ static int option_inquiry(struct us_data *us)  	result = memcmp(buffer+8, "Option", 6); +	if (result != 0) +		result = memcmp(buffer+8, "ZCOPTION", 8); +  	/* Read the CSW */  	usb_stor_bulk_transfer_buf(us,  			us->recv_bulk_pipe, diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index fcb32021721..e20dc525d17 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -961,7 +961,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us)  				 US_BULK_GET_MAX_LUN,   				 USB_DIR_IN | USB_TYPE_CLASS |   				 USB_RECIP_INTERFACE, -				 0, us->ifnum, us->iobuf, 1, HZ); +				 0, us->ifnum, us->iobuf, 1, 10*HZ);  	US_DEBUGP("GetMaxLUN command result is %d, data is %d\n",   		  result, us->iobuf[0]); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 1b9c5dd0fb2..7477d411959 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -838,6 +838,13 @@ UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001,  		US_SC_DEVICE, US_PR_DEVICE, NULL,  		US_FL_FIX_CAPACITY ), +/* Reported by Rogerio Brito <rbrito@ime.usp.br> */ +UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001, +		"Prolific Technology, Inc.", +		"Mass Storage Device", +		US_SC_DEVICE, US_PR_DEVICE, NULL, +		US_FL_NOT_LOCKABLE ), +  /* Reported by Richard -=[]=- <micro_flyer@hotmail.com> */  /* Change to bcdDeviceMin (0x0100 to 0x0001) reported by   * Thomas Bartosik <tbartdev@gmx-topmail.de> */  |