Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / drivers / usb / class / cdc-acm.c
index 6647081..210b533 100644 (file)
@@ -293,6 +293,12 @@ static void acm_ctrl_irq(struct urb *urb)
                break;
 
        case USB_CDC_NOTIFY_SERIAL_STATE:
+               if (le16_to_cpu(dr->wLength) != 2) {
+                       dev_dbg(&acm->control->dev,
+                               "%s - malformed serial state\n", __func__);
+                       break;
+               }
+
                tty = tty_port_tty_get(&acm->port);
                newctrl = get_unaligned_le16(data);
 
@@ -323,11 +329,10 @@ static void acm_ctrl_irq(struct urb *urb)
 
        default:
                dev_dbg(&acm->control->dev,
-                       "%s - unknown notification %d received: index %d "
-                       "len %d data0 %d data1 %d\n",
+                       "%s - unknown notification %d received: index %d len %d\n",
                        __func__,
-                       dr->bNotificationType, dr->wIndex,
-                       dr->wLength, data[0], data[1]);
+                       dr->bNotificationType, dr->wIndex, dr->wLength);
+
                break;
        }
 exit:
@@ -911,16 +916,24 @@ static int acm_probe(struct usb_interface *intf,
        unsigned long quirks;
        int num_rx_buf;
        int i;
+       unsigned int elength = 0;
        int combined_interfaces = 0;
 
        /* normal quirks */
        quirks = (unsigned long)id->driver_info;
+
+       if (quirks == IGNORE_DEVICE)
+               return -ENODEV;
+
        num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
 
        /* handle quirks deadly to normal probing*/
        if (quirks == NO_UNION_NORMAL) {
                data_interface = usb_ifnum_to_if(usb_dev, 1);
                control_interface = usb_ifnum_to_if(usb_dev, 0);
+               /* we would crash */
+               if (!data_interface || !control_interface)
+                       return -ENODEV;
                goto skip_normal_probe;
        }
 
@@ -946,6 +959,12 @@ static int acm_probe(struct usb_interface *intf,
        }
 
        while (buflen > 0) {
+               elength = buffer[0];
+               if (!elength) {
+                       dev_err(&intf->dev, "skipping garbage byte\n");
+                       elength = 1;
+                       goto next_desc;
+               }
                if (buffer[1] != USB_DT_CS_INTERFACE) {
                        dev_err(&intf->dev, "skipping garbage\n");
                        goto next_desc;
@@ -953,6 +972,8 @@ static int acm_probe(struct usb_interface *intf,
 
                switch (buffer[2]) {
                case USB_CDC_UNION_TYPE: /* we've found it */
+                       if (elength < sizeof(struct usb_cdc_union_desc))
+                               goto next_desc;
                        if (union_header) {
                                dev_err(&intf->dev, "More than one "
                                        "union descriptor, skipping ...\n");
@@ -961,31 +982,38 @@ static int acm_probe(struct usb_interface *intf,
                        union_header = (struct usb_cdc_union_desc *)buffer;
                        break;
                case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
+                       if (elength < sizeof(struct usb_cdc_country_functional_desc))
+                               goto next_desc;
                        cfd = (struct usb_cdc_country_functional_desc *)buffer;
                        break;
                case USB_CDC_HEADER_TYPE: /* maybe check version */
                        break; /* for now we ignore it */
                case USB_CDC_ACM_TYPE:
+                       if (elength < 4)
+                               goto next_desc;
                        ac_management_function = buffer[3];
                        break;
                case USB_CDC_CALL_MANAGEMENT_TYPE:
+                       if (elength < 5)
+                               goto next_desc;
                        call_management_function = buffer[3];
                        call_interface_num = buffer[4];
                        if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
                                dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
                        break;
                default:
-                       /* there are LOTS more CDC descriptors that
+                       /*
+                        * there are LOTS more CDC descriptors that
                         * could legitimately be found here.
                         */
                        dev_dbg(&intf->dev, "Ignoring descriptor: "
-                                       "type %02x, length %d\n",
-                                       buffer[2], buffer[0]);
+                                       "type %02x, length %ud\n",
+                                       buffer[2], elength);
                        break;
                }
 next_desc:
-               buflen -= buffer[0];
-               buffer += buffer[0];
+               buflen -= elength;
+               buffer += elength;
        }
 
        if (!union_header) {
@@ -1011,10 +1039,11 @@ next_desc:
        } else {
                control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
                data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
-               if (!control_interface || !data_interface) {
-                       dev_dbg(&intf->dev, "no interfaces\n");
-                       return -ENODEV;
-               }
+       }
+
+       if (!control_interface || !data_interface) {
+               dev_dbg(&intf->dev, "no interfaces\n");
+               return -ENODEV;
        }
 
        if (data_interface_num != call_interface_num)
@@ -1132,7 +1161,6 @@ made_compressed_probe:
        spin_lock_init(&acm->write_lock);
        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;
@@ -1181,14 +1209,14 @@ made_compressed_probe:
                urb->transfer_dma = rb->dma;
                if (acm->is_int_ep) {
                        usb_fill_int_urb(urb, acm->dev,
-                                        acm->rx_endpoint,
+                                        usb_rcvintpipe(usb_dev, epread->bEndpointAddress),
                                         rb->base,
                                         acm->readsize,
                                         acm_read_bulk_callback, rb,
                                         acm->bInterval);
                } else {
                        usb_fill_bulk_urb(urb, acm->dev,
-                                         acm->rx_endpoint,
+                                         usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress),
                                          rb->base,
                                          acm->readsize,
                                          acm_read_bulk_callback, rb);
@@ -1216,6 +1244,8 @@ made_compressed_probe:
                                usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
                                NULL, acm->writesize, acm_write_bulk, snd);
                snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+               if (quirks & SEND_ZERO_PACKET)
+                       snd->urb->transfer_flags |= URB_ZERO_PACKET;
                snd->instance = acm;
        }
 
@@ -1278,6 +1308,11 @@ skip_countries:
 
        acm_table[minor] = acm;
 
+       if (quirks & CLEAR_HALT_CONDITIONS) {
+               usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress));
+               usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress));
+       }
+
        return 0;
 alloc_fail7:
        for (i = 0; i < ACM_NW; i++)
@@ -1511,6 +1546,7 @@ static const struct usb_device_id acm_ids[] = {
        .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
        },
        { USB_DEVICE(0x2184, 0x001c) }, /* GW Instek AFG-2225 */
+       { USB_DEVICE(0x2184, 0x0036) }, /* GW Instek AFG-125 */
        { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
        },
        /* Motorola H24 HSPA module: */
@@ -1557,6 +1593,10 @@ static const struct usb_device_id acm_ids[] = {
        .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
        },
 
+       { USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */
+       .driver_info = CLEAR_HALT_CONDITIONS,
+       },
+
        /* Nokia S60 phones expose two ACM channels. The first is
         * a modem and is picked up by the standard AT-command
         * information below. The second is 'vendor-specific' but
@@ -1636,6 +1676,16 @@ static const struct usb_device_id acm_ids[] = {
        .driver_info = NO_DATA_INTERFACE,
        },
 
+       /*Samsung phone in firmware update mode */
+       { USB_DEVICE(0x04e8, 0x685d),
+       .driver_info = IGNORE_DEVICE,
+       },
+
+       /* Exclude Infineon Flash Loader utility */
+       { USB_DEVICE(0x058b, 0x0041),
+       .driver_info = IGNORE_DEVICE,
+       },
+
        /* control interfaces without any protocol set */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
                USB_CDC_PROTO_NONE) },
@@ -1654,6 +1704,10 @@ static const struct usb_device_id acm_ids[] = {
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
                USB_CDC_ACM_PROTO_AT_CDMA) },
 
+       { USB_DEVICE(0x1519, 0x0452), /* Intel 7260 modem */
+       .driver_info = SEND_ZERO_PACKET,
+       },
+
        { }
 };