ChangeSet 1.1115, 2003/05/07 15:51:02-07:00, greg@kroah.com

TTY: add tty class support for all tty devices.


 drivers/char/tty_io.c |  146 +++++++++++++++++++++++++++++++++++++++++---------
 include/linux/tty.h   |    3 -
 2 files changed, 122 insertions(+), 27 deletions(-)


diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Wed May  7 16:00:04 2003
+++ b/drivers/char/tty_io.c	Wed May  7 16:00:04 2003
@@ -2088,22 +2088,6 @@
 }
 
 #ifdef CONFIG_DEVFS_FS
-static void tty_register_devfs(struct tty_driver *driver, unsigned index)
-{
-	dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
-	char buf[32];
-
-	if (index >= driver->num) {
-		printk(KERN_ERR "Attempt to register invalid tty line number "
-		       "with devfs (%d).\n", index);
-		return;
-	}
-
-	tty_line_name(driver, index, buf);
-	devfs_register(NULL, buf, 0, MAJOR(dev), MINOR(dev),
-		S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL);
-}
-
 static void tty_unregister_devfs(struct tty_driver *driver, int index)
 {
 	char path[64];
@@ -2111,21 +2095,131 @@
 	devfs_remove(path);
 }
 #else
-# define tty_register_devfs(driver, index)	do { } while (0)
 # define tty_unregister_devfs(driver, index)	do { } while (0)
 #endif /* CONFIG_DEVFS_FS */
 
-/*
- * Register a tty device described by <driver>, with minor number <minor>.
+static struct class tty_class = {
+	.name	= "tty",
+};
+
+struct tty_dev {
+	struct list_head node;
+	dev_t dev;
+	struct class_device class_dev;
+};
+#define to_tty_dev(d) container_of(d, struct tty_dev, class_dev)
+
+static LIST_HEAD(tty_dev_list);
+
+static ssize_t show_dev(struct class_device *class_dev, char *buf)
+{
+	struct tty_dev *tty_dev = to_tty_dev(class_dev);
+	return sprintf(buf, "%04x\n", tty_dev->dev);
+}
+static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
+
+static void tty_add_class_device(char *name, dev_t dev, struct device *device)
+{
+	struct tty_dev *tty_dev = NULL;
+	char *temp;
+	int retval;
+
+	tty_dev = kmalloc(sizeof(*tty_dev), GFP_KERNEL);
+	if (!tty_dev)
+		return;
+	memset(tty_dev, 0x00, sizeof(*tty_dev));
+
+	/* stupid '/' in tty name strings... */
+	temp = strchr(name, '/');
+	if (temp && (temp[1] != 0x00))
+		++temp;
+	else
+		temp = name;
+
+	tty_dev->class_dev.dev = device;
+	tty_dev->class_dev.class = &tty_class;
+	snprintf(tty_dev->class_dev.class_id, BUS_ID_SIZE, "%s", temp);
+	retval = class_device_register(&tty_dev->class_dev);
+	if (retval)
+		goto error;
+	class_device_create_file (&tty_dev->class_dev, &class_device_attr_dev);
+	tty_dev->dev = dev;
+	list_add(&tty_dev->node, &tty_dev_list);
+	return;
+error:
+	kfree(tty_dev);
+}
+
+void tty_remove_class_device(dev_t dev)
+{
+	struct tty_dev *tty_dev = NULL;
+	struct list_head *tmp;
+	int found = 0;
+
+	list_for_each (tmp, &tty_dev_list) {
+		tty_dev = list_entry(tmp, struct tty_dev, node);
+		if ((MAJOR(tty_dev->dev) == MAJOR(dev)) &&
+		    (MINOR(tty_dev->dev) == MINOR(dev))) {
+			found = 1;
+			break;
+		}
+	}
+	if (found) {
+		list_del(&tty_dev->node);
+		class_device_unregister(&tty_dev->class_dev);
+		kfree(tty_dev);
+	}
+}
+
+/**
+ * tty_register_device - register a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
+ * @device: a struct device that is associated with this tty device.
+ *	This field is optional, if there is no known struct device for this
+ *	tty device it can be set to NULL safely.
+ *
+ * This call is required to be made to register an individual tty device if
+ * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set.  If that
+ * bit is not set, this function should not be called.
  */
-void tty_register_device(struct tty_driver *driver, unsigned index)
+void tty_register_device(struct tty_driver *driver, unsigned index,
+			 struct device *device)
 {
-	tty_register_devfs(driver, index);
+	dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
+	char name[64];
+
+	if (index >= driver->num) {
+		printk(KERN_ERR "Attempt to register invalid tty line number "
+		       " (%d).\n", index);
+		return;
+	}
+
+	tty_line_name(driver, index, name);
+	devfs_register(NULL, name, 0, MAJOR(dev), MINOR(dev),
+		S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL);
+
+	/* stupid console driver devfs names... change vc/X into ttyX */
+	if (driver->type == TTY_DRIVER_TYPE_CONSOLE)
+		sprintf(name, "tty%d", MINOR(dev));
+
+	/* we don't care about the ptys */
+	if (driver->type != TTY_DRIVER_TYPE_PTY)
+		tty_add_class_device (name, dev, device);
 }
 
+/**
+ * tty_unregister_device - unregister a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
+ *
+ * If a tty device is registered with a call to tty_register_device() then
+ * this function must be made when the tty device is gone.
+ */
 void tty_unregister_device(struct tty_driver *driver, unsigned index)
 {
 	tty_unregister_devfs(driver, index);
+	tty_remove_class_device(MKDEV(driver->major, driver->minor_start) + index);
 }
 
 EXPORT_SYMBOL(tty_register_device);
@@ -2207,7 +2301,7 @@
 	
 	if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
 		for(i = 0; i < driver->num; i++)
-		    tty_register_device(driver, i);
+		    tty_register_device(driver, i, NULL);
 	}
 	proc_tty_register_driver(driver);
 	return error;
@@ -2288,10 +2382,6 @@
 extern int vty_init(void);
 #endif
 
-static struct class tty_class = {
-	.name	= "tty",
-};
-
 static int __init tty_class_init(void)
 {
 	return class_register(&tty_class);
@@ -2311,6 +2401,7 @@
 
 	devfs_register (NULL, "tty", 0, TTYAUX_MAJOR, 0,
 			S_IFCHR | S_IRUGO | S_IWUGO, &tty_fops, NULL);
+	tty_add_class_device ("tty", MKDEV(TTYAUX_MAJOR, 0), NULL);
 
 	if (register_chrdev_region(TTYAUX_MAJOR, 1, 1,
 				   "/dev/console", &tty_fops) < 0)
@@ -2318,6 +2409,7 @@
 
 	devfs_register (NULL, "console", 0, TTYAUX_MAJOR, 1,
 			S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL);
+	tty_add_class_device ("console", MKDEV(TTYAUX_MAJOR, 1), NULL);
 
 #ifdef CONFIG_UNIX98_PTYS
 	if (register_chrdev_region(TTYAUX_MAJOR, 2, 1,
@@ -2326,6 +2418,7 @@
 
 	devfs_register (NULL, "ptmx", 0, TTYAUX_MAJOR, 2,
 			S_IFCHR | S_IRUGO | S_IWUGO, &tty_fops, NULL);
+	tty_add_class_device ("ptmx", MKDEV(TTYAUX_MAJOR, 2), NULL);
 #endif
 	
 #ifdef CONFIG_VT
@@ -2335,6 +2428,7 @@
 
 	devfs_register (NULL, "vc/0", 0, TTY_MAJOR, 0,
 			S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL);
+	tty_add_class_device ("tty0", MKDEV(TTY_MAJOR, 0), NULL);
 
 	vty_init();
 #endif
diff -Nru a/include/linux/tty.h b/include/linux/tty.h
--- a/include/linux/tty.h	Wed May  7 16:00:04 2003
+++ b/include/linux/tty.h	Wed May  7 16:00:04 2003
@@ -243,6 +243,7 @@
 #define L_PENDIN(tty)	_L_FLAG((tty),PENDIN)
 #define L_IEXTEN(tty)	_L_FLAG((tty),IEXTEN)
 
+struct device;
 /*
  * Where all of the state associated with a tty is kept while the tty
  * is open.  Since the termios state should be kept even if the tty
@@ -380,7 +381,7 @@
 extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
 extern int tty_register_driver(struct tty_driver *driver);
 extern int tty_unregister_driver(struct tty_driver *driver);
-extern void tty_register_device(struct tty_driver *driver, unsigned index);
+extern void tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev);
 extern void tty_unregister_device(struct tty_driver *driver, unsigned index);
 extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
 			     int buflen);
