linux/drivers/usb/chipidea/debug.c
<<
>>
Prefs
   1#include <linux/kernel.h>
   2#include <linux/device.h>
   3#include <linux/types.h>
   4#include <linux/spinlock.h>
   5#include <linux/debugfs.h>
   6#include <linux/seq_file.h>
   7#include <linux/uaccess.h>
   8#include <linux/usb/ch9.h>
   9#include <linux/usb/gadget.h>
  10
  11#include "ci.h"
  12#include "udc.h"
  13#include "bits.h"
  14#include "debug.h"
  15
  16/**
  17 * ci_device_show: prints information about device capabilities and status
  18 */
  19static int ci_device_show(struct seq_file *s, void *data)
  20{
  21        struct ci_hdrc *ci = s->private;
  22        struct usb_gadget *gadget = &ci->gadget;
  23
  24        seq_printf(s, "speed             = %d\n", gadget->speed);
  25        seq_printf(s, "max_speed         = %d\n", gadget->max_speed);
  26        seq_printf(s, "is_otg            = %d\n", gadget->is_otg);
  27        seq_printf(s, "is_a_peripheral   = %d\n", gadget->is_a_peripheral);
  28        seq_printf(s, "b_hnp_enable      = %d\n", gadget->b_hnp_enable);
  29        seq_printf(s, "a_hnp_support     = %d\n", gadget->a_hnp_support);
  30        seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
  31        seq_printf(s, "name              = %s\n",
  32                   (gadget->name ? gadget->name : ""));
  33
  34        if (!ci->driver)
  35                return 0;
  36
  37        seq_printf(s, "gadget function   = %s\n",
  38                       (ci->driver->function ? ci->driver->function : ""));
  39        seq_printf(s, "gadget max speed  = %d\n", ci->driver->max_speed);
  40
  41        return 0;
  42}
  43
  44static int ci_device_open(struct inode *inode, struct file *file)
  45{
  46        return single_open(file, ci_device_show, inode->i_private);
  47}
  48
  49static const struct file_operations ci_device_fops = {
  50        .open           = ci_device_open,
  51        .read           = seq_read,
  52        .llseek         = seq_lseek,
  53        .release        = single_release,
  54};
  55
  56/**
  57 * ci_port_test_show: reads port test mode
  58 */
  59static int ci_port_test_show(struct seq_file *s, void *data)
  60{
  61        struct ci_hdrc *ci = s->private;
  62        unsigned long flags;
  63        unsigned mode;
  64
  65        spin_lock_irqsave(&ci->lock, flags);
  66        mode = hw_port_test_get(ci);
  67        spin_unlock_irqrestore(&ci->lock, flags);
  68
  69        seq_printf(s, "mode = %u\n", mode);
  70
  71        return 0;
  72}
  73
  74/**
  75 * ci_port_test_write: writes port test mode
  76 */
  77static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
  78                                  size_t count, loff_t *ppos)
  79{
  80        struct seq_file *s = file->private_data;
  81        struct ci_hdrc *ci = s->private;
  82        unsigned long flags;
  83        unsigned mode;
  84        char buf[32];
  85        int ret;
  86
  87        if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
  88                return -EFAULT;
  89
  90        if (sscanf(buf, "%u", &mode) != 1)
  91                return -EINVAL;
  92
  93        spin_lock_irqsave(&ci->lock, flags);
  94        ret = hw_port_test_set(ci, mode);
  95        spin_unlock_irqrestore(&ci->lock, flags);
  96
  97        return ret ? ret : count;
  98}
  99
 100static int ci_port_test_open(struct inode *inode, struct file *file)
 101{
 102        return single_open(file, ci_port_test_show, inode->i_private);
 103}
 104
 105static const struct file_operations ci_port_test_fops = {
 106        .open           = ci_port_test_open,
 107        .write          = ci_port_test_write,
 108        .read           = seq_read,
 109        .llseek         = seq_lseek,
 110        .release        = single_release,
 111};
 112
 113/**
 114 * ci_qheads_show: DMA contents of all queue heads
 115 */
 116static int ci_qheads_show(struct seq_file *s, void *data)
 117{
 118        struct ci_hdrc *ci = s->private;
 119        unsigned long flags;
 120        unsigned i, j;
 121
 122        if (ci->role != CI_ROLE_GADGET) {
 123                seq_printf(s, "not in gadget mode\n");
 124                return 0;
 125        }
 126
 127        spin_lock_irqsave(&ci->lock, flags);
 128        for (i = 0; i < ci->hw_ep_max/2; i++) {
 129                struct ci_hw_ep *hweprx = &ci->ci_hw_ep[i];
 130                struct ci_hw_ep *hweptx =
 131                        &ci->ci_hw_ep[i + ci->hw_ep_max/2];
 132                seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
 133                           i, (u32)hweprx->qh.dma, (u32)hweptx->qh.dma);
 134                for (j = 0; j < (sizeof(struct ci_hw_qh)/sizeof(u32)); j++)
 135                        seq_printf(s, " %04X:    %08X    %08X\n", j,
 136                                   *((u32 *)hweprx->qh.ptr + j),
 137                                   *((u32 *)hweptx->qh.ptr + j));
 138        }
 139        spin_unlock_irqrestore(&ci->lock, flags);
 140
 141        return 0;
 142}
 143
 144static int ci_qheads_open(struct inode *inode, struct file *file)
 145{
 146        return single_open(file, ci_qheads_show, inode->i_private);
 147}
 148
 149static const struct file_operations ci_qheads_fops = {
 150        .open           = ci_qheads_open,
 151        .read           = seq_read,
 152        .llseek         = seq_lseek,
 153        .release        = single_release,
 154};
 155
 156/**
 157 * ci_requests_show: DMA contents of all requests currently queued (all endpts)
 158 */
 159static int ci_requests_show(struct seq_file *s, void *data)
 160{
 161        struct ci_hdrc *ci = s->private;
 162        unsigned long flags;
 163        struct list_head   *ptr = NULL;
 164        struct ci_hw_req *req = NULL;
 165        struct td_node *node, *tmpnode;
 166        unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32);
 167
 168        if (ci->role != CI_ROLE_GADGET) {
 169                seq_printf(s, "not in gadget mode\n");
 170                return 0;
 171        }
 172
 173        spin_lock_irqsave(&ci->lock, flags);
 174        for (i = 0; i < ci->hw_ep_max; i++)
 175                list_for_each(ptr, &ci->ci_hw_ep[i].qh.queue) {
 176                        req = list_entry(ptr, struct ci_hw_req, queue);
 177
 178                        list_for_each_entry_safe(node, tmpnode, &req->tds, td) {
 179                                seq_printf(s, "EP=%02i: TD=%08X %s\n",
 180                                           i % (ci->hw_ep_max / 2),
 181                                           (u32)node->dma,
 182                                           ((i < ci->hw_ep_max/2) ?
 183                                           "RX" : "TX"));
 184
 185                                for (j = 0; j < qsize; j++)
 186                                        seq_printf(s, " %04X:    %08X\n", j,
 187                                                   *((u32 *)node->ptr + j));
 188                        }
 189                }
 190        spin_unlock_irqrestore(&ci->lock, flags);
 191
 192        return 0;
 193}
 194
 195static int ci_requests_open(struct inode *inode, struct file *file)
 196{
 197        return single_open(file, ci_requests_show, inode->i_private);
 198}
 199
 200static const struct file_operations ci_requests_fops = {
 201        .open           = ci_requests_open,
 202        .read           = seq_read,
 203        .llseek         = seq_lseek,
 204        .release        = single_release,
 205};
 206
 207static int ci_role_show(struct seq_file *s, void *data)
 208{
 209        struct ci_hdrc *ci = s->private;
 210
 211        seq_printf(s, "%s\n", ci_role(ci)->name);
 212
 213        return 0;
 214}
 215
 216static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
 217                             size_t count, loff_t *ppos)
 218{
 219        struct seq_file *s = file->private_data;
 220        struct ci_hdrc *ci = s->private;
 221        enum ci_role role;
 222        char buf[8];
 223        int ret;
 224
 225        if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 226                return -EFAULT;
 227
 228        for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
 229                if (ci->roles[role] &&
 230                    !strncmp(buf, ci->roles[role]->name,
 231                             strlen(ci->roles[role]->name)))
 232                        break;
 233
 234        if (role == CI_ROLE_END || role == ci->role)
 235                return -EINVAL;
 236
 237        ci_role_stop(ci);
 238        ret = ci_role_start(ci, role);
 239
 240        return ret ? ret : count;
 241}
 242
 243static int ci_role_open(struct inode *inode, struct file *file)
 244{
 245        return single_open(file, ci_role_show, inode->i_private);
 246}
 247
 248static const struct file_operations ci_role_fops = {
 249        .open           = ci_role_open,
 250        .write          = ci_role_write,
 251        .read           = seq_read,
 252        .llseek         = seq_lseek,
 253        .release        = single_release,
 254};
 255
 256/**
 257 * dbg_create_files: initializes the attribute interface
 258 * @ci: device
 259 *
 260 * This function returns an error code
 261 */
 262int dbg_create_files(struct ci_hdrc *ci)
 263{
 264        struct dentry *dent;
 265
 266        ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
 267        if (!ci->debugfs)
 268                return -ENOMEM;
 269
 270        dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
 271                                   &ci_device_fops);
 272        if (!dent)
 273                goto err;
 274
 275        dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs,
 276                                   ci, &ci_port_test_fops);
 277        if (!dent)
 278                goto err;
 279
 280        dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
 281                                   &ci_qheads_fops);
 282        if (!dent)
 283                goto err;
 284
 285        dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
 286                                   &ci_requests_fops);
 287        if (!dent)
 288                goto err;
 289
 290        dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
 291                                   &ci_role_fops);
 292        if (dent)
 293                return 0;
 294err:
 295        debugfs_remove_recursive(ci->debugfs);
 296        return -ENOMEM;
 297}
 298
 299/**
 300 * dbg_remove_files: destroys the attribute interface
 301 * @ci: device
 302 */
 303void dbg_remove_files(struct ci_hdrc *ci)
 304{
 305        debugfs_remove_recursive(ci->debugfs);
 306}
 307