static int debug;
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
-static spinlock_t table_lock;
+static DEFINE_MUTEX(table_lock);
static LIST_HEAD(usb_serial_driver_list);
struct usb_serial *usb_serial_get_by_index(unsigned index)
{
struct usb_serial *serial;
- spin_lock(&table_lock);
+ mutex_lock(&table_lock);
serial = serial_table[index];
if (serial)
kref_get(&serial->kref);
- spin_unlock(&table_lock);
+ mutex_unlock(&table_lock);
return serial;
}
unsigned int i, j;
int good_spot;
- dbg("%s %d", __FUNCTION__, num_ports);
+ dbg("%s %d", __func__, num_ports);
*minor = 0;
- spin_lock(&table_lock);
+ mutex_lock(&table_lock);
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
if (serial_table[i])
continue;
*minor = i;
j = 0;
- dbg("%s - minor base = %d", __FUNCTION__, *minor);
+ dbg("%s - minor base = %d", __func__, *minor);
for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) {
serial_table[i] = serial;
serial->port[j++]->number = i;
}
- spin_unlock(&table_lock);
+ mutex_unlock(&table_lock);
return serial;
}
- spin_unlock(&table_lock);
+ mutex_unlock(&table_lock);
return NULL;
}
{
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (serial == NULL)
return;
serial = to_usb_serial(kref);
- dbg("%s - %s", __FUNCTION__, serial->type->description);
+ dbg("%s - %s", __func__, serial->type->description);
serial->type->shutdown(serial);
void usb_serial_put(struct usb_serial *serial)
{
- spin_lock(&table_lock);
+ mutex_lock(&table_lock);
kref_put(&serial->kref, destroy_serial);
- spin_unlock(&table_lock);
+ mutex_unlock(&table_lock);
}
/*****************************************************************************
unsigned int portNumber;
int retval;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* get the serial object associated with this tty pointer */
serial = usb_serial_get_by_index(tty->index);
goto bailout_mutex_unlock;
}
+ retval = usb_autopm_get_interface(serial->interface);
+ if (retval)
+ goto bailout_module_put;
/* only call the device specific open if this
* is the first time the port is opened */
retval = serial->type->open(port, filp);
if (retval)
- goto bailout_module_put;
+ goto bailout_interface_put;
}
mutex_unlock(&port->mutex);
return 0;
+bailout_interface_put:
+ usb_autopm_put_interface(serial->interface);
bailout_module_put:
module_put(serial->type->driver.owner);
bailout_mutex_unlock:
if (!port)
return;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
mutex_lock(&port->mutex);
}
--port->open_count;
- if (port->open_count == 0) {
+ if (port->open_count == 0)
/* only call the device specific close if this
* port is being closed by the last owner */
port->serial->type->close(port, filp);
+ if (port->open_count == (port->console? 1 : 0)) {
if (port->tty) {
if (port->tty->driver_data)
port->tty->driver_data = NULL;
port->tty = NULL;
}
+ }
+ if (port->open_count == 0) {
+ usb_autopm_put_interface(port->serial->interface);
module_put(port->serial->type->driver.owner);
}
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
- if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
+ if (port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
- dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
+ dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
- if (!port->open_count) {
- retval = -EINVAL;
- dbg("%s - port not opened", __FUNCTION__);
- goto exit;
- }
+ /* open_count is managed under the mutex lock for the tty so cannot
+ drop to zero until after the last close completes */
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
retval = port->serial->type->write(port, buf, count);
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
-
- if (!port)
- goto exit;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
- goto exit;
- }
-
+ dbg("%s - port %d", __func__, port->number);
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
- retval = port->serial->type->write_room(port);
-
-exit:
- return retval;
+ return port->serial->type->write_room(port);
}
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
-
- if (!port)
- goto exit;
-
- dbg("%s = port %d", __FUNCTION__, port->number);
-
- if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
- goto exit;
- }
+ dbg("%s = port %d", __func__, port->number);
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
- retval = port->serial->type->chars_in_buffer(port);
-
-exit:
- return retval;
+ return port->serial->type->chars_in_buffer(port);
}
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = tty->driver_data;
+ dbg("%s - port %d", __func__, port->number);
- if (!port)
- return;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (!port->open_count) {
- dbg ("%s - port not open", __FUNCTION__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
if (port->serial->type->throttle)
port->serial->type->throttle(port);
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = tty->driver_data;
+ dbg("%s - port %d", __func__, port->number);
- if (!port)
- return;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
if (port->serial->type->unthrottle)
port->serial->type->unthrottle(port);
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
- if (!port)
- goto exit;
-
- dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
- if (!port->open_count) {
- dbg ("%s - port not open", __FUNCTION__);
- goto exit;
- }
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
- if (port->serial->type->ioctl)
+ if (port->serial->type->ioctl) {
+ lock_kernel();
retval = port->serial->type->ioctl(port, file, cmd, arg);
+ unlock_kernel();
+ }
else
retval = -ENOIOCTLCMD;
-
-exit:
return retval;
}
static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
{
struct usb_serial_port *port = tty->driver_data;
+ dbg("%s - port %d", __func__, port->number);
- if (!port)
- return;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
if (port->serial->type->set_termios)
port->serial->type->set_termios(port, old);
+ else
+ tty_termios_copy_hw(tty->termios, old);
}
static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
- return;
- }
+ dbg("%s - port %d", __func__, port->number);
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
- if (port->serial->type->break_ctl)
+ if (port->serial->type->break_ctl) {
+ lock_kernel();
port->serial->type->break_ctl(port, break_state);
+ unlock_kernel();
+ }
}
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
off_t begin = 0;
char tmp[40];
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
length += sprintf (page, "usbserinfo:1.0 driver:2.0\n");
for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
serial = usb_serial_get_by_index(i);
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return -ENODEV;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
- return -ENODEV;
- }
+ dbg("%s - port %d", __func__, port->number);
+ WARN_ON(!port->open_count);
if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(port, file);
-
return -EINVAL;
}
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return -ENODEV;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
- return -ENODEV;
- }
+ dbg("%s - port %d", __func__, port->number);
+ WARN_ON(!port->open_count);
if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(port, file, set, clear);
-
return -EINVAL;
}
container_of(work, struct usb_serial_port, work);
struct tty_struct *tty;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port)
return;
{
struct usb_serial_port *port = to_usb_serial_port(dev);
- dbg ("%s - %s", __FUNCTION__, dev->bus_id);
+ dbg ("%s - %s", __func__, dev_name(dev));
port_free(port);
}
{
usb_kill_urb(port->read_urb);
usb_kill_urb(port->write_urb);
+ /*
+ * This is tricky.
+ * Some drivers submit the read_urb in the
+ * handler for the write_urb or vice versa
+ * this order determines the order in which
+ * usb_kill_urb() must be used to reliably
+ * kill the URBs. As it is unknown here,
+ * both orders must be used in turn.
+ * The call below is not redundant.
+ */
+ usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb);
}
serial = kzalloc(sizeof(*serial), GFP_KERNEL);
if (!serial) {
- dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&dev->dev, "%s - out of memory\n", __func__);
return NULL;
}
serial->dev = usb_get_dev(dev);
serial->type = driver;
serial->interface = interface;
kref_init(&serial->kref);
+ mutex_init(&serial->disc_mutex);
return serial;
}
static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
{
- struct list_head *p;
const struct usb_device_id *id;
- struct usb_serial_driver *t;
+ struct usb_serial_driver *drv;
/* Check if the usb id matches a known device */
- list_for_each(p, &usb_serial_driver_list) {
- t = list_entry(p, struct usb_serial_driver, driver_list);
- id = get_iface_id(t, iface);
+ list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
+ id = get_iface_id(drv, iface);
if (id)
- return t;
+ return drv;
}
return NULL;
serial = create_serial (dev, interface, type);
if (!serial) {
unlock_kernel();
- dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&interface->dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
/* END HORRIBLE HACK FOR PL2303 */
#endif
- /* found all that we need */
- dev_info(&interface->dev, "%s converter detected\n", type->description);
-
#ifdef CONFIG_USB_SERIAL_GENERIC
if (type == &usb_serial_generic_device) {
num_ports = num_bulk_out;
serial->num_interrupt_in = num_interrupt_in;
serial->num_interrupt_out = num_interrupt_out;
+ /* found all that we need */
+ dev_info(&interface->dev, "%s converter detected\n",
+ type->description);
+
/* create our ports, we need as many as the max endpoints */
/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
max_endpoints = max(num_bulk_in, num_bulk_out);
serial->num_port_pointers = max_endpoints;
unlock_kernel();
- dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
+ dbg("%s - setting up %d port structures for this device", __func__, max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
if (!port)
port->dev.bus = &usb_serial_bus_type;
port->dev.release = &port_release;
- snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
- dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);
+ dev_set_name(&port->dev, "ttyUSB%d", port->number);
+ dbg ("%s - registering %s", __func__, dev_name(&port->dev));
retval = device_register(&port->dev);
if (retval)
dev_err(&port->dev, "Error registering port device, "
struct usb_serial_port *port;
usb_serial_console_disconnect(serial);
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
+ mutex_lock(&serial->disc_mutex);
usb_set_intfdata (interface, NULL);
- if (serial) {
- for (i = 0; i < serial->num_ports; ++i) {
- port = serial->port[i];
- if (port) {
- if (port->tty)
- tty_hangup(port->tty);
- kill_traffic(port);
- }
+ /* must set a flag, to signal subdrivers */
+ serial->disconnected = 1;
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (port) {
+ if (port->tty)
+ tty_hangup(port->tty);
+ kill_traffic(port);
}
- /* let the last holder of this object
- * cause it to be cleaned up */
- usb_serial_put(serial);
}
+ /* let the last holder of this object
+ * cause it to be cleaned up */
+ mutex_unlock(&serial->disc_mutex);
+ usb_serial_put(serial);
dev_info(dev, "device disconnected\n");
}
struct usb_serial_port *port;
int i, r = 0;
- if (serial) {
- for (i = 0; i < serial->num_ports; ++i) {
- port = serial->port[i];
- if (port)
- kill_traffic(port);
- }
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (port)
+ kill_traffic(port);
}
if (serial->type->suspend)
- serial->type->suspend(serial, message);
+ r = serial->type->suspend(serial, message);
return r;
}
{
struct usb_serial *serial = usb_get_intfdata(intf);
- return serial->type->resume(serial);
+ if (serial->type->resume)
+ return serial->type->resume(serial);
+ return 0;
}
EXPORT_SYMBOL(usb_serial_resume);
return -ENOMEM;
/* Initialize our global data */
- spin_lock_init(&table_lock);
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL;
}
result = bus_register(&usb_serial_bus_type);
if (result) {
- err("%s - registering bus driver failed", __FUNCTION__);
+ err("%s - registering bus driver failed", __func__);
goto exit_bus;
}
usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
usb_serial_tty_driver->init_termios = tty_std_termios;
usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ usb_serial_tty_driver->init_termios.c_ispeed = 9600;
+ usb_serial_tty_driver->init_termios.c_ospeed = 9600;
tty_set_operations(usb_serial_tty_driver, &serial_ops);
result = tty_register_driver(usb_serial_tty_driver);
if (result) {
- err("%s - tty_register_driver failed", __FUNCTION__);
+ err("%s - tty_register_driver failed", __func__);
goto exit_reg_driver;
}
/* register the USB driver */
result = usb_register(&usb_serial_driver);
if (result < 0) {
- err("%s - usb_register failed", __FUNCTION__);
+ err("%s - usb_register failed", __func__);
goto exit_tty;
}
/* register the generic driver, if we should */
result = usb_serial_generic_register(debug);
if (result < 0) {
- err("%s - registering generic driver failed", __FUNCTION__);
+ err("%s - registering generic driver failed", __func__);
goto exit_generic;
}
bus_unregister(&usb_serial_bus_type);
exit_bus:
- err ("%s - returning with error %d", __FUNCTION__, result);
+ err ("%s - returning with error %d", __func__, result);
put_tty_driver(usb_serial_tty_driver);
return result;
}
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
set_to_generic_if_null(device, shutdown);
+ set_to_generic_if_null(device, resume);
}
int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */