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#include <linux/usb/phy.h>
  11#include <linux/usb/otg.h>
  12#include <linux/usb/otg-fsm.h>
  13#include <linux/usb/chipidea.h>
  14
  15#include "ci.h"
  16#include "udc.h"
  17#include "bits.h"
  18#include "otg.h"
  19
  20/**
  21 * ci_device_show: prints information about device capabilities and status
  22 */
  23static int ci_device_show(struct seq_file *s, void *data)
  24{
  25        struct ci_hdrc *ci = s->private;
  26        struct usb_gadget *gadget = &ci->gadget;
  27
  28        seq_printf(s, "speed             = %d\n", gadget->speed);
  29        seq_printf(s, "max_speed         = %d\n", gadget->max_speed);
  30        seq_printf(s, "is_otg            = %d\n", gadget->is_otg);
  31        seq_printf(s, "is_a_peripheral   = %d\n", gadget->is_a_peripheral);
  32        seq_printf(s, "b_hnp_enable      = %d\n", gadget->b_hnp_enable);
  33        seq_printf(s, "a_hnp_support     = %d\n", gadget->a_hnp_support);
  34        seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
  35        seq_printf(s, "name              = %s\n",
  36                   (gadget->name ? gadget->name : ""));
  37
  38        if (!ci->driver)
  39                return 0;
  40
  41        seq_printf(s, "gadget function   = %s\n",
  42                       (ci->driver->function ? ci->driver->function : ""));
  43        seq_printf(s, "gadget max speed  = %d\n", ci->driver->max_speed);
  44
  45        return 0;
  46}
  47
  48static int ci_device_open(struct inode *inode, struct file *file)
  49{
  50        return single_open(file, ci_device_show, inode->i_private);
  51}
  52
  53static const struct file_operations ci_device_fops = {
  54        .open           = ci_device_open,
  55        .read           = seq_read,
  56        .llseek         = seq_lseek,
  57        .release        = single_release,
  58};
  59
  60/**
  61 * ci_port_test_show: reads port test mode
  62 */
  63static int ci_port_test_show(struct seq_file *s, void *data)
  64{
  65        struct ci_hdrc *ci = s->private;
  66        unsigned long flags;
  67        unsigned mode;
  68
  69        pm_runtime_get_sync(ci->dev);
  70        spin_lock_irqsave(&ci->lock, flags);
  71        mode = hw_port_test_get(ci);
  72        spin_unlock_irqrestore(&ci->lock, flags);
  73        pm_runtime_put_sync(ci->dev);
  74
  75        seq_printf(s, "mode = %u\n", mode);
  76
  77        return 0;
  78}
  79
  80/**
  81 * ci_port_test_write: writes port test mode
  82 */
  83static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
  84                                  size_t count, loff_t *ppos)
  85{
  86        struct seq_file *s = file->private_data;
  87        struct ci_hdrc *ci = s->private;
  88        unsigned long flags;
  89        unsigned mode;
  90        char buf[32];
  91        int ret;
  92
  93        count = min_t(size_t, sizeof(buf) - 1, count);
  94        if (copy_from_user(buf, ubuf, count))
  95                return -EFAULT;
  96
  97        /* sscanf requires a zero terminated string */
  98        buf[count] = '\0';
  99
 100        if (sscanf(buf, "%u", &mode) != 1)
 101                return -EINVAL;
 102
 103        if (mode > 255)
 104                return -EBADRQC;
 105
 106        pm_runtime_get_sync(ci->dev);
 107        spin_lock_irqsave(&ci->lock, flags);
 108        ret = hw_port_test_set(ci, mode);
 109        spin_unlock_irqrestore(&ci->lock, flags);
 110        pm_runtime_put_sync(ci->dev);
 111
 112        return ret ? ret : count;
 113}
 114
 115static int ci_port_test_open(struct inode *inode, struct file *file)
 116{
 117        return single_open(file, ci_port_test_show, inode->i_private);
 118}
 119
 120static const struct file_operations ci_port_test_fops = {
 121        .open           = ci_port_test_open,
 122        .write          = ci_port_test_write,
 123        .read           = seq_read,
 124        .llseek         = seq_lseek,
 125        .release        = single_release,
 126};
 127
 128/**
 129 * ci_qheads_show: DMA contents of all queue heads
 130 */
 131static int ci_qheads_show(struct seq_file *s, void *data)
 132{
 133        struct ci_hdrc *ci = s->private;
 134        unsigned long flags;
 135        unsigned i, j;
 136
 137        if (ci->role != CI_ROLE_GADGET) {
 138                seq_printf(s, "not in gadget mode\n");
 139                return 0;
 140        }
 141
 142        spin_lock_irqsave(&ci->lock, flags);
 143        for (i = 0; i < ci->hw_ep_max/2; i++) {
 144                struct ci_hw_ep *hweprx = &ci->ci_hw_ep[i];
 145                struct ci_hw_ep *hweptx =
 146                        &ci->ci_hw_ep[i + ci->hw_ep_max/2];
 147                seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
 148                           i, (u32)hweprx->qh.dma, (u32)hweptx->qh.dma);
 149                for (j = 0; j < (sizeof(struct ci_hw_qh)/sizeof(u32)); j++)
 150                        seq_printf(s, " %04X:    %08X    %08X\n", j,
 151                                   *((u32 *)hweprx->qh.ptr + j),
 152                                   *((u32 *)hweptx->qh.ptr + j));
 153        }
 154        spin_unlock_irqrestore(&ci->lock, flags);
 155
 156        return 0;
 157}
 158
 159static int ci_qheads_open(struct inode *inode, struct file *file)
 160{
 161        return single_open(file, ci_qheads_show, inode->i_private);
 162}
 163
 164static const struct file_operations ci_qheads_fops = {
 165        .open           = ci_qheads_open,
 166        .read           = seq_read,
 167        .llseek         = seq_lseek,
 168        .release        = single_release,
 169};
 170
 171/**
 172 * ci_requests_show: DMA contents of all requests currently queued (all endpts)
 173 */
 174static int ci_requests_show(struct seq_file *s, void *data)
 175{
 176        struct ci_hdrc *ci = s->private;
 177        unsigned long flags;
 178        struct ci_hw_req *req = NULL;
 179        struct td_node *node, *tmpnode;
 180        unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32);
 181
 182        if (ci->role != CI_ROLE_GADGET) {
 183                seq_printf(s, "not in gadget mode\n");
 184                return 0;
 185        }
 186
 187        spin_lock_irqsave(&ci->lock, flags);
 188        for (i = 0; i < ci->hw_ep_max; i++)
 189                list_for_each_entry(req, &ci->ci_hw_ep[i].qh.queue, queue) {
 190                        list_for_each_entry_safe(node, tmpnode, &req->tds, td) {
 191                                seq_printf(s, "EP=%02i: TD=%08X %s\n",
 192                                           i % (ci->hw_ep_max / 2),
 193                                           (u32)node->dma,
 194                                           ((i < ci->hw_ep_max/2) ?
 195                                           "RX" : "TX"));
 196
 197                                for (j = 0; j < qsize; j++)
 198                                        seq_printf(s, " %04X:    %08X\n", j,
 199                                                   *((u32 *)node->ptr + j));
 200                        }
 201                }
 202        spin_unlock_irqrestore(&ci->lock, flags);
 203
 204        return 0;
 205}
 206
 207static int ci_requests_open(struct inode *inode, struct file *file)
 208{
 209        return single_open(file, ci_requests_show, inode->i_private);
 210}
 211
 212static const struct file_operations ci_requests_fops = {
 213        .open           = ci_requests_open,
 214        .read           = seq_read,
 215        .llseek         = seq_lseek,
 216        .release        = single_release,
 217};
 218
 219static int ci_otg_show(struct seq_file *s, void *unused)
 220{
 221        struct ci_hdrc *ci = s->private;
 222        struct otg_fsm *fsm;
 223
 224        if (!ci || !ci_otg_is_fsm_mode(ci))
 225                return 0;
 226
 227        fsm = &ci->fsm;
 228
 229        /* ------ State ----- */
 230        seq_printf(s, "OTG state: %s\n\n",
 231                        usb_otg_state_string(ci->otg.state));
 232
 233        /* ------ State Machine Variables ----- */
 234        seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop);
 235
 236        seq_printf(s, "a_bus_req: %d\n", fsm->a_bus_req);
 237
 238        seq_printf(s, "a_srp_det: %d\n", fsm->a_srp_det);
 239
 240        seq_printf(s, "a_vbus_vld: %d\n", fsm->a_vbus_vld);
 241
 242        seq_printf(s, "b_conn: %d\n", fsm->b_conn);
 243
 244        seq_printf(s, "adp_change: %d\n", fsm->adp_change);
 245
 246        seq_printf(s, "power_up: %d\n", fsm->power_up);
 247
 248        seq_printf(s, "a_bus_resume: %d\n", fsm->a_bus_resume);
 249
 250        seq_printf(s, "a_bus_suspend: %d\n", fsm->a_bus_suspend);
 251
 252        seq_printf(s, "a_conn: %d\n", fsm->a_conn);
 253
 254        seq_printf(s, "b_bus_req: %d\n", fsm->b_bus_req);
 255
 256        seq_printf(s, "b_bus_suspend: %d\n", fsm->b_bus_suspend);
 257
 258        seq_printf(s, "b_se0_srp: %d\n", fsm->b_se0_srp);
 259
 260        seq_printf(s, "b_ssend_srp: %d\n", fsm->b_ssend_srp);
 261
 262        seq_printf(s, "b_sess_vld: %d\n", fsm->b_sess_vld);
 263
 264        seq_printf(s, "b_srp_done: %d\n", fsm->b_srp_done);
 265
 266        seq_printf(s, "drv_vbus: %d\n", fsm->drv_vbus);
 267
 268        seq_printf(s, "loc_conn: %d\n", fsm->loc_conn);
 269
 270        seq_printf(s, "loc_sof: %d\n", fsm->loc_sof);
 271
 272        seq_printf(s, "adp_prb: %d\n", fsm->adp_prb);
 273
 274        seq_printf(s, "id: %d\n", fsm->id);
 275
 276        seq_printf(s, "protocol: %d\n", fsm->protocol);
 277
 278        return 0;
 279}
 280
 281static int ci_otg_open(struct inode *inode, struct file *file)
 282{
 283        return single_open(file, ci_otg_show, inode->i_private);
 284}
 285
 286static const struct file_operations ci_otg_fops = {
 287        .open                   = ci_otg_open,
 288        .read                   = seq_read,
 289        .llseek                 = seq_lseek,
 290        .release                = single_release,
 291};
 292
 293static int ci_role_show(struct seq_file *s, void *data)
 294{
 295        struct ci_hdrc *ci = s->private;
 296
 297        seq_printf(s, "%s\n", ci_role(ci)->name);
 298
 299        return 0;
 300}
 301
 302static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
 303                             size_t count, loff_t *ppos)
 304{
 305        struct seq_file *s = file->private_data;
 306        struct ci_hdrc *ci = s->private;
 307        enum ci_role role;
 308        char buf[8];
 309        int ret;
 310
 311        if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 312                return -EFAULT;
 313
 314        for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
 315                if (ci->roles[role] &&
 316                    !strncmp(buf, ci->roles[role]->name,
 317                             strlen(ci->roles[role]->name)))
 318                        break;
 319
 320        if (role == CI_ROLE_END || role == ci->role)
 321                return -EINVAL;
 322
 323        pm_runtime_get_sync(ci->dev);
 324        disable_irq(ci->irq);
 325        ci_role_stop(ci);
 326        ret = ci_role_start(ci, role);
 327        enable_irq(ci->irq);
 328        pm_runtime_put_sync(ci->dev);
 329
 330        return ret ? ret : count;
 331}
 332
 333static int ci_role_open(struct inode *inode, struct file *file)
 334{
 335        return single_open(file, ci_role_show, inode->i_private);
 336}
 337
 338static const struct file_operations ci_role_fops = {
 339        .open           = ci_role_open,
 340        .write          = ci_role_write,
 341        .read           = seq_read,
 342        .llseek         = seq_lseek,
 343        .release        = single_release,
 344};
 345
 346static int ci_registers_show(struct seq_file *s, void *unused)
 347{
 348        struct ci_hdrc *ci = s->private;
 349        u32 tmp_reg;
 350
 351        if (!ci || ci->in_lpm)
 352                return -EPERM;
 353
 354        /* ------ Registers ----- */
 355        tmp_reg = hw_read_intr_enable(ci);
 356        seq_printf(s, "USBINTR reg: %08x\n", tmp_reg);
 357
 358        tmp_reg = hw_read_intr_status(ci);
 359        seq_printf(s, "USBSTS reg: %08x\n", tmp_reg);
 360
 361        tmp_reg = hw_read(ci, OP_USBMODE, ~0);
 362        seq_printf(s, "USBMODE reg: %08x\n", tmp_reg);
 363
 364        tmp_reg = hw_read(ci, OP_USBCMD, ~0);
 365        seq_printf(s, "USBCMD reg: %08x\n", tmp_reg);
 366
 367        tmp_reg = hw_read(ci, OP_PORTSC, ~0);
 368        seq_printf(s, "PORTSC reg: %08x\n", tmp_reg);
 369
 370        if (ci->is_otg) {
 371                tmp_reg = hw_read_otgsc(ci, ~0);
 372                seq_printf(s, "OTGSC reg: %08x\n", tmp_reg);
 373        }
 374
 375        return 0;
 376}
 377
 378static int ci_registers_open(struct inode *inode, struct file *file)
 379{
 380        return single_open(file, ci_registers_show, inode->i_private);
 381}
 382
 383static const struct file_operations ci_registers_fops = {
 384        .open                   = ci_registers_open,
 385        .read                   = seq_read,
 386        .llseek                 = seq_lseek,
 387        .release                = single_release,
 388};
 389
 390/**
 391 * dbg_create_files: initializes the attribute interface
 392 * @ci: device
 393 *
 394 * This function returns an error code
 395 */
 396int dbg_create_files(struct ci_hdrc *ci)
 397{
 398        struct dentry *dent;
 399
 400        ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
 401        if (!ci->debugfs)
 402                return -ENOMEM;
 403
 404        dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
 405                                   &ci_device_fops);
 406        if (!dent)
 407                goto err;
 408
 409        dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs,
 410                                   ci, &ci_port_test_fops);
 411        if (!dent)
 412                goto err;
 413
 414        dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
 415                                   &ci_qheads_fops);
 416        if (!dent)
 417                goto err;
 418
 419        dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
 420                                   &ci_requests_fops);
 421        if (!dent)
 422                goto err;
 423
 424        if (ci_otg_is_fsm_mode(ci)) {
 425                dent = debugfs_create_file("otg", S_IRUGO, ci->debugfs, ci,
 426                                        &ci_otg_fops);
 427                if (!dent)
 428                        goto err;
 429        }
 430
 431        dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
 432                                   &ci_role_fops);
 433        if (!dent)
 434                goto err;
 435
 436        dent = debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci,
 437                                &ci_registers_fops);
 438
 439        if (dent)
 440                return 0;
 441err:
 442        debugfs_remove_recursive(ci->debugfs);
 443        return -ENOMEM;
 444}
 445
 446/**
 447 * dbg_remove_files: destroys the attribute interface
 448 * @ci: device
 449 */
 450void dbg_remove_files(struct ci_hdrc *ci)
 451{
 452        debugfs_remove_recursive(ci->debugfs);
 453}
 454