summaryrefslogtreecommitdiff
path: root/drivers/usb/class
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/class')
-rw-r--r--drivers/usb/class/Kconfig6
-rw-r--r--drivers/usb/class/cdc-acm.c61
-rw-r--r--drivers/usb/class/cdc-wdm.c42
-rw-r--r--drivers/usb/class/usbtmc.c26
4 files changed, 70 insertions, 65 deletions
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 316aac8e4ca1..bb8b73682a70 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -2,11 +2,10 @@
# USB Class driver configuration
#
comment "USB Device Class drivers"
- depends on USB
config USB_ACM
tristate "USB Modem (CDC ACM) support"
- depends on USB && TTY
+ depends on TTY
---help---
This driver supports USB modems and ISDN adapters which support the
Communication Device Class Abstract Control Model interface.
@@ -21,7 +20,6 @@ config USB_ACM
config USB_PRINTER
tristate "USB Printer support"
- depends on USB
help
Say Y here if you want to connect a USB printer to your computer's
USB port.
@@ -31,7 +29,6 @@ config USB_PRINTER
config USB_WDM
tristate "USB Wireless Device Management support"
- depends on USB
---help---
This driver supports the WMC Device Management functionality
of cell phones compliant to the CDC WMC specification. You can use
@@ -42,7 +39,6 @@ config USB_WDM
config USB_TMC
tristate "USB Test and Measurement Class support"
- depends on USB
help
Say Y here if you want to connect a USB device that follows
the USB.org specification for USB Test and Measurement devices
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 8ac25adf31b4..171d7a9df3ae 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -292,7 +292,6 @@ static void acm_ctrl_irq(struct urb *urb)
{
struct acm *acm = urb->context;
struct usb_cdc_notification *dr = urb->transfer_buffer;
- struct tty_struct *tty;
unsigned char *data;
int newctrl;
int retval;
@@ -327,17 +326,12 @@ static void acm_ctrl_irq(struct urb *urb)
break;
case USB_CDC_NOTIFY_SERIAL_STATE:
- tty = tty_port_tty_get(&acm->port);
newctrl = get_unaligned_le16(data);
- if (tty) {
- if (!acm->clocal &&
- (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
- dev_dbg(&acm->control->dev,
- "%s - calling hangup\n", __func__);
- tty_hangup(tty);
- }
- tty_kref_put(tty);
+ if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
+ dev_dbg(&acm->control->dev, "%s - calling hangup\n",
+ __func__);
+ tty_port_tty_hangup(&acm->port, false);
}
acm->ctrlin = newctrl;
@@ -475,15 +469,10 @@ static void acm_write_bulk(struct urb *urb)
static void acm_softint(struct work_struct *work)
{
struct acm *acm = container_of(work, struct acm, work);
- struct tty_struct *tty;
dev_vdbg(&acm->data->dev, "%s\n", __func__);
- tty = tty_port_tty_get(&acm->port);
- if (!tty)
- return;
- tty_wakeup(tty);
- tty_kref_put(tty);
+ tty_port_tty_wakeup(&acm->port);
}
/*
@@ -593,7 +582,6 @@ static void acm_port_destruct(struct tty_port *port)
dev_dbg(&acm->control->dev, "%s\n", __func__);
- tty_unregister_device(acm_tty_driver, acm->minor);
acm_release_minor(acm);
usb_put_intf(acm->control);
kfree(acm->country_codes);
@@ -840,14 +828,6 @@ static int acm_tty_ioctl(struct tty_struct *tty,
return rv;
}
-static const __u32 acm_tty_speed[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600,
- 1200, 1800, 2400, 4800, 9600, 19200, 38400,
- 57600, 115200, 230400, 460800, 500000, 576000,
- 921600, 1000000, 1152000, 1500000, 2000000,
- 2500000, 3000000, 3500000, 4000000
-};
-
static void acm_tty_set_termios(struct tty_struct *tty,
struct ktermios *termios_old)
{
@@ -977,6 +957,8 @@ static int acm_probe(struct usb_interface *intf,
int num_rx_buf;
int i;
int combined_interfaces = 0;
+ struct device *tty_dev;
+ int rv = -ENOMEM;
/* normal quirks */
quirks = (unsigned long)id->driver_info;
@@ -1339,11 +1321,24 @@ skip_countries:
usb_set_intfdata(data_interface, acm);
usb_get_intf(control_interface);
- tty_port_register_device(&acm->port, acm_tty_driver, minor,
+ tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor,
&control_interface->dev);
+ if (IS_ERR(tty_dev)) {
+ rv = PTR_ERR(tty_dev);
+ goto alloc_fail8;
+ }
return 0;
+alloc_fail8:
+ if (acm->country_codes) {
+ device_remove_file(&acm->control->dev,
+ &dev_attr_wCountryCodes);
+ device_remove_file(&acm->control->dev,
+ &dev_attr_iCountryCodeRelDate);
+ }
+ device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
alloc_fail7:
+ usb_set_intfdata(intf, NULL);
for (i = 0; i < ACM_NW; i++)
usb_free_urb(acm->wb[i].urb);
alloc_fail6:
@@ -1359,7 +1354,7 @@ alloc_fail2:
acm_release_minor(acm);
kfree(acm);
alloc_fail:
- return -ENOMEM;
+ return rv;
}
static void stop_data_traffic(struct acm *acm)
@@ -1411,6 +1406,8 @@ static void acm_disconnect(struct usb_interface *intf)
stop_data_traffic(acm);
+ tty_unregister_device(acm_tty_driver, acm->minor);
+
usb_free_urb(acm->ctrlurb);
for (i = 0; i < ACM_NW; i++)
usb_free_urb(acm->wb[i].urb);
@@ -1503,15 +1500,9 @@ err_out:
static int acm_reset_resume(struct usb_interface *intf)
{
struct acm *acm = usb_get_intfdata(intf);
- struct tty_struct *tty;
- if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
- tty = tty_port_tty_get(&acm->port);
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
- }
+ if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
+ tty_port_tty_hangup(&acm->port, false);
return acm_resume(intf);
}
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 5f0cb417b736..8a230f0ef77c 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -13,6 +13,7 @@
*/
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -56,6 +57,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_RESPONDING 7
#define WDM_SUSPENDING 8
#define WDM_RESETTING 9
+#define WDM_OVERFLOW 10
#define WDM_MAX 16
@@ -155,6 +157,7 @@ static void wdm_in_callback(struct urb *urb)
{
struct wdm_device *desc = urb->context;
int status = urb->status;
+ int length = urb->actual_length;
spin_lock(&desc->iuspin);
clear_bit(WDM_RESPONDING, &desc->flags);
@@ -185,9 +188,17 @@ static void wdm_in_callback(struct urb *urb)
}
desc->rerr = status;
- desc->reslength = urb->actual_length;
- memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength);
- desc->length += desc->reslength;
+ if (length + desc->length > desc->wMaxCommand) {
+ /* The buffer would overflow */
+ set_bit(WDM_OVERFLOW, &desc->flags);
+ } else {
+ /* we may already be in overflow */
+ if (!test_bit(WDM_OVERFLOW, &desc->flags)) {
+ memmove(desc->ubuf + desc->length, desc->inbuf, length);
+ desc->length += length;
+ desc->reslength = length;
+ }
+ }
skip_error:
wake_up(&desc->wait);
@@ -435,6 +446,11 @@ retry:
rv = -ENODEV;
goto err;
}
+ if (test_bit(WDM_OVERFLOW, &desc->flags)) {
+ clear_bit(WDM_OVERFLOW, &desc->flags);
+ rv = -ENOBUFS;
+ goto err;
+ }
i++;
if (file->f_flags & O_NONBLOCK) {
if (!test_bit(WDM_READ, &desc->flags)) {
@@ -478,6 +494,7 @@ retry:
spin_unlock_irq(&desc->iuspin);
goto retry;
}
+
if (!desc->reslength) { /* zero length read */
dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__);
clear_bit(WDM_READ, &desc->flags);
@@ -628,6 +645,22 @@ static int wdm_release(struct inode *inode, struct file *file)
return 0;
}
+static long wdm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct wdm_device *desc = file->private_data;
+ int rv = 0;
+
+ switch (cmd) {
+ case IOCTL_WDM_MAX_COMMAND:
+ if (copy_to_user((void __user *)arg, &desc->wMaxCommand, sizeof(desc->wMaxCommand)))
+ rv = -EFAULT;
+ break;
+ default:
+ rv = -ENOTTY;
+ }
+ return rv;
+}
+
static const struct file_operations wdm_fops = {
.owner = THIS_MODULE,
.read = wdm_read,
@@ -636,6 +669,8 @@ static const struct file_operations wdm_fops = {
.flush = wdm_flush,
.release = wdm_release,
.poll = wdm_poll,
+ .unlocked_ioctl = wdm_ioctl,
+ .compat_ioctl = wdm_ioctl,
.llseek = noop_llseek,
};
@@ -1004,6 +1039,7 @@ static int wdm_post_reset(struct usb_interface *intf)
struct wdm_device *desc = wdm_find_device(intf);
int rv;
+ clear_bit(WDM_OVERFLOW, &desc->flags);
clear_bit(WDM_RESETTING, &desc->flags);
rv = recover_from_urb_loss(desc);
mutex_unlock(&desc->wlock);
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 70d69d06054f..4c5506ae5e45 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -718,50 +718,32 @@ exit:
static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data)
{
- u8 *buffer;
int rv;
- buffer = kmalloc(2, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
if (rv < 0) {
dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
rv);
- goto exit;
+ return rv;
}
- rv = 0;
-
-exit:
- kfree(buffer);
- return rv;
+ return 0;
}
static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
{
- u8 *buffer;
int rv;
- buffer = kmalloc(2, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
rv = usb_clear_halt(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
if (rv < 0) {
dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
rv);
- goto exit;
+ return rv;
}
- rv = 0;
-
-exit:
- kfree(buffer);
- return rv;
+ return 0;
}
static int get_capabilities(struct usbtmc_device_data *data)