All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] detour TTY driver
@ 2010-05-15 10:17 Samo Pogacnik
  2010-05-29 22:17 ` Samo Pogacnik
  0 siblings, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-05-15 10:17 UTC (permalink / raw)
  To: linux-embedded; +Cc: linux kernel

Hi,

Here is the initial suggestion for a simple detour TTY driver, which
provides the ability to write user messages through printk. This allows
user output to be inlined with kernel output. Together with printk
time-stamping enabled, a detailed boot sequence analyses is possible.
Additionally, console logs could have been stored through the same
mechanism as kernel messages and does not require the system logger to
be started very/too soon.

regards, Samo

---
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux-2.6.33.3/Documentation/devices.txt b_linux-2.6.33.3/Documentation/devices.txt
index 53d64d3..f889097 100644
--- a_linux-2.6.33.3/Documentation/devices.txt
+++ b_linux-2.6.33.3/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/detour	Detour via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
diff --git a_linux-2.6.33.3/drivers/char/Kconfig b_linux-2.6.33.3/drivers/char/Kconfig
index e023682..4d21e2d 100644
--- a_linux-2.6.33.3/drivers/char/Kconfig
+++ b_linux-2.6.33.3/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config DETOUR_TTY
+	bool "TTY driver to detour user output via printk"
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/detour.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff --git a_linux-2.6.33.3/drivers/char/Makefile b_linux-2.6.33.3/drivers/char/Makefile
index f957edf..b84db55 100644
--- a_linux-2.6.33.3/drivers/char/Makefile
+++ b_linux-2.6.33.3/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_DETOUR_TTY)	+= dty.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
diff --git a_linux-2.6.33.3/drivers/char/dty.c b_linux-2.6.33.3/drivers/char/dty.c
new file mode 100644
index 0000000..3ffe248
--- /dev/null
+++ b_linux-2.6.33.3/drivers/char/dty.c
@@ -0,0 +1,137 @@
+/*
+ *  linux/drivers/char/detour.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/device.h>
+#include <linux/tty.h>
+
+static struct tty_driver *dty_driver;
+
+static const char *detour_tag = "[D] ";
+#define DETOUR_STR_SIZE 508
+
+/*
+ *	Our simple preformatting:
+ *	- every cr is replaced by '^'nl combination
+ *	- every non cr or nl ended write is padded with '\'nl combination
+ *	- adds a detour source tag in front of each line
+ *
+ * 	This is useful for logging purposes (kind of a logging ldisc?).
+ */
+static void detour_printk(const unsigned char *buf, int count)
+{
+	static char tmp[DETOUR_STR_SIZE + 4];
+	static int curr;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		tmp[curr] = buf[i];
+		if (curr < DETOUR_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				tmp[curr] = '^';
+				tmp[curr + 1] = '\n';
+				tmp[curr + 2] = '\0';
+				printk(KERN_INFO "%s%s", detour_tag, tmp);
+				curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", detour_tag, tmp);
+				curr = 0;
+				break;
+			default:
+				curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[curr + 1] = '\\';
+			tmp[curr + 2] = '\n';
+			tmp[curr + 3] = '\0';
+			printk(KERN_INFO "%s%s", detour_tag, tmp);
+			curr = 0;
+		}
+	}
+	if (curr > 0) {
+		/* non nl or cr terminated message */
+		tmp[curr + 0] = '\\';
+		tmp[curr + 1] = '\n';
+		tmp[curr + 2] = '\0';
+		printk(KERN_INFO "%s%s", detour_tag, tmp);
+		curr = 0;
+	}
+}
+
+/*
+ *	Dummy tty ops open for succesfull terminal device open.
+ */
+static int dty_open(struct tty_struct *tty, struct file *filp)
+{
+	return 0;
+}
+
+/*
+ *	File ops (not tty ops) write avoids ldisc inserting additional CRs.
+ *	We simply throw this to our preformatter, which calls printk.
+ */
+static ssize_t detour_write(struct file *file, const char __user *buf,
+	size_t count, loff_t *ppos)
+{
+	detour_printk(buf, count);
+	return count;
+}
+
+static const struct tty_operations dty_ops = {
+	.open = dty_open,
+};
+
+static struct file_operations detour_fops;
+
+static int __init dty_init(void)
+{
+	dty_driver = alloc_tty_driver(1);
+	if (!dty_driver)
+		panic("Couldn't allocate pty driver");
+
+	dty_driver->owner = THIS_MODULE;
+	dty_driver->driver_name = "dty";
+	dty_driver->name = "detour";
+	dty_driver->major = TTYAUX_MAJOR;
+	dty_driver->minor_start = 3;
+	dty_driver->num = 1;
+	dty_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	dty_driver->init_termios = tty_std_termios;
+	dty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+		TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(dty_driver, &dty_ops);
+
+	if (tty_register_driver(dty_driver))
+		panic("Couldn't register dty driver");
+
+	/* register our fops write function */
+	tty_default_fops(&detour_fops);
+	detour_fops.write = detour_write;
+
+	cdev_init(&dty_driver->cdev, &detour_fops);
+
+	/* create our unnumbered device */
+	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+		dty_driver->name);
+
+	return 0;
+}
+module_init(dty_init);
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver
  2010-05-15 10:17 [PATCH] detour TTY driver Samo Pogacnik
@ 2010-05-29 22:17 ` Samo Pogacnik
  2010-05-29 22:54   ` Alan Cox
  0 siblings, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-05-29 22:17 UTC (permalink / raw)
  To: linux-embedded; +Cc: linux kernel, Randy Dunlap, Alan Cox

On Sat, 15 May 2010 12:17:00 +0200 Samo Pogacnik wrote:
> Hi,
> 
> Here is the initial suggestion for a simple detour TTY driver, which
> provides the ability to write user messages through printk. This allows
> user output to be inlined with kernel output. Together with printk
> time-stamping enabled, a detailed boot sequence analyses is possible.
> Additionally, console logs could have been stored through the same
> mechanism as kernel messages and does not require the system logger to
> be started very/too soon.
> 
Hi again,

This version of patch provides the ability to initially redirect console
to "detour TTY" (on driver initialization), if "detour" boot command
line option is set. 

best regards, Samo

p.s.
Randy, Alan: Would you be so kind to comment on usability and
acceptability of this tty driver approach? Thanks.

---
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..f889097 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/detour	Detour via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
diff --git a_linux/Documentation/kernel-parameters.txt b_linux/Documentation/kernel-parameters.txt
index 839b21b..1fd9f09 100644
--- a_linux/Documentation/kernel-parameters.txt
+++ b_linux/Documentation/kernel-parameters.txt
@@ -623,6 +623,8 @@ and is between 256 and 4096 characters. It is defined in the file
 			Defaults to the default architecture's huge page size
 			if not specified.
 
+	detour		[KNL] Initial console redirect via detour tty.
+
 	dhash_entries=	[KNL]
 			Set number of hash buckets for dentry cache.
 
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..f81781d 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,21 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config DETOUR_TTY
+	bool "TTY driver to detour user output via printk"
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/detour. By setting boot command line option "detour",
+	  the console is initially redirected to detour TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..b84db55 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_DETOUR_TTY)	+= dty.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
diff --git a_linux/drivers/char/dty.c b_linux/drivers/char/dty.c
new file mode 100644
index 0000000..4c9018f
--- /dev/null
+++ b_linux/drivers/char/dty.c
@@ -0,0 +1,183 @@
+/*
+ *  linux/drivers/char/detour.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/security.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+
+static int console_detour;
+static struct tty_driver *dty_driver;
+
+/*
+ * Set console_detour to 1.
+ */
+void set_console_detour(void)
+{
+	console_detour = 1;
+}
+EXPORT_SYMBOL(set_console_detour);
+
+/*
+ * Our simple preformatting:
+ * - every cr is replaced by '^'nl combination
+ * - every non cr or nl ended write is padded with '\'nl combination
+ * - adds a detour source tag in front of each line
+ *
+ * This is useful for logging purposes (kind of a logging ldisc?).
+ */
+static const char *detour_tag = "[D] ";
+#define DETOUR_STR_SIZE 508
+
+static void detour_printk(const unsigned char *buf, int count)
+{
+	static char tmp[DETOUR_STR_SIZE + 4];
+	static int curr;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		tmp[curr] = buf[i];
+		if (curr < DETOUR_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				tmp[curr] = '^';
+				tmp[curr + 1] = '\n';
+				tmp[curr + 2] = '\0';
+				printk(KERN_INFO "%s%s", detour_tag, tmp);
+				curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", detour_tag, tmp);
+				curr = 0;
+				break;
+			default:
+				curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[curr + 1] = '\\';
+			tmp[curr + 2] = '\n';
+			tmp[curr + 3] = '\0';
+			printk(KERN_INFO "%s%s", detour_tag, tmp);
+			curr = 0;
+		}
+	}
+	if (curr > 0) {
+		/* non nl or cr terminated message */
+		tmp[curr + 0] = '\\';
+		tmp[curr + 1] = '\n';
+		tmp[curr + 2] = '\0';
+		printk(KERN_INFO "%s%s", detour_tag, tmp);
+		curr = 0;
+	}
+}
+
+/*
+ *	Dummy tty ops open for succesfull terminal device open.
+ */
+static int dty_open(struct tty_struct *tty, struct file *filp)
+{
+	return 0;
+}
+
+/*
+ *	File ops (not tty ops) write avoids ldisc inserting additional CRs.
+ *	We simply throw this to our preformatter, which calls printk.
+ */
+static ssize_t detour_write(struct file *file, const char __user *buf,
+	size_t count, loff_t *ppos)
+{
+	detour_printk(buf, count);
+	return count;
+}
+
+static const struct tty_operations dty_ops = {
+	.open = dty_open,
+};
+
+static struct file_operations detour_fops;
+static void initial_console_redirect(void);
+
+static int __init dty_init(void)
+{
+	dty_driver = alloc_tty_driver(1);
+	if (!dty_driver)
+		panic("Couldn't allocate pty driver");
+
+	dty_driver->owner = THIS_MODULE;
+	dty_driver->driver_name = "dty";
+	dty_driver->name = "detour";
+	dty_driver->major = TTYAUX_MAJOR;
+	dty_driver->minor_start = 3;
+	dty_driver->num = 1;
+	dty_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	dty_driver->init_termios = tty_std_termios;
+	dty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+		TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(dty_driver, &dty_ops);
+
+	if (tty_register_driver(dty_driver))
+		panic("Couldn't register dty driver");
+
+	/* register our fops write function */
+	tty_default_fops(&detour_fops);
+	detour_fops.write = detour_write;
+
+	cdev_init(&dty_driver->cdev, &detour_fops);
+
+	/* create our unnumbered device */
+	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+		dty_driver->name);
+
+	if (console_detour > 0)
+		initial_console_redirect();
+
+	return 0;
+}
+module_init(dty_init);
+
+/*
+ * Support for internal handling of console redirection via detour.
+ */
+static struct file detour_file;
+static struct inode detour_inode;
+static struct dentry detour_dentry;
+
+static void initial_console_redirect(void)
+{
+	long ret;
+
+	/* re-register our fops write function */
+	detour_fops.write = detour_write;
+
+	detour_file.f_dentry = &detour_dentry;
+	detour_file.f_dentry->d_inode = &detour_inode;
+	detour_file.f_op = &detour_fops;
+	detour_file.f_mode |= FMODE_WRITE;
+	security_file_alloc(&detour_file);
+	INIT_LIST_HEAD(&detour_file.f_u.fu_list);
+
+	detour_inode.i_rdev = MKDEV(TTYAUX_MAJOR, 3);
+	security_inode_alloc(&detour_inode);
+	INIT_LIST_HEAD(&detour_inode.inotify_watches);
+
+	ret = detour_fops.open(&detour_inode, &detour_file);
+	printk(KERN_INFO "detour_fops.open() returned %ld\n", ret);
+	ret = detour_fops.unlocked_ioctl(&detour_file, TIOCCONS, 0);
+	printk(KERN_INFO "detour_fops.ioctl() returned %ld\n", ret);
+}
diff --git a_linux/init/main.c b_linux/init/main.c
index 5c85402..be9dee9 100644
--- a_linux/init/main.c
+++ b_linux/init/main.c
@@ -263,6 +263,18 @@ static int __init loglevel(char *str)
 
 early_param("loglevel", loglevel);
 
+#ifdef CONFIG_DETOUR_TTY
+extern void set_console_detour(void);
+
+static int __init detour(char *str)
+{
+	set_console_detour();
+	return 0;
+}
+
+early_param("detour", detour);
+#endif
+
 /*
  * Unknown boot options get handed to init, unless they look like
  * unused parameters (modprobe will find them in /proc/cmdline).



^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver
  2010-05-29 22:17 ` Samo Pogacnik
@ 2010-05-29 22:54   ` Alan Cox
  2010-05-29 22:59     ` Al Viro
  2010-05-29 23:33     ` Samo Pogacnik
  0 siblings, 2 replies; 48+ messages in thread
From: Alan Cox @ 2010-05-29 22:54 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: linux-embedded, linux kernel, Randy Dunlap

> Randy, Alan: Would you be so kind to comment on usability and
> acceptability of this tty driver approach? Thanks.

Not sure the naming is ideal (detour what where, simply calling it
'/dev/ttyprintk' might be clearer - but this is detail

> +void set_console_detour(void)
> +{
> +	console_detour = 1;
> +}
> +EXPORT_SYMBOL(set_console_detour);

module parameters can be set compiled in with modulename.option=foo so
there are easier ways to do that.

> + * Our simple preformatting:
> + * - every cr is replaced by '^'nl combination
> + * - every non cr or nl ended write is padded with '\'nl combination
> + * - adds a detour source tag in front of each line

This seems to make it more ambiguous


> +/*
> + *	Dummy tty ops open for succesfull terminal device open.
> + */
> +static int dty_open(struct tty_struct *tty, struct file *filp)
> +{
> +	return 0;

The kernel really expects posix behaviour but I'm not sure how much it
really matters in this case. Fixing that isn't hard though (use tty_port
helpers and basically no supporting functions)


> +	/* register our fops write function */
> +	tty_default_fops(&detour_fops);
> +	detour_fops.write = detour_write;

No. The behaviour of a tty is very precisely defined by the standards and
stomping over things you shouldn't is not good at all. Remember your tty
sets its own initial termios settings so you can set those to give the
initial behaviour you want. You need the tty layer here in your case
anyway as you don't have sufficient locking otherwise !

Also I'd provide a write_room method which always answers 'lots'

Do you need a recursion check. Suppose I open this device and capture
printk console messages to it ? Alternatively maybe you need an ioctl
handler to trap that case and reject it as a stupidity filter (or both ?)

> +	cdev_init(&dty_driver->cdev, &detour_fops);
> +
> +	/* create our unnumbered device */
> +	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
> +		dty_driver->name);

These need to check for failures.


> +static void initial_console_redirect(void)
> +{
> +	long ret;
> +
> +	/* re-register our fops write function */
> +	detour_fops.write = detour_write;
> +
> +	detour_file.f_dentry = &detour_dentry;
> +	detour_file.f_dentry->d_inode = &detour_inode;
> +	detour_file.f_op = &detour_fops;
> +	detour_file.f_mode |= FMODE_WRITE;
> +	security_file_alloc(&detour_file);
> +	INIT_LIST_HEAD(&detour_file.f_u.fu_list);
> +
> +	detour_inode.i_rdev = MKDEV(TTYAUX_MAJOR, 3);
> +	security_inode_alloc(&detour_inode);
> +	INIT_LIST_HEAD(&detour_inode.inotify_watches);
> +
> +	ret = detour_fops.open(&detour_inode, &detour_file);
> +	printk(KERN_INFO "detour_fops.open() returned %ld\n", ret);
> +	ret = detour_fops.unlocked_ioctl(&detour_file, TIOCCONS, 0);
> +	printk(KERN_INFO "detour_fops.ioctl() returned %ld\n", ret);
> +}

Bletch.. I'm really opposed to this kind of hackery. Fix your userspace a
tiny bit.

So
- Write only tty that uses printk: Looks good to me, implementation
  quibbles only
- Magic kernel hacks to shuffle things around in the initial console
  logic - hideous. I still really think you need to fix your userspace


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver
  2010-05-29 22:54   ` Alan Cox
@ 2010-05-29 22:59     ` Al Viro
  2010-05-29 23:33     ` Samo Pogacnik
  1 sibling, 0 replies; 48+ messages in thread
From: Al Viro @ 2010-05-29 22:59 UTC (permalink / raw)
  To: Alan Cox; +Cc: Samo Pogacnik, linux-embedded, linux kernel, Randy Dunlap

On Sat, May 29, 2010 at 11:54:02PM +0100, Alan Cox wrote:
> > +	/* re-register our fops write function */
> > +	detour_fops.write = detour_write;
> > +
> > +	detour_file.f_dentry = &detour_dentry;
> > +	detour_file.f_dentry->d_inode = &detour_inode;
> > +	detour_file.f_op = &detour_fops;
> > +	detour_file.f_mode |= FMODE_WRITE;
> > +	security_file_alloc(&detour_file);
> > +	INIT_LIST_HEAD(&detour_file.f_u.fu_list);
> > +
> > +	detour_inode.i_rdev = MKDEV(TTYAUX_MAJOR, 3);
> > +	security_inode_alloc(&detour_inode);
> > +	INIT_LIST_HEAD(&detour_inode.inotify_watches);
> > +
> > +	ret = detour_fops.open(&detour_inode, &detour_file);
> > +	printk(KERN_INFO "detour_fops.open() returned %ld\n", ret);
> > +	ret = detour_fops.unlocked_ioctl(&detour_file, TIOCCONS, 0);
> > +	printk(KERN_INFO "detour_fops.ioctl() returned %ld\n", ret);

That alone is enough for a NAK.  Do Not Do That.  Fake struct file/dentry/inode
and their uses are not acceptable.  Neither is modifying file_operations,
while we are at it.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver
  2010-05-29 22:54   ` Alan Cox
  2010-05-29 22:59     ` Al Viro
@ 2010-05-29 23:33     ` Samo Pogacnik
  2010-06-09 22:37       ` [PATCH] detour TTY driver - now ttyprintk Samo Pogacnik
  1 sibling, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-05-29 23:33 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-embedded, linux kernel, Randy Dunlap, Al Viro

> > +static void initial_console_redirect(void)
> > +{
> > +	long ret;
> > +
> > +	/* re-register our fops write function */
> > +	detour_fops.write = detour_write;
> > +
> > +	detour_file.f_dentry = &detour_dentry;
> > +	detour_file.f_dentry->d_inode = &detour_inode;
> > +	detour_file.f_op = &detour_fops;
> > +	detour_file.f_mode |= FMODE_WRITE;
> > +	security_file_alloc(&detour_file);
> > +	INIT_LIST_HEAD(&detour_file.f_u.fu_list);
> > +
> > +	detour_inode.i_rdev = MKDEV(TTYAUX_MAJOR, 3);
> > +	security_inode_alloc(&detour_inode);
> > +	INIT_LIST_HEAD(&detour_inode.inotify_watches);
> > +
> > +	ret = detour_fops.open(&detour_inode, &detour_file);
> > +	printk(KERN_INFO "detour_fops.open() returned %ld\n", ret);
> > +	ret = detour_fops.unlocked_ioctl(&detour_file, TIOCCONS, 0);
> > +	printk(KERN_INFO "detour_fops.ioctl() returned %ld\n", ret);
> > +}
> 
> Bletch.. I'm really opposed to this kind of hackery. Fix your userspace a
> tiny bit.
> 
> So
> - Write only tty that uses printk: Looks good to me, implementation
>   quibbles only
> - Magic kernel hacks to shuffle things around in the initial console
>   logic - hideous. I still really think you need to fix your userspace
> 

Thank you for all comments. I'll try to follow them (might take some
time) and i'll remove the internal console redirection magic for sure. 

regards, Samo


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-05-29 23:33     ` Samo Pogacnik
@ 2010-06-09 22:37       ` Samo Pogacnik
  2010-06-11 12:44         ` Alan Cox
  0 siblings, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-06-09 22:37 UTC (permalink / raw)
  To: linux-embedded; +Cc: linux kernel, Alan Cox

Hi,

This is another version of former detour TTY driver, trying to follow
Alan's suggestions:
- renamed from detour to ttyprintk
- removed possibility for initial internal redirection of console to
this tty
- providing hopefully more proper open/close tty operations
- fixed initial termios settings
- added primitive write_room operation
- added ratelimting support (recursion check) and an ioctl trap to catch
ratelimiting being activated. i'd appreciate a suggestion on this ioctl
command naming/value and on location of its definition?
- additional error checking

I also have a question about the tioccons() function from the tty_io.c.
Should this function also check, if the redirection tty has been opened
for writing, since there are going to be implicit writes to this tty for
each console message? This would prevent users without write permissions
to successfully perform TIOCCONS ioctl. This would also prevent writing
capable users to successfully perform TIOCCONS with read-only opened
tty, but failing to write console messages to the redirection tty
afterwards. This seems to happen because the mode of opened tty at the
time of issuing TIOCCONS ioctl is remembered.

Alan, could you please give the patch bellow another look?

thanks, Samo

---
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..5e569e4
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,305 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+/*
+ * Ratelimiting support to handle to much output to this device,
+ * because of explicit writes or because of unintentional recursive
+ * setup (caught printks again sent to this device).
+ */
+static struct ratelimit_state ttyprintk_rs = {
+	.interval = DEFAULT_RATELIMIT_INTERVAL,
+	.burst = DEFAULT_RATELIMIT_BURST,
+};
+
+/*
+ * Ratelimiting action and notification support
+ */
+static DECLARE_WAIT_QUEUE_HEAD(ttyprintk_ratelimit_wq);
+static int ttyprintk_ratelimit_event;
+
+#define ttyprintk_ratelimited(fmt, ...) \
+{ \
+	if (__ratelimit(&ttyprintk_rs)) { \
+		ttyprintk_ratelimit_event = 0; \
+		printk(KERN_INFO fmt, ##__VA_ARGS__); \
+	} else { \
+		ttyprintk_ratelimit_event = 1; \
+		wake_up_all(&ttyprintk_ratelimit_wq); \
+	} \
+}
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ */
+static const char *tpk_tag = "[U] "; /* U for User */
+#define TTY_PRINTK_STR_SIZE 508
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TTY_PRINTK_STR_SIZE + 4];
+	static int curr;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		tmp[curr] = buf[i];
+		if (curr < TTY_PRINTK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[curr + 0] = '\n';
+				tmp[curr + 1] = '\0';
+				ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+				curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[curr + 1] = '\0';
+				ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+				curr = 0;
+				break;
+			default:
+				curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[curr + 1] = '\\';
+			tmp[curr + 2] = '\n';
+			tmp[curr + 3] = '\0';
+			ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+			curr = 0;
+		}
+	}
+	if (curr > 0) {
+		/* non nl or cr terminated message - add nl */
+		tmp[curr + 0] = '\n';
+		tmp[curr + 1] = '\0';
+		ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+		curr = 0;
+	}
+
+	return count;
+}
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+	spinlock_t lock;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *port = &tpk_port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	port->port.count++;
+	tty->driver_data = port;
+	port->port.tty = tty;
+	clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+	mutex_init(&port->port_write_mutex);
+	port->port.flags |= ASYNC_INITIALIZED;
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *port = tty->driver_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (tty_hung_up_p(filp)) {
+		spin_unlock_irqrestore(&port->lock, flags);
+		return;
+	}
+
+	if (tty->count == 1 && port->port.count != 1) {
+		printk(KERN_ERR "tpk_close: bad port count;"
+			" tty->count is 1, port count is %d\n",
+			port->port.count);
+		port->port.count = 1;
+	}
+
+	if (port->port.count > 1) {
+		port->port.count--;
+
+		spin_unlock_irqrestore(&port->lock, flags);
+
+		return;
+	}
+	port->port.flags |= ASYNC_CLOSING;
+	/*
+	 * We have no HW to wait for its buffer to clear; and we notify
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	spin_unlock_irqrestore(&port->lock, flags);
+	/*
+	 * We have no HW to handle to stop accepting input.
+	 */
+	if (--port->port.count < 0) {
+		printk(KERN_ERR
+			"tpk_close: bad port usage count for ttyprintk: %d\n",
+			port->port.count);
+		port->port.count = 0;
+	}
+
+	tty_ldisc_flush(tty);
+	spin_lock_irqsave(&port->lock, flags);
+	tty->closing = 0;
+	port->port.tty = NULL;
+	spin_unlock_irqrestore(&port->lock, flags);
+	port->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+}
+
+/*
+ * TTY operations write function.
+ */
+int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct ttyprintk_port *port;
+	int ret;
+
+	port = tty->driver_data;
+
+	if (!port)
+		return 0;
+
+	if (!(port->port.flags & ASYNC_INITIALIZED))
+		return 0;
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&port->port_write_mutex);
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&port->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+int tpk_write_room(struct tty_struct *tty)
+{
+	return TTY_PRINTK_STR_SIZE;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+#define	TPKRLEV	(('e'<<8) | 0) /* Wait for ttyprintk ratelimiting event*/
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *port;
+
+	port = tty->driver_data;
+
+	if (!port)
+		return -EINVAL;
+
+	switch (cmd) {
+	case TPKRLEV:
+		wait_event_interruptible(ttyprintk_ratelimit_wq,
+			(ttyprintk_ratelimit_event != 0));
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	memset(&tpk_port, 0, sizeof(tpk_port));
+	tty_port_init(&tpk_port.port);
+	spin_lock_init(&tpk_port.lock);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);




^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-09 22:37       ` [PATCH] detour TTY driver - now ttyprintk Samo Pogacnik
@ 2010-06-11 12:44         ` Alan Cox
  2010-06-11 21:32           ` Samo Pogacnik
  2010-06-11 23:31           ` Samo Pogacnik
  0 siblings, 2 replies; 48+ messages in thread
From: Alan Cox @ 2010-06-11 12:44 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: linux-embedded, linux kernel


> +/*
> + * TTY operations open function.
> + */
> +static int tpk_open(struct tty_struct *tty, struct file *filp)
> +{
> +	struct ttyprintk_port *port = &tpk_port;

You can replace the rest with

	return tty_port_open(port, tty, filp);
}

> + * TTY operations close function.
> + */
> +static void tpk_close(struct tty_struct *tty, struct file *filp)
> +{
> +	struct ttyprintk_port *port = tty->driver_data;

and
	tty_port_close(port, tty, filp);

> +}

which saves a lot of work

> +
> +/*
> + * TTY operations write function.
> + */
> +int tpk_write(struct tty_struct *tty,
> +		const unsigned char *buf, int count)
> +{
> +	struct ttyprintk_port *port;
> +	int ret;
> +
> +	port = tty->driver_data;
> +
> +	if (!port)
> +		return 0;
> +
> +	if (!(port->port.flags & ASYNC_INITIALIZED))
> +		return 0;

These two can't happen if you use tty_port_* so it is better to blow up.
If you think you may be seeing it occur then use WARN_ON() or similar

> +
> +	/* exclusive use of tpk_printk within this tty */
> +	mutex_lock(&port->port_write_mutex);
> +	ret = tpk_printk(buf, count);
> +	mutex_unlock(&port->port_write_mutex);

And this is serialized by the caller (not that having your own lock is
any harm)


> +#define	TPKRLEV	(('e'<<8) | 0) /* Wait for ttyprintk ratelimiting event*/
> +static int tpk_ioctl(struct tty_struct *tty, struct file *file,
> +			unsigned int cmd, unsigned long arg)
> +{
> +	struct ttyprintk_port *port;
> +
> +	port = tty->driver_data;
> +
> +	if (!port)
> +		return -EINVAL;
> +
> +	switch (cmd) {
> +	case TPKRLEV:
> +		wait_event_interruptible(ttyprintk_ratelimit_wq,
> +			(ttyprintk_ratelimit_event != 0));

Ok that wasn't quite what I had in mind. 

What I was thinking was needed was this

	/* Stop TIOCCONS */
	case TIOCCONS:
		return -EOPNOTSUPP;

only it won't work that way. I'll sort that out in tty_io.c once the
driver is happy. That way anything trying to mis-redirect the console
will get stopped early which is probably more reliable than a ratelimit ?


> +	memset(&tpk_port, 0, sizeof(tpk_port));

It's static so that isn't needed

> +	tty_port_init(&tpk_port.port);
> +	spin_lock_init(&tpk_port.lock);

The one other bit you will need to use the helpers is

struct tty_port_operations null_ops = { };

	tpk_port.port->ops = &null_ops;


Alan

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-11 12:44         ` Alan Cox
@ 2010-06-11 21:32           ` Samo Pogacnik
  2010-06-21 14:38             ` Alan Cox
  2010-06-11 23:31           ` Samo Pogacnik
  1 sibling, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-06-11 21:32 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-embedded, linux kernel


> > +#define	TPKRLEV	(('e'<<8) | 0) /* Wait for ttyprintk ratelimiting event*/
> > +static int tpk_ioctl(struct tty_struct *tty, struct file *file,
> > +			unsigned int cmd, unsigned long arg)
> > +{
> > +	struct ttyprintk_port *port;
> > +
> > +	port = tty->driver_data;
> > +
> > +	if (!port)
> > +		return -EINVAL;
> > +
> > +	switch (cmd) {
> > +	case TPKRLEV:
> > +		wait_event_interruptible(ttyprintk_ratelimit_wq,
> > +			(ttyprintk_ratelimit_event != 0));
> 
> Ok that wasn't quite what I had in mind. 
> 
> What I was thinking was needed was this
> 
> 	/* Stop TIOCCONS */
> 	case TIOCCONS:
> 		return -EOPNOTSUPP;
> 
> only it won't work that way. I'll sort that out in tty_io.c once the
> driver is happy. That way anything trying to mis-redirect the console
> will get stopped early which is probably more reliable than a ratelimit ?
> 
I'm thinking to leave the ratelimit support in for the time being. I had
in mind cases, when someone does
 "cat /proc/kmsg > dev/ttyprintk" or
suppose the console is redirected to ttyprintk (which i would like to be
able to do from user program) and then someone does:
 "cat /proc/kmsg > /dev/console"... or
if console is redirected after this command ?

Were you thinking of some other mis-redirection case?

Samo


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-11 12:44         ` Alan Cox
  2010-06-11 21:32           ` Samo Pogacnik
@ 2010-06-11 23:31           ` Samo Pogacnik
  1 sibling, 0 replies; 48+ messages in thread
From: Samo Pogacnik @ 2010-06-11 23:31 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-embedded, linux kernel


> > +/*
> > + * TTY operations open function.
> > + */
> > +static int tpk_open(struct tty_struct *tty, struct file *filp)
> > +{
> > +	struct ttyprintk_port *port = &tpk_port;
> 
> You can replace the rest with
> 
> 	return tty_port_open(port, tty, filp);
> }
> 
fixed

> > + * TTY operations close function.
> > + */
> > +static void tpk_close(struct tty_struct *tty, struct file *filp)
> > +{
> > +	struct ttyprintk_port *port = tty->driver_data;
> 
> and
> 	tty_port_close(port, tty, filp);
> 
> > +}
> 
> which saves a lot of work
> 
yeah right, done

> > +
> > +/*
> > + * TTY operations write function.
> > + */
> > +int tpk_write(struct tty_struct *tty,
> > +		const unsigned char *buf, int count)
> > +{
> > +	struct ttyprintk_port *port;
> > +	int ret;
> > +
> > +	port = tty->driver_data;
> > +
> > +	if (!port)
> > +		return 0;
> > +
> > +	if (!(port->port.flags & ASYNC_INITIALIZED))
> > +		return 0;
> 
> These two can't happen if you use tty_port_* so it is better to blow up.
> If you think you may be seeing it occur then use WARN_ON() or similar
> 
the two checks were removed

> > +
> > +	/* exclusive use of tpk_printk within this tty */
> > +	mutex_lock(&port->port_write_mutex);
> > +	ret = tpk_printk(buf, count);
> > +	mutex_unlock(&port->port_write_mutex);
> 
> And this is serialized by the caller (not that having your own lock is
> any harm)
> 
own lock peserved just in case

> 
> > +#define	TPKRLEV	(('e'<<8) | 0) /* Wait for ttyprintk ratelimiting event*/
> > +static int tpk_ioctl(struct tty_struct *tty, struct file *file,
> > +			unsigned int cmd, unsigned long arg)
> > +{
> > +	struct ttyprintk_port *port;
> > +
> > +	port = tty->driver_data;
> > +
> > +	if (!port)
> > +		return -EINVAL;
> > +
> > +	switch (cmd) {
> > +	case TPKRLEV:
> > +		wait_event_interruptible(ttyprintk_ratelimit_wq,
> > +			(ttyprintk_ratelimit_event != 0));
> 
> Ok that wasn't quite what I had in mind. 
ratelimiting remained present

> 
> What I was thinking was needed was this
> 
> 	/* Stop TIOCCONS */
> 	case TIOCCONS:
> 		return -EOPNOTSUPP;
> 
added

> only it won't work that way. I'll sort that out in tty_io.c once the
> driver is happy. That way anything trying to mis-redirect the console
> will get stopped early which is probably more reliable than a ratelimit ?
> 
> > +	memset(&tpk_port, 0, sizeof(tpk_port));
> 
memset removed

> It's static so that isn't needed
> 
> > +	tty_port_init(&tpk_port.port);
> > +	spin_lock_init(&tpk_port.lock);
> 
> The one other bit you will need to use the helpers is
> 
> struct tty_port_operations null_ops = { };
> 
> 	tpk_port.port->ops = &null_ops;
> 
> Alan
Also added, with many thanks,

Samo
----
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..333490d
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,248 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+/*
+ * Ratelimiting support to handle to much output to this device,
+ * because of explicit writes or because of unintentional recursive
+ * setup (caught printks again sent to this device).
+ */
+static struct ratelimit_state ttyprintk_rs = {
+	.interval = DEFAULT_RATELIMIT_INTERVAL,
+	.burst = DEFAULT_RATELIMIT_BURST,
+};
+
+/*
+ * Ratelimiting action and notification support
+ */
+static DECLARE_WAIT_QUEUE_HEAD(ttyprintk_ratelimit_wq);
+static int ttyprintk_ratelimit_event;
+
+#define ttyprintk_ratelimited(fmt, ...) \
+{ \
+	if (__ratelimit(&ttyprintk_rs)) { \
+		ttyprintk_ratelimit_event = 0; \
+		printk(KERN_INFO fmt, ##__VA_ARGS__); \
+	} else { \
+		ttyprintk_ratelimit_event = 1; \
+		wake_up_all(&ttyprintk_ratelimit_wq); \
+	} \
+}
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ */
+static const char *tpk_tag = "[U] "; /* U for User */
+#define TTY_PRINTK_STR_SIZE 508
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TTY_PRINTK_STR_SIZE + 4];
+	static int curr;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		tmp[curr] = buf[i];
+		if (curr < TTY_PRINTK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[curr + 0] = '\n';
+				tmp[curr + 1] = '\0';
+				ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+				curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[curr + 1] = '\0';
+				ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+				curr = 0;
+				break;
+			default:
+				curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[curr + 1] = '\\';
+			tmp[curr + 2] = '\n';
+			tmp[curr + 3] = '\0';
+			ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+			curr = 0;
+		}
+	}
+	if (curr > 0) {
+		/* non nl or cr terminated message - add nl */
+		tmp[curr + 0] = '\n';
+		tmp[curr + 1] = '\0';
+		ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+		curr = 0;
+	}
+
+	return count;
+}
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	tty->driver_data = &tpk_port;
+
+	return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+	int ret;
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+int tpk_write_room(struct tty_struct *tty)
+{
+	return TTY_PRINTK_STR_SIZE;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+#define	TPKRLEV	(('e'<<8) | 0) /* Wait for ttyprintk ratelimiting event*/
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *port;
+
+	port = tty->driver_data;
+
+	if (!port)
+		return -EINVAL;
+
+	switch (cmd) {
+	/* Catch ratelimiting activation */
+	case TPKRLEV:
+		wait_event_interruptible(ttyprintk_ratelimit_wq,
+			(ttyprintk_ratelimit_event != 0));
+		break;
+	/* Stop TIOCCONS */
+	case TIOCCONS:
+		return -EOPNOTSUPP;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);



^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-11 21:32           ` Samo Pogacnik
@ 2010-06-21 14:38             ` Alan Cox
  2010-06-22 22:06               ` Samo Pogacnik
  0 siblings, 1 reply; 48+ messages in thread
From: Alan Cox @ 2010-06-21 14:38 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: linux-embedded, linux kernel

> I'm thinking to leave the ratelimit support in for the time being. I had
> in mind cases, when someone does
>  "cat /proc/kmsg > dev/ttyprintk" or
> suppose the console is redirected to ttyprintk (which i would like to be
> able to do from user program)

Console as in the printk sense would then loop.

If you are going to do the flow control you should probably do something
like


write_room()
{
	if (!flow_controlled)
		space = 8192;
	return space;
}

write()
{
	space -= len;
}

then your flow control will behave properly and slow down users rather
than losing data (except stuff sent without blocking)


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-21 14:38             ` Alan Cox
@ 2010-06-22 22:06               ` Samo Pogacnik
  2010-06-22 22:21                 ` Alan Cox
  0 siblings, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-06-22 22:06 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-embedded, linux kernel

On 21.06.2010 (Mon) at 15:38 +0100 Alan Cox wrote:
> > I'm thinking to leave the ratelimit support in for the time being. I had
> > in mind cases, when someone does
> >  "cat /proc/kmsg > dev/ttyprintk" or
> > suppose the console is redirected to ttyprintk (which i would like to be
> > able to do from user program)
> 
> Console as in the printk sense would then loop.
> 
> If you are going to do the flow control you should probably do something
> like
> 
> 
> write_room()
> {
> 	if (!flow_controlled)
> 		space = 8192;
> 	return space;
> }
> 
> write()
> {
> 	space -= len;
> }
> 
> then your flow control will behave properly and slow down users rather
> than losing data (except stuff sent without blocking)
> 
For correct flow control, i suppose current empty space of the real
(final) printk buffer is needed. On the other hand my intermediate
pre-formatting buffer is only "one line" long, but serialized on access
in a way that it is always completely available (except for the time of
tpk_printk() function running). As such intermediate buffer only defines
maximum write_room space.

Now there are two ideas. The first one is to dig out current real printk
buffer space (smells like hacking?) and adapt write_room to that space
in some logical manner. And the other would be to use ratelimit support
to switch between max and zero in write_room answer and remove other
retelimit response?

What do you suggest, do i miss something?

regards, Samo


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-22 22:06               ` Samo Pogacnik
@ 2010-06-22 22:21                 ` Alan Cox
  2010-06-25 10:43                   ` Samo Pogacnik
  0 siblings, 1 reply; 48+ messages in thread
From: Alan Cox @ 2010-06-22 22:21 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: linux-embedded, linux kernel

> For correct flow control, i suppose current empty space of the real
> (final) printk buffer is needed. On the other hand my intermediate

Console drivers have their own buffering so that doesn't really work. If
you want to just avoid explosions then you don't need to be quite so
clever

> in some logical manner. And the other would be to use ratelimit support
> to switch between max and zero in write_room answer and remove other
> retelimit response?

Yes - except that a driver isn't permitted to reduce the write room space
by more than bytes written. That is if you offer 512 bytes you can't
offer 0 until 512 bytes have been written - hence the design of the pseudo
code I posted in the previous message.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-22 22:21                 ` Alan Cox
@ 2010-06-25 10:43                   ` Samo Pogacnik
  2010-06-25 11:03                     ` Alan Cox
  0 siblings, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-06-25 10:43 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-embedded, linux kernel


> > in some logical manner. And the other would be to use ratelimit support
> > to switch between max and zero in write_room answer and remove other
> > retelimit response?
> 
> Yes - except that a driver isn't permitted to reduce the write room space
> by more than bytes written. That is if you offer 512 bytes you can't
> offer 0 until 512 bytes have been written - hence the design of the pseudo
> code I posted in the previous message.

Now flow control is provided in a way that each write ratelimit false
detection shrinks available space for its output lenth. On the other
hand write returns available space back to maximum on true ratelimit
detection result. Additionaly each next write_room returns at least one
character space under high load, if zero space is reached. 

Additionally a private ttyprintk_ratelimit function is provided to
suppress "missed callbacks" printks, because we do not really miss
anything.

regards, Samo
----
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..344f2d3
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,264 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * Ratelimiting support to handle to much output to this device,
+ * because of explicit writes or because of unintentional loop
+ * setup (caught printks again sent to this device).
+ */
+static struct ratelimit_state ttyprintk_rs = {
+	.interval = DEFAULT_RATELIMIT_INTERVAL,
+	.burst = DEFAULT_RATELIMIT_BURST,
+};
+
+#define ttyprintk_printk(fmt, ...) \
+{ \
+	printk(KERN_INFO fmt, ##__VA_ARGS__); \
+}
+
+/*
+ * Our private ratelimit function, to suppress its printk warnings about
+ * missed callbacks, which are irrelevant in a flow control mechanism.
+ */
+static int ttyprintk_ratelimit(struct ratelimit_state *rs,
+				struct ttyprintk_port *tpkp)
+{
+	int ret;
+
+	/* exclusive call of ttyprintk_ratelimit within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	/* clear ratelimit missed callbacks counter */
+	rs->missed = 0;
+	ret = __ratelimit(rs);
+	mutex_unlock(&tpkp->port_write_mutex);
+	return ret;
+}
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ */
+#define TTY_PRINTK_STR_SIZE 508
+static int tpk_space = TTY_PRINTK_STR_SIZE;
+static const char *tpk_tag = "[U] "; /* U for User */
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TTY_PRINTK_STR_SIZE + 4];
+	static int curr;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		tmp[curr] = buf[i];
+		if (curr < TTY_PRINTK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[curr + 0] = '\n';
+				tmp[curr + 1] = '\0';
+				ttyprintk_printk("%s%s", tpk_tag, tmp);
+				curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[curr + 1] = '\0';
+				ttyprintk_printk("%s%s", tpk_tag, tmp);
+				curr = 0;
+				break;
+			default:
+				curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[curr + 1] = '\\';
+			tmp[curr + 2] = '\n';
+			tmp[curr + 3] = '\0';
+			ttyprintk_printk("%s%s", tpk_tag, tmp);
+			curr = 0;
+		}
+	}
+	if ((tpk_space == TTY_PRINTK_STR_SIZE) && (curr > 0)) {
+		/* non nl or cr terminated message - add nl */
+		tmp[curr + 0] = '\n';
+		tmp[curr + 1] = '\0';
+		ttyprintk_printk("%s%s", tpk_tag, tmp);
+		curr = 0;
+	}
+
+	return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	tty->driver_data = &tpk_port;
+
+	return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+	int ret;
+
+	if (ttyprintk_ratelimit(&ttyprintk_rs, tpkp))
+		tpk_space = TTY_PRINTK_STR_SIZE;
+	else {
+		if (tpk_space > count)
+			tpk_space -= count;
+		else
+			tpk_space = 0;
+	}
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+	int ret = tpk_space;
+
+	/* allow char by char under max pressure */
+	if (tpk_space == 0)
+		tpk_space = 1;
+
+	return ret;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *port;
+
+	port = tty->driver_data;
+
+	if (!port)
+		return -EINVAL;
+
+	switch (cmd) {
+	/* Stop TIOCCONS */
+	case TIOCCONS:
+		return -EOPNOTSUPP;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);



^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-25 10:43                   ` Samo Pogacnik
@ 2010-06-25 11:03                     ` Alan Cox
  2010-06-26  1:48                       ` Samo Pogacnik
                                         ` (3 more replies)
  0 siblings, 4 replies; 48+ messages in thread
From: Alan Cox @ 2010-06-25 11:03 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: linux-embedded, linux kernel

> +static int tpk_write_room(struct tty_struct *tty)
> +{
> +	int ret = tpk_space;
> +
> +	/* allow char by char under max pressure */
> +	if (tpk_space == 0)
> +		tpk_space = 1;

That won't do what you think, the ldisc will keep seeing progress and
generate millions of 1 byte I/Os in a loop !

Otherwise looks excellent.


> +	switch (cmd) {
> +	/* Stop TIOCCONS */
> +	case TIOCCONS:
> +		return -EOPNOTSUPP;

And I'll fix this bit up to work properly in the core code.


With my devices.txt owner hat on I'll allocate the minor as you suggest
(and double check this causes no problems), with my tty hat on can you
send it to GregKH for merging into the tree.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-25 11:03                     ` Alan Cox
@ 2010-06-26  1:48                       ` Samo Pogacnik
  2010-06-27 13:35                         ` Alan Cox
  2010-06-26 15:12                       ` Samo Pogacnik
                                         ` (2 subsequent siblings)
  3 siblings, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-06-26  1:48 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-embedded, linux kernel

> > +static int tpk_write_room(struct tty_struct *tty)
> > +{
> > +	int ret = tpk_space;
> > +
> > +	/* allow char by char under max pressure */
> > +	if (tpk_space == 0)
> > +		tpk_space = 1;
> 
> That won't do what you think, the ldisc will keep seeing progress and
> generate millions of 1 byte I/Os in a loop !

I thought that this would automatically reduce processor load, which is
obviously not the case. Sorry for the delay, but i am trying to figure
out how to slow down write method when under pressure.

And that setting tpk_space to 1 would then be just in case we reach 0 to
enable further processing.

Samo



^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-25 11:03                     ` Alan Cox
  2010-06-26  1:48                       ` Samo Pogacnik
@ 2010-06-26 15:12                       ` Samo Pogacnik
  2010-08-24 20:03                       ` Samo Pogacnik
  2010-08-24 20:57                       ` Samo Pogacnik
  3 siblings, 0 replies; 48+ messages in thread
From: Samo Pogacnik @ 2010-06-26 15:12 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-embedded, linux kernel

> > +static int tpk_write_room(struct tty_struct *tty)
> > +{
> > +	int ret = tpk_space;
> > +
> > +	/* allow char by char under max pressure */
> > +	if (tpk_space == 0)
> > +		tpk_space = 1;
> 
> That won't do what you think, the ldisc will keep seeing progress and
> generate millions of 1 byte I/Os in a loop !
> 
Somewhat changed to slowly increase delay in write, if ratelimiting
doesn't end.

> Otherwise looks excellent.
> 
Thanks to you.

> 
> > +	switch (cmd) {
> > +	/* Stop TIOCCONS */
> > +	case TIOCCONS:
> > +		return -EOPNOTSUPP;
> 
> And I'll fix this bit up to work properly in the core code.
> 
> 
> With my devices.txt owner hat on I'll allocate the minor as you suggest
> (and double check this causes no problems), with my tty hat on can you
> send it to GregKH for merging into the tree.
I am not sure if i understand. Should i exclude devices.txt from patch
before sending it to GregKH?

Samo
---
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..2fefa93
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,297 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/ratelimit.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+#define TTY_PRINTK_STR_SIZE 508
+static int tpk_space = TTY_PRINTK_STR_SIZE;
+static const char *tpk_tag = "[U] "; /* U for User */
+
+/*
+ * Ratelimiting support to handle to much output to this device,
+ * because of explicit writes or because of unintentional loop
+ * setup (caught printks again sent to this device).
+ */
+static struct ratelimit_state ttyprintk_rs = {
+	.interval = DEFAULT_RATELIMIT_INTERVAL,
+	.burst = DEFAULT_RATELIMIT_BURST,
+};
+
+static int tpk_ratelimiting;
+
+#define ttyprintk_printk(fmt, ...) \
+{ \
+	printk(KERN_INFO fmt, ##__VA_ARGS__); \
+}
+
+/*
+ * Our private ratelimit function, to suppress its printk warnings about
+ * missed callbacks, which are irrelevant in a flow control mechanism.
+ */
+static void ttyprintk_ratelimit(struct ratelimit_state *rs, int count)
+{
+	/* clear ratelimit missed callbacks counter */
+	rs->missed = 0;
+	if (__ratelimit(rs)) {
+		tpk_ratelimiting = 0;
+		tpk_space = TTY_PRINTK_STR_SIZE;
+		rs->burst = DEFAULT_RATELIMIT_BURST;
+	} else {
+		tpk_ratelimiting = 1;
+		if (TTY_PRINTK_STR_SIZE > count)
+			tpk_space = TTY_PRINTK_STR_SIZE - count;
+		else
+			tpk_space = 0;
+	}
+}
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ */
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TTY_PRINTK_STR_SIZE + 4];
+	static int curr;
+	int i = curr;
+
+	if (buf == NULL) {
+		/* flush tmp[] */
+		if (curr > 0) {
+			/* non nl or cr terminated message - add nl */
+			tmp[curr + 0] = '\n';
+			tmp[curr + 1] = '\0';
+			ttyprintk_printk("%s%s", tpk_tag, tmp);
+			curr = 0;
+		}
+		return i;
+	}
+
+	for (i = 0; i < count; i++) {
+		tmp[curr] = buf[i];
+		if (curr < TTY_PRINTK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[curr + 0] = '\n';
+				tmp[curr + 1] = '\0';
+				ttyprintk_printk("%s%s", tpk_tag, tmp);
+				curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[curr + 1] = '\0';
+				ttyprintk_printk("%s%s", tpk_tag, tmp);
+				curr = 0;
+				break;
+			default:
+				curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[curr + 1] = '\\';
+			tmp[curr + 2] = '\n';
+			tmp[curr + 3] = '\0';
+			ttyprintk_printk("%s%s", tpk_tag, tmp);
+			curr = 0;
+		}
+	}
+	if ((tpk_ratelimiting == 0) && (curr > 0)) {
+		/* non nl or cr terminated message - add nl */
+		tmp[curr + 0] = '\n';
+		tmp[curr + 1] = '\0';
+		ttyprintk_printk("%s%s", tpk_tag, tmp);
+		curr = 0;
+	}
+
+	return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	tty->driver_data = &tpk_port;
+
+	return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	mutex_lock(&tpkp->port_write_mutex);
+	/* flush tpk_printk buffer */
+	tpk_printk(NULL, 0);
+	tpk_space = TTY_PRINTK_STR_SIZE;
+	tpk_ratelimiting = 0;
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	static unsigned int tpk_write_delay;
+	struct ttyprintk_port *tpkp = tty->driver_data;
+	int ret;
+
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	ttyprintk_ratelimit(&ttyprintk_rs, count);
+	if (tpk_ratelimiting == 0) {
+		tpk_write_delay = 0;
+	} else {
+		/* increase delay under pressure upto 10 secs */
+		if (tpk_write_delay < 1000000)
+			tpk_write_delay++;
+		msleep_interruptible(tpk_write_delay / 100);
+
+		/* eliminate delay in ratelimiting */
+		ttyprintk_rs.burst = 1;
+		ttyprintk_rs.begin = 0;
+		__ratelimit(&ttyprintk_rs);
+	}
+
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+	int ret = tpk_space;
+
+	/* just in case we reach zero space, let one char available */
+	if (tpk_space == 0)
+		tpk_space = 1;
+
+	return ret;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *port;
+
+	port = tty->driver_data;
+
+	if (!port)
+		return -EINVAL;
+
+	switch (cmd) {
+	/* Stop TIOCCONS */
+	case TIOCCONS:
+		return -EOPNOTSUPP;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);



^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-26  1:48                       ` Samo Pogacnik
@ 2010-06-27 13:35                         ` Alan Cox
  2010-06-28 23:27                           ` Samo Pogacnik
  2010-07-03 19:21                           ` Samo Pogacnik
  0 siblings, 2 replies; 48+ messages in thread
From: Alan Cox @ 2010-06-27 13:35 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: linux-embedded, linux kernel

> I thought that this would automatically reduce processor load, which is
> obviously not the case. Sorry for the delay, but i am trying to figure
> out how to slow down write method when under pressure.

Ok I played with this a bit. Much to my surprise until I thought about it
in detail it all works fine without any of the ratelimiting at all. There
is a problem if you manage to redirect the console *in kernel* to the
printk driver, but that needs stopping anyway and rate limit won't fix it
(you blow the stack before it kicks in)

In the case where userspace loads it hard and its a graphical console
then we use a lot of CPU power drawing stuff on screen, but killing the
process does as is expected.

With a serial console the printk itself blocks which blocks the line
discipline which in turn slows stuff down.

The only two bad things I can see how to cause are

- Slowing down output by stuffing lots of extra data into the port (which
  I can do anyway just fine) so isn't worse than before.

- Filling up the dmesg log easily and hiding important messages. Not
  really a problem in this case bcause the whole point of this is
  embedded and capturing those messages as if they were system ones.

So much to my surprise the flow control is a red herring and best left
out.

Alan

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-27 13:35                         ` Alan Cox
@ 2010-06-28 23:27                           ` Samo Pogacnik
  2010-07-03 19:21                           ` Samo Pogacnik
  1 sibling, 0 replies; 48+ messages in thread
From: Samo Pogacnik @ 2010-06-28 23:27 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-embedded, linux kernel

Dne 27.06.2010 (ned) ob 14:35 +0100 je Alan Cox zapisal(a):
> > I thought that this would automatically reduce processor load, which is
> > obviously not the case. Sorry for the delay, but i am trying to figure
> > out how to slow down write method when under pressure.
> 
> Ok I played with this a bit. Much to my surprise until I thought about it
> in detail it all works fine without any of the ratelimiting at all. There
> is a problem if you manage to redirect the console *in kernel* to the
> printk driver, but that needs stopping anyway and rate limit won't fix it
> (you blow the stack before it kicks in)
> 
> In the case where userspace loads it hard and its a graphical console
> then we use a lot of CPU power drawing stuff on screen, but killing the
> process does as is expected.
> 
> With a serial console the printk itself blocks which blocks the line
> discipline which in turn slows stuff down.
> 
> The only two bad things I can see how to cause are
> 
> - Slowing down output by stuffing lots of extra data into the port (which
>   I can do anyway just fine) so isn't worse than before.
> 
> - Filling up the dmesg log easily and hiding important messages. Not
>   really a problem in this case bcause the whole point of this is
>   embedded and capturing those messages as if they were system ones.
> 
> So much to my surprise the flow control is a red herring and best left
> out.
> 
> Alan

If without flow control, do you think it makes sense to very slowly
introduce more and more delay (interruptible) into tty's write operation
when output rate is "too" high? That way non-error conditions would not
suffer (not discarding any messages, only delaying additional 1 msec on
100 writes), when ratelimit would have been exceeded from time to time.
And on the other hand endless high-volume output, which is probably an
error condition, would slowly give away more and more of its processing
time. Maybe this would also help if output is made on behalf of some
high RT-prioritized process?

Of course, i can easily remove ratelimiting as well, if the situation
with flow control isn't clear and this only complicates things.

Samo



^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-27 13:35                         ` Alan Cox
  2010-06-28 23:27                           ` Samo Pogacnik
@ 2010-07-03 19:21                           ` Samo Pogacnik
  1 sibling, 0 replies; 48+ messages in thread
From: Samo Pogacnik @ 2010-07-03 19:21 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-embedded, linux kernel

Hi,

Please bear with me for a bit longer, because i got slightly modified
perspective of some things i did within the driver.
I.e. somewhere down the road i forgot that my pre-formatting function
does not really limit output buffer size with its "one-line" buffer
size. So now 4K output size is assumed and always provided by
write_room(). The other thing is that i tried to resolve two things
being in conflict. I tried to fit driver to existing distro
initialization, which required immediate output also for not line
terminated strings. And on the other hand not line terminated strings
could have been provided by line discipline all the time. So i finally
removed immediate output code and let user takes care by terminating
lines if immediate output is required.

There is additional possibility to fine tune ratelimiting and printk
delaying parameters via defines also with more comments added.

Alan, if you agree, i would send this one to GregKH?

regards, Samo
---
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..22da614
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,283 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/ratelimit.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * Ratelimiting support to handle to much output to this device,
+ * because of explicit writes or because of unintentional loop
+ * setup (caught printks again sent to this device).
+ * Max TPK...BURST printks per TPK...INTERVAL
+ */
+#define TPK_RATELIMIT_INTERVAL (1 * HZ)
+#define TPK_RATELIMIT_BURST 10
+static struct ratelimit_state ttyprintk_rs = {
+	.interval = TPK_RATELIMIT_INTERVAL,
+	.burst = TPK_RATELIMIT_BURST,
+};
+
+static int tpk_ratelimiting;
+
+/*
+ * Our private ratelimit function, to suppress its printk warnings about
+ * missed callbacks, which doesn't really happen (not discarding messages).
+ * Calls final printk at the end.
+ * Raise delay on every TPK_SCALE_DELAY ratelimited printk for another
+ * milisecond and can not exceed TPK_MAX_DELAY.
+ * Delay is reset allways, when ratelimiting ends.
+ */
+#define TPK_SCALE_DELAY 10
+#define TPK_MAX_DELAY 2000 /* 1 secs */
+static void ttyprintk_ratelimit(const char *tag, const char *buf)
+{
+	static unsigned int tpk_write_delay;
+
+	/* clear ratelimit missed callbacks counter */
+	ttyprintk_rs.missed = 0;
+	if (__ratelimit(&ttyprintk_rs)) {
+		tpk_ratelimiting = 0;
+		ttyprintk_rs.burst = TPK_RATELIMIT_BURST;
+	} else
+		tpk_ratelimiting = 1;
+
+	if (tpk_ratelimiting == 0) {
+		tpk_write_delay = 0;
+	} else {
+		/* increase delay under pressure */
+		if (tpk_write_delay < (TPK_MAX_DELAY * TPK_SCALE_DELAY))
+			tpk_write_delay++;
+		msleep_interruptible(tpk_write_delay / TPK_SCALE_DELAY);
+
+		/* eliminate delay in ratelimiting */
+		ttyprintk_rs.burst = 1;
+		ttyprintk_rs.begin = 0;
+		__ratelimit(&ttyprintk_rs);
+	}
+
+	/* send the string down the drain */
+	printk(KERN_INFO "%s%s", tag, buf);
+}
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ * - TPK_STR_SIZE isn't really the write_room limiting factor, bcause
+ *   it is emptied on the fly during preformatting.
+ */
+#define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
+#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
+static const char *tpk_tag = "[U] "; /* U for User */
+static int tpk_curr;
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TPK_STR_SIZE + 4];
+	int i = tpk_curr;
+
+	if (buf == NULL) {
+		/* flush tmp[] */
+		if (tpk_curr > 0) {
+			/* non nl or cr terminated message - add nl */
+			tmp[tpk_curr + 0] = '\n';
+			tmp[tpk_curr + 1] = '\0';
+			ttyprintk_ratelimit(tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+		return i;
+	}
+
+	for (i = 0; i < count; i++) {
+		tmp[tpk_curr] = buf[i];
+		if (tpk_curr < TPK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[tpk_curr + 0] = '\n';
+				tmp[tpk_curr + 1] = '\0';
+				ttyprintk_ratelimit(tpk_tag, tmp);
+				tpk_curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[tpk_curr + 1] = '\0';
+				ttyprintk_ratelimit(tpk_tag, tmp);
+				tpk_curr = 0;
+				break;
+			default:
+				tpk_curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[tpk_curr + 1] = '\\';
+			tmp[tpk_curr + 2] = '\n';
+			tmp[tpk_curr + 3] = '\0';
+			ttyprintk_ratelimit(tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+	}
+
+	return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	tty->driver_data = &tpk_port;
+
+	return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	mutex_lock(&tpkp->port_write_mutex);
+	/* flush tpk_printk buffer */
+	tpk_printk(NULL, 0);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+	int ret;
+
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+	return TPK_MAX_ROOM;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	if (!tpkp)
+		return -EINVAL;
+
+	switch (cmd) {
+	/* Stop TIOCCONS */
+	case TIOCCONS:
+		return -EOPNOTSUPP;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);



^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-25 11:03                     ` Alan Cox
  2010-06-26  1:48                       ` Samo Pogacnik
  2010-06-26 15:12                       ` Samo Pogacnik
@ 2010-08-24 20:03                       ` Samo Pogacnik
  2010-08-24 20:13                         ` Greg KH
  2010-08-24 20:57                       ` Samo Pogacnik
  3 siblings, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-08-24 20:03 UTC (permalink / raw)
  To: linux kernel; +Cc: linux-embedded, Alan Cox, Greg Kroah-Hartman

On 25.06.2010 (Fri) at 12:03 +0100 Alan Cox wrote: 
> With my devices.txt owner hat on I'll allocate the minor as you suggest
> (and double check this causes no problems), with my tty hat on can you
> send it to GregKH for merging into the tree.

Hi,

I hope that this TTY driver is ok for merging. It is very basic -
removed all flow control and rate limiting. Patch has been generated
against 2.6.34 kernel version.

regards, Samo
---
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..c40c161
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,225 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ * - TPK_STR_SIZE isn't really the write_room limiting factor, bcause
+ *   it is emptied on the fly during preformatting.
+ */
+#define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
+#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
+static const char *tpk_tag = "[U] "; /* U for User */
+static int tpk_curr;
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TPK_STR_SIZE + 4];
+	int i = tpk_curr;
+
+	if (buf == NULL) {
+		/* flush tmp[] */
+		if (tpk_curr > 0) {
+			/* non nl or cr terminated message - add nl */
+			tmp[tpk_curr + 0] = '\n';
+			tmp[tpk_curr + 1] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+		return i;
+	}
+
+	for (i = 0; i < count; i++) {
+		tmp[tpk_curr] = buf[i];
+		if (tpk_curr < TPK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[tpk_curr + 0] = '\n';
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				break;
+			default:
+				tpk_curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[tpk_curr + 1] = '\\';
+			tmp[tpk_curr + 2] = '\n';
+			tmp[tpk_curr + 3] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+	}
+
+	return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	tty->driver_data = &tpk_port;
+
+	return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	mutex_lock(&tpkp->port_write_mutex);
+	/* flush tpk_printk buffer */
+	tpk_printk(NULL, 0);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+	int ret;
+
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+	return TPK_MAX_ROOM;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	if (!tpkp)
+		return -EINVAL;
+
+	switch (cmd) {
+	/* Stop TIOCCONS */
+	case TIOCCONS:
+		return -EOPNOTSUPP;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);



^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 20:03                       ` Samo Pogacnik
@ 2010-08-24 20:13                         ` Greg KH
  0 siblings, 0 replies; 48+ messages in thread
From: Greg KH @ 2010-08-24 20:13 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: linux kernel, linux-embedded, Alan Cox

On Tue, Aug 24, 2010 at 10:03:13PM +0200, Samo Pogacnik wrote:
> On 25.06.2010 (Fri) at 12:03 +0100 Alan Cox wrote: 
> > With my devices.txt owner hat on I'll allocate the minor as you suggest
> > (and double check this causes no problems), with my tty hat on can you
> > send it to GregKH for merging into the tree.
> 
> Hi,
> 
> I hope that this TTY driver is ok for merging. It is very basic -
> removed all flow control and rate limiting. Patch has been generated
> against 2.6.34 kernel version.
> 
> regards, Samo
> ---
> Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>

I need some information on what this patch is, and why we would want it,
so that it can be put into the changelog.  Care to resend it with that
information present?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-06-25 11:03                     ` Alan Cox
                                         ` (2 preceding siblings ...)
  2010-08-24 20:03                       ` Samo Pogacnik
@ 2010-08-24 20:57                       ` Samo Pogacnik
  2010-08-24 21:10                         ` Greg KH
  3 siblings, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-08-24 20:57 UTC (permalink / raw)
  To: linux kernel; +Cc: linux-embedded, Alan Cox, Greg Kroah-Hartman

On 25.06.2010 (Fri) at 12:03 +0100 Alan Cox wrote: 
> With my devices.txt owner hat on I'll allocate the minor as you suggest
> (and double check this causes no problems), with my tty hat on can you
> send it to GregKH for merging into the tree.

Hi,

I hope that this TTY driver is ok for merging. It is very basic -
removed all flow control and rate limiting. Patch has been generated
against 2.6.34 kernel version.

Ttyprintk is a pseudo TTY driver, which allows users to make printk messages,
via output to ttyprintk device. It is possible to store "console" messages
inline with kernel messages for better analyses of the boot process, for
example.

regards, Samo
---
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..c40c161
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,225 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ * - TPK_STR_SIZE isn't really the write_room limiting factor, bcause
+ *   it is emptied on the fly during preformatting.
+ */
+#define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
+#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
+static const char *tpk_tag = "[U] "; /* U for User */
+static int tpk_curr;
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TPK_STR_SIZE + 4];
+	int i = tpk_curr;
+
+	if (buf == NULL) {
+		/* flush tmp[] */
+		if (tpk_curr > 0) {
+			/* non nl or cr terminated message - add nl */
+			tmp[tpk_curr + 0] = '\n';
+			tmp[tpk_curr + 1] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+		return i;
+	}
+
+	for (i = 0; i < count; i++) {
+		tmp[tpk_curr] = buf[i];
+		if (tpk_curr < TPK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[tpk_curr + 0] = '\n';
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				break;
+			default:
+				tpk_curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[tpk_curr + 1] = '\\';
+			tmp[tpk_curr + 2] = '\n';
+			tmp[tpk_curr + 3] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+	}
+
+	return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	tty->driver_data = &tpk_port;
+
+	return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	mutex_lock(&tpkp->port_write_mutex);
+	/* flush tpk_printk buffer */
+	tpk_printk(NULL, 0);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+	int ret;
+
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+	return TPK_MAX_ROOM;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	if (!tpkp)
+		return -EINVAL;
+
+	switch (cmd) {
+	/* Stop TIOCCONS */
+	case TIOCCONS:
+		return -EOPNOTSUPP;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);



^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 20:57                       ` Samo Pogacnik
@ 2010-08-24 21:10                         ` Greg KH
  2010-08-24 22:09                           ` Samo Pogacnik
  2010-08-24 22:16                           ` Alan Cox
  0 siblings, 2 replies; 48+ messages in thread
From: Greg KH @ 2010-08-24 21:10 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: linux kernel, linux-embedded, Alan Cox

On Tue, Aug 24, 2010 at 10:57:50PM +0200, Samo Pogacnik wrote:
> On 25.06.2010 (Fri) at 12:03 +0100 Alan Cox wrote: 
> > With my devices.txt owner hat on I'll allocate the minor as you suggest
> > (and double check this causes no problems), with my tty hat on can you
> > send it to GregKH for merging into the tree.
> 
> Hi,
> 
> I hope that this TTY driver is ok for merging. It is very basic -
> removed all flow control and rate limiting. Patch has been generated
> against 2.6.34 kernel version.
> 
> Ttyprintk is a pseudo TTY driver, which allows users to make printk messages,
> via output to ttyprintk device. It is possible to store "console" messages
> inline with kernel messages for better analyses of the boot process, for
> example.

Why does this need to be a tty driver?  Why not a misc device?

And what about the normal way of just writing to /dev/kmsg to do this?
Why a whole new driver for this same functionality?

confused,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 22:16                           ` Alan Cox
@ 2010-08-24 22:02                             ` Greg KH
  0 siblings, 0 replies; 48+ messages in thread
From: Greg KH @ 2010-08-24 22:02 UTC (permalink / raw)
  To: Alan Cox; +Cc: Samo Pogacnik, linux kernel, linux-embedded

On Tue, Aug 24, 2010 at 11:16:41PM +0100, Alan Cox wrote:
> > Why does this need to be a tty driver?  Why not a misc device?
> 
> So you can use it as a"console" (in the user space sense) tty device on
> embedded devices which don't have a meaningful normal output subsystem.

But can't you do that today with kmsg?  The startup of systemd does this
in a way that handles all of the log messages very nicely, and the
embedded people are sure to pick it up as well because of the
simplicity.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 21:10                         ` Greg KH
@ 2010-08-24 22:09                           ` Samo Pogacnik
  2010-08-24 22:20                             ` Greg KH
  2010-08-24 22:16                           ` Alan Cox
  1 sibling, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-08-24 22:09 UTC (permalink / raw)
  To: Greg KH; +Cc: linux kernel, linux-embedded, Alan Cox

On 24.08.2010 (Tue) at 14:10 -0700 Greg KH wrote:
> On Tue, Aug 24, 2010 at 10:57:50PM +0200, Samo Pogacnik wrote:
> > On 25.06.2010 (Fri) at 12:03 +0100 Alan Cox wrote: 
> > > With my devices.txt owner hat on I'll allocate the minor as you suggest
> > > (and double check this causes no problems), with my tty hat on can you
> > > send it to GregKH for merging into the tree.
> > 
> > Hi,
> > 
> > I hope that this TTY driver is ok for merging. It is very basic -
> > removed all flow control and rate limiting. Patch has been generated
> > against 2.6.34 kernel version.
> > 
> > Ttyprintk is a pseudo TTY driver, which allows users to make printk messages,
> > via output to ttyprintk device. It is possible to store "console" messages
> > inline with kernel messages for better analyses of the boot process, for
> > example.
> 
> Why does this need to be a tty driver?  Why not a misc device?
Thanks for the response. I'll try to explain.
Well it all started with a kernel hack, which internaly redirected
console output to printk function to be able to capture console messages
inline with real kernel messages. Console messages have also been
automatically stored via system logging facility, which was very useful
especially for analyzes of the initrd part of the userspace system
initialization. Through initial posts (thread: console logging detour
via printk) Alan suggested, that a separate TTY driver could provide
this functionality and that may initial hacking isn't acceptable.
> 
> And what about the normal way of just writing to /dev/kmsg to do this?
> Why a whole new driver for this same functionality?
I must admit, i was not aware of the /dev/kmsg driver, but i made a few
tests and found out that it seems not to be possible to redirect console
to kmsg.

regards, Samo


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 21:10                         ` Greg KH
  2010-08-24 22:09                           ` Samo Pogacnik
@ 2010-08-24 22:16                           ` Alan Cox
  2010-08-24 22:02                             ` Greg KH
  1 sibling, 1 reply; 48+ messages in thread
From: Alan Cox @ 2010-08-24 22:16 UTC (permalink / raw)
  To: Greg KH; +Cc: Samo Pogacnik, linux kernel, linux-embedded

> Why does this need to be a tty driver?  Why not a misc device?

So you can use it as a"console" (in the user space sense) tty device on
embedded devices which don't have a meaningful normal output subsystem.

Alan

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 22:09                           ` Samo Pogacnik
@ 2010-08-24 22:20                             ` Greg KH
  2010-08-24 22:50                               ` Samo Pogacnik
  0 siblings, 1 reply; 48+ messages in thread
From: Greg KH @ 2010-08-24 22:20 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: linux kernel, linux-embedded, Alan Cox

On Wed, Aug 25, 2010 at 12:09:57AM +0200, Samo Pogacnik wrote:
> On 24.08.2010 (Tue) at 14:10 -0700 Greg KH wrote:
> > On Tue, Aug 24, 2010 at 10:57:50PM +0200, Samo Pogacnik wrote:
> > > On 25.06.2010 (Fri) at 12:03 +0100 Alan Cox wrote: 
> > > > With my devices.txt owner hat on I'll allocate the minor as you suggest
> > > > (and double check this causes no problems), with my tty hat on can you
> > > > send it to GregKH for merging into the tree.
> > > 
> > > Hi,
> > > 
> > > I hope that this TTY driver is ok for merging. It is very basic -
> > > removed all flow control and rate limiting. Patch has been generated
> > > against 2.6.34 kernel version.
> > > 
> > > Ttyprintk is a pseudo TTY driver, which allows users to make printk messages,
> > > via output to ttyprintk device. It is possible to store "console" messages
> > > inline with kernel messages for better analyses of the boot process, for
> > > example.
> > 
> > Why does this need to be a tty driver?  Why not a misc device?
> Thanks for the response. I'll try to explain.
> Well it all started with a kernel hack, which internaly redirected
> console output to printk function to be able to capture console messages
> inline with real kernel messages. Console messages have also been
> automatically stored via system logging facility, which was very useful
> especially for analyzes of the initrd part of the userspace system
> initialization. Through initial posts (thread: console logging detour
> via printk) Alan suggested, that a separate TTY driver could provide
> this functionality and that may initial hacking isn't acceptable.

That's what kmsg can do :)

> > And what about the normal way of just writing to /dev/kmsg to do this?
> > Why a whole new driver for this same functionality?
> I must admit, i was not aware of the /dev/kmsg driver, but i made a few
> tests and found out that it seems not to be possible to redirect console
> to kmsg.

See how systemd does this, as it sounds like exactly what you want to
do.  Look in either Fedora 14, or openSUSE Factory for examples of this,
with no kernel changes needed.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 22:20                             ` Greg KH
@ 2010-08-24 22:50                               ` Samo Pogacnik
  2010-08-24 22:57                                 ` Greg KH
  0 siblings, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-08-24 22:50 UTC (permalink / raw)
  To: Greg KH; +Cc: linux kernel, linux-embedded, Alan Cox

Dne 24.08.2010 (tor) ob 15:20 -0700 je Greg KH zapisal(a):
> > > And what about the normal way of just writing to /dev/kmsg to do this?
> > > Why a whole new driver for this same functionality?
> > I must admit, i was not aware of the /dev/kmsg driver, but i made a few
> > tests and found out that it seems not to be possible to redirect console
> > to kmsg.
> 
> See how systemd does this, as it sounds like exactly what you want to
> do.  Look in either Fedora 14, or openSUSE Factory for examples of this,
> with no kernel changes needed.
> 
I'll check out systemd. 

however:)
It may be that systemd does not cover the initrd part of the
initialization and it may be an overkill do introduce systemd to an
existing system just to be analyzed.

regards, Samo


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 22:50                               ` Samo Pogacnik
@ 2010-08-24 22:57                                 ` Greg KH
  2010-08-24 23:22                                   ` Alan Cox
  0 siblings, 1 reply; 48+ messages in thread
From: Greg KH @ 2010-08-24 22:57 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: linux kernel, linux-embedded, Alan Cox

On Wed, Aug 25, 2010 at 12:50:32AM +0200, Samo Pogacnik wrote:
> Dne 24.08.2010 (tor) ob 15:20 -0700 je Greg KH zapisal(a):
> > > > And what about the normal way of just writing to /dev/kmsg to do this?
> > > > Why a whole new driver for this same functionality?
> > > I must admit, i was not aware of the /dev/kmsg driver, but i made a few
> > > tests and found out that it seems not to be possible to redirect console
> > > to kmsg.
> > 
> > See how systemd does this, as it sounds like exactly what you want to
> > do.  Look in either Fedora 14, or openSUSE Factory for examples of this,
> > with no kernel changes needed.
> > 
> I'll check out systemd. 
> 
> however:)
> It may be that systemd does not cover the initrd part of the
> initialization and it may be an overkill do introduce systemd to an
> existing system just to be analyzed.

No, it does cover that.  You should be able to do that with a simple
console redirection to /dev/kmsg  What happened when you tried to do
that?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 23:22                                   ` Alan Cox
@ 2010-08-24 23:12                                     ` Greg KH
  2010-08-24 23:51                                       ` Alan Cox
  2010-08-25  7:40                                       ` [PATCH] detour TTY driver - now ttyprintk Kay Sievers
  0 siblings, 2 replies; 48+ messages in thread
From: Greg KH @ 2010-08-24 23:12 UTC (permalink / raw)
  To: Alan Cox, Kay Sievers; +Cc: Samo Pogacnik, linux kernel, linux-embedded

On Wed, Aug 25, 2010 at 12:22:21AM +0100, Alan Cox wrote:
> > No, it does cover that.  You should be able to do that with a simple
> > console redirection to /dev/kmsg  What happened when you tried to do
> > that?
> 
> stty: standard input: Inappropriate ioctl for device

Kay, how does systemd handle the kmsg console redirection?

> It's value is twofold
> 
> - formatting

Ick, we really want to format things from userspace here?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 22:57                                 ` Greg KH
@ 2010-08-24 23:22                                   ` Alan Cox
  2010-08-24 23:12                                     ` Greg KH
  0 siblings, 1 reply; 48+ messages in thread
From: Alan Cox @ 2010-08-24 23:22 UTC (permalink / raw)
  To: Greg KH; +Cc: Samo Pogacnik, linux kernel, linux-embedded

> No, it does cover that.  You should be able to do that with a simple
> console redirection to /dev/kmsg  What happened when you tried to do
> that?

stty: standard input: Inappropriate ioctl for device

It's value is twofold

- formatting
- tty ioctls work as they should on a console (eg vhangup)

and its a tiny driver with no impact on the rest of the kernel - so to me
it seems useful in that form.

Alan

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 23:12                                     ` Greg KH
@ 2010-08-24 23:51                                       ` Alan Cox
  2010-08-25  0:41                                         ` Greg KH
  2010-08-25  7:40                                       ` [PATCH] detour TTY driver - now ttyprintk Kay Sievers
  1 sibling, 1 reply; 48+ messages in thread
From: Alan Cox @ 2010-08-24 23:51 UTC (permalink / raw)
  To: Greg KH; +Cc: Kay Sievers, Samo Pogacnik, linux kernel, linux-embedded

> > - formatting
> 
> Ick, we really want to format things from userspace here?

Depends what you are trying to do.

Put an embedded hat on

Do you want to be able to flip between a real debug interface and a
logging device on the same software set without risking changing behaviour

Do you want to load a 70K daemon and an initrd or burn about 1.5K on a
kernel interface ?

Alan

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 23:51                                       ` Alan Cox
@ 2010-08-25  0:41                                         ` Greg KH
  2010-08-25  6:50                                           ` Marco Stornelli
  2010-08-25 10:08                                           ` Alan Cox
  0 siblings, 2 replies; 48+ messages in thread
From: Greg KH @ 2010-08-25  0:41 UTC (permalink / raw)
  To: Alan Cox; +Cc: Kay Sievers, Samo Pogacnik, linux kernel, linux-embedded

On Wed, Aug 25, 2010 at 12:51:52AM +0100, Alan Cox wrote:
> > > - formatting
> > 
> > Ick, we really want to format things from userspace here?
> 
> Depends what you are trying to do.
> 
> Put an embedded hat on
> 
> Do you want to be able to flip between a real debug interface and a
> logging device on the same software set without risking changing behaviour

I don't understand this point.

> Do you want to load a 70K daemon and an initrd or burn about 1.5K on a
> kernel interface ?

I'd rather burn 0K on the one we have today :)

Seriously, look at how Fedora 14 handles this, why can't you do the same
for embedded systems all from userspace, no additional code needed
anywhere.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25  0:41                                         ` Greg KH
@ 2010-08-25  6:50                                           ` Marco Stornelli
  2010-08-25 10:08                                           ` Alan Cox
  1 sibling, 0 replies; 48+ messages in thread
From: Marco Stornelli @ 2010-08-25  6:50 UTC (permalink / raw)
  To: Samo Pogacnik
  Cc: Alan Cox, Kay Sievers, linux kernel, linux-embedded, Greg KH

2010/8/25 Greg KH <gregkh@suse.de>:
> On Wed, Aug 25, 2010 at 12:51:52AM +0100, Alan Cox wrote:
>
> Seriously, look at how Fedora 14 handles this, why can't you do the same
> for embedded systems all from userspace, no additional code needed
> anywhere.
>
> thanks,
>
> greg k-h
> --

Samo sometimes ago I gave you some information on the system startup
about OpenSuse, have you look at it? It's possible that what Greg
said, it's true.

Regards,

Marco

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-24 23:12                                     ` Greg KH
  2010-08-24 23:51                                       ` Alan Cox
@ 2010-08-25  7:40                                       ` Kay Sievers
  2010-08-25  7:48                                         ` Kay Sievers
  1 sibling, 1 reply; 48+ messages in thread
From: Kay Sievers @ 2010-08-25  7:40 UTC (permalink / raw)
  To: Greg KH; +Cc: Alan Cox, Samo Pogacnik, linux kernel, linux-embedded

On Wed, Aug 25, 2010 at 01:12, Greg KH <gregkh@suse.de> wrote:
> On Wed, Aug 25, 2010 at 12:22:21AM +0100, Alan Cox wrote:
>> > No, it does cover that.  You should be able to do that with a simple
>> > console redirection to /dev/kmsg  What happened when you tried to do
>> > that?
>>
>> stty: standard input: Inappropriate ioctl for device
>
> Kay, how does systemd handle the kmsg console redirection?

Systemd does not steal the console, this is done by plymouth, in the
same way blogd can do that. It uses a pty and rewrites the messages.

Systemd does pass syslog to the kernel buffer during early boot. Init
provides /dev/log. With systemd, the started services usually don't
get the console connected, but use syslog anyway or the stdout/err
gets redirected to syslog.

With systemd the console is not too useful because we start everything
in parallel. If all the services would put out stuff there like sysv
did, it would look like a real mess.

Kay

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25  7:40                                       ` [PATCH] detour TTY driver - now ttyprintk Kay Sievers
@ 2010-08-25  7:48                                         ` Kay Sievers
  0 siblings, 0 replies; 48+ messages in thread
From: Kay Sievers @ 2010-08-25  7:48 UTC (permalink / raw)
  To: Greg KH; +Cc: Alan Cox, Samo Pogacnik, linux kernel, linux-embedded

On Wed, Aug 25, 2010 at 09:40, Kay Sievers <kay.sievers@vrfy.org> wrote:
> On Wed, Aug 25, 2010 at 01:12, Greg KH <gregkh@suse.de> wrote:
>> On Wed, Aug 25, 2010 at 12:22:21AM +0100, Alan Cox wrote:
>>> > No, it does cover that.  You should be able to do that with a simple
>>> > console redirection to /dev/kmsg  What happened when you tried to do
>>> > that?
>>>
>>> stty: standard input: Inappropriate ioctl for device
>>
>> Kay, how does systemd handle the kmsg console redirection?
>
> Systemd does not steal the console, this is done by plymouth, in the
> same way blogd can do that. It uses a pty and rewrites the messages.
>
> Systemd does pass syslog to the kernel buffer during early boot. Init
> provides /dev/log. With systemd, the started services usually don't
> get the console connected, but use syslog anyway or the stdout/err
> gets redirected to syslog.
>
> With systemd the console is not too useful because we start everything
> in parallel. If all the services would put out stuff there like sysv
> did, it would look like a real mess.

Or isn't that what you asked for? We just write the stuff that arrives
at syslog to /dev/kmsg to put things in the kernel log buffer.

Also initrds are usually using
  exec < /dev/console > /dev/kmsg 2>&1
to get stuff directly to the kernel buffer.

What does /dev/ttyprintk offer on top of that?

Kay

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25  0:41                                         ` Greg KH
  2010-08-25  6:50                                           ` Marco Stornelli
@ 2010-08-25 10:08                                           ` Alan Cox
  2010-08-25 15:57                                             ` Greg KH
  1 sibling, 1 reply; 48+ messages in thread
From: Alan Cox @ 2010-08-25 10:08 UTC (permalink / raw)
  To: Greg KH; +Cc: Kay Sievers, Samo Pogacnik, linux kernel, linux-embedded

> > Do you want to be able to flip between a real debug interface and a
> > logging device on the same software set without risking changing behaviour
> 
> I don't understand this point.

A tty has a very specific set of behaviours simply by being a tty. Some
applications rely upon them so being able to flip between the two
interfaces is useful.

> > Do you want to load a 70K daemon and an initrd or burn about 1.5K on a
> > kernel interface ?
> 
> I'd rather burn 0K on the one we have today :)

So say "N" when configuring

> Seriously, look at how Fedora 14 handles this, why can't you do the same
> for embedded systems all from userspace, no additional code needed
> anywhere.

Its a whole set of extra processes and daemons and stuff, and
minimally uses something like 70K even if its very compact (8K stack, 40K+
page tables, 16K of buffers, code, data) - oh and I forgot the fifo
buffering and pty cost - so its near 100K. 1.5K v 100K - for something
1.5K of kernel code that anyone else can turn off and would be off by
default ?

On a lot of embedded systems you don't have all the stuff Fedora carts
around. No modules, initrds, magic front end processes, graphical startup
daemons etc, all of which work to produce that feature IFF you have pty
support in your kernel, and for the current code also glibc.

You also want errors to get out (or stored) even if there are crashes -
which the Fedora one is not very good at. To be fair in the Fedora world
its not a big deal to say 'Oh dear, boot with ....'. Embedded isn't the
same, and you want to capture the odd rare error reliably.

Alan



^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25 10:08                                           ` Alan Cox
@ 2010-08-25 15:57                                             ` Greg KH
  2010-08-25 17:11                                               ` Alan Cox
  0 siblings, 1 reply; 48+ messages in thread
From: Greg KH @ 2010-08-25 15:57 UTC (permalink / raw)
  To: Alan Cox; +Cc: Kay Sievers, Samo Pogacnik, linux kernel, linux-embedded

On Wed, Aug 25, 2010 at 11:08:13AM +0100, Alan Cox wrote:
> > > Do you want to be able to flip between a real debug interface and a
> > > logging device on the same software set without risking changing behaviour
> > 
> > I don't understand this point.
> 
> A tty has a very specific set of behaviours simply by being a tty. Some
> applications rely upon them so being able to flip between the two
> interfaces is useful.

Would that work for this driver in use as a console?

> > Seriously, look at how Fedora 14 handles this, why can't you do the same
> > for embedded systems all from userspace, no additional code needed
> > anywhere.
> 
> Its a whole set of extra processes and daemons and stuff, and
> minimally uses something like 70K even if its very compact (8K stack, 40K+
> page tables, 16K of buffers, code, data) - oh and I forgot the fifo
> buffering and pty cost - so its near 100K. 1.5K v 100K - for something
> 1.5K of kernel code that anyone else can turn off and would be off by
> default ?

  exec < /dev/console > /dev/kmsg 2>&1

That's one extra process, not that much, right?

> On a lot of embedded systems you don't have all the stuff Fedora carts
> around. No modules, initrds, magic front end processes, graphical startup
> daemons etc, all of which work to produce that feature IFF you have pty
> support in your kernel, and for the current code also glibc.

It sounded like they had an initrd that they cared about here.

> You also want errors to get out (or stored) even if there are crashes -
> which the Fedora one is not very good at. To be fair in the Fedora world
> its not a big deal to say 'Oh dear, boot with ....'. Embedded isn't the
> same, and you want to capture the odd rare error reliably.

again, the above exec line should work for what the embedded people
want, right?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25 17:11                                               ` Alan Cox
@ 2010-08-25 17:10                                                 ` Greg KH
  2010-08-25 18:14                                                   ` Alan Cox
  2010-08-25 18:44                                                   ` Samo Pogacnik
  0 siblings, 2 replies; 48+ messages in thread
From: Greg KH @ 2010-08-25 17:10 UTC (permalink / raw)
  To: Alan Cox; +Cc: Kay Sievers, Samo Pogacnik, linux kernel, linux-embedded

On Wed, Aug 25, 2010 at 06:11:08PM +0100, Alan Cox wrote:
> > Would that work for this driver in use as a console?
> 
> Yes
> 
> >   exec < /dev/console > /dev/kmsg 2>&1
> > 
> > That's one extra process, not that much, right?
> 
> About 150K or so way too much and its not robust.

Fair enough.  So, with this driver, would it make sense for the distros
to switch over to using it instead of the above line in their initrd?

> > > You also want errors to get out (or stored) even if there are crashes -
> > > which the Fedora one is not very good at. To be fair in the Fedora world
> > > its not a big deal to say 'Oh dear, boot with ....'. Embedded isn't the
> > > same, and you want to capture the odd rare error reliably.
> > 
> > again, the above exec line should work for what the embedded people
> > want, right?
> 
> We didn't *need* devtmpfs either - that was a little bit of user space.
> It's a similar thing - you can do the job better in 1.5K of kernel code
> than 150K or more of user space - which is not trivial on a box with no
> swap.

Ok, I didn't realize it really was that big.

Samo, care to resend the patch?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25 15:57                                             ` Greg KH
@ 2010-08-25 17:11                                               ` Alan Cox
  2010-08-25 17:10                                                 ` Greg KH
  0 siblings, 1 reply; 48+ messages in thread
From: Alan Cox @ 2010-08-25 17:11 UTC (permalink / raw)
  To: Greg KH; +Cc: Kay Sievers, Samo Pogacnik, linux kernel, linux-embedded

> Would that work for this driver in use as a console?

Yes

>   exec < /dev/console > /dev/kmsg 2>&1
> 
> That's one extra process, not that much, right?

About 150K or so way too much and its not robust.

> > You also want errors to get out (or stored) even if there are crashes -
> > which the Fedora one is not very good at. To be fair in the Fedora world
> > its not a big deal to say 'Oh dear, boot with ....'. Embedded isn't the
> > same, and you want to capture the odd rare error reliably.
> 
> again, the above exec line should work for what the embedded people
> want, right?

We didn't *need* devtmpfs either - that was a little bit of user space.
It's a similar thing - you can do the job better in 1.5K of kernel code
than 150K or more of user space - which is not trivial on a box with no
swap.

Alan

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25 17:10                                                 ` Greg KH
@ 2010-08-25 18:14                                                   ` Alan Cox
  2010-08-25 18:16                                                     ` Greg KH
  2010-08-25 18:44                                                   ` Samo Pogacnik
  1 sibling, 1 reply; 48+ messages in thread
From: Alan Cox @ 2010-08-25 18:14 UTC (permalink / raw)
  To: Greg KH; +Cc: Kay Sievers, Samo Pogacnik, linux kernel, linux-embedded

> > > That's one extra process, not that much, right?
> > 
> > About 150K or so way too much and its not robust.
> 
> Fair enough.  So, with this driver, would it make sense for the distros
> to switch over to using it instead of the above line in their initrd?

Distros no - I doubt any normal PC distro would turn the facility on.
Embedded - yes especially deeply embedded.

> Ok, I didn't realize it really was that big.

libc page tables
app page tables
stacks (kernel and user)
arguments/exec page
buffers

Yes - it soon adds up.

Alan

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25 18:14                                                   ` Alan Cox
@ 2010-08-25 18:16                                                     ` Greg KH
  2010-08-25 19:30                                                       ` Alan Cox
  2010-08-26 17:24                                                       ` Samo Pogacnik
  0 siblings, 2 replies; 48+ messages in thread
From: Greg KH @ 2010-08-25 18:16 UTC (permalink / raw)
  To: Alan Cox; +Cc: Kay Sievers, Samo Pogacnik, linux kernel, linux-embedded

On Wed, Aug 25, 2010 at 07:14:37PM +0100, Alan Cox wrote:
> > > > That's one extra process, not that much, right?
> > > 
> > > About 150K or so way too much and its not robust.
> > 
> > Fair enough.  So, with this driver, would it make sense for the distros
> > to switch over to using it instead of the above line in their initrd?
> 
> Distros no - I doubt any normal PC distro would turn the facility on.
> Embedded - yes especially deeply embedded.

So should this be dependent on CONFIG_EMBEDDED then?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25 17:10                                                 ` Greg KH
  2010-08-25 18:14                                                   ` Alan Cox
@ 2010-08-25 18:44                                                   ` Samo Pogacnik
  2010-09-01 22:50                                                       ` gregkh
  1 sibling, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-08-25 18:44 UTC (permalink / raw)
  To: linux kernel; +Cc: linux-embedded, Greg KH, Alan Cox, Kay Sievers

On 25.08.2010 Greg KH wrote:
> Samo, care to resend the patch?
> 
Sure, here it is:
---
I hope that this TTY driver is ok for merging. It is very basic -
removed all flow control and rate limiting. Patch has been generated
against 2.6.34 kernel version.

Ttyprintk is a pseudo TTY driver, which allows users to make printk
messages, via output to ttyprintk device. It is possible to store
"console" messages inline with kernel messages for better analyses of
the boot process, for example.

regards, Samo
---
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..c40c161
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,225 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ * - TPK_STR_SIZE isn't really the write_room limiting factor, bcause
+ *   it is emptied on the fly during preformatting.
+ */
+#define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
+#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
+static const char *tpk_tag = "[U] "; /* U for User */
+static int tpk_curr;
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TPK_STR_SIZE + 4];
+	int i = tpk_curr;
+
+	if (buf == NULL) {
+		/* flush tmp[] */
+		if (tpk_curr > 0) {
+			/* non nl or cr terminated message - add nl */
+			tmp[tpk_curr + 0] = '\n';
+			tmp[tpk_curr + 1] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+		return i;
+	}
+
+	for (i = 0; i < count; i++) {
+		tmp[tpk_curr] = buf[i];
+		if (tpk_curr < TPK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[tpk_curr + 0] = '\n';
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				break;
+			default:
+				tpk_curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[tpk_curr + 1] = '\\';
+			tmp[tpk_curr + 2] = '\n';
+			tmp[tpk_curr + 3] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+	}
+
+	return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	tty->driver_data = &tpk_port;
+
+	return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	mutex_lock(&tpkp->port_write_mutex);
+	/* flush tpk_printk buffer */
+	tpk_printk(NULL, 0);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+	int ret;
+
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+	return TPK_MAX_ROOM;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	if (!tpkp)
+		return -EINVAL;
+
+	switch (cmd) {
+	/* Stop TIOCCONS */
+	case TIOCCONS:
+		return -EOPNOTSUPP;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);



^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25 18:16                                                     ` Greg KH
@ 2010-08-25 19:30                                                       ` Alan Cox
  2010-08-26 17:24                                                       ` Samo Pogacnik
  1 sibling, 0 replies; 48+ messages in thread
From: Alan Cox @ 2010-08-25 19:30 UTC (permalink / raw)
  To: Greg KH; +Cc: Kay Sievers, Samo Pogacnik, linux kernel, linux-embedded

On Wed, 25 Aug 2010 11:16:47 -0700
Greg KH <gregkh@suse.de> wrote:

> On Wed, Aug 25, 2010 at 07:14:37PM +0100, Alan Cox wrote:
> > > > > That's one extra process, not that much, right?
> > > > 
> > > > About 150K or so way too much and its not robust.
> > > 
> > > Fair enough.  So, with this driver, would it make sense for the distros
> > > to switch over to using it instead of the above line in their initrd?
> > 
> > Distros no - I doubt any normal PC distro would turn the facility on.
> > Embedded - yes especially deeply embedded.
> 
> So should this be dependent on CONFIG_EMBEDDED then?

No objection to that

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-25 18:16                                                     ` Greg KH
  2010-08-25 19:30                                                       ` Alan Cox
@ 2010-08-26 17:24                                                       ` Samo Pogacnik
  2010-08-26 23:02                                                         ` Greg KH
  1 sibling, 1 reply; 48+ messages in thread
From: Samo Pogacnik @ 2010-08-26 17:24 UTC (permalink / raw)
  To: Greg KH; +Cc: Alan Cox, Kay Sievers, linux kernel, linux-embedded

On 25.08.2010 (sre) at 11:16 -0700 Greg KH wrote:
> On Wed, Aug 25, 2010 at 07:14:37PM +0100, Alan Cox wrote:
> > > > > That's one extra process, not that much, right?
> > > > 
> > > > About 150K or so way too much and its not robust.
> > > 
> > > Fair enough.  So, with this driver, would it make sense for the distros
> > > to switch over to using it instead of the above line in their initrd?
> > 
> > Distros no - I doubt any normal PC distro would turn the facility on.
> > Embedded - yes especially deeply embedded.
> 
> So should this be dependent on CONFIG_EMBEDDED then?
> 

Should i resend the patch with CONFIG_EMBEDDED dependency enabled? I do
not have any real objections to that, except that the driver operates
the same way regardless of the (non-)embedded configuration.

regards, Samo


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH] detour TTY driver - now ttyprintk
  2010-08-26 17:24                                                       ` Samo Pogacnik
@ 2010-08-26 23:02                                                         ` Greg KH
  0 siblings, 0 replies; 48+ messages in thread
From: Greg KH @ 2010-08-26 23:02 UTC (permalink / raw)
  To: Samo Pogacnik; +Cc: Alan Cox, Kay Sievers, linux kernel, linux-embedded

On Thu, Aug 26, 2010 at 07:24:44PM +0200, Samo Pogacnik wrote:
> On 25.08.2010 (sre) at 11:16 -0700 Greg KH wrote:
> > On Wed, Aug 25, 2010 at 07:14:37PM +0100, Alan Cox wrote:
> > > > > > That's one extra process, not that much, right?
> > > > > 
> > > > > About 150K or so way too much and its not robust.
> > > > 
> > > > Fair enough.  So, with this driver, would it make sense for the distros
> > > > to switch over to using it instead of the above line in their initrd?
> > > 
> > > Distros no - I doubt any normal PC distro would turn the facility on.
> > > Embedded - yes especially deeply embedded.
> > 
> > So should this be dependent on CONFIG_EMBEDDED then?
> > 
> 
> Should i resend the patch with CONFIG_EMBEDDED dependency enabled? I do
> not have any real objections to that, except that the driver operates
> the same way regardless of the (non-)embedded configuration.

No, I can change it when I apply the patch next week (sorry, swamped at
the moment.)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* patch "add ttyprintk driver" added to gregkh-2.6 tree
  2010-08-25 18:44                                                   ` Samo Pogacnik
@ 2010-09-01 22:50                                                       ` gregkh
  0 siblings, 0 replies; 48+ messages in thread
From: gregkh @ 2010-09-01 22:50 UTC (permalink / raw)
  To: samo_pogacnik, alan, gregkh, kay.sievers, linux-embedded, linux-kernel


This is a note to let you know that I've just added the patch titled

    add ttyprintk driver

to my gregkh-2.6 tree which can be found in directory form at:
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/
 and in git form at:
    git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/patches.git

The filename of this patch is:
    add-ttyprintk-driver.patch

The patch will show up in the next release of the linux-next tree
(usually sometime within the next 24 hours during the week.)

If this patch meets the merge guidelines for a bugfix, it should be
merged into Linus's tree before the next major kernel release.
If not, it will be merged into Linus's tree during the next merge window.

Either way, you will probably be copied on the patch when it gets sent
to Linus for merging so that others can see what is happening in kernel
development.

If you have any questions about this process, please let me know.


>From samo_pogacnik@t-2.net  Wed Sep  1 15:35:26 2010
Subject: add ttyprintk driver
From: Samo Pogacnik <samo_pogacnik@t-2.net>
To: linux kernel <linux-kernel@vger.kernel.org>
Cc: linux-embedded <linux-embedded@vger.kernel.org>,
	Greg KH <gregkh@suse.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>,
	Kay Sievers <kay.sievers@vrfy.org>
Date: Wed, 25 Aug 2010 20:44:07 +0200
Message-Id: <1282761847.5857.9.camel@itpsd6lap>


Ttyprintk is a pseudo TTY driver, which allows users to make printk
messages, via output to ttyprintk device. It is possible to store
"console" messages inline with kernel messages for better analyses of
the boot process, for example.

Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
 Documentation/devices.txt |    1 
 drivers/char/Kconfig      |   15 +++
 drivers/char/Makefile     |    1 
 drivers/char/ttyprintk.c  |  225 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 242 insertions(+)

--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -493,6 +493,21 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	depends on EMBEDDED
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -12,6 +12,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.
 obj-y				+= tty_mutex.o
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
--- /dev/null
+++ b/drivers/char/ttyprintk.c
@@ -0,0 +1,225 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ * - TPK_STR_SIZE isn't really the write_room limiting factor, bcause
+ *   it is emptied on the fly during preformatting.
+ */
+#define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
+#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
+static const char *tpk_tag = "[U] "; /* U for User */
+static int tpk_curr;
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TPK_STR_SIZE + 4];
+	int i = tpk_curr;
+
+	if (buf == NULL) {
+		/* flush tmp[] */
+		if (tpk_curr > 0) {
+			/* non nl or cr terminated message - add nl */
+			tmp[tpk_curr + 0] = '\n';
+			tmp[tpk_curr + 1] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+		return i;
+	}
+
+	for (i = 0; i < count; i++) {
+		tmp[tpk_curr] = buf[i];
+		if (tpk_curr < TPK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[tpk_curr + 0] = '\n';
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				break;
+			default:
+				tpk_curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[tpk_curr + 1] = '\\';
+			tmp[tpk_curr + 2] = '\n';
+			tmp[tpk_curr + 3] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+	}
+
+	return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	tty->driver_data = &tpk_port;
+
+	return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	mutex_lock(&tpkp->port_write_mutex);
+	/* flush tpk_printk buffer */
+	tpk_printk(NULL, 0);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+	int ret;
+
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+	return TPK_MAX_ROOM;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	if (!tpkp)
+		return -EINVAL;
+
+	switch (cmd) {
+	/* Stop TIOCCONS */
+	case TIOCCONS:
+		return -EOPNOTSUPP;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);


^ permalink raw reply	[flat|nested] 48+ messages in thread

* patch "add ttyprintk driver" added to gregkh-2.6 tree
@ 2010-09-01 22:50                                                       ` gregkh
  0 siblings, 0 replies; 48+ messages in thread
From: gregkh @ 2010-09-01 22:50 UTC (permalink / raw)
  To: samo_pogacnik, alan, gregkh, kay.sievers, linux-embedded, linux-kernel


This is a note to let you know that I've just added the patch titled

    add ttyprintk driver

to my gregkh-2.6 tree which can be found in directory form at:
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/
 and in git form at:
    git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/patches.git

The filename of this patch is:
    add-ttyprintk-driver.patch

The patch will show up in the next release of the linux-next tree
(usually sometime within the next 24 hours during the week.)

If this patch meets the merge guidelines for a bugfix, it should be
merged into Linus's tree before the next major kernel release.
If not, it will be merged into Linus's tree during the next merge window.

Either way, you will probably be copied on the patch when it gets sent
to Linus for merging so that others can see what is happening in kernel
development.

If you have any questions about this process, please let me know.


From samo_pogacnik@t-2.net  Wed Sep  1 15:35:26 2010
Subject: add ttyprintk driver
From: Samo Pogacnik <samo_pogacnik@t-2.net>
To: linux kernel <linux-kernel@vger.kernel.org>
Cc: linux-embedded <linux-embedded@vger.kernel.org>,
	Greg KH <gregkh@suse.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>,
	Kay Sievers <kay.sievers@vrfy.org>
Date: Wed, 25 Aug 2010 20:44:07 +0200
Message-Id: <1282761847.5857.9.camel@itpsd6lap>


Ttyprintk is a pseudo TTY driver, which allows users to make printk
messages, via output to ttyprintk device. It is possible to store
"console" messages inline with kernel messages for better analyses of
the boot process, for example.

Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
 Documentation/devices.txt |    1 
 drivers/char/Kconfig      |   15 +++
 drivers/char/Makefile     |    1 
 drivers/char/ttyprintk.c  |  225 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 242 insertions(+)

--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -493,6 +493,21 @@ config LEGACY_PTY_COUNT
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	depends on EMBEDDED
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -12,6 +12,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.
 obj-y				+= tty_mutex.o
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
--- /dev/null
+++ b/drivers/char/ttyprintk.c
@@ -0,0 +1,225 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ * - TPK_STR_SIZE isn't really the write_room limiting factor, bcause
+ *   it is emptied on the fly during preformatting.
+ */
+#define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
+#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
+static const char *tpk_tag = "[U] "; /* U for User */
+static int tpk_curr;
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TPK_STR_SIZE + 4];
+	int i = tpk_curr;
+
+	if (buf == NULL) {
+		/* flush tmp[] */
+		if (tpk_curr > 0) {
+			/* non nl or cr terminated message - add nl */
+			tmp[tpk_curr + 0] = '\n';
+			tmp[tpk_curr + 1] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+		return i;
+	}
+
+	for (i = 0; i < count; i++) {
+		tmp[tpk_curr] = buf[i];
+		if (tpk_curr < TPK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[tpk_curr + 0] = '\n';
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				break;
+			default:
+				tpk_curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[tpk_curr + 1] = '\\';
+			tmp[tpk_curr + 2] = '\n';
+			tmp[tpk_curr + 3] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+	}
+
+	return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	tty->driver_data = &tpk_port;
+
+	return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	mutex_lock(&tpkp->port_write_mutex);
+	/* flush tpk_printk buffer */
+	tpk_printk(NULL, 0);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+	int ret;
+
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+	return TPK_MAX_ROOM;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	if (!tpkp)
+		return -EINVAL;
+
+	switch (cmd) {
+	/* Stop TIOCCONS */
+	case TIOCCONS:
+		return -EOPNOTSUPP;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2010-09-01 22:51 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-15 10:17 [PATCH] detour TTY driver Samo Pogacnik
2010-05-29 22:17 ` Samo Pogacnik
2010-05-29 22:54   ` Alan Cox
2010-05-29 22:59     ` Al Viro
2010-05-29 23:33     ` Samo Pogacnik
2010-06-09 22:37       ` [PATCH] detour TTY driver - now ttyprintk Samo Pogacnik
2010-06-11 12:44         ` Alan Cox
2010-06-11 21:32           ` Samo Pogacnik
2010-06-21 14:38             ` Alan Cox
2010-06-22 22:06               ` Samo Pogacnik
2010-06-22 22:21                 ` Alan Cox
2010-06-25 10:43                   ` Samo Pogacnik
2010-06-25 11:03                     ` Alan Cox
2010-06-26  1:48                       ` Samo Pogacnik
2010-06-27 13:35                         ` Alan Cox
2010-06-28 23:27                           ` Samo Pogacnik
2010-07-03 19:21                           ` Samo Pogacnik
2010-06-26 15:12                       ` Samo Pogacnik
2010-08-24 20:03                       ` Samo Pogacnik
2010-08-24 20:13                         ` Greg KH
2010-08-24 20:57                       ` Samo Pogacnik
2010-08-24 21:10                         ` Greg KH
2010-08-24 22:09                           ` Samo Pogacnik
2010-08-24 22:20                             ` Greg KH
2010-08-24 22:50                               ` Samo Pogacnik
2010-08-24 22:57                                 ` Greg KH
2010-08-24 23:22                                   ` Alan Cox
2010-08-24 23:12                                     ` Greg KH
2010-08-24 23:51                                       ` Alan Cox
2010-08-25  0:41                                         ` Greg KH
2010-08-25  6:50                                           ` Marco Stornelli
2010-08-25 10:08                                           ` Alan Cox
2010-08-25 15:57                                             ` Greg KH
2010-08-25 17:11                                               ` Alan Cox
2010-08-25 17:10                                                 ` Greg KH
2010-08-25 18:14                                                   ` Alan Cox
2010-08-25 18:16                                                     ` Greg KH
2010-08-25 19:30                                                       ` Alan Cox
2010-08-26 17:24                                                       ` Samo Pogacnik
2010-08-26 23:02                                                         ` Greg KH
2010-08-25 18:44                                                   ` Samo Pogacnik
2010-09-01 22:50                                                     ` patch "add ttyprintk driver" added to gregkh-2.6 tree gregkh
2010-09-01 22:50                                                       ` gregkh
2010-08-25  7:40                                       ` [PATCH] detour TTY driver - now ttyprintk Kay Sievers
2010-08-25  7:48                                         ` Kay Sievers
2010-08-24 22:16                           ` Alan Cox
2010-08-24 22:02                             ` Greg KH
2010-06-11 23:31           ` Samo Pogacnik

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.