diff options
author | Neil Chen <neilc@nvidia.com> | 2013-07-17 13:34:21 +0800 |
---|---|---|
committer | Suresh Mangipudi <smangipudi@nvidia.com> | 2013-11-10 21:29:05 -0800 |
commit | 06863e28f0a92be1731de963e2ec43d72b2889b9 (patch) | |
tree | 99fac01742ae5b78b53299e32b24d3801b56b627 /drivers/usb/host | |
parent | 62ec95291e1c977eeb3129a82f2522ad8e673f4e (diff) |
USB: debugfs: USB test mode support by usb debugfs
To generate USB testmode pattern by accessing usb debugfs. It
need to be enabled with enable "CONFIG_USB_DEBUG" in def_config.
And disable autosuspend by sysfs before test as below:
echo on > /sys/bus/usb/devices/.../power/control
Bug 1323709
Change-Id: I2c9d4cb304435e9d36f11a97a8db2d2ffd582ecf
Signed-off-by: Neil Chen <neilc@nvidia.com>
Reviewed-on: http://git-master/r/303705
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Suresh Mangipudi <smangipudi@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-dbg.c | 129 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 2 |
2 files changed, 131 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 5429d2645bbc..d4c0e95363f8 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2001-2002 by David Brownell + * Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved. * * 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 @@ -18,6 +19,29 @@ /* this file is part of ehci-hcd.c */ +#define PTC_SHIFT 16 +#define PTC_MASK (0xF << PTC_SHIFT) +#define TEST_MODE_DISABLE 0 +#define J_STATE 1 +#define K_STATE 2 +#define SE0_NAK 3 +#define PACKET 4 +#define FORCE_ENABLE_HS 5 +#define FORCE_ENABLE_FS 6 +#define FORCE_ENABLE_LS 7 +#define TESTMODES_SIZE 8 + +static char *testmodes[TESTMODES_SIZE] = { + "TEST_MODE_DISABLE", + "J_STATE", + "K_STATE", + "SE0", + "PACKET", + "FORCE_ENABLE_HS", + "FORCE_ENABLE_FS", + "FORCE_ENABLE_LS" +}; + #ifdef DEBUG /* check the values in the HCSPARAMS register @@ -336,6 +360,9 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } static int debug_async_open(struct inode *, struct file *); static int debug_periodic_open(struct inode *, struct file *); static int debug_registers_open(struct inode *, struct file *); +static int debug_testmodes_open(struct inode *, struct file *); +static ssize_t debug_testmodes_write(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos); static int debug_async_open(struct inode *, struct file *); static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); @@ -362,6 +389,14 @@ static const struct file_operations debug_registers_fops = { .release = debug_close, .llseek = default_llseek, }; +static const struct file_operations debug_testmodes_fops = { + .owner = THIS_MODULE, + .open = debug_testmodes_open, + .read = debug_output, + .write = debug_testmodes_write, + .release = debug_close, + .llseek = default_llseek, +}; static struct dentry *ehci_debug_root; @@ -844,6 +879,33 @@ done: return buf->alloc_size - size; } +static ssize_t fill_testmodes_buffer(struct debug_buffer *buf) +{ + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + unsigned long flags; + unsigned temp, size, i, ptc; + char *next; + + hcd = bus_to_hcd(buf->bus); + ehci = hcd_to_ehci(hcd); + next = buf->output_buf; + size = buf->alloc_size; + spin_lock_irqsave(&ehci->lock, flags); + ptc = (ehci_readl(ehci, &ehci->regs->port_status[0]) + & PTC_MASK) >> PTC_SHIFT; + for (i = 0; i < TESTMODES_SIZE; i++) { + if (ptc == i) + temp = scnprintf(next, size, "-> %s\n", testmodes[i]); + else + temp = scnprintf(next, size, " %s\n", testmodes[i]); + size -= temp; + next += temp; + } + spin_unlock_irqrestore(&ehci->lock, flags); + return buf->alloc_size - size; +} + static struct debug_buffer *alloc_buffer(struct usb_bus *bus, ssize_t (*fill_func)(struct debug_buffer *)) { @@ -919,6 +981,7 @@ static int debug_close(struct inode *inode, struct file *file) return 0; } + static int debug_async_open(struct inode *inode, struct file *file) { file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); @@ -946,6 +1009,68 @@ static int debug_registers_open(struct inode *inode, struct file *file) return file->private_data ? 0 : -ENOMEM; } +static int debug_testmodes_open(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf; + buf = alloc_buffer(inode->i_private, fill_testmodes_buffer); + + if (!buf) + return -ENOMEM; + + buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE; + file->private_data = buf; + return 0; +} + +static ssize_t debug_testmodes_write(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + struct usb_device *hub; + char buf[50]; + size_t len, slen; + int i; + int status = -1; + u32 val; + + hcd = bus_to_hcd(((struct debug_buffer *)file->private_data)->bus); + ehci = hcd_to_ehci(hcd); + hub = hcd->self.root_hub; + + len = min(count, (size_t) sizeof(buf) - 1); + if (copy_from_user(buf, buffer, len)) + return -EFAULT; + buf[len] = '\0'; + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + for (i = 0; i < TESTMODES_SIZE; i++) { + slen = strlen(testmodes[i]); + if (!strncmp(buf, testmodes[i], slen)) { + + /*clear the last testmode*/ + val = ehci_readl(ehci, &ehci->regs->port_status[0]) + & ~PORT_RWC_BITS; + val &= ~(PTC_MASK | PORT_RWC_BITS); + ehci_writel(ehci, val, &ehci->regs->port_status[0]); + + /*issue the new testmode*/ + val = ehci_readl(ehci, &ehci->regs->port_status[0]); + val |= (i << PTC_SHIFT) & PTC_MASK; + val &= ~PORT_RWC_BITS; + ehci_writel(ehci, val, &ehci->regs->port_status[0]); + + status = 0; + break; + } + } + if (status >= 0) + return count; + else + return -EINVAL; +} + static inline void create_debug_files (struct ehci_hcd *ehci) { struct usb_bus *bus = &ehci_to_hcd(ehci)->self; @@ -966,6 +1091,10 @@ static inline void create_debug_files (struct ehci_hcd *ehci) &debug_registers_fops)) goto file_error; + if (!debugfs_create_file("testmode", S_IRUGO, ehci->debug_dir, bus, + &debug_testmodes_fops)) + goto file_error; + return; file_error: diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 162aeecf98ec..9cf090fc4337 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -4,6 +4,7 @@ * Maintainer: Alan Stern <stern@rowland.harvard.edu> * * Copyright (c) 2000-2004 by David Brownell + * Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved. * * 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 @@ -39,6 +40,7 @@ #include <linux/dma-mapping.h> #include <linux/debugfs.h> #include <linux/slab.h> +#include <linux/uaccess.h> #include <asm/byteorder.h> #include <asm/io.h> |