diff options
Diffstat (limited to 'drivers/usb/class')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 95 | ||||
| -rw-r--r-- | drivers/usb/class/cdc-wdm.c | 53 | ||||
| -rw-r--r-- | drivers/usb/class/usblp.c | 45 | ||||
| -rw-r--r-- | drivers/usb/class/usbtmc.c | 97 |
4 files changed, 184 insertions, 106 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 36bf051b345b..54be4aa1dcb2 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -28,13 +28,14 @@ #include <linux/serial.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> +#include <linux/tty_ldisc.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/cdc.h> #include <asm/byteorder.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/idr.h> #include <linux/list.h> @@ -318,6 +319,16 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) } difference = acm->ctrlin ^ newctrl; + + if ((difference & USB_CDC_SERIAL_STATE_DCD) && acm->port.tty) { + struct tty_ldisc *ld = tty_ldisc_ref(acm->port.tty); + if (ld) { + if (ld->ops->dcd_change) + ld->ops->dcd_change(acm->port.tty, newctrl & USB_CDC_SERIAL_STATE_DCD); + tty_ldisc_deref(ld); + } + } + spin_lock_irqsave(&acm->read_lock, flags); acm->ctrlin = newctrl; acm->oldcount = acm->iocount; @@ -360,7 +371,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) static void acm_ctrl_irq(struct urb *urb) { struct acm *acm = urb->context; - struct usb_cdc_notification *dr = urb->transfer_buffer; + struct usb_cdc_notification *dr; unsigned int current_size = urb->actual_length; unsigned int expected_size, copy_size, alloc_size; int retval; @@ -387,14 +398,25 @@ static void acm_ctrl_irq(struct urb *urb) usb_mark_last_busy(acm->dev); - if (acm->nb_index) + if (acm->nb_index == 0) { + /* + * The first chunk of a message must contain at least the + * notification header with the length field, otherwise we + * can't get an expected_size. + */ + if (current_size < sizeof(struct usb_cdc_notification)) { + dev_dbg(&acm->control->dev, "urb too short\n"); + goto exit; + } + dr = urb->transfer_buffer; + } else { dr = (struct usb_cdc_notification *)acm->notification_buffer; - + } /* size = notification-header + (optional) data */ expected_size = sizeof(struct usb_cdc_notification) + le16_to_cpu(dr->wLength); - if (current_size < expected_size) { + if (acm->nb_index != 0 || current_size < expected_size) { /* notification is transmitted fragmented, reassemble */ if (acm->nb_size < expected_size) { u8 *new_buffer; @@ -651,13 +673,13 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) return tty_port_open(&acm->port, tty, filp); } -static void acm_port_dtr_rts(struct tty_port *port, int raise) +static void acm_port_dtr_rts(struct tty_port *port, bool active) { struct acm *acm = container_of(port, struct acm, port); int val; int res; - if (raise) + if (active) val = USB_CDC_CTRL_DTR | USB_CDC_CTRL_RTS; else val = 0; @@ -789,8 +811,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) tty_port_close(&acm->port, tty, filp); } -static int acm_tty_write(struct tty_struct *tty, - const unsigned char *buf, int count) +static ssize_t acm_tty_write(struct tty_struct *tty, const u8 *buf, + size_t count) { struct acm *acm = tty->driver_data; int stat; @@ -801,7 +823,7 @@ static int acm_tty_write(struct tty_struct *tty, if (!count) return 0; - dev_vdbg(&acm->data->dev, "%d bytes from tty layer\n", count); + dev_vdbg(&acm->data->dev, "%zu bytes from tty layer\n", count); spin_lock_irqsave(&acm->write_lock, flags); wbn = acm_wb_alloc(acm); @@ -818,7 +840,7 @@ static int acm_tty_write(struct tty_struct *tty, } count = (count > acm->writesize) ? acm->writesize : count; - dev_vdbg(&acm->data->dev, "writing %d bytes\n", count); + dev_vdbg(&acm->data->dev, "writing %zu bytes\n", count); memcpy(wb->buf, buf, count); wb->len = count; @@ -853,6 +875,19 @@ static unsigned int acm_tty_write_room(struct tty_struct *tty) return acm_wb_is_avail(acm) ? acm->writesize : 0; } +static void acm_tty_flush_buffer(struct tty_struct *tty) +{ + struct acm *acm = tty->driver_data; + unsigned long flags; + int i; + + spin_lock_irqsave(&acm->write_lock, flags); + for (i = 0; i < ACM_NW; i++) + if (acm->wb[i].use) + usb_unlink_urb(acm->wb[i].urb); + spin_unlock_irqrestore(&acm->write_lock, flags); +} + static unsigned int acm_tty_chars_in_buffer(struct tty_struct *tty) { struct acm *acm = tty->driver_data; @@ -892,6 +927,9 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state) struct acm *acm = tty->driver_data; int retval; + if (!(acm->ctrl_caps & USB_CDC_CAP_BRK)) + return -EOPNOTSUPP; + retval = acm_send_break(acm, state ? 0xffff : 0); if (retval < 0) dev_dbg(&acm->control->dev, @@ -935,10 +973,12 @@ static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) struct acm *acm = tty->driver_data; ss->line = acm->minor; + mutex_lock(&acm->port.mutex); ss->close_delay = jiffies_to_msecs(acm->port.close_delay) / 10; ss->closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : jiffies_to_msecs(acm->port.closing_wait) / 10; + mutex_unlock(&acm->port.mutex); return 0; } @@ -1435,7 +1475,7 @@ made_compressed_probe: if (!acm->country_codes) goto skip_countries; acm->country_code_size = cfd->bLength - 4; - memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, + memcpy(acm->country_codes, cfd->wCountryCodes, cfd->bLength - 4); acm->country_rel_date = cfd->iCountryCodeRelDate; @@ -1480,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)) { @@ -1487,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; @@ -1531,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 */ @@ -1558,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); @@ -1698,13 +1734,16 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, - { USB_DEVICE(0x045b, 0x023c), /* Renesas USB Download mode */ + { USB_DEVICE(0x045b, 0x023c), /* Renesas R-Car H3 USB Download mode */ .driver_info = DISABLE_ECHO, /* Don't echo banner */ }, - { USB_DEVICE(0x045b, 0x0248), /* Renesas USB Download mode */ + { USB_DEVICE(0x045b, 0x0247), /* Renesas R-Car D3 USB Download mode */ .driver_info = DISABLE_ECHO, /* Don't echo banner */ }, - { USB_DEVICE(0x045b, 0x024D), /* Renesas USB Download mode */ + { USB_DEVICE(0x045b, 0x0248), /* Renesas R-Car M3-N USB Download mode */ + .driver_info = DISABLE_ECHO, /* Don't echo banner */ + }, + { USB_DEVICE(0x045b, 0x024D), /* Renesas R-Car E3 USB Download mode */ .driver_info = DISABLE_ECHO, /* Don't echo banner */ }, { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */ @@ -1734,6 +1773,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */ .driver_info = SINGLE_RX_URB, }, + { USB_DEVICE(0x1901, 0x0006), /* GE Healthcare Patient Monitor UI Controller */ + .driver_info = DISABLE_ECHO, /* DISABLE ECHO in termios flag */ + }, { USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, @@ -2016,6 +2058,7 @@ static const struct tty_operations acm_ops = { .hangup = acm_tty_hangup, .write = acm_tty_write, .write_room = acm_tty_write_room, + .flush_buffer = acm_tty_flush_buffer, .ioctl = acm_tty_ioctl, .throttle = acm_tty_throttle, .unthrottle = acm_tty_unthrottle, diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 1f0951be15ab..ecd6d1f39e49 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -26,7 +26,7 @@ #include <linux/usb/cdc.h> #include <linux/wwan.h> #include <asm/byteorder.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/usb/cdc-wdm.h> #define DRIVER_AUTHOR "Oliver Neukum" @@ -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); @@ -266,14 +270,14 @@ static void wdm_int_callback(struct urb *urb) dev_err(&desc->intf->dev, "Stall on int endpoint\n"); goto sw; /* halt is cleared in work */ default: - dev_err(&desc->intf->dev, + dev_err_ratelimited(&desc->intf->dev, "nonzero urb status received: %d\n", status); break; } } if (urb->actual_length < sizeof(struct usb_cdc_notification)) { - dev_err(&desc->intf->dev, "wdm_int_callback - %d bytes\n", + dev_err_ratelimited(&desc->intf->dev, "wdm_int_callback - %d bytes\n", urb->actual_length); goto exit; } @@ -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; @@ -929,7 +935,8 @@ static void wdm_wwan_init(struct wdm_device *desc) return; } - port = wwan_create_port(&intf->dev, desc->wwanp_type, &wdm_wwan_port_ops, desc); + port = wwan_create_port(&intf->dev, desc->wwanp_type, &wdm_wwan_port_ops, + NULL, desc); if (IS_ERR(port)) { dev_err(&intf->dev, "%s: Unable to create WWAN port\n", dev_name(intf->usb_dev)); @@ -1004,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 5a2e43331064..a7a1d38b6bef 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -34,6 +34,7 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/minmax.h> #include <linux/sched/signal.h> #include <linux/signal.h> #include <linux/poll.h> @@ -87,7 +88,7 @@ /* Get two-int array: [0]=vendor ID, [1]=product ID: */ #define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len) /* Perform class specific soft reset */ -#define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0); +#define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0) /* * A DEVICE_ID string may include the printer's serial number. @@ -366,7 +367,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 +753,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 +780,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,22 +863,24 @@ 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; } - count = len < avail - usblp->readcount ? len : avail - usblp->readcount; + count = min_t(ssize_t, len, avail - usblp->readcount); if (count != 0 && copy_to_user(buffer, usblp->readbuf + usblp->readcount, count)) { count = -EFAULT; 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 +981,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 +1040,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 +1160,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 +1171,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; } @@ -1337,11 +1349,12 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol) if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) return -EINVAL; + alts = usblp->protocol[protocol].alt_setting; + if (alts < 0) + return -EINVAL; + /* Don't unnecessarily set the interface if there's a single alt. */ if (usblp->intf->num_altsetting > 1) { - alts = usblp->protocol[protocol].alt_setting; - if (alts < 0) - return -EINVAL; r = usb_set_interface(usblp->dev, usblp->ifnum, alts); if (r < 0) { printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n", diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 4bb6d304eb4b..206f1b738ed3 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; } @@ -754,7 +760,7 @@ static struct urb *usbtmc_create_urb(void) if (!urb) return NULL; - dmabuf = kmalloc(bufsize, GFP_KERNEL); + dmabuf = kzalloc(bufsize, GFP_KERNEL); if (!dmabuf) { usb_free_urb(urb); return NULL; @@ -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; } @@ -1920,14 +1936,14 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, u8 *buffer = NULL; int rv; unsigned int is_in, pipe; - unsigned long res; - res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest)); - if (res) + if (copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest))) return -EFAULT; if (request.req.wLength > USBTMC_BUFSIZE) return -EMSGSIZE; + if (request.req.wLength == 0) /* Length-0 requests are never IN */ + request.req.bRequestType &= ~USB_DIR_IN; is_in = request.req.bRequestType & USB_DIR_IN; @@ -1938,9 +1954,8 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, if (!is_in) { /* Send control data to device */ - res = copy_from_user(buffer, request.data, - request.req.wLength); - if (res) { + if (copy_from_user(buffer, request.data, + request.req.wLength)) { rv = -EFAULT; goto exit; } @@ -1966,8 +1981,7 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, if (rv && is_in) { /* Read control data from device */ - res = copy_to_user(request.data, buffer, rv); - if (res) + if (copy_to_user(request.data, buffer, rv)) rv = -EFAULT; } @@ -2184,7 +2198,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; @@ -2590,4 +2604,5 @@ static struct usb_driver usbtmc_driver = { module_usb_driver(usbtmc_driver); +MODULE_DESCRIPTION("USB Test & Measurement class driver"); MODULE_LICENSE("GPL"); |
