USB: serial: io_edgeport: fix possible sleep-in-atomic
[pandora-kernel.git] / drivers / usb / serial / io_edgeport.c
index 2ee8075..eb70184 100644 (file)
@@ -114,7 +114,6 @@ struct edgeport_port {
        wait_queue_head_t       wait_chase;             /* for handling sleeping while waiting for chase to finish */
        wait_queue_head_t       wait_open;              /* for handling sleeping while waiting for open to finish */
        wait_queue_head_t       wait_command;           /* for handling sleeping while waiting for command to finish */
-       wait_queue_head_t       delta_msr_wait;         /* for handling sleeping while waiting for msr change to happen */
 
        struct async_icount     icount;
        struct usb_serial_port  *port;                  /* loop back to the owner of this object */
@@ -497,21 +496,25 @@ static int get_epic_descriptor(struct edgeport_serial *ep)
        int result;
        struct usb_serial *serial = ep->serial;
        struct edgeport_product_info *product_info = &ep->product_info;
-       struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+       struct edge_compatibility_descriptor *epic;
        struct edge_compatibility_bits *bits;
 
        ep->is_epic = 0;
+
+       epic = kmalloc(sizeof(*epic), GFP_KERNEL);
+       if (!epic)
+               return -ENOMEM;
+
        result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                                 USB_REQUEST_ION_GET_EPIC_DESC,
                                 0xC0, 0x00, 0x00,
-                                &ep->epic_descriptor,
-                                sizeof(struct edge_compatibility_descriptor),
+                                epic, sizeof(*epic),
                                 300);
-
        dbg("%s result = %d", __func__, result);
 
-       if (result > 0) {
+       if (result == sizeof(*epic)) {
                ep->is_epic = 1;
+               memcpy(&ep->epic_descriptor, epic, sizeof(*epic));
                memset(product_info, 0, sizeof(struct edgeport_product_info));
 
                product_info->NumPorts = epic->NumPorts;
@@ -540,8 +543,16 @@ static int get_epic_descriptor(struct edgeport_serial *ep)
                dbg("  IOSPWriteLCR     : %s", bits->IOSPWriteLCR       ? "TRUE": "FALSE");
                dbg("  IOSPSetBaudRate  : %s", bits->IOSPSetBaudRate    ? "TRUE": "FALSE");
                dbg("  TrueEdgeport     : %s", bits->TrueEdgeport       ? "TRUE": "FALSE");
+
+               result = 0;
+       } else if (result >= 0) {
+               dev_warn(&serial->interface->dev, "short epic descriptor received: %d\n",
+                        result);
+               result = -EIO;
        }
 
+       kfree(epic);
+
        return result;
 }
 
@@ -885,7 +896,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
        /* initialize our wait queues */
        init_waitqueue_head(&edge_port->wait_open);
        init_waitqueue_head(&edge_port->wait_chase);
-       init_waitqueue_head(&edge_port->delta_msr_wait);
        init_waitqueue_head(&edge_port->wait_command);
 
        /* initialize our icount structure */
@@ -1703,13 +1713,17 @@ static int edge_ioctl(struct tty_struct *tty,
                dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
                cprev = edge_port->icount;
                while (1) {
-                       prepare_to_wait(&edge_port->delta_msr_wait,
+                       prepare_to_wait(&port->delta_msr_wait,
                                                &wait, TASK_INTERRUPTIBLE);
                        schedule();
-                       finish_wait(&edge_port->delta_msr_wait, &wait);
+                       finish_wait(&port->delta_msr_wait, &wait);
                        /* see if a signal did it */
                        if (signal_pending(current))
                                return -ERESTARTSYS;
+
+                       if (port->serial->disconnected)
+                               return -EIO;
+
                        cnow = edge_port->icount;
                        if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
                            cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
@@ -2090,7 +2104,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
                        icount->dcd++;
                if (newMsr & EDGEPORT_MSR_DELTA_RI)
                        icount->rng++;
-               wake_up_interruptible(&edge_port->delta_msr_wait);
+               wake_up_interruptible(&edge_port->port->delta_msr_wait);
        }
 
        /* Save the new modem status */
@@ -2249,8 +2263,7 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr,
  * rom_read
  *     reads a number of bytes from the Edgeport device starting at the given
  *     address.
- *     If successful returns the number of bytes read, otherwise it returns
- *     a negative error number of the problem.
+ *     Returns zero on success or a negative error number.
  ****************************************************************************/
 static int rom_read(struct usb_serial *serial, __u16 extAddr,
                                        __u16 addr, __u16 length, __u8 *data)
@@ -2282,12 +2295,17 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr,
                                        USB_REQUEST_ION_READ_ROM,
                                        0xC0, addr, extAddr, transfer_buffer,
                                        current_length, 300);
-               if (result < 0)
+               if (result < current_length) {
+                       if (result >= 0)
+                               result = -EIO;
                        break;
+               }
                memcpy(data, transfer_buffer, current_length);
                length -= current_length;
                addr += current_length;
                data += current_length;
+
+               result = 0;
        }
 
        kfree(transfer_buffer);
@@ -2369,7 +2387,6 @@ static int write_cmd_usb(struct edgeport_port *edge_port,
                dev_err(&edge_port->port->dev,
                    "%s - usb_submit_urb(write command) failed, status = %d\n",
                                                        __func__, status);
-               usb_kill_urb(urb);
                usb_free_urb(urb);
                atomic_dec(&CmdUrbs);
                return status;
@@ -2758,10 +2775,11 @@ static void get_manufacturing_desc(struct edgeport_serial *edge_serial)
                                EDGE_MANUF_DESC_LEN,
                                (__u8 *)(&edge_serial->manuf_descriptor));
 
-       if (response < 1)
+       if (response < 0) {
                dev_err(&edge_serial->serial->dev->dev,
-                       "error in getting manufacturer descriptor\n");
-       else {
+                       "error in getting manufacturer descriptor: %d\n",
+                       response);
+       } else {
                char string[30];
                dbg("**Manufacturer Descriptor");
                dbg("  RomSize:        %dK",
@@ -2817,10 +2835,11 @@ static void get_boot_desc(struct edgeport_serial *edge_serial)
                                EDGE_BOOT_DESC_LEN,
                                (__u8 *)(&edge_serial->boot_descriptor));
 
-       if (response < 1)
+       if (response < 0) {
                dev_err(&edge_serial->serial->dev->dev,
-                               "error in getting boot descriptor\n");
-       else {
+                       "error in getting boot descriptor: %d\n",
+                       response);
+       } else {
                dbg("**Boot Descriptor:");
                dbg("  BootCodeLength: %d",
                    le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength));
@@ -2934,6 +2953,11 @@ static int edge_startup(struct usb_serial *serial)
                                        EDGE_COMPATIBILITY_MASK1,
                                        EDGE_COMPATIBILITY_MASK2 };
 
+       if (serial->num_bulk_in < 1 || serial->num_interrupt_in < 1) {
+               dev_err(&serial->interface->dev, "missing endpoints\n");
+               return -ENODEV;
+       }
+
        dev = serial->dev;
 
        /* create our private serial structure */
@@ -2958,7 +2982,7 @@ static int edge_startup(struct usb_serial *serial)
        dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
 
        /* Read the epic descriptor */
-       if (get_epic_descriptor(edge_serial) <= 0) {
+       if (get_epic_descriptor(edge_serial) < 0) {
                /* memcpy descriptor to Supports structures */
                memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
                       sizeof(struct edge_compatibility_bits));