USB: serial: fix race between probe and open
[linux-flexiantxendom0.git] / drivers / usb / serial / usb-serial.c
index dab679e..38d7ebd 100644 (file)
@@ -406,7 +406,7 @@ static void serial_unthrottle(struct tty_struct *tty)
                port->serial->type->unthrottle(tty);
 }
 
-static int serial_ioctl(struct tty_struct *tty, struct file *file,
+static int serial_ioctl(struct tty_struct *tty,
                                        unsigned int cmd, unsigned long arg)
 {
        struct usb_serial_port *port = tty->driver_data;
@@ -417,7 +417,7 @@ static int serial_ioctl(struct tty_struct *tty, struct file *file,
        /* pass on to the driver specific version of this function
           if it is available */
        if (port->serial->type->ioctl) {
-               retval = port->serial->type->ioctl(tty, file, cmd, arg);
+               retval = port->serial->type->ioctl(tty, cmd, arg);
        } else
                retval = -ENOIOCTLCMD;
        return retval;
@@ -911,9 +911,8 @@ int usb_serial_probe(struct usb_interface *interface,
                        dev_err(&interface->dev, "No free urbs available\n");
                        goto probe_error;
                }
-               buffer_size = serial->type->bulk_in_size;
-               if (!buffer_size)
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+               buffer_size = max_t(int, serial->type->bulk_in_size,
+                               usb_endpoint_maxp(endpoint));
                port->bulk_in_size = buffer_size;
                port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
                port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -943,7 +942,7 @@ int usb_serial_probe(struct usb_interface *interface,
                        goto probe_error;
                buffer_size = serial->type->bulk_out_size;
                if (!buffer_size)
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       buffer_size = usb_endpoint_maxp(endpoint);
                port->bulk_out_size = buffer_size;
                port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
                port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -991,7 +990,7 @@ int usb_serial_probe(struct usb_interface *interface,
                                                "No free urbs available\n");
                                goto probe_error;
                        }
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       buffer_size = usb_endpoint_maxp(endpoint);
                        port->interrupt_in_endpointAddress =
                                                endpoint->bEndpointAddress;
                        port->interrupt_in_buffer = kmalloc(buffer_size,
@@ -1022,7 +1021,7 @@ int usb_serial_probe(struct usb_interface *interface,
                                                "No free urbs available\n");
                                goto probe_error;
                        }
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       buffer_size = usb_endpoint_maxp(endpoint);
                        port->interrupt_out_size = buffer_size;
                        port->interrupt_out_endpointAddress =
                                                endpoint->bEndpointAddress;
@@ -1060,6 +1059,12 @@ int usb_serial_probe(struct usb_interface *interface,
                serial->attached = 1;
        }
 
+       /* Avoid race with tty_open and serial_install by setting the
+        * disconnected flag and not clearing it until all ports have been
+        * registered.
+        */
+       serial->disconnected = 1;
+
        if (get_free_serial(serial, num_ports, &minor) == NULL) {
                dev_err(&interface->dev, "No more free serial devices\n");
                goto probe_error;
@@ -1084,6 +1089,8 @@ int usb_serial_probe(struct usb_interface *interface,
                }
        }
 
+       serial->disconnected = 0;
+
        usb_serial_console_init(debug, minor);
 
 exit: