patch-2.3.99-pre7 linux/drivers/usb/serial/usbserial.c

Next file: linux/drivers/usb/serial/visor.c
Previous file: linux/drivers/usb/serial/usb-serial.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/usbserial.c linux/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 @@
 #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 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 @@
 		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 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 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_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_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 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_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 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 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_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 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_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 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 @@
 	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 @@
 	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 @@
 	/* 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 @@
 		}
 
 		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 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 @@
 	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 @@
 void usb_serial_exit(void)
 {
 	usb_deregister(&usb_serial_driver);
+	tty_unregister_driver(&serial_tty_driver);
 }
 
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)