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