Google
  Web www.spinics.net

Re: PATCH: usb ehci debug port device gadget

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


On Tue, 22 Jun 2010 10:19:25 -0700
Greg KH <greg@xxxxxxxxx> wrote:

> Could you port it to 2.6.35-rc3 and resend it with a signed-off-by
> line so that we can apply it to the tree if it all works out properly?

Here is the patch for 2.6.35-rc3.

The most recent kernel i've been able to test on my board is
2.6.35-rc1.

I noticed the following warning in the kernel logs:

[  338.090820] ------------[ cut here ]------------
[  338.095489] WARNING: at kernel/mutex.c:214 __mutex_lock_slowpath+0x64/0x218()
[  338.102661] Modules linked in: g_dbgp [last unloaded: g_dbgp]
[  338.108520] [<c0038268>] (unwind_backtrace+0x0/0xec) from [<c0057558>] (warn_slowpath_common+0x4c/0x7c)
[  338.117980] [<c0057558>] (warn_slowpath_common+0x4c/0x7c) from [<c00575a4>] (warn_slowpath_null+0x1c/0x24)
[  338.127716] [<c00575a4>] (warn_slowpath_null+0x1c/0x24) from [<c03b537c>] (__mutex_lock_slowpath+0x64/0x218)
[  338.137603] [<c03b537c>] (__mutex_lock_slowpath+0x64/0x218) from [<c03b553c>] (mutex_lock+0xc/0x1c)
[  338.146759] [<c03b553c>] (mutex_lock+0xc/0x1c) from [<c020eb14>] (echo_set_canon_col+0x18/0x40)
[  338.155517] [<c020eb14>] (echo_set_canon_col+0x18/0x40) from [<c0210e3c>] (n_tty_receive_buf+0xbb8/0x1058)
[  338.165222] [<c0210e3c>] (n_tty_receive_buf+0xbb8/0x1058) from [<c0213458>] (flush_to_ldisc+0xd4/0x170)
[  338.174743] [<c0213458>] (flush_to_ldisc+0xd4/0x170) from [<bf0073d8>] (gs_rx_push+0x118/0x1c4 [g_dbgp])
[  338.184326] [<bf0073d8>] (gs_rx_push+0x118/0x1c4 [g_dbgp]) from [<c005bd80>] (tasklet_action+0x74/0xb8)
[  338.193817] [<c005bd80>] (tasklet_action+0x74/0xb8) from [<c005c3cc>] (__do_softirq+0x78/0x100)
[  338.202606] [<c005c3cc>] (__do_softirq+0x78/0x100) from [<c005c494>] (irq_exit+0x40/0x94)
[  338.210876] [<c005c494>] (irq_exit+0x40/0x94) from [<c0033078>] (asm_do_IRQ+0x78/0x98)
[  338.218872] [<c0033078>] (asm_do_IRQ+0x78/0x98) from [<c0033ab4>] (__irq_svc+0x34/0x80)
[  338.226928] Exception stack(0xc04f7f30 to 0xc04f7f78)
[  338.232025] 7f20:                                     15e2d62c 40000013 40000013 c0506c88
[  338.240264] 7f40: 15e2d62c 00000152 c0506c88 0000132f 00001324 c0505ff8 c0555ea0 c0555fe0
[  338.248535] 7f60: c04fbfe8 c04f7f78 c003da48 c0076550 60000013 ffffffff
[  338.255218] [<c0033ab4>] (__irq_svc+0x34/0x80) from [<c0076550>] (tick_nohz_stop_sched_tick+0x384/0x3d0)
[  338.264801] [<c0076550>] (tick_nohz_stop_sched_tick+0x384/0x3d0) from [<c0034e4c>] (cpu_idle+0x20/0x84)
[  338.274291] [<c0034e4c>] (cpu_idle+0x20/0x84) from [<c0008b0c>] (start_kernel+0x254/0x2b8)
[  338.282623] [<c0008b0c>] (start_kernel+0x254/0x2b8) from [<80008034>] (0x80008034)
[  338.290252] ---[ end trace c425a969cdc97fc2 ]---

My module does not make use of any mutex. It happens only once (first
time g_dbgp module is used). It seems to be related with gserial_xxxx()
code which is called by my module when it receives the DEBUG feature. I
don't have time and skills to look into gserial code.

The host side debug port was feeded by a 2.6.34.

thanks,

stf

 Signed-off-by: Stephane Duverger <stephane.duverger@xxxxxxxxx>

---
 arch/arm/mach-omap2/usb-ehci.c     |    1 +
 drivers/usb/gadget/Kconfig         |   28 +++
 drivers/usb/gadget/Makefile        |    2 +
 drivers/usb/gadget/dbgp.c          |  444 ++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/u_serial.c      |    1 +
 drivers/usb/musb/musb_gadget_ep0.c |    3 +
 6 files changed, 479 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/gadget/dbgp.c

diff --git a/arch/arm/mach-omap2/usb-ehci.c b/arch/arm/mach-omap2/usb-ehci.c
index c68f799..465699f 100644
--- a/arch/arm/mach-omap2/usb-ehci.c
+++ b/arch/arm/mach-omap2/usb-ehci.c
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 #include <plat/mux.h>
 
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 591ae9f..be41b25 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -913,6 +913,34 @@ config USB_G_HID
 	  Say "y" to link the driver statically, or "m" to build a
 	  dynamically linked module called "g_hid".
 
+config USB_G_DBGP
+        tristate "EHCI Debug Device Gadget"
+        help
+          This gadget emulates an EHCI Debug device. This is useful when you want
+          to interact with an EHCI Debug Port.
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "g_dbgp".
+
+if USB_G_DBGP
+choice
+	prompt "EHCI Debug Device mode"
+	default USB_G_DBGP_SERIAL
+
+config USB_G_DBGP_PRINTK
+        depends on USB_G_DBGP
+	bool "printk"
+	help
+	  Directly printk() received data. No interaction.
+
+config USB_G_DBGP_SERIAL
+        depends on USB_G_DBGP
+	bool "serial"
+	help
+	  Userland can interact using /dev/ttyGSxxx.
+endchoice
+endif
+
 # put drivers that need isochronous transfer support (for audio
 # or video class gadget drivers), or specific hardware, here.
 config USB_G_WEBCAM
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 9bcde11..379fe3c 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -44,6 +44,7 @@ g_printer-objs			:= printer.o
 g_cdc-objs			:= cdc2.o
 g_multi-objs			:= multi.o
 g_hid-objs			:= hid.o
+g_dbgp-objs                     := dbgp.o
 g_nokia-objs			:= nokia.o
 g_webcam-objs			:= webcam.o
 
@@ -60,6 +61,7 @@ obj-$(CONFIG_USB_G_PRINTER)	+= g_printer.o
 obj-$(CONFIG_USB_MIDI_GADGET)	+= g_midi.o
 obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
 obj-$(CONFIG_USB_G_HID)		+= g_hid.o
+obj-$(CONFIG_USB_G_DBGP)        += g_dbgp.o
 obj-$(CONFIG_USB_G_MULTI)	+= g_multi.o
 obj-$(CONFIG_USB_G_NOKIA)	+= g_nokia.o
 obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c
new file mode 100644
index 0000000..2d31472
--- /dev/null
+++ b/drivers/usb/gadget/dbgp.c
@@ -0,0 +1,444 @@
+/*
+ * dbgp.c -- EHCI Debug Port device gadget
+ *
+ * Copyright (C) 2010 Stephane Duverger
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/* verbose messages */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* See comments in "zero.c" */
+#include "epautoconf.c"
+
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+#include "u_serial.c"
+#endif
+
+#define DRIVER_VENDOR_ID	0x0525 /* NetChip */
+#define DRIVER_PRODUCT_ID	0xc0de /* undefined */
+
+#define USB_DEBUG_MAX_PACKET_SIZE     8
+#define DBGP_REQ_EP0_LEN              128
+#define DBGP_REQ_LEN                  512
+
+static struct dbgp {
+	struct usb_gadget  *gadget;
+	struct usb_request *req;
+	struct usb_ep      *i_ep;
+	struct usb_ep      *o_ep;
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+	struct gserial     *serial;
+#endif
+} dbgp;
+
+static struct usb_device_descriptor device_desc = {
+	.bLength = sizeof device_desc,
+	.bDescriptorType = USB_DT_DEVICE,
+	.bcdUSB = __constant_cpu_to_le16(0x0200),
+	.bDeviceClass =	USB_CLASS_VENDOR_SPEC,
+	.idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID),
+	.idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID),
+	.bNumConfigurations = 1,
+};
+
+static struct usb_debug_descriptor dbg_desc = {
+	.bLength = sizeof dbg_desc,
+	.bDescriptorType = USB_DT_DEBUG,
+};
+
+static struct usb_endpoint_descriptor i_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bmAttributes = USB_ENDPOINT_XFER_BULK,
+	.bEndpointAddress = USB_DIR_IN,
+};
+
+static struct usb_endpoint_descriptor o_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bmAttributes = USB_ENDPOINT_XFER_BULK,
+	.bEndpointAddress = USB_DIR_OUT,
+};
+
+#ifdef CONFIG_USB_G_DBGP_PRINTK
+static int dbgp_consume(char *buf, unsigned len)
+{
+	char c;
+
+	if (!len)
+		return 0;
+
+	c = buf[len-1];
+	if (c != 0)
+		buf[len-1] = 0;
+
+	printk("%s%c", buf, c);
+	return 0;
+}
+
+static void __disable_ep(struct usb_ep *ep)
+{
+	if (ep && ep->driver_data == dbgp.gadget) {
+		usb_ep_disable(ep);
+		ep->driver_data = NULL;
+	}
+}
+
+static void dbgp_disable_ep(void)
+{
+	__disable_ep(dbgp.i_ep);
+	__disable_ep(dbgp.o_ep);
+}
+
+static void dbgp_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int stp;
+	int err=0;
+	int status = req->status;
+
+	if (ep == dbgp.i_ep) {
+		stp = 1;
+		goto fail;
+	}
+
+	if (status != 0) {
+		stp = 2;
+		goto release_req;
+	}
+
+	dbgp_consume(req->buf, req->actual);
+
+	req->length = DBGP_REQ_LEN;
+	err = usb_ep_queue(ep, req, GFP_ATOMIC);
+	if (err < 0) {
+		stp = 3;
+		goto release_req;
+	}
+
+	return;
+
+release_req:
+	if (req->buf)
+		kfree(req->buf);
+	usb_ep_free_request(dbgp.o_ep, req);
+	dbgp_disable_ep();
+fail:
+	dev_dbg(&dbgp.gadget->dev, "complete: failure (%d:%d) ==> %d\n", stp, err, status);
+}
+
+static int dbgp_enable_ep_req(struct usb_ep *ep)
+{
+	int err, stp;
+	struct usb_request *req;
+
+	req = usb_ep_alloc_request(ep, GFP_KERNEL);
+	if (! req) {
+		err = -ENOMEM;
+		stp = 1;
+		goto fail_1;
+	}
+
+	req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL);
+	if (! req->buf) {
+		err = -ENOMEM;
+		stp = 2;
+		goto fail_2;
+	}
+
+	req->complete = dbgp_complete;
+	req->length = DBGP_REQ_LEN;
+	err = usb_ep_queue(ep, req, GFP_ATOMIC);
+	if (err < 0) {
+		stp = 3;
+		goto fail_3;
+	}
+
+	return 0;
+
+fail_3:
+	kfree(req->buf);
+fail_2:
+	usb_ep_free_request(dbgp.o_ep, req);
+fail_1:
+	dev_dbg(&dbgp.gadget->dev, "enable ep req: failure (%d:%d)\n", stp, err);
+	return err;
+}
+
+static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
+{
+	int err = usb_ep_enable(ep, desc);
+	ep->driver_data = dbgp.gadget;
+	return err;
+}
+
+static int dbgp_enable_ep(void)
+{
+	int err, stp;
+
+	err = __enable_ep(dbgp.i_ep, &i_desc);
+	if (err < 0) {
+		stp = 1;
+		goto fail_1;
+	}
+
+	err = __enable_ep(dbgp.o_ep, &o_desc);
+	if (err < 0) {
+		stp = 2;
+		goto fail_2;
+	}
+
+	err = dbgp_enable_ep_req(dbgp.o_ep);
+	if (err < 0) {
+		stp = 3;
+		goto fail_3;
+	}
+
+	return 0;
+
+fail_3:
+	__disable_ep(dbgp.o_ep);
+fail_2:
+	__disable_ep(dbgp.i_ep);
+fail_1:
+	dev_dbg(&dbgp.gadget->dev, "enable ep: failure (%d:%d)\n", stp, err);
+	return err;
+}
+#endif
+
+static void dbgp_disconnect(struct usb_gadget *gadget)
+{
+#ifdef CONFIG_USB_G_DBGP_PRINTK
+	dbgp_disable_ep();
+#else
+	gserial_disconnect(dbgp.serial);
+#endif
+}
+
+static void dbgp_unbind(struct usb_gadget *gadget)
+{
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+	if (dbgp.serial)
+		kfree(dbgp.serial);
+#endif
+	if (dbgp.req) {
+		if (dbgp.req->buf)
+			kfree(dbgp.req->buf);
+		usb_ep_free_request(gadget->ep0, dbgp.req);
+	}
+
+	gadget->ep0->driver_data = NULL;
+}
+
+static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
+{
+	int stp;
+
+	usb_ep_autoconfig_reset(gadget);
+
+	dbgp.i_ep = usb_ep_autoconfig(gadget, &i_desc);
+	if (! dbgp.i_ep) {
+		stp = 1;
+		goto fail_1;
+	}
+
+	dbgp.i_ep->driver_data = gadget;
+	i_desc.wMaxPacketSize = __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
+
+	dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc);
+	if (! dbgp.o_ep) {
+		dbgp.i_ep->driver_data = NULL;
+		stp = 2;
+		goto fail_2;
+	}
+
+	dbgp.o_ep->driver_data = gadget;
+	o_desc.wMaxPacketSize = __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
+
+	dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress & 0x7f;
+	dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress & 0x7f;
+
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+	dbgp.serial->in = dbgp.i_ep;
+	dbgp.serial->out = dbgp.o_ep;
+
+	dbgp.serial->in_desc = &i_desc;
+	dbgp.serial->out_desc = &o_desc;
+
+	if (gserial_setup(gadget, 1) < 0) {
+		stp = 3;
+		goto fail_3;
+	}
+
+	return 0;
+
+fail_3:
+	dbgp.o_ep->driver_data = NULL;
+#else
+	return 0;
+#endif
+fail_2:
+	dbgp.i_ep->driver_data = NULL;
+fail_1:
+	dev_dbg(&dbgp.gadget->dev, "ep config: failure (%d)\n", stp);
+	return -ENODEV;
+}
+
+static int __init dbgp_bind(struct usb_gadget *gadget)
+{
+	int err, stp;
+
+	dbgp.gadget = gadget;
+
+	dbgp.req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+	if (! dbgp.req) {
+		err = -ENOMEM;
+		stp = 1;
+		goto fail;
+	}
+
+	dbgp.req->buf = kmalloc(DBGP_REQ_EP0_LEN, GFP_KERNEL);
+	if (! dbgp.req->buf) {
+		err = -ENOMEM;
+		stp = 2;
+		goto fail;
+	}
+
+	dbgp.req->length = DBGP_REQ_EP0_LEN;
+	gadget->ep0->driver_data = gadget;
+
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+	dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
+	if (!dbgp.serial) {
+		stp = 3;
+		err = -ENOMEM;
+		goto fail;
+	}
+#endif
+	err = dbgp_configure_endpoints(gadget);
+	if (err < 0) {
+		stp = 4;
+		goto fail;
+	}
+
+	dev_dbg(&dbgp.gadget->dev, "bind: success\n");
+	return 0;
+
+fail:
+	dev_dbg(&gadget->dev, "bind: failure (%d:%d)\n", stp, err);
+	dbgp_unbind(gadget);
+	return err;
+}
+
+static void dbgp_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+/*
+	dev_dbg(&dbgp.gadget->dev, "setup complete: %d, %d/%d\n",
+		req->status, req->actual, req->length);
+*/
+}
+
+static int dbgp_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	struct usb_request *req = dbgp.req;
+	u8 request = ctrl->bRequest;
+	u16 value = le16_to_cpu(ctrl->wValue);
+	u16 length = le16_to_cpu(ctrl->wLength);
+	int err = 0;
+	void *data;
+	u16 len;
+
+	gadget->ep0->driver_data = gadget;
+
+	if (request == USB_REQ_GET_DESCRIPTOR) {
+		switch (value>>8) {
+		case USB_DT_DEVICE:
+			dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
+			len = sizeof device_desc;
+			data = &device_desc;
+			break;
+		case USB_DT_DEBUG:
+			dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");
+			len = sizeof dbg_desc;
+			data = &dbg_desc;
+			break;
+		default:
+			goto fail;
+		}
+	}
+	else if (request == USB_REQ_SET_FEATURE && value == USB_DEVICE_DEBUG_MODE) {
+		len = 0;
+		data = NULL;
+		dev_dbg(&dbgp.gadget->dev, "setup: feat debug\n");
+#ifdef CONFIG_USB_G_DBGP_PRINTK
+		if ((err=dbgp_enable_ep()) < 0)
+#else
+		if ((err=gserial_connect(dbgp.serial, 0)) < 0)
+#endif
+			goto fail;
+	}
+	else
+		goto fail;
+
+	if (len >= 0) {
+		req->length = min(length, len);
+		req->zero = len < req->length;
+		if (data && req->length)
+			memcpy(req->buf, data, req->length);
+
+		req->complete = dbgp_setup_complete;
+		return usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+	}
+
+fail:
+	dev_dbg(&dbgp.gadget->dev, "setup: failure req %x v %x\n", request, value);
+	return err;
+}
+
+static struct usb_gadget_driver dbgp_driver = {
+	.function = "dbgp",
+	.speed = USB_SPEED_HIGH,
+	.bind = dbgp_bind,
+	.unbind = dbgp_unbind,
+	.setup = dbgp_setup,
+	.disconnect = dbgp_disconnect,
+	.driver	= {
+		.owner = THIS_MODULE,
+		.name = "dbgp"
+	},
+};
+
+static int __init dbgp_init(void)
+{
+	return usb_gadget_register_driver(&dbgp_driver);
+}
+
+static void __exit dbgp_exit(void)
+{
+	usb_gadget_unregister_driver(&dbgp_driver);
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+	gserial_cleanup();
+#endif
+}
+
+MODULE_AUTHOR("Stephane Duverger");
+MODULE_LICENSE("GPL");
+module_init(dbgp_init);
+module_exit(dbgp_exit);
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 16bdf77..a1446d2 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -18,6 +18,7 @@
 /* #define VERBOSE_DEBUG */
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/delay.h>
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 21b9788..495779b 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -402,6 +402,9 @@ __acquires(musb->lock)
 					musb->g.a_alt_hnp_support = 1;
 					break;
 #endif
+                                case USB_DEVICE_DEBUG_MODE:
+					handled = 0;
+                                        break;
 stall:
 				default:
 					handled = -EINVAL;
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


B and H Foto and Electronics Corp.

[Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]    [Yosemite Photos]    [Free Online Dating]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Devices]     [Old Linux USB Devel Archive]

Add to Google Powered by Linux