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

Reply via email to