summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/usbserial.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/usbserial.c')
-rw-r--r--drivers/usb/serial/usbserial.c309
1 files changed, 115 insertions, 194 deletions
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 588fed5d1..9fe65ae8d 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -1,7 +1,7 @@
/*
* USB Serial Converter driver
*
- * (C) Copyright (C) 1999, 2000
+ * Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -14,6 +14,16 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (05/03/2000) gkh
+ * Added the Digi Acceleport driver from Al Borchers and Peter Berger.
+ *
+ * (05/02/2000) gkh
+ * Changed devfs and tty register code to work properly now. This was based on
+ * the ACM driver changes by Vojtech Pavlik.
+ *
+ * (04/27/2000) Ryan VanderBijl
+ * Put calls to *_paranoia_checks into one function.
+ *
* (04/23/2000) gkh
* Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
* Moved when the startup code printed out the devices that are supported.
@@ -282,15 +292,13 @@ static struct usb_serial_device_type *usb_serial_devices[] = {
#ifdef CONFIG_USB_SERIAL_OMNINET
&zyxel_omninet_device,
#endif
+#ifdef CONFIG_USB_SERIAL_DIGI_ACCELEPORT
+ &digi_acceleport_device,
+#endif
NULL
};
-/* variables needed for the tty_driver structure */
-static char *driver_name = "usb";
-static char *tty_driver_name = "usb/tty/%d";
-
-
/* local function prototypes */
static int serial_open (struct tty_struct *tty, struct file * filp);
static void serial_close (struct tty_struct *tty, struct file * filp);
@@ -312,12 +320,27 @@ static struct usb_driver usb_serial_driver = {
};
static int serial_refcount;
+static struct tty_driver serial_tty_driver;
static struct tty_struct * serial_tty[SERIAL_TTY_MINORS];
static struct termios * serial_termios[SERIAL_TTY_MINORS];
static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, };
+static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function)
+{
+ /* if no port was specified, or it fails a paranoia check */
+ if (!port ||
+ port_paranoia_check (port, function) ||
+ serial_paranoia_check (port->serial, function)) {
+ /* then say that we dont have a valid usb_serial thing, which will
+ * end up genrating -ENODEV return values */
+ return NULL;
+ }
+
+ return port->serial;
+}
+
static struct usb_serial *get_serial_by_minor (int minor)
{
@@ -357,7 +380,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
serial_table[i] = serial;
return serial;
- }
+ }
return NULL;
}
@@ -454,16 +477,9 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
static void serial_close(struct tty_struct *tty, struct file * filp)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
+ struct usb_serial *serial = get_usb_serial (port, "serial_close");
- dbg("serial_close");
-
- if (port_paranoia_check (port, "serial_close")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_close")) {
+ if (!serial) {
return;
}
@@ -486,16 +502,9 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_write");
+ struct usb_serial *serial = get_usb_serial (port, "serial_write");
- if (port_paranoia_check (port, "serial_write")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_write")) {
+ if (!serial) {
return -ENODEV;
}
@@ -518,26 +527,19 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_write_room");
-
- if (port_paranoia_check (port, "serial_write")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_write")) {
+ struct usb_serial *serial = get_usb_serial (port, "serial_write_room");
+
+ if (!serial) {
return -ENODEV;
}
-
+
dbg("serial_write_room port %d", port->number);
if (!port->active) {
dbg ("port not open");
return -EINVAL;
}
-
+
/* pass on to the driver specific version of this function if it is available */
if (serial->type->write_room) {
return (serial->type->write_room(port));
@@ -550,24 +552,17 @@ static int serial_write_room (struct tty_struct *tty)
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_chars_in_buffer");
-
- if (port_paranoia_check (port, "serial_chars_in_buffer")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
+ struct usb_serial *serial = get_usb_serial (port, "serial_chars_in_buffer");
+
+ if (!serial) {
return -ENODEV;
}
-
+
if (!port->active) {
dbg ("port not open");
return -EINVAL;
}
-
+
/* pass on to the driver specific version of this function if it is available */
if (serial->type->chars_in_buffer) {
return (serial->type->chars_in_buffer(port));
@@ -580,21 +575,14 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_throttle");
-
- if (port_paranoia_check (port, "serial_throttle")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_throttle")) {
+ struct usb_serial *serial = get_usb_serial (port, "serial_throttle");
+
+ if (!serial) {
return;
}
-
+
dbg("serial_throttle port %d", port->number);
-
+
if (!port->active) {
dbg ("port not open");
return;
@@ -612,21 +600,14 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_unthrottle");
-
- if (port_paranoia_check (port, "serial_unthrottle")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_unthrottle")) {
+ struct usb_serial *serial = get_usb_serial (port, "serial_unthrottle");
+
+ if (!serial) {
return;
}
-
+
dbg("serial_unthrottle port %d", port->number);
-
+
if (!port->active) {
dbg ("port not open");
return;
@@ -644,21 +625,14 @@ static void serial_unthrottle (struct tty_struct * tty)
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_ioctl");
-
- if (port_paranoia_check (port, "serial_ioctl")) {
- return -ENODEV;
- }
+ struct usb_serial *serial = get_usb_serial (port, "serial_ioctl");
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_ioctl")) {
+ if (!serial) {
return -ENODEV;
}
-
+
dbg("serial_ioctl port %d", port->number);
-
+
if (!port->active) {
dbg ("port not open");
return -ENODEV;
@@ -676,16 +650,9 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
static void serial_set_termios (struct tty_struct *tty, struct termios * old)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_set_termios");
-
- if (port_paranoia_check (port, "serial_set_termios")) {
- return;
- }
+ struct usb_serial *serial = get_usb_serial (port, "serial_set_termios");
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_set_termios")) {
+ if (!serial) {
return;
}
@@ -708,16 +675,9 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_break");
-
- if (port_paranoia_check (port, "serial_break")) {
- return;
- }
+ struct usb_serial *serial = get_usb_serial (port, "serial_break");
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_break")) {
+ if (!serial) {
return;
}
@@ -861,22 +821,15 @@ static int generic_chars_in_buffer (struct usb_serial_port *port)
static void generic_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
- struct tty_struct *tty;
- unsigned char *data = urb->transfer_buffer;
+ struct usb_serial *serial = get_usb_serial (port, "generic_read_bulk_callback");
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
int i;
- dbg("generic_read_bulk_callback");
-
- if (port_paranoia_check (port, "generic_read_bulk_callback")) {
+ if (!serial) {
return;
}
- serial = port->serial;
- if (serial_paranoia_check (serial, "generic_read_bulk_callback")) {
- return;
- }
-
if (urb->status) {
dbg("nonzero read bulk status received: %d", urb->status);
return;
@@ -911,20 +864,13 @@ static void generic_read_bulk_callback (struct urb *urb)
static void generic_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
- struct tty_struct *tty;
-
- dbg("generic_write_bulk_callback");
+ struct usb_serial *serial = get_usb_serial (port, "generic_write_bulk_callback");
+ struct tty_struct *tty;
- if (port_paranoia_check (port, "generic_write_bulk_callback")) {
+ if (!serial) {
return;
}
- serial = port->serial;
- if (serial_paranoia_check (serial, "generic_write_bulk_callback")) {
- return;
- }
-
if (urb->status) {
dbg("nonzero write bulk status received: %d", urb->status);
return;
@@ -940,48 +886,6 @@ static void generic_write_bulk_callback (struct urb *urb)
}
-static struct tty_driver * usb_serial_tty_driver_init (struct usb_serial *serial)
-{
- struct tty_driver *serial_tty_driver;
-
- if (!(serial_tty_driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL))) {
- err("Out of memory");
- return NULL;
- }
-
- memset (serial_tty_driver, 0x00, sizeof(struct tty_driver));
-
- /* initialize the entries that we don't want to be NULL */
- serial_tty_driver->magic = TTY_DRIVER_MAGIC;
- serial_tty_driver->driver_name = driver_name;
- serial_tty_driver->name = tty_driver_name;
- serial_tty_driver->major = SERIAL_TTY_MAJOR;
- serial_tty_driver->minor_start = serial->minor;
- serial_tty_driver->num = serial->num_ports;
- serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_tty_driver->flags = TTY_DRIVER_REAL_RAW;
- serial_tty_driver->refcount = &serial_refcount;
- serial_tty_driver->table = serial_tty;
- serial_tty_driver->termios = serial_termios;
- serial_tty_driver->termios_locked = serial_termios_locked;
- serial_tty_driver->open = serial_open;
- serial_tty_driver->close = serial_close;
- serial_tty_driver->write = serial_write;
- serial_tty_driver->write_room = serial_write_room;
- serial_tty_driver->ioctl = serial_ioctl;
- serial_tty_driver->set_termios = serial_set_termios;
- serial_tty_driver->throttle = serial_throttle;
- serial_tty_driver->unthrottle = serial_unthrottle;
- serial_tty_driver->break_ctl = serial_break;
- serial_tty_driver->chars_in_buffer = serial_chars_in_buffer;
- serial_tty_driver->init_termios = tty_std_termios;
- serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-
- return serial_tty_driver;
-}
-
-
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_serial *serial = NULL;
@@ -1101,18 +1005,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
serial->num_bulk_out = num_bulk_out;
serial->num_interrupt_in = num_interrupt_in;
- /* initialize a tty_driver for this device */
- serial->tty_driver = usb_serial_tty_driver_init (serial);
- if (serial->tty_driver == NULL) {
- err("Can't create a tty_serial_driver");
- goto probe_error;
- }
-
- if (tty_register_driver (serial->tty_driver)) {
- err("failed to register tty driver");
- goto probe_error;
- }
-
/* if this device type has a startup function, call it */
if (type->startup) {
if (type->startup (serial)) {
@@ -1196,14 +1088,16 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
max_endpoints = MAX(max_endpoints, num_interrupt_in);
for (i = 0; i < max_endpoints; ++i) {
port = &serial->port[i];
- port->number = i;
+ port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
}
+ /* initialize the devfs nodes for this device and let the user know what ports we are bound to */
for (i = 0; i < serial->num_ports; ++i) {
- info("%s converter now attached to ttyUSB%d",
- type->name, serial->minor + i);
+ tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number);
+ info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)",
+ type->name, serial->port[i].number, serial->port[i].number);
}
return serial; /* success */
@@ -1235,13 +1129,6 @@ probe_error:
/* return the minor range that this device had */
return_serial (serial);
- /* if this device has a tty_driver, then unregister it and free it */
- if (serial->tty_driver) {
- tty_unregister_driver (serial->tty_driver);
- kfree (serial->tty_driver);
- serial->tty_driver = NULL;
- }
-
/* free up any memory that we allocated */
kfree (serial);
MOD_DEC_USE_COUNT;
@@ -1291,18 +1178,13 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
}
for (i = 0; i < serial->num_ports; ++i) {
- info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
+ tty_unregister_devfs (&serial_tty_driver, serial->port[i].number);
+ info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->port[i].number);
}
/* return the minor range that this device had */
return_serial (serial);
- /* if this device has a tty_driver, then unregister it and free it */
- if (serial->tty_driver) {
- tty_unregister_driver (serial->tty_driver);
- kfree (serial->tty_driver);
- serial->tty_driver = NULL;
- }
/* free up any memory that we allocated */
kfree (serial);
@@ -1314,6 +1196,35 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
}
+static struct tty_driver serial_tty_driver = {
+ magic: TTY_DRIVER_MAGIC,
+ driver_name: "usb-serial",
+ name: "usb/tts/%d",
+ major: SERIAL_TTY_MAJOR,
+ minor_start: 0,
+ num: SERIAL_TTY_MINORS,
+ type: TTY_DRIVER_TYPE_SERIAL,
+ subtype: SERIAL_TYPE_NORMAL,
+ flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+ refcount: &serial_refcount,
+ table: serial_tty,
+ termios: serial_termios,
+ termios_locked: serial_termios_locked,
+
+ open: serial_open,
+ close: serial_close,
+ write: serial_write,
+ write_room: serial_write_room,
+ ioctl: serial_ioctl,
+ set_termios: serial_set_termios,
+ throttle: serial_throttle,
+ unthrottle: serial_unthrottle,
+ break_ctl: serial_break,
+ chars_in_buffer: serial_chars_in_buffer,
+};
+
+
int usb_serial_init(void)
{
int i;
@@ -1336,9 +1247,18 @@ int usb_serial_init(void)
if (!something)
info ("USB Serial driver is not configured for any devices!");
+ /* register the tty driver */
+ serial_tty_driver.init_termios = tty_std_termios;
+ serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ if (tty_register_driver (&serial_tty_driver)) {
+ err("failed to register tty driver");
+ return -1;
+ }
+
/* register the USB driver */
result = usb_register(&usb_serial_driver);
if (result < 0) {
+ tty_unregister_driver(&serial_tty_driver);
err("usb_register failed for the usb-serial driver. Error number %d", result);
return -1;
}
@@ -1350,6 +1270,7 @@ int usb_serial_init(void)
void usb_serial_exit(void)
{
usb_deregister(&usb_serial_driver);
+ tty_unregister_driver(&serial_tty_driver);
}