Commit 2d651289 authored by Alexander Shishkin's avatar Alexander Shishkin Committed by Greg Kroah-Hartman

usb: chipidea: convert debug entries in sysfs to debugfs

Currently, we have a bunch of files in sysfs that display all sorts of
debugging information for the device controller, so they have to move to
debugfs where they belong. The "registers" interface have been removed,
since it doesn't fit into the current driver design as is and it's hardly
a good idea to touch the registers from userspace anyway.
Signed-off-by: default avatarAlexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 69b7e8d3
...@@ -129,6 +129,7 @@ struct hw_bank { ...@@ -129,6 +129,7 @@ struct hw_bank {
* @vbus_active: is VBUS active * @vbus_active: is VBUS active
* @transceiver: pointer to USB PHY, if any * @transceiver: pointer to USB PHY, if any
* @hcd: pointer to usb_hcd for ehci host driver * @hcd: pointer to usb_hcd for ehci host driver
* @debugfs: root dentry for this controller in debugfs
*/ */
struct ci13xxx { struct ci13xxx {
struct device *dev; struct device *dev;
...@@ -164,6 +165,7 @@ struct ci13xxx { ...@@ -164,6 +165,7 @@ struct ci13xxx {
bool global_phy; bool global_phy;
struct usb_phy *transceiver; struct usb_phy *transceiver;
struct usb_hcd *hcd; struct usb_hcd *hcd;
struct dentry *debugfs;
}; };
static inline struct ci_role_driver *ci_role(struct ci13xxx *ci) static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
...@@ -11,223 +14,113 @@ ...@@ -11,223 +14,113 @@
#include "debug.h" #include "debug.h"
/** /**
* hw_register_read: reads all device registers (execute without interruption) * ci_device_show: prints information about device capabilities and status
* @buf: destination buffer
* @size: buffer size
*
* This function returns number of registers read
*/ */
static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size) static int ci_device_show(struct seq_file *s, void *data)
{ {
unsigned i; struct ci13xxx *ci = s->private;
struct usb_gadget *gadget = &ci->gadget;
if (size > ci->hw_bank.size)
size = ci->hw_bank.size;
for (i = 0; i < size; i++)
buf[i] = hw_read(ci, i * sizeof(u32), ~0);
return size;
}
/**
* hw_register_write: writes to register
* @addr: register address
* @data: register value
*
* This function returns an error code
*/
static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data)
{
/* align */
addr /= sizeof(u32);
if (addr >= ci->hw_bank.size) seq_printf(s, "speed = %d\n", gadget->speed);
return -EINVAL; seq_printf(s, "max_speed = %d\n", gadget->max_speed);
seq_printf(s, "is_otg = %d\n", gadget->is_otg);
seq_printf(s, "is_a_peripheral = %d\n", gadget->is_a_peripheral);
seq_printf(s, "b_hnp_enable = %d\n", gadget->b_hnp_enable);
seq_printf(s, "a_hnp_support = %d\n", gadget->a_hnp_support);
seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
seq_printf(s, "name = %s\n",
(gadget->name ? gadget->name : ""));
if (!ci->driver)
return 0;
/* align */ seq_printf(s, "gadget function = %s\n",
addr *= sizeof(u32); (ci->driver->function ? ci->driver->function : ""));
seq_printf(s, "gadget max speed = %d\n", ci->driver->max_speed);
hw_write(ci, addr, ~0, data);
return 0; return 0;
} }
/** static int ci_device_open(struct inode *inode, struct file *file)
* hw_intr_clear: disables interrupt & clears interrupt status (execute without
* interruption)
* @n: interrupt bit
*
* This function returns an error code
*/
static int hw_intr_clear(struct ci13xxx *ci, int n)
{ {
if (n >= REG_BITS) return single_open(file, ci_device_show, inode->i_private);
return -EINVAL;
hw_write(ci, OP_USBINTR, BIT(n), 0);
hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
return 0;
} }
/** static const struct file_operations ci_device_fops = {
* hw_intr_force: enables interrupt & forces interrupt status (execute without .open = ci_device_open,
* interruption) .read = seq_read,
* @n: interrupt bit .llseek = seq_lseek,
* .release = single_release,
* This function returns an error code };
*/
static int hw_intr_force(struct ci13xxx *ci, int n)
{
if (n >= REG_BITS)
return -EINVAL;
hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
hw_write(ci, OP_USBINTR, BIT(n), BIT(n));
hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0);
return 0;
}
/**
* show_device: prints information about device capabilities and status
*
* Check "device.h" for details
*/
static ssize_t show_device(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
struct usb_gadget *gadget = &ci->gadget;
int n = 0;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
return 0;
}
n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
gadget->speed);
n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
gadget->max_speed);
n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
gadget->is_otg);
n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
gadget->is_a_peripheral);
n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
gadget->b_hnp_enable);
n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
gadget->a_hnp_support);
n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
gadget->a_alt_hnp_support);
n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
(gadget->name ? gadget->name : ""));
return n;
}
static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
/**
* show_driver: prints information about attached gadget (if any)
*
* Check "device.h" for details
*/
static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
struct usb_gadget_driver *driver = ci->driver;
int n = 0;
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
}
if (driver == NULL)
return scnprintf(buf, PAGE_SIZE,
"There is no gadget attached!\n");
n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
(driver->function ? driver->function : ""));
n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
driver->max_speed);
return n;
}
static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
/** /**
* show_port_test: reads port test mode * ci_port_test_show: reads port test mode
*
* Check "device.h" for details
*/ */
static ssize_t show_port_test(struct device *dev, static int ci_port_test_show(struct seq_file *s, void *data)
struct device_attribute *attr, char *buf)
{ {
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); struct ci13xxx *ci = s->private;
unsigned long flags; unsigned long flags;
unsigned mode; unsigned mode;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "EINVAL\n");
return 0;
}
spin_lock_irqsave(&ci->lock, flags); spin_lock_irqsave(&ci->lock, flags);
mode = hw_port_test_get(ci); mode = hw_port_test_get(ci);
spin_unlock_irqrestore(&ci->lock, flags); spin_unlock_irqrestore(&ci->lock, flags);
return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); seq_printf(s, "mode = %u\n", mode);
return 0;
} }
/** /**
* store_port_test: writes port test mode * ci_port_test_write: writes port test mode
*
* Check "device.h" for details
*/ */
static ssize_t store_port_test(struct device *dev, static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
struct device_attribute *attr, size_t count, loff_t *ppos)
const char *buf, size_t count)
{ {
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); struct seq_file *s = file->private_data;
struct ci13xxx *ci = s->private;
unsigned long flags; unsigned long flags;
unsigned mode; unsigned mode;
char buf[32];
int ret;
if (attr == NULL || buf == NULL) { if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
dev_err(ci->dev, "[%s] EINVAL\n", __func__); return -EFAULT;
goto done;
}
if (sscanf(buf, "%u", &mode) != 1) { if (sscanf(buf, "%u", &mode) != 1)
dev_err(ci->dev, "<mode>: set port test mode"); return -EINVAL;
goto done;
}
spin_lock_irqsave(&ci->lock, flags); spin_lock_irqsave(&ci->lock, flags);
if (hw_port_test_set(ci, mode)) ret = hw_port_test_set(ci, mode);
dev_err(ci->dev, "invalid mode\n");
spin_unlock_irqrestore(&ci->lock, flags); spin_unlock_irqrestore(&ci->lock, flags);
done: return ret ? ret : count;
return count;
} }
static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
show_port_test, store_port_test); static int ci_port_test_open(struct inode *inode, struct file *file)
{
return single_open(file, ci_port_test_show, inode->i_private);
}
static const struct file_operations ci_port_test_fops = {
.open = ci_port_test_open,
.write = ci_port_test_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/** /**
* show_qheads: DMA contents of all queue heads * ci_qheads_show: DMA contents of all queue heads
*
* Check "device.h" for details
*/ */
static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, static int ci_qheads_show(struct seq_file *s, void *data)
char *buf)
{ {
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); struct ci13xxx *ci = s->private;
unsigned long flags; unsigned long flags;
unsigned i, j, n = 0; unsigned i, j;
if (attr == NULL || buf == NULL) { if (ci->role != CI_ROLE_GADGET) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__); seq_printf(s, "not in gadget mode\n");
return 0; return 0;
} }
...@@ -236,197 +129,119 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, ...@@ -236,197 +129,119 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i]; struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
struct ci13xxx_ep *mEpTx = struct ci13xxx_ep *mEpTx =
&ci->ci13xxx_ep[i + ci->hw_ep_max/2]; &ci->ci13xxx_ep[i + ci->hw_ep_max/2];
n += scnprintf(buf + n, PAGE_SIZE - n, seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
"EP=%02i: RX=%08X TX=%08X\n", i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++)
for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { seq_printf(s, " %04X: %08X %08X\n", j,
n += scnprintf(buf + n, PAGE_SIZE - n, *((u32 *)mEpRx->qh.ptr + j),
" %04X: %08X %08X\n", j, *((u32 *)mEpTx->qh.ptr + j));
*((u32 *)mEpRx->qh.ptr + j),
*((u32 *)mEpTx->qh.ptr + j));
}
} }
spin_unlock_irqrestore(&ci->lock, flags); spin_unlock_irqrestore(&ci->lock, flags);
return n; return 0;
} }
static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
/** static int ci_qheads_open(struct inode *inode, struct file *file)
* show_registers: dumps all registers
*
* Check "device.h" for details
*/
#define DUMP_ENTRIES 512
static ssize_t show_registers(struct device *dev,
struct device_attribute *attr, char *buf)
{ {
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); return single_open(file, ci_qheads_show, inode->i_private);
unsigned long flags;
u32 *dump;
unsigned i, k, n = 0;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
return 0;
}
dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
if (!dump) {
dev_err(ci->dev, "%s: out of memory\n", __func__);
return 0;
}
spin_lock_irqsave(&ci->lock, flags);
k = hw_register_read(ci, dump, DUMP_ENTRIES);
spin_unlock_irqrestore(&ci->lock, flags);
for (i = 0; i < k; i++) {
n += scnprintf(buf + n, PAGE_SIZE - n,
"reg[0x%04X] = 0x%08X\n",
i * (unsigned)sizeof(u32), dump[i]);
}
kfree(dump);
return n;
} }
/** static const struct file_operations ci_qheads_fops = {
* store_registers: writes value to register address .open = ci_qheads_open,
* .read = seq_read,
* Check "device.h" for details .llseek = seq_lseek,
*/ .release = single_release,
static ssize_t store_registers(struct device *dev, };
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long addr, data, flags;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
goto done;
}
if (sscanf(buf, "%li %li", &addr, &data) != 2) {
dev_err(ci->dev,
"<addr> <data>: write data to register address\n");
goto done;
}
spin_lock_irqsave(&ci->lock, flags);
if (hw_register_write(ci, addr, data))
dev_err(ci->dev, "invalid address range\n");
spin_unlock_irqrestore(&ci->lock, flags);
done:
return count;
}
static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
show_registers, store_registers);
/** /**
* show_requests: DMA contents of all requests currently queued (all endpts) * ci_requests_show: DMA contents of all requests currently queued (all endpts)
*
* Check "device.h" for details
*/ */
static ssize_t show_requests(struct device *dev, struct device_attribute *attr, static int ci_requests_show(struct seq_file *s, void *data)
char *buf)
{ {
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); struct ci13xxx *ci = s->private;
unsigned long flags; unsigned long flags;
struct list_head *ptr = NULL; struct list_head *ptr = NULL;
struct ci13xxx_req *req = NULL; struct ci13xxx_req *req = NULL;
unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32);
if (attr == NULL || buf == NULL) { if (ci->role != CI_ROLE_GADGET) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__); seq_printf(s, "not in gadget mode\n");
return 0; return 0;
} }
spin_lock_irqsave(&ci->lock, flags); spin_lock_irqsave(&ci->lock, flags);
for (i = 0; i < ci->hw_ep_max; i++) for (i = 0; i < ci->hw_ep_max; i++)
list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) {
{
req = list_entry(ptr, struct ci13xxx_req, queue); req = list_entry(ptr, struct ci13xxx_req, queue);
n += scnprintf(buf + n, PAGE_SIZE - n, seq_printf(s, "EP=%02i: TD=%08X %s\n",
"EP=%02i: TD=%08X %s\n", i % ci->hw_ep_max/2, (u32)req->dma,
i % ci->hw_ep_max/2, (u32)req->dma, ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
((i < ci->hw_ep_max/2) ? "RX" : "TX"));
for (j = 0; j < qSize; j++) for (j = 0; j < qsize; j++)
n += scnprintf(buf + n, PAGE_SIZE - n, seq_printf(s, " %04X: %08X\n", j,
" %04X: %08X\n", j, *((u32 *)req->ptr + j));
*((u32 *)req->ptr + j));
} }
spin_unlock_irqrestore(&ci->lock, flags); spin_unlock_irqrestore(&ci->lock, flags);
return n; return 0;
}
static int ci_requests_open(struct inode *inode, struct file *file)
{
return single_open(file, ci_requests_show, inode->i_private);
} }
static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
static const struct file_operations ci_requests_fops = {
.open = ci_requests_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/** /**
* dbg_create_files: initializes the attribute interface * dbg_create_files: initializes the attribute interface
* @dev: device * @ci: device
* *
* This function returns an error code * This function returns an error code
*/ */
int dbg_create_files(struct device *dev) int dbg_create_files(struct ci13xxx *ci)
{ {
int retval = 0; struct dentry *dent;
if (dev == NULL) ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
return -EINVAL; if (!ci->debugfs)
retval = device_create_file(dev, &dev_attr_device); return -ENOMEM;
if (retval)
goto done; dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
retval = device_create_file(dev, &dev_attr_driver); &ci_device_fops);
if (retval) if (!dent)
goto rm_device; goto err;
retval = device_create_file(dev, &dev_attr_port_test);
if (retval) dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs,
goto rm_driver; ci, &ci_port_test_fops);
retval = device_create_file(dev, &dev_attr_qheads); if (!dent)
if (retval) goto err;
goto rm_port_test;
retval = device_create_file(dev, &dev_attr_registers); dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
if (retval) &ci_qheads_fops);
goto rm_qheads; if (!dent)
retval = device_create_file(dev, &dev_attr_requests); goto err;
if (retval)
goto rm_registers; dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
return 0; &ci_requests_fops);
if (dent)
rm_registers: return 0;
device_remove_file(dev, &dev_attr_registers); err:
rm_qheads: debugfs_remove_recursive(ci->debugfs);
device_remove_file(dev, &dev_attr_qheads); return -ENOMEM;
rm_port_test:
device_remove_file(dev, &dev_attr_port_test);
rm_driver:
device_remove_file(dev, &dev_attr_driver);
rm_device:
device_remove_file(dev, &dev_attr_device);
done:
return retval;
} }
/** /**
* dbg_remove_files: destroys the attribute interface * dbg_remove_files: destroys the attribute interface
* @dev: device * @ci: device
*
* This function returns an error code
*/ */
int dbg_remove_files(struct device *dev) void dbg_remove_files(struct ci13xxx *ci)
{ {
if (dev == NULL) debugfs_remove_recursive(ci->debugfs);
return -EINVAL;
device_remove_file(dev, &dev_attr_requests);
device_remove_file(dev, &dev_attr_registers);
device_remove_file(dev, &dev_attr_qheads);
device_remove_file(dev, &dev_attr_port_test);
device_remove_file(dev, &dev_attr_driver);
device_remove_file(dev, &dev_attr_device);
return 0;
} }
...@@ -14,17 +14,16 @@ ...@@ -14,17 +14,16 @@
#define __DRIVERS_USB_CHIPIDEA_DEBUG_H #define __DRIVERS_USB_CHIPIDEA_DEBUG_H
#ifdef CONFIG_USB_CHIPIDEA_DEBUG #ifdef CONFIG_USB_CHIPIDEA_DEBUG
int dbg_create_files(struct device *dev); int dbg_create_files(struct ci13xxx *ci);
int dbg_remove_files(struct device *dev); void dbg_remove_files(struct ci13xxx *ci);
#else #else
static inline int dbg_create_files(struct device *dev) static inline int dbg_create_files(struct ci13xxx *ci)
{ {
return 0; return 0;
} }
static inline int dbg_remove_files(struct device *dev) static inline void dbg_remove_files(struct ci13xxx *ci)
{ {
return 0;
} }
#endif #endif
......
...@@ -1697,7 +1697,7 @@ static int udc_start(struct ci13xxx *ci) ...@@ -1697,7 +1697,7 @@ static int udc_start(struct ci13xxx *ci)
goto put_transceiver; goto put_transceiver;
} }
retval = dbg_create_files(ci->dev); retval = dbg_create_files(ci);
if (retval) if (retval)
goto unreg_device; goto unreg_device;
...@@ -1726,7 +1726,7 @@ static int udc_start(struct ci13xxx *ci) ...@@ -1726,7 +1726,7 @@ static int udc_start(struct ci13xxx *ci)
dev_err(dev, "error = %i\n", retval); dev_err(dev, "error = %i\n", retval);
remove_dbg: remove_dbg:
dbg_remove_files(ci->dev); dbg_remove_files(ci);
unreg_device: unreg_device:
device_unregister(&ci->gadget.dev); device_unregister(&ci->gadget.dev);
put_transceiver: put_transceiver:
...@@ -1763,7 +1763,7 @@ static void udc_stop(struct ci13xxx *ci) ...@@ -1763,7 +1763,7 @@ static void udc_stop(struct ci13xxx *ci)
if (ci->global_phy) if (ci->global_phy)
usb_put_phy(ci->transceiver); usb_put_phy(ci->transceiver);
} }
dbg_remove_files(ci->dev); dbg_remove_files(ci);
device_unregister(&ci->gadget.dev); device_unregister(&ci->gadget.dev);
/* my kobject is dynamic, I swear! */ /* my kobject is dynamic, I swear! */
memset(&ci->gadget, 0, sizeof(ci->gadget)); memset(&ci->gadget, 0, sizeof(ci->gadget));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment