This will need more testing than I can do on a 2M RAM deskjet. Mainly
I have not managed to build modular and squeeze insmod/rmmod into
initramfs yet.
In addition to messages, you can also "console=ttyGS0 init=/bin/sh" with
this, but to do so you have to force init/main.c to wait several seconds
before opening /dev/console. That part's not in the patch.
--- ucl-pristine/linux-2.6.x/drivers/usb/gadget/Kconfig 2010-02-16
12:02:16.000000000 -0500
+++ ucl-patched/linux-2.6.x/drivers/usb/gadget/Kconfig 2010-04-21
23:36:29.000000000 -0400
#
# Controllers available only in discrete form (and all PCI controllers)
@@ -672,4 +684,15 @@
make MS-Windows work with CDC ACM.
+config USB_G_SERIAL_CONSOLE
+ tristate "Serial Gadget Console Support"
+ depends on USB_G_SERIAL
+ help
+ Support for console on ttyGS devices. Note this is not an
+ "early console" and since the USB system takes a while to
+ come up, this is generally not going to help debug early
+ boot oopses. However, early messages will be dumped to
+ the console if the kernel manages to stay up long enough
+ for the console to instantiate.
+
config USB_MIDI_GADGET
tristate "MIDI Gadget (EXPERIMENTAL)"
--- ucl-pristine/linux-2.6.x/drivers/usb/gadget/u_serial.c 2010-04-21
23:26:35.000000000 -0400
+++ ucl-patched/linux-2.6.x/drivers/usb/gadget/u_serial.c 2010-04-21
23:27:31.000000000 -0400
@@ -6,4 +6,6 @@
* Copyright (C) 2008 by Nokia Corporation
*
+ * Console support Copyright (C) 2010 Brian S. Julin (b...@abrij.org)
+ *
* This code also borrows from usbserial.c, which is
* Copyright (C) 1999 - 2002 Greg Kroah-Hartman (g...@kroah.com)
@@ -25,4 +27,6 @@
#include <linux/tty_flip.h>
+#include <linux/console.h>
+
#include "u_serial.h"
@@ -93,5 +97,9 @@
struct gs_port {
spinlock_t port_lock; /* guard port_* access */
+#ifdef CONFIG_USB_G_SERIAL_CONSOLE
+ int stole_lock; /* for console oopses */
+ struct console port_console;
+#endif
struct gserial *port_usb;
struct tty_struct *port_tty;
@@ -238,4 +246,37 @@
}
+#ifdef CONFIG_USB_G_SERIAL_CONSOLE
+/*
+ * gs_buf_putr
+ *
+ * As per gs_buf_put, but add '\r' to any '\n's
+ */
+static unsigned
+gs_buf_putr(struct gs_buf *gb, const char *buf, unsigned count)
+{
+ unsigned i;
+ unsigned j;
+ unsigned ret;
+
+ for (i = 0, j = 0; i < count; i++) {
+ if (buf[i] != '\n')
+ continue;
+ ret = gs_buf_put(gb, buf + j, i - j);
+ if (ret != i - j)
+ return j + ret;
+ j += ret;
+ /* Do not lose an \n on a buffer seam. */
+ if (gs_buf_space_avail(gb) < 2)
+ return j;
+ gs_buf_put(gb, "\r\n", 2);
+ j++;
+ }
+ if (j < count) {
+ j += gs_buf_put(gb, buf + j, count - j);
+ }
+ return j;
+}
+#endif
+
/*
* gs_buf_get
@@ -389,6 +430,8 @@
if (status) {
+#ifndef CONFIG_USB_G_SERIAL_CONSOLE
pr_debug("%s: %s %s err %d\n",
__func__, "queue", in->name, status);
+#endif
list_add(&req->list, pool);
break;
@@ -440,6 +483,8 @@
if (status) {
+#ifndef CONFIG_USB_G_SERIAL_CONSOLE
pr_debug("%s: %s %s err %d\n",
__func__, "queue", out->name, status);
+#endif
list_add(&req->list, pool);
break;
@@ -681,10 +726,12 @@
/* unblock any pending writes into our circular buffer */
- if (started) {
- tty_wakeup(port->port_tty);
- } else {
- gs_free_requests(ep, head);
- gs_free_requests(port->port_usb->in, &port->write_pool);
- status = -EIO;
+ if (port->port_tty) {
+ if (started) {
+ tty_wakeup(port->port_tty);
+ } else {
+ gs_free_requests(ep, head);
+ gs_free_requests(port->port_usb->in, &port->write_pool);
+ status = -EIO;
+ }
}
@@ -901,4 +948,86 @@
}
+#ifdef CONFIG_USB_G_SERIAL_CONSOLE
+/* This stolen/adapted from serial/sn_console.c */
+static void gs_console_write(struct console *cons, const char *buf, unsigned
count)
+{
+ unsigned long flags = 0;
+ unsigned status;
+ struct gs_port *port;
+
+ port = cons->data;
+
+ /* Just chuck everything if USB side is not up. */
+ if (!port->port_usb) return;
+
+ /* somebody really wants this output, might be an
+ * oops, kdb, panic, etc. make sure they get it. */
+ if (spin_is_locked(&port->port_lock)) {
+ char *get = port->port_write_buf.buf_get;
+ char *put = port->port_write_buf.buf_put;
+ int got_lock = 0;
+ int counter;
+
+ /*
+ * We attempt to determine if someone has died with the
+ * lock. We wait ~20 secs after the head and tail ptrs
+ * stop moving and assume the lock holder is not functional
+ * and plow ahead. If the lock is freed within the time out
+ * period we re-get the lock and go ahead normally. We also
+ * remember if we have plowed ahead so that we don't have
+ * to wait out the time out period again - the asumption
+ * is that we will time out again.
+ */
+ for (counter = 0; counter < 150; mdelay(125), counter++) {
+ if (!spin_is_locked(&port->port_lock) ||
port->stole_lock) {
+ if (!port->stole_lock)
+ break;
+ spin_lock_irqsave(&port->port_lock, flags);
+ got_lock = 1;
+ break;
+ }
+ /* still locked */
+ if ((get != port->port_write_buf.buf_get)
+ || (put != port->port_write_buf.buf_put)) {
+ put = port->port_write_buf.buf_put;
+ get = port->port_write_buf.buf_get;
+ counter = 0;
+ }
+ }
+ /* Make space by flushing any waiting output */
+ if (port->port_usb)
+ gs_start_tx(port);
+ while (count) {
+ count -= gs_buf_putr(&port->port_write_buf, buf, count);
+ if (port->port_usb) break;
+ /* Flush our stuff immediately */
+ if (!gs_start_tx(port))
+ mdelay(125);
+ }
+ if (got_lock) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ port->stole_lock = 0;
+ } else {
+ /* fell thru */
+ port->stole_lock = 1;
+ }
+ return;
+ }
+ port->stole_lock = 0;
+ spin_lock_irqsave(&port->port_lock, flags);
+ /* Flush out any waiting output so we have as much space as possible */
+ if (port->port_usb)
+ status = gs_start_tx(port);
+ while (count) {
+ count -= gs_buf_putr(&port->port_write_buf, buf, count);
+ if (port->port_usb) break;
+ /* Flush our stuff immediately */
+ if (!gs_start_tx(port))
+ mdelay(125);
+ }
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+#endif
+
static int gs_put_char(struct tty_struct *tty, unsigned char ch)
{
@@ -1015,4 +1144,45 @@
static struct tty_driver *gs_tty_driver;
+#ifdef CONFIG_USB_G_SERIAL_CONSOLE
+struct tty_driver *gs_console_device(struct console *cons, int *gidx)
+{
+ struct gs_port *port;
+ port = container_of(cons, struct gs_port, port_console);
+ if (gidx)
+ *gidx = port->port_num;
+ return gs_tty_driver;
+}
+
+static int gs_console_setup (struct console *cons, char *options)
+{
+ struct gs_port *port;
+ int status = 0;
+
+ /*
+ * If this is called we are about to become the active console. (?)
+ *
+ * That is not what this hook is for, but it serves our purposes.
+ *
+ * Since there is no actual tty yet, we have to do some of what is
+ * normally done in gs_open.
+ */
+ port = container_of(cons, struct gs_port, port_console);
+ if (port->port_write_buf.buf_buf == NULL) {
+ status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE);
+ }
+
+ /* Start the I/O stream */
+ if (port->port_usb) {
+ struct gserial *gser = port->port_usb;
+
+ gs_start_io(port);
+
+ if (gser->connect)
+ gser->connect(gser);
+ }
+ return status;
+}
+#endif
+
static int __init
gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
@@ -1133,4 +1303,18 @@
count, (count == 1) ? "" : "s");
+#ifdef CONFIG_USB_G_SERIAL_CONSOLE
+ for (i = 0; i < count; i++) {
+ struct gs_port *p;
+
+ p = ports[i].port;
+ strcpy(p->port_console.name,PREFIX);
+ p->port_console.write = gs_console_write;
+ p->port_console.device = gs_console_device;
+ p->port_console.setup = gs_console_setup;
+ p->port_console.flags = CON_PRINTBUFFER;
+ p->port_console.index = p->port_num;
+ p->port_console.data = p;
+ }
+#endif
return status;
fail:
@@ -1269,4 +1453,7 @@
}
+#ifdef CONFIG_USB_G_SERIAL_CONSOLE
+ register_console(&port->port_console);
+#endif
spin_unlock_irqrestore(&port->port_lock, flags);
@@ -1311,4 +1498,8 @@
tty_hangup(port->port_tty);
}
+
+#ifdef CONFIG_USB_G_SERIAL_CONSOLE
+ unregister_console(&port->port_console);
+#endif
spin_unlock_irqrestore(&port->port_lock, flags);
_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev