diff options
Diffstat (limited to 'drivers/usb/class')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 18 | ||||
| -rw-r--r-- | drivers/usb/class/cdc-wdm.c | 44 | ||||
| -rw-r--r-- | drivers/usb/class/usblp.c | 33 | ||||
| -rw-r--r-- | drivers/usb/class/usbtmc.c | 80 | 
4 files changed, 102 insertions, 73 deletions
| diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index c2ecfa3c8349..73f9476774ae 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1520,6 +1520,12 @@ skip_countries:  			goto err_remove_files;  	} +	if (quirks & CLEAR_HALT_CONDITIONS) { +		/* errors intentionally ignored */ +		usb_clear_halt(usb_dev, acm->in); +		usb_clear_halt(usb_dev, acm->out); +	} +  	tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor,  			&control_interface->dev);  	if (IS_ERR(tty_dev)) { @@ -1527,11 +1533,6 @@ skip_countries:  		goto err_release_data_interface;  	} -	if (quirks & CLEAR_HALT_CONDITIONS) { -		usb_clear_halt(usb_dev, acm->in); -		usb_clear_halt(usb_dev, acm->out); -	} -  	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);  	return 0; @@ -1571,7 +1572,6 @@ err_put_port:  static void acm_disconnect(struct usb_interface *intf)  {  	struct acm *acm = usb_get_intfdata(intf); -	struct tty_struct *tty;  	int i;  	/* sibling interface is already cleaning up */ @@ -1598,11 +1598,7 @@ static void acm_disconnect(struct usb_interface *intf)  	usb_set_intfdata(acm->data, NULL);  	mutex_unlock(&acm->mutex); -	tty = tty_port_tty_get(&acm->port); -	if (tty) { -		tty_vhangup(tty); -		tty_kref_put(tty); -	} +	tty_port_tty_vhangup(&acm->port);  	cancel_delayed_work_sync(&acm->dwork); diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 86ee39db013f..ecd6d1f39e49 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -92,7 +92,6 @@ struct wdm_device {  	u16			wMaxCommand;  	u16			wMaxPacketSize;  	__le16			inum; -	int			reslength;  	int			length;  	int			read;  	int			count; @@ -214,6 +213,11 @@ static void wdm_in_callback(struct urb *urb)  	if (desc->rerr == 0 && status != -EPIPE)  		desc->rerr = status; +	if (length == 0) { +		dev_dbg(&desc->intf->dev, "received ZLP\n"); +		goto skip_zlp; +	} +  	if (length + desc->length > desc->wMaxCommand) {  		/* The buffer would overflow */  		set_bit(WDM_OVERFLOW, &desc->flags); @@ -222,18 +226,18 @@ static void wdm_in_callback(struct urb *urb)  		if (!test_bit(WDM_OVERFLOW, &desc->flags)) {  			memmove(desc->ubuf + desc->length, desc->inbuf, length);  			desc->length += length; -			desc->reslength = length;  		}  	}  skip_error:  	if (desc->rerr) {  		/* -		 * Since there was an error, userspace may decide to not read -		 * any data after poll'ing. +		 * If there was a ZLP or an error, userspace may decide to not +		 * read any data after poll'ing.  		 * We should respond to further attempts from the device to send  		 * data, so that we can get unstuck.  		 */ +skip_zlp:  		schedule_work(&desc->service_outs_intr);  	} else {  		set_bit(WDM_READ, &desc->flags); @@ -585,15 +589,6 @@ retry:  			goto retry;  		} -		if (!desc->reslength) { /* zero length read */ -			dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ\n"); -			clear_bit(WDM_READ, &desc->flags); -			rv = service_outstanding_interrupt(desc); -			spin_unlock_irq(&desc->iuspin); -			if (rv < 0) -				goto err; -			goto retry; -		}  		cntr = desc->length;  		spin_unlock_irq(&desc->iuspin);  	} @@ -726,7 +721,7 @@ static int wdm_open(struct inode *inode, struct file *file)  		rv = -EBUSY;  		goto out;  	} - +	smp_rmb(); /* ordered against wdm_wwan_port_stop() */  	rv = usb_autopm_get_interface(desc->intf);  	if (rv < 0) {  		dev_err(&desc->intf->dev, "Error autopm - %d\n", rv); @@ -829,6 +824,7 @@ static struct usb_class_driver wdm_class = {  static int wdm_wwan_port_start(struct wwan_port *port)  {  	struct wdm_device *desc = wwan_port_get_drvdata(port); +	int rv;  	/* The interface is both exposed via the WWAN framework and as a  	 * legacy usbmisc chardev. If chardev is already open, just fail @@ -848,7 +844,15 @@ static int wdm_wwan_port_start(struct wwan_port *port)  	wwan_port_txon(port);  	/* Start getting events */ -	return usb_submit_urb(desc->validity, GFP_KERNEL); +	rv = usb_submit_urb(desc->validity, GFP_KERNEL); +	if (rv < 0) { +		wwan_port_txoff(port); +		desc->manage_power(desc->intf, 0); +		/* this must be last lest we race with chardev open */ +		clear_bit(WDM_WWAN_IN_USE, &desc->flags); +	} + +	return rv;  }  static void wdm_wwan_port_stop(struct wwan_port *port) @@ -859,8 +863,10 @@ static void wdm_wwan_port_stop(struct wwan_port *port)  	poison_urbs(desc);  	desc->manage_power(desc->intf, 0);  	clear_bit(WDM_READ, &desc->flags); -	clear_bit(WDM_WWAN_IN_USE, &desc->flags);  	unpoison_urbs(desc); +	smp_wmb(); /* ordered against wdm_open() */ +	/* this must be last lest we open a poisoned device */ +	clear_bit(WDM_WWAN_IN_USE, &desc->flags);  }  static void wdm_wwan_port_tx_complete(struct urb *urb) @@ -868,7 +874,7 @@ static void wdm_wwan_port_tx_complete(struct urb *urb)  	struct sk_buff *skb = urb->context;  	struct wdm_device *desc = skb_shinfo(skb)->destructor_arg; -	usb_autopm_put_interface(desc->intf); +	usb_autopm_put_interface_async(desc->intf);  	wwan_port_txon(desc->wwanp);  	kfree_skb(skb);  } @@ -898,7 +904,7 @@ static int wdm_wwan_port_tx(struct wwan_port *port, struct sk_buff *skb)  	req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE);  	req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;  	req->wValue = 0; -	req->wIndex = desc->inum; +	req->wIndex = desc->inum; /* already converted */  	req->wLength = cpu_to_le16(skb->len);  	skb_shinfo(skb)->destructor_arg = desc; @@ -1005,7 +1011,7 @@ static void service_interrupt_work(struct work_struct *work)  	spin_lock_irq(&desc->iuspin);  	service_outstanding_interrupt(desc); -	if (!desc->resp_count) { +	if (!desc->resp_count && (desc->length || desc->rerr)) {  		set_bit(WDM_READ, &desc->flags);  		wake_up(&desc->wait);  	} diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index e2527faa6592..acbefccbdb2a 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -366,7 +366,8 @@ static int usblp_check_status(struct usblp *usblp, int err)  	int error;  	mutex_lock(&usblp->mut); -	if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { +	error = usblp_read_status(usblp, usblp->statusbuf); +	if (error < 0) {  		mutex_unlock(&usblp->mut);  		printk_ratelimited(KERN_ERR  				"usblp%d: error %d reading printer status\n", @@ -751,14 +752,16 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t  		rv = -EINTR;  		goto raise_biglock;  	} -	if ((rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK))) < 0) +	rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK)); +	if (rv < 0)  		goto raise_wait;  	while (writecount < count) {  		/*  		 * Step 1: Submit next block.  		 */ -		if ((transfer_length = count - writecount) > USBLP_BUF_SIZE) +		transfer_length = count - writecount; +		if (transfer_length > USBLP_BUF_SIZE)  			transfer_length = USBLP_BUF_SIZE;  		rv = -ENOMEM; @@ -776,7 +779,9 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t  		spin_lock_irq(&usblp->lock);  		usblp->wcomplete = 0;  		spin_unlock_irq(&usblp->lock); -		if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { + +		rv = usb_submit_urb(writeurb, GFP_KERNEL); +		if (rv < 0) {  			usblp->wstatus = 0;  			spin_lock_irq(&usblp->lock);  			usblp->no_paper = 0; @@ -857,9 +862,10 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo  		goto done;  	} -	if ((avail = usblp->rstatus) < 0) { +	avail = usblp->rstatus; +	if (avail < 0) {  		printk(KERN_ERR "usblp%d: error %d reading from printer\n", -		    usblp->minor, (int)avail); +			usblp->minor, (int)avail);  		usblp_submit_read(usblp);  		count = -EIO;  		goto done; @@ -872,7 +878,8 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo  		goto done;  	} -	if ((usblp->readcount += count) == avail) { +	usblp->readcount += count; +	if (usblp->readcount == avail) {  		if (usblp_submit_read(usblp) < 0) {  			/* We don't want to leak USB return codes into errno. */  			if (count == 0) @@ -973,7 +980,8 @@ static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock)  			break;  		}  		set_current_state(TASK_INTERRUPTIBLE); -		if ((rc = usblp_rtest(usblp, nonblock)) < 0) { +		rc = usblp_rtest(usblp, nonblock); +		if (rc < 0) {  			mutex_unlock(&usblp->mut);  			break;  		} @@ -1031,7 +1039,8 @@ static int usblp_submit_read(struct usblp *usblp)  	usblp->readcount = 0; /* XXX Why here? */  	usblp->rcomplete = 0;  	spin_unlock_irqrestore(&usblp->lock, flags); -	if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) { +	rc = usb_submit_urb(urb, GFP_KERNEL); +	if (rc < 0) {  		dev_dbg(&usblp->intf->dev, "error submitting urb (%d)\n", rc);  		spin_lock_irqsave(&usblp->lock, flags);  		usblp->rstatus = rc; @@ -1150,7 +1159,8 @@ static int usblp_probe(struct usb_interface *intf,  	/* Malloc device ID string buffer to the largest expected length,  	 * since we can re-query it on an ioctl and a dynamic string  	 * could change in length. */ -	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) { +	usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL); +	if (!usblp->device_id_string) {  		retval = -ENOMEM;  		goto abort;  	} @@ -1160,7 +1170,8 @@ static int usblp_probe(struct usb_interface *intf,  	 * malloc both regardless of bidirectionality, because the  	 * alternate setting can be changed later via an ioctl.  	 */ -	if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) { +	usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL); +	if (!usblp->readbuf) {  		retval = -ENOMEM;  		goto abort;  	} diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 34e46ef308ab..75de29725a45 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -482,6 +482,8 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb)  	u8 *buffer;  	u8 tag;  	int rv; +	long wait_rv; +	unsigned long expire;  	dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",  		data->iin_ep_present); @@ -511,16 +513,18 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb)  	}  	if (data->iin_ep_present) { -		rv = wait_event_interruptible_timeout( +		expire = msecs_to_jiffies(file_data->timeout); +		wait_rv = wait_event_interruptible_timeout(  			data->waitq,  			atomic_read(&data->iin_data_valid) != 0, -			file_data->timeout); -		if (rv < 0) { -			dev_dbg(dev, "wait interrupted %d\n", rv); +			expire); +		if (wait_rv < 0) { +			dev_dbg(dev, "wait interrupted %ld\n", wait_rv); +			rv = wait_rv;  			goto exit;  		} -		if (rv == 0) { +		if (wait_rv == 0) {  			dev_dbg(dev, "wait timed out\n");  			rv = -ETIMEDOUT;  			goto exit; @@ -539,6 +543,8 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb)  	dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)*stb, rv); +	rv = 0; +   exit:  	/* bump interrupt bTag */  	data->iin_bTag += 1; @@ -559,14 +565,15 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,  	rv = usbtmc_get_stb(file_data, &stb); -	if (rv > 0) { -		srq_asserted = atomic_xchg(&file_data->srq_asserted, -					srq_asserted); -		if (srq_asserted) -			stb |= 0x40; /* Set RQS bit */ +	if (rv < 0) +		return rv; + +	srq_asserted = atomic_xchg(&file_data->srq_asserted, srq_asserted); +	if (srq_asserted) +		stb |= 0x40; /* Set RQS bit */ + +	rv = put_user(stb, (__u8 __user *)arg); -		rv = put_user(stb, (__u8 __user *)arg); -	}  	return rv;  } @@ -602,9 +609,9 @@ static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data,  {  	struct usbtmc_device_data *data = file_data->data;  	struct device *dev = &data->intf->dev; -	int rv;  	u32 timeout;  	unsigned long expire; +	long wait_rv;  	if (!data->iin_ep_present) {  		dev_dbg(dev, "no interrupt endpoint present\n"); @@ -618,25 +625,24 @@ static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data,  	mutex_unlock(&data->io_mutex); -	rv = wait_event_interruptible_timeout( -			data->waitq, -			atomic_read(&file_data->srq_asserted) != 0 || -			atomic_read(&file_data->closing), -			expire); +	wait_rv = wait_event_interruptible_timeout( +		data->waitq, +		atomic_read(&file_data->srq_asserted) != 0 || +		atomic_read(&file_data->closing), +		expire);  	mutex_lock(&data->io_mutex);  	/* Note! disconnect or close could be called in the meantime */  	if (atomic_read(&file_data->closing) || data->zombie) -		rv = -ENODEV; +		return -ENODEV; -	if (rv < 0) { -		/* dev can be invalid now! */ -		pr_debug("%s - wait interrupted %d\n", __func__, rv); -		return rv; +	if (wait_rv < 0) { +		dev_dbg(dev, "%s - wait interrupted %ld\n", __func__, wait_rv); +		return wait_rv;  	} -	if (rv == 0) { +	if (wait_rv == 0) {  		dev_dbg(dev, "%s - wait timed out\n", __func__);  		return -ETIMEDOUT;  	} @@ -830,6 +836,7 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data,  	unsigned long expire;  	int bufcount = 1;  	int again = 0; +	long wait_rv;  	/* mutex already locked */ @@ -942,19 +949,24 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data,  		if (!(flags & USBTMC_FLAG_ASYNC)) {  			dev_dbg(dev, "%s: before wait time %lu\n",  				__func__, expire); -			retval = wait_event_interruptible_timeout( +			wait_rv = wait_event_interruptible_timeout(  				file_data->wait_bulk_in,  				usbtmc_do_transfer(file_data),  				expire); -			dev_dbg(dev, "%s: wait returned %d\n", -				__func__, retval); +			dev_dbg(dev, "%s: wait returned %ld\n", +				__func__, wait_rv); + +			if (wait_rv < 0) { +				retval = wait_rv; +				goto error; +			} -			if (retval <= 0) { -				if (retval == 0) -					retval = -ETIMEDOUT; +			if (wait_rv == 0) { +				retval = -ETIMEDOUT;  				goto error;  			} +  		}  		urb = usb_get_from_anchor(&file_data->in_anchor); @@ -1380,7 +1392,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,  	if (!buffer)  		return -ENOMEM; -	mutex_lock(&data->io_mutex); +	retval = mutex_lock_interruptible(&data->io_mutex); +	if (retval < 0) +		goto exit_nolock; +  	if (data->zombie) {  		retval = -ENODEV;  		goto exit; @@ -1503,6 +1518,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,  exit:  	mutex_unlock(&data->io_mutex); +exit_nolock:  	kfree(buffer);  	return retval;  } @@ -2186,7 +2202,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  	case USBTMC_IOCTL_GET_STB:  		retval = usbtmc_get_stb(file_data, &tmp_byte); -		if (retval > 0) +		if (!retval)  			retval = put_user(tmp_byte, (__u8 __user *)arg);  		break; | 
