]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/usb/chipidea/debug.c
usb: chipidea: convert debug entries in sysfs to debugfs
[karo-tx-linux.git] / drivers / usb / chipidea / debug.c
index 898aca59191516cd7f9f8193066a9f5fe1c07882..057ae09025bfcc15456bd86152329d7f193b6d93 100644 (file)
@@ -2,6 +2,9 @@
 #include <linux/device.h>
 #include <linux/types.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/gadget.h>
 
 #include "debug.h"
 
 /**
- * hw_register_read: reads all device registers (execute without interruption)
- * @buf:  destination buffer
- * @size: buffer size
- *
- * This function returns number of registers read
+ * ci_device_show: prints information about device capabilities and status
  */
-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;
-
-       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);
+       struct ci13xxx *ci = s->private;
+       struct usb_gadget *gadget = &ci->gadget;
 
-       if (addr >= ci->hw_bank.size)
-               return -EINVAL;
+       seq_printf(s, "speed             = %d\n", gadget->speed);
+       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 */
-       addr *= sizeof(u32);
+       seq_printf(s, "gadget function   = %s\n",
+                      (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;
 }
 
-/**
- * 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)
+static int ci_device_open(struct inode *inode, struct file *file)
 {
-       if (n >= REG_BITS)
-               return -EINVAL;
-
-       hw_write(ci, OP_USBINTR, BIT(n), 0);
-       hw_write(ci, OP_USBSTS,  BIT(n), BIT(n));
-       return 0;
+       return single_open(file, ci_device_show, inode->i_private);
 }
 
-/**
- * hw_intr_force: enables interrupt & forces interrupt status (execute without
- *                interruption)
- * @n: interrupt bit
- *
- * 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);
+static const struct file_operations ci_device_fops = {
+       .open           = ci_device_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 /**
- * show_port_test: reads port test mode
- *
- * Check "device.h" for details
+ * ci_port_test_show: reads port test mode
  */
-static ssize_t show_port_test(struct device *dev,
-                             struct device_attribute *attr, char *buf)
+static int ci_port_test_show(struct seq_file *s, void *data)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+       struct ci13xxx *ci = s->private;
        unsigned long flags;
        unsigned mode;
 
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "EINVAL\n");
-               return 0;
-       }
-
        spin_lock_irqsave(&ci->lock, flags);
        mode = hw_port_test_get(ci);
        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
- *
- * Check "device.h" for details
+ * ci_port_test_write: writes port test mode
  */
-static ssize_t store_port_test(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count)
+static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
+                                 size_t count, loff_t *ppos)
 {
-       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 mode;
+       char buf[32];
+       int ret;
 
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "[%s] EINVAL\n", __func__);
-               goto done;
-       }
+       if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
 
-       if (sscanf(buf, "%u", &mode) != 1) {
-               dev_err(ci->dev, "<mode>: set port test mode");
-               goto done;
-       }
+       if (sscanf(buf, "%u", &mode) != 1)
+               return -EINVAL;
 
        spin_lock_irqsave(&ci->lock, flags);
-       if (hw_port_test_set(ci, mode))
-               dev_err(ci->dev, "invalid mode\n");
+       ret = hw_port_test_set(ci, mode);
        spin_unlock_irqrestore(&ci->lock, flags);
 
- done:
-       return count;
+       return ret ? ret : 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
- *
- * Check "device.h" for details
+ * ci_qheads_show: DMA contents of all queue heads
  */
-static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
-                          char *buf)
+static int ci_qheads_show(struct seq_file *s, void *data)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+       struct ci13xxx *ci = s->private;
        unsigned long flags;
-       unsigned i, j, n = 0;
+       unsigned i, j;
 
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "[%s] EINVAL\n", __func__);
+       if (ci->role != CI_ROLE_GADGET) {
+               seq_printf(s, "not in gadget mode\n");
                return 0;
        }
 
@@ -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 *mEpTx =
                        &ci->ci13xxx_ep[i + ci->hw_ep_max/2];
-               n += scnprintf(buf + n, PAGE_SIZE - n,
-                              "EP=%02i: RX=%08X TX=%08X\n",
-                              i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
-               for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
-                       n += scnprintf(buf + n, PAGE_SIZE - n,
-                                      " %04X:    %08X    %08X\n", j,
-                                      *((u32 *)mEpRx->qh.ptr + j),
-                                      *((u32 *)mEpTx->qh.ptr + j));
-               }
+               seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
+                          i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
+               for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++)
+                       seq_printf(s, " %04X:    %08X    %08X\n", j,
+                                  *((u32 *)mEpRx->qh.ptr + j),
+                                  *((u32 *)mEpTx->qh.ptr + j));
        }
        spin_unlock_irqrestore(&ci->lock, flags);
 
-       return n;
+       return 0;
 }
-static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
 
-/**
- * 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)
+static int ci_qheads_open(struct inode *inode, struct file *file)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
-       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;
+       return single_open(file, ci_qheads_show, inode->i_private);
 }
 
-/**
- * store_registers: writes value to register address
- *
- * Check "device.h" for details
- */
-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);
+static const struct file_operations ci_qheads_fops = {
+       .open           = ci_qheads_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 /**
- * show_requests: DMA contents of all requests currently queued (all endpts)
- *
- * Check "device.h" for details
+ * ci_requests_show: DMA contents of all requests currently queued (all endpts)
  */
-static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
-                            char *buf)
+static int ci_requests_show(struct seq_file *s, void *data)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+       struct ci13xxx *ci = s->private;
        unsigned long flags;
        struct list_head   *ptr = 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) {
-               dev_err(ci->dev, "[%s] EINVAL\n", __func__);
+       if (ci->role != CI_ROLE_GADGET) {
+               seq_printf(s, "not in gadget mode\n");
                return 0;
        }
 
        spin_lock_irqsave(&ci->lock, flags);
        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);
 
-                       n += scnprintf(buf + n, PAGE_SIZE - n,
-                                       "EP=%02i: TD=%08X %s\n",
-                                       i % ci->hw_ep_max/2, (u32)req->dma,
-                                       ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
+                       seq_printf(s, "EP=%02i: TD=%08X %s\n",
+                                  i % ci->hw_ep_max/2, (u32)req->dma,
+                                  ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
 
-                       for (j = 0; j < qSize; j++)
-                               n += scnprintf(buf + n, PAGE_SIZE - n,
-                                               " %04X:    %08X\n", j,
-                                               *((u32 *)req->ptr + j));
+                       for (j = 0; j < qsize; j++)
+                               seq_printf(s, " %04X:    %08X\n", j,
+                                          *((u32 *)req->ptr + j));
                }
        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
- * @dev: device
+ * @ci: device
  *
  * This function returns an error code
  */
-int dbg_create_files(struct device *dev)
+int dbg_create_files(struct ci13xxx *ci)
 {
-       int retval = 0;
-
-       if (dev == NULL)
-               return -EINVAL;
-       retval = device_create_file(dev, &dev_attr_device);
-       if (retval)
-               goto done;
-       retval = device_create_file(dev, &dev_attr_driver);
-       if (retval)
-               goto rm_device;
-       retval = device_create_file(dev, &dev_attr_port_test);
-       if (retval)
-               goto rm_driver;
-       retval = device_create_file(dev, &dev_attr_qheads);
-       if (retval)
-               goto rm_port_test;
-       retval = device_create_file(dev, &dev_attr_registers);
-       if (retval)
-               goto rm_qheads;
-       retval = device_create_file(dev, &dev_attr_requests);
-       if (retval)
-               goto rm_registers;
-       return 0;
-
- rm_registers:
-       device_remove_file(dev, &dev_attr_registers);
- rm_qheads:
-       device_remove_file(dev, &dev_attr_qheads);
- 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;
+       struct dentry *dent;
+
+       ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
+       if (!ci->debugfs)
+               return -ENOMEM;
+
+       dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
+                                  &ci_device_fops);
+       if (!dent)
+               goto err;
+
+       dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs,
+                                  ci, &ci_port_test_fops);
+       if (!dent)
+               goto err;
+
+       dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
+                                  &ci_qheads_fops);
+       if (!dent)
+               goto err;
+
+       dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
+                                  &ci_requests_fops);
+       if (dent)
+               return 0;
+err:
+       debugfs_remove_recursive(ci->debugfs);
+       return -ENOMEM;
 }
 
 /**
  * dbg_remove_files: destroys the attribute interface
- * @dev: device
- *
- * This function returns an error code
+ * @ci: device
  */
-int dbg_remove_files(struct device *dev)
+void dbg_remove_files(struct ci13xxx *ci)
 {
-       if (dev == NULL)
-               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;
+       debugfs_remove_recursive(ci->debugfs);
 }