Merge tag 'v3.9-rc3' into next
Merge with mainline to bring in module_platform_driver_probe() and devm_ioremap_resource().
This commit is contained in:
@@ -6,7 +6,7 @@ comment "USB Device Class drivers"
|
||||
|
||||
config USB_ACM
|
||||
tristate "USB Modem (CDC ACM) support"
|
||||
depends on USB
|
||||
depends on USB && TTY
|
||||
---help---
|
||||
This driver supports USB modems and ISDN adapters which support the
|
||||
Communication Device Class Abstract Control Model interface.
|
||||
|
@@ -410,19 +410,12 @@ static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags)
|
||||
|
||||
static void acm_process_read_urb(struct acm *acm, struct urb *urb)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (!urb->actual_length)
|
||||
return;
|
||||
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length);
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
tty_kref_put(tty);
|
||||
tty_insert_flip_string(&acm->port, urb->transfer_buffer,
|
||||
urb->actual_length);
|
||||
tty_flip_buffer_push(&acm->port);
|
||||
}
|
||||
|
||||
static void acm_read_bulk_callback(struct urb *urb)
|
||||
@@ -787,6 +780,10 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
|
||||
tmp.flags = ASYNC_LOW_LATENCY;
|
||||
tmp.xmit_fifo_size = acm->writesize;
|
||||
tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
|
||||
tmp.close_delay = acm->port.close_delay / 10;
|
||||
tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
|
||||
ASYNC_CLOSING_WAIT_NONE :
|
||||
acm->port.closing_wait / 10;
|
||||
|
||||
if (copy_to_user(info, &tmp, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
@@ -794,6 +791,37 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_serial_info(struct acm *acm,
|
||||
struct serial_struct __user *newinfo)
|
||||
{
|
||||
struct serial_struct new_serial;
|
||||
unsigned int closing_wait, close_delay;
|
||||
int retval = 0;
|
||||
|
||||
if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
|
||||
return -EFAULT;
|
||||
|
||||
close_delay = new_serial.close_delay * 10;
|
||||
closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
|
||||
ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
|
||||
|
||||
mutex_lock(&acm->port.mutex);
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
if ((close_delay != acm->port.close_delay) ||
|
||||
(closing_wait != acm->port.closing_wait))
|
||||
retval = -EPERM;
|
||||
else
|
||||
retval = -EOPNOTSUPP;
|
||||
} else {
|
||||
acm->port.close_delay = close_delay;
|
||||
acm->port.closing_wait = closing_wait;
|
||||
}
|
||||
|
||||
mutex_unlock(&acm->port.mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int acm_tty_ioctl(struct tty_struct *tty,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
@@ -804,6 +832,9 @@ static int acm_tty_ioctl(struct tty_struct *tty,
|
||||
case TIOCGSERIAL: /* gets serial port data */
|
||||
rv = get_serial_info(acm, (struct serial_struct __user *) arg);
|
||||
break;
|
||||
case TIOCSSERIAL:
|
||||
rv = set_serial_info(acm, (struct serial_struct __user *) arg);
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
@@ -1568,6 +1599,9 @@ static const struct usb_device_id acm_ids[] = {
|
||||
{ USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */
|
||||
.driver_info = NO_UNION_NORMAL,
|
||||
},
|
||||
{ USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */
|
||||
.driver_info = NO_UNION_NORMAL,
|
||||
},
|
||||
{ USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
|
||||
.driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
|
||||
},
|
||||
|
@@ -56,6 +56,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 +156,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 +187,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 +445,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 +493,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);
|
||||
@@ -1004,6 +1020,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);
|
||||
|
Reference in New Issue
Block a user