[PATCH v2] USB: msm72k_udc: Add debugfs support

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

 



Provide debugfs files for reading endpoint registers and associated
requests info, re-enumeration and resetting the hardware.

This patch was originally developed by Google and is available at
http://android.git.kernel.org/?p=kernel/experimental.git.

CC: Mike Lockwood <lockwood@xxxxxxxxxxx>
CC: Brian Swetland <swetland@xxxxxxxxxx>
Signed-off-by: Pavankumar Kondeti <pkondeti@xxxxxxxxxxxxxx>
---
 drivers/usb/gadget/msm72k_udc.c |  164 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 164 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 3fa4192..6ec1a32 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -27,8 +27,10 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/platform_device.h>
+#include <linux/debugfs.h>
 #include <linux/workqueue.h>
 #include <linux/clk.h>
+#include <linux/uaccess.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -138,6 +140,7 @@ static void usb_do_work(struct work_struct *w);
 #define USB_FLAG_START          0x0001
 #define USB_FLAG_VBUS_ONLINE    0x0002
 #define USB_FLAG_VBUS_OFFLINE   0x0004
+#define USB_FLAG_RESET          0x0008
 
 /**
  * struct usb_info: privated data of this driver.
@@ -155,6 +158,7 @@ static void usb_do_work(struct work_struct *w);
  *         USB_FLAG_START: set upon gadget driver registration.
  *         USB_FLAG_VBUS_ONLINE: set upon VBUS presence.
  *         USB_FLAG_VBUS_OFFLINE: set upon VBUS absence.
+ *         USB_FLAG_RESET: set upon reset request from debug file.
  * @online: indicates USB configured state. set upon set_config request.
  * @running: indicates pull-up state.
  * @pool: DMA pool for allocating endpoint queue items (dTD).
@@ -1216,6 +1220,12 @@ static void usb_do_work(struct work_struct *w)
 				usb_do_work_check_vbus(ui);
 				break;
 			}
+			if (flags & USB_FLAG_RESET) {
+				dev_info(&ui->pdev->dev, "ONLINE -> RESET\n");
+				usb_reset(ui);
+				dev_info(&ui->pdev->dev, "RESET -> ONLINE\n");
+				break;
+			}
 			break;
 		case USB_STATE_OFFLINE:
 			/* If we were signaled to go online and vbus is still
@@ -1269,6 +1279,158 @@ void msm_hsusb_set_vbus_state(int online)
 		spin_unlock_irqrestore(&ui->lock, flags);
 }
 
+#if defined(CONFIG_DEBUG_FS)
+void usb_function_reenumerate(void)
+{
+	struct usb_info *ui = the_usb_info;
+
+	/* disable and re-enable the D+ pullup */
+	msm72k_pullup(&ui->gadget, false);
+	usleep_range(10000, 12000);
+	msm72k_pullup(&ui->gadget, true);
+}
+
+static char debug_buffer[PAGE_SIZE];
+
+static ssize_t debug_read_status(struct file *file, char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct usb_info *ui = file->private_data;
+	char *buf = debug_buffer;
+	unsigned long flags;
+	struct msm_endpoint *ept;
+	struct msm_request *req;
+	int n;
+	int i = 0;
+
+	spin_lock_irqsave(&ui->lock, flags);
+
+	i += scnprintf(buf + i, PAGE_SIZE - i,
+		       "regs: setup=%08x prime=%08x stat=%08x done=%08x\n",
+		       readl(USB_ENDPTSETUPSTAT),
+		       readl(USB_ENDPTPRIME),
+		       readl(USB_ENDPTSTAT),
+		       readl(USB_ENDPTCOMPLETE));
+	i += scnprintf(buf + i, PAGE_SIZE - i,
+		       "regs:   cmd=%08x   sts=%08x intr=%08x port=%08x\n\n",
+		       readl(USB_USBCMD),
+		       readl(USB_USBSTS),
+		       readl(USB_USBINTR),
+		       readl(USB_PORTSC));
+
+
+	for (n = 0; n < 32; n++) {
+		ept = ui->ept + n;
+		if (ept->ep.maxpacket == 0)
+			continue;
+
+		i += scnprintf(buf + i, PAGE_SIZE - i,
+			       "ept%d %s cfg=%08x active=%08x next=%08x"
+			       "info=%08x\n", ept->num,
+			       (ept->flags & EPT_FLAG_IN) ? "in " : "out",
+			       ept->head->config, ept->head->active,
+			       ept->head->next, ept->head->info);
+
+		for (req = ept->req; req; req = req->next)
+			i += scnprintf(buf + i, PAGE_SIZE - i,
+				       "  req @%08x next=%08x info=%08x"
+				       "page0=%08x %c %c\n",
+				       req->item_dma, req->item->next,
+				       req->item->info, req->item->page0,
+				       req->busy ? 'B' : ' ',
+				       req->live ? 'L' : ' '
+				);
+	}
+
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return simple_read_from_buffer(ubuf, count, ppos, buf, i);
+}
+
+static ssize_t debug_write_reset(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	struct usb_info *ui = file->private_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ui->lock, flags);
+	ui->flags |= USB_FLAG_RESET;
+	schedule_work(&ui->work);
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return count;
+}
+
+static ssize_t debug_write_cycle(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	usb_function_reenumerate();
+	return count;
+}
+
+static ssize_t debug_write_vbus(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	char kbuf[8];
+	size_t len;
+
+	len = min(count, sizeof(kbuf) - 1);
+	if (copy_from_user(kbuf, buf, len))
+		return -EFAULT;
+	kbuf[len] = '\0';
+
+	if (strncmp(kbuf, "on", 2) == 0)
+		msm_hsusb_set_vbus_state(1);
+	else if (strncmp(kbuf, "off", 3) == 0)
+		msm_hsusb_set_vbus_state(0);
+	else
+		return -EINVAL;
+
+	return count;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+const struct file_operations debug_stat_ops = {
+	.open = debug_open,
+	.read = debug_read_status,
+};
+
+const struct file_operations debug_reset_ops = {
+	.open = debug_open,
+	.write = debug_write_reset,
+};
+
+const struct file_operations debug_cycle_ops = {
+	.open = debug_open,
+	.write = debug_write_cycle,
+};
+
+const struct file_operations debug_vbus_ops = {
+	.open = debug_open,
+	.write = debug_write_vbus,
+};
+
+static void usb_debugfs_init(struct usb_info *ui)
+{
+	struct dentry *dent;
+	dent = debugfs_create_dir(dev_name(&ui->pdev->dev), 0);
+	if (IS_ERR(dent))
+		return;
+
+	debugfs_create_file("status", 0444, dent, ui, &debug_stat_ops);
+	debugfs_create_file("reset", 0220, dent, ui, &debug_reset_ops);
+	debugfs_create_file("cycle", 0220, dent, ui, &debug_cycle_ops);
+	debugfs_create_file("vbus", 0220, dent, ui, &debug_vbus_ops);
+}
+#else
+static void usb_debugfs_init(struct usb_info *ui) {}
+#endif			/* CONFIG_DEBUG_FS */
+
 static int
 msm72k_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 {
@@ -1576,6 +1738,8 @@ static int msm72k_probe(struct platform_device *pdev)
 
 	the_usb_info = ui;
 
+	usb_debugfs_init(ui);
+
 	usb_prepare(ui);
 
 	return 0;
-- 
1.7.1

--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
--
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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux