Blob Blame Raw
From 771516d92320eccf7c517ec6481c257b564bf5dd Mon Sep 17 00:00:00 2001
From: Vladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Date: Fri, 1 Feb 2013 21:49:29 +0100
Subject: [PATCH 150/482] 	Implement USBDebug (full USB stack variant).

---
 ChangeLog                                |  4 ++
 grub-core/Makefile.core.def              |  6 +++
 grub-core/bus/usb/serial/common.c        | 11 ++--
 grub-core/bus/usb/serial/ftdi.c          |  4 +-
 grub-core/bus/usb/serial/pl2303.c        |  4 +-
 grub-core/bus/usb/serial/usbdebug_late.c | 93 ++++++++++++++++++++++++++++++++
 grub-core/bus/usb/usb.c                  |  2 +
 include/grub/usbdesc.h                   |  9 ++++
 include/grub/usbserial.h                 |  7 ++-
 9 files changed, 134 insertions(+), 6 deletions(-)
 create mode 100644 grub-core/bus/usb/serial/usbdebug_late.c

diff --git a/ChangeLog b/ChangeLog
index 4141f6a..2e681c1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2013-02-01  Vladimir Serbinenko  <phcoder@gmail.com>
 
+	Implement USBDebug (full USB stack variant).
+
+2013-02-01  Vladimir Serbinenko  <phcoder@gmail.com>
+
 	* grub-core/commands/lsacpi.c: Show more info. Hide some boring parts
 	unless they have unexpected values.
 
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 4609a4b..c006abf 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -448,6 +448,12 @@ module = {
 };
 
 module = {
+  name = usbserial_usbdebug;
+  common = bus/usb/serial/usbdebug_late.c;
+  enable = usb;
+};
+
+module = {
   name = uhci;
   common = bus/usb/uhci.c;
   enable = x86;
diff --git a/grub-core/bus/usb/serial/common.c b/grub-core/bus/usb/serial/common.c
index 9530259..06f2b0e 100644
--- a/grub-core/bus/usb/serial/common.c
+++ b/grub-core/bus/usb/serial/common.c
@@ -42,7 +42,8 @@ static int usbnum = 0;
 
 int
 grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno,
-		       struct grub_serial_driver *driver)
+		       struct grub_serial_driver *driver, int in_endp,
+		       int out_endp)
 {
   struct grub_serial_port *port;
   int j;
@@ -73,12 +74,16 @@ grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno,
       struct grub_usb_desc_endp *endp;
       endp = &usbdev->config[0].interf[interfno].descendp[j];
 
-      if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2)
+      if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2
+	  && (in_endp == GRUB_USB_SERIAL_ENDPOINT_LAST_MATCHING
+	      || in_endp == endp->endp_addr))
 	{
 	  /* Bulk IN endpoint.  */
 	  port->in_endp = endp;
 	}
-      else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2)
+      else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2
+	       && (out_endp == GRUB_USB_SERIAL_ENDPOINT_LAST_MATCHING
+		   || out_endp == endp->endp_addr))
 	{
 	  /* Bulk OUT endpoint.  */
 	  port->out_endp = endp;
diff --git a/grub-core/bus/usb/serial/ftdi.c b/grub-core/bus/usb/serial/ftdi.c
index 15ea8fb..e94fd27 100644
--- a/grub-core/bus/usb/serial/ftdi.c
+++ b/grub-core/bus/usb/serial/ftdi.c
@@ -193,7 +193,9 @@ grub_ftdi_attach (grub_usb_device_t usbdev, int configno, int interfno)
     return 0;
 
   return grub_usbserial_attach (usbdev, configno, interfno,
-				&grub_ftdi_driver);
+				&grub_ftdi_driver,
+				GRUB_USB_SERIAL_ENDPOINT_LAST_MATCHING,
+				GRUB_USB_SERIAL_ENDPOINT_LAST_MATCHING);
 }
 
 static struct grub_usb_attach_desc attach_hook =
diff --git a/grub-core/bus/usb/serial/pl2303.c b/grub-core/bus/usb/serial/pl2303.c
index 5433763..f46c6ac 100644
--- a/grub-core/bus/usb/serial/pl2303.c
+++ b/grub-core/bus/usb/serial/pl2303.c
@@ -208,7 +208,9 @@ grub_pl2303_attach (grub_usb_device_t usbdev, int configno, int interfno)
     return 0;
 
   return grub_usbserial_attach (usbdev, configno, interfno,
-				&grub_pl2303_driver);
+				&grub_pl2303_driver,
+				GRUB_USB_SERIAL_ENDPOINT_LAST_MATCHING,
+				GRUB_USB_SERIAL_ENDPOINT_LAST_MATCHING);
 }
 
 static struct grub_usb_attach_desc attach_hook =
diff --git a/grub-core/bus/usb/serial/usbdebug_late.c b/grub-core/bus/usb/serial/usbdebug_late.c
new file mode 100644
index 0000000..23526e1
--- /dev/null
+++ b/grub-core/bus/usb/serial/usbdebug_late.c
@@ -0,0 +1,93 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010,2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/serial.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/usb.h>
+#include <grub/usbserial.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+
+/* Fetch a key.  */
+static int
+usbdebug_late_hw_fetch (struct grub_serial_port *port)
+{
+  return grub_usbserial_fetch (port, 0);
+}
+
+/* Put a character.  */
+static void
+usbdebug_late_hw_put (struct grub_serial_port *port, const int c)
+{
+  char cc = c;
+
+  grub_usb_bulk_write (port->usbdev, port->out_endp->endp_addr, 1, &cc);
+}
+
+static grub_err_t
+usbdebug_late_hw_configure (struct grub_serial_port *port __attribute__ ((unused)),
+			    struct grub_serial_config *config __attribute__ ((unused)))
+{
+  return GRUB_ERR_NONE;
+}
+
+static struct grub_serial_driver grub_usbdebug_late_driver =
+  {
+    .configure = usbdebug_late_hw_configure,
+    .fetch = usbdebug_late_hw_fetch,
+    .put = usbdebug_late_hw_put,
+    .fini = grub_usbserial_fini
+  };
+
+static int
+grub_usbdebug_late_attach (grub_usb_device_t usbdev, int configno, int interfno)
+{
+  grub_usb_err_t err;
+  struct grub_usb_desc_debug debugdesc;
+
+  err = grub_usb_get_descriptor (usbdev, GRUB_USB_DESCRIPTOR_DEBUG, configno,
+				 sizeof (debugdesc), (char *) &debugdesc);
+  if (err)
+    return 0;
+
+  return grub_usbserial_attach (usbdev, configno, interfno,
+				&grub_usbdebug_late_driver,
+				debugdesc.in_endp, debugdesc.out_endp);
+}
+
+static struct grub_usb_attach_desc attach_hook =
+{
+  .class = 0xff,
+  .hook = grub_usbdebug_late_attach
+};
+
+GRUB_MOD_INIT(usbserial_usbdebug_late)
+{
+  grub_usb_register_attach_hook_class (&attach_hook);
+}
+
+GRUB_MOD_FINI(usbserial_usbdebug_late)
+{
+  grub_serial_unregister_driver (&grub_usbdebug_late_driver);
+  grub_usb_unregister_attach_hook_class (&attach_hook);
+}
diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c
index 5df08e9..41d8010 100644
--- a/grub-core/bus/usb/usb.c
+++ b/grub-core/bus/usb/usb.c
@@ -309,6 +309,8 @@ void grub_usb_device_attach (grub_usb_device_t dev)
 	  grub_print_error ();
 	  grub_dl_load ("usbserial_pl2303");
 	  grub_print_error ();
+	  grub_dl_load ("usbserial_usbdebug");
+	  grub_print_error ();
 	  break;
 	}
     }
diff --git a/include/grub/usbdesc.h b/include/grub/usbdesc.h
index 84b723a..7d14152 100644
--- a/include/grub/usbdesc.h
+++ b/include/grub/usbdesc.h
@@ -28,6 +28,7 @@ typedef enum {
   GRUB_USB_DESCRIPTOR_STRING,
   GRUB_USB_DESCRIPTOR_INTERFACE,
   GRUB_USB_DESCRIPTOR_ENDPOINT,
+  GRUB_USB_DESCRIPTOR_DEBUG = 10,
   GRUB_USB_DESCRIPTOR_HUB = 0x29
 } grub_usb_descriptor_t;
 
@@ -111,6 +112,14 @@ struct grub_usb_desc_str
   grub_uint16_t str[0];
 } __attribute__ ((packed));
 
+struct grub_usb_desc_debug
+{
+  grub_uint8_t length;
+  grub_uint8_t type;
+  grub_uint8_t in_endp;
+  grub_uint8_t out_endp;
+} __attribute__ ((packed));
+
 struct grub_usb_usb_hubdesc
 {
   grub_uint8_t length;
diff --git a/include/grub/usbserial.h b/include/grub/usbserial.h
index 7420125..f81f97a 100644
--- a/include/grub/usbserial.h
+++ b/include/grub/usbserial.h
@@ -27,7 +27,12 @@ void grub_usbserial_detach (grub_usb_device_t usbdev, int configno,
 
 int
 grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno,
-		       struct grub_serial_driver *driver);
+		       struct grub_serial_driver *driver, int in_endp,
+		       int out_endp);
+enum
+  {
+    GRUB_USB_SERIAL_ENDPOINT_LAST_MATCHING = -1
+  };
 int
 grub_usbserial_fetch (struct grub_serial_port *port, grub_size_t header_size);
 
-- 
1.8.2.1