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 | 135 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 135 insertions(+), 0 deletions(-) diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c index e405dc4..84315a2 100644 --- a/drivers/usb/gadget/msm72k_udc.c +++ b/drivers/usb/gadget/msm72k_udc.c @@ -26,6 +26,7 @@ #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> @@ -118,6 +119,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 { /* lock for register/queue/device state changes */ @@ -1152,6 +1154,12 @@ static void usb_do_work(struct work_struct *w) usb_do_work_check_vbus(ui); break; } + if (flags & USB_FLAG_RESET) { + INFO("ONLINE -> RESET\n"); + usb_reset(ui); + INFO("RESET -> ONLINE\n"); + break; + } break; case USB_STATE_OFFLINE: /* If we were signaled to go online and vbus is still @@ -1196,6 +1204,131 @@ 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 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, +}; + +static void usb_debugfs_init(struct usb_info *ui) +{ + struct dentry *dent; + dent = debugfs_create_dir("usb", 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); +} +#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) { @@ -1483,6 +1616,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