linux/drivers/usb/host/ohci-dbg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-1.0+
   2/*
   3 * OHCI HCD (Host Controller Driver) for USB.
   4 *
   5 * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
   6 * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
   7 *
   8 * This file is licenced under the GPL.
   9 */
  10
  11/*-------------------------------------------------------------------------*/
  12
  13#define edstring(ed_type) ({ char *temp; \
  14        switch (ed_type) { \
  15        case PIPE_CONTROL:      temp = "ctrl"; break; \
  16        case PIPE_BULK:         temp = "bulk"; break; \
  17        case PIPE_INTERRUPT:    temp = "intr"; break; \
  18        default:                temp = "isoc"; break; \
  19        } temp;})
  20#define pipestring(pipe) edstring(usb_pipetype(pipe))
  21
  22
  23#define ohci_dbg_sw(ohci, next, size, format, arg...) \
  24        do { \
  25        if (next != NULL) { \
  26                unsigned s_len; \
  27                s_len = scnprintf (*next, *size, format, ## arg ); \
  28                *size -= s_len; *next += s_len; \
  29        } else \
  30                ohci_dbg(ohci,format, ## arg ); \
  31        } while (0);
  32
  33/* Version for use where "next" is the address of a local variable */
  34#define ohci_dbg_nosw(ohci, next, size, format, arg...) \
  35        do { \
  36                unsigned s_len; \
  37                s_len = scnprintf(*next, *size, format, ## arg); \
  38                *size -= s_len; *next += s_len; \
  39        } while (0);
  40
  41
  42static void ohci_dump_intr_mask (
  43        struct ohci_hcd *ohci,
  44        char *label,
  45        u32 mask,
  46        char **next,
  47        unsigned *size)
  48{
  49        ohci_dbg_sw (ohci, next, size, "%s 0x%08x%s%s%s%s%s%s%s%s%s\n",
  50                label,
  51                mask,
  52                (mask & OHCI_INTR_MIE) ? " MIE" : "",
  53                (mask & OHCI_INTR_OC) ? " OC" : "",
  54                (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
  55                (mask & OHCI_INTR_FNO) ? " FNO" : "",
  56                (mask & OHCI_INTR_UE) ? " UE" : "",
  57                (mask & OHCI_INTR_RD) ? " RD" : "",
  58                (mask & OHCI_INTR_SF) ? " SF" : "",
  59                (mask & OHCI_INTR_WDH) ? " WDH" : "",
  60                (mask & OHCI_INTR_SO) ? " SO" : ""
  61                );
  62}
  63
  64static void maybe_print_eds (
  65        struct ohci_hcd *ohci,
  66        char *label,
  67        u32 value,
  68        char **next,
  69        unsigned *size)
  70{
  71        if (value)
  72                ohci_dbg_sw (ohci, next, size, "%s %08x\n", label, value);
  73}
  74
  75static char *hcfs2string (int state)
  76{
  77        switch (state) {
  78                case OHCI_USB_RESET:    return "reset";
  79                case OHCI_USB_RESUME:   return "resume";
  80                case OHCI_USB_OPER:     return "operational";
  81                case OHCI_USB_SUSPEND:  return "suspend";
  82        }
  83        return "?";
  84}
  85
  86static const char *rh_state_string(struct ohci_hcd *ohci)
  87{
  88        switch (ohci->rh_state) {
  89        case OHCI_RH_HALTED:
  90                return "halted";
  91        case OHCI_RH_SUSPENDED:
  92                return "suspended";
  93        case OHCI_RH_RUNNING:
  94                return "running";
  95        }
  96        return "?";
  97}
  98
  99// dump control and status registers
 100static void
 101ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
 102{
 103        struct ohci_regs __iomem *regs = controller->regs;
 104        u32                     temp;
 105
 106        temp = ohci_readl (controller, &regs->revision) & 0xff;
 107        ohci_dbg_sw (controller, next, size,
 108                "OHCI %d.%d, %s legacy support registers, rh state %s\n",
 109                0x03 & (temp >> 4), (temp & 0x0f),
 110                (temp & 0x0100) ? "with" : "NO",
 111                rh_state_string(controller));
 112
 113        temp = ohci_readl (controller, &regs->control);
 114        ohci_dbg_sw (controller, next, size,
 115                "control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n",
 116                temp,
 117                (temp & OHCI_CTRL_RWE) ? " RWE" : "",
 118                (temp & OHCI_CTRL_RWC) ? " RWC" : "",
 119                (temp & OHCI_CTRL_IR) ? " IR" : "",
 120                hcfs2string (temp & OHCI_CTRL_HCFS),
 121                (temp & OHCI_CTRL_BLE) ? " BLE" : "",
 122                (temp & OHCI_CTRL_CLE) ? " CLE" : "",
 123                (temp & OHCI_CTRL_IE) ? " IE" : "",
 124                (temp & OHCI_CTRL_PLE) ? " PLE" : "",
 125                temp & OHCI_CTRL_CBSR
 126                );
 127
 128        temp = ohci_readl (controller, &regs->cmdstatus);
 129        ohci_dbg_sw (controller, next, size,
 130                "cmdstatus 0x%05x SOC=%d%s%s%s%s\n", temp,
 131                (temp & OHCI_SOC) >> 16,
 132                (temp & OHCI_OCR) ? " OCR" : "",
 133                (temp & OHCI_BLF) ? " BLF" : "",
 134                (temp & OHCI_CLF) ? " CLF" : "",
 135                (temp & OHCI_HCR) ? " HCR" : ""
 136                );
 137
 138        ohci_dump_intr_mask (controller, "intrstatus",
 139                        ohci_readl (controller, &regs->intrstatus),
 140                        next, size);
 141        ohci_dump_intr_mask (controller, "intrenable",
 142                        ohci_readl (controller, &regs->intrenable),
 143                        next, size);
 144        // intrdisable always same as intrenable
 145
 146        maybe_print_eds (controller, "ed_periodcurrent",
 147                        ohci_readl (controller, &regs->ed_periodcurrent),
 148                        next, size);
 149
 150        maybe_print_eds (controller, "ed_controlhead",
 151                        ohci_readl (controller, &regs->ed_controlhead),
 152                        next, size);
 153        maybe_print_eds (controller, "ed_controlcurrent",
 154                        ohci_readl (controller, &regs->ed_controlcurrent),
 155                        next, size);
 156
 157        maybe_print_eds (controller, "ed_bulkhead",
 158                        ohci_readl (controller, &regs->ed_bulkhead),
 159                        next, size);
 160        maybe_print_eds (controller, "ed_bulkcurrent",
 161                        ohci_readl (controller, &regs->ed_bulkcurrent),
 162                        next, size);
 163
 164        maybe_print_eds (controller, "donehead",
 165                        ohci_readl (controller, &regs->donehead), next, size);
 166}
 167
 168#define dbg_port_sw(hc,num,value,next,size) \
 169        ohci_dbg_sw (hc, next, size, \
 170                "roothub.portstatus [%d] " \
 171                "0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
 172                num, temp, \
 173                (temp & RH_PS_PRSC) ? " PRSC" : "", \
 174                (temp & RH_PS_OCIC) ? " OCIC" : "", \
 175                (temp & RH_PS_PSSC) ? " PSSC" : "", \
 176                (temp & RH_PS_PESC) ? " PESC" : "", \
 177                (temp & RH_PS_CSC) ? " CSC" : "", \
 178                \
 179                (temp & RH_PS_LSDA) ? " LSDA" : "", \
 180                (temp & RH_PS_PPS) ? " PPS" : "", \
 181                (temp & RH_PS_PRS) ? " PRS" : "", \
 182                (temp & RH_PS_POCI) ? " POCI" : "", \
 183                (temp & RH_PS_PSS) ? " PSS" : "", \
 184                \
 185                (temp & RH_PS_PES) ? " PES" : "", \
 186                (temp & RH_PS_CCS) ? " CCS" : "" \
 187                );
 188
 189
 190static void
 191ohci_dump_roothub (
 192        struct ohci_hcd *controller,
 193        int verbose,
 194        char **next,
 195        unsigned *size)
 196{
 197        u32                     temp, i;
 198
 199        temp = roothub_a (controller);
 200        if (temp == ~(u32)0)
 201                return;
 202
 203        if (verbose) {
 204                ohci_dbg_sw (controller, next, size,
 205                        "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d(%d)\n", temp,
 206                        ((temp & RH_A_POTPGT) >> 24) & 0xff,
 207                        (temp & RH_A_NOCP) ? " NOCP" : "",
 208                        (temp & RH_A_OCPM) ? " OCPM" : "",
 209                        (temp & RH_A_DT) ? " DT" : "",
 210                        (temp & RH_A_NPS) ? " NPS" : "",
 211                        (temp & RH_A_PSM) ? " PSM" : "",
 212                        (temp & RH_A_NDP), controller->num_ports
 213                        );
 214                temp = roothub_b (controller);
 215                ohci_dbg_sw (controller, next, size,
 216                        "roothub.b %08x PPCM=%04x DR=%04x\n",
 217                        temp,
 218                        (temp & RH_B_PPCM) >> 16,
 219                        (temp & RH_B_DR)
 220                        );
 221                temp = roothub_status (controller);
 222                ohci_dbg_sw (controller, next, size,
 223                        "roothub.status %08x%s%s%s%s%s%s\n",
 224                        temp,
 225                        (temp & RH_HS_CRWE) ? " CRWE" : "",
 226                        (temp & RH_HS_OCIC) ? " OCIC" : "",
 227                        (temp & RH_HS_LPSC) ? " LPSC" : "",
 228                        (temp & RH_HS_DRWE) ? " DRWE" : "",
 229                        (temp & RH_HS_OCI) ? " OCI" : "",
 230                        (temp & RH_HS_LPS) ? " LPS" : ""
 231                        );
 232        }
 233
 234        for (i = 0; i < controller->num_ports; i++) {
 235                temp = roothub_portstatus (controller, i);
 236                dbg_port_sw (controller, i, temp, next, size);
 237        }
 238}
 239
 240static void ohci_dump(struct ohci_hcd *controller)
 241{
 242        ohci_dbg (controller, "OHCI controller state\n");
 243
 244        // dumps some of the state we know about
 245        ohci_dump_status (controller, NULL, NULL);
 246        if (controller->hcca)
 247                ohci_dbg (controller,
 248                        "hcca frame #%04x\n", ohci_frame_no(controller));
 249        ohci_dump_roothub (controller, 1, NULL, NULL);
 250}
 251
 252static const char data0 [] = "DATA0";
 253static const char data1 [] = "DATA1";
 254
 255static void ohci_dump_td (const struct ohci_hcd *ohci, const char *label,
 256                const struct td *td)
 257{
 258        u32     tmp = hc32_to_cpup (ohci, &td->hwINFO);
 259
 260        ohci_dbg (ohci, "%s td %p%s; urb %p index %d; hw next td %08x\n",
 261                label, td,
 262                (tmp & TD_DONE) ? " (DONE)" : "",
 263                td->urb, td->index,
 264                hc32_to_cpup (ohci, &td->hwNextTD));
 265        if ((tmp & TD_ISO) == 0) {
 266                const char      *toggle, *pid;
 267                u32     cbp, be;
 268
 269                switch (tmp & TD_T) {
 270                case TD_T_DATA0: toggle = data0; break;
 271                case TD_T_DATA1: toggle = data1; break;
 272                case TD_T_TOGGLE: toggle = "(CARRY)"; break;
 273                default: toggle = "(?)"; break;
 274                }
 275                switch (tmp & TD_DP) {
 276                case TD_DP_SETUP: pid = "SETUP"; break;
 277                case TD_DP_IN: pid = "IN"; break;
 278                case TD_DP_OUT: pid = "OUT"; break;
 279                default: pid = "(bad pid)"; break;
 280                }
 281                ohci_dbg (ohci, "     info %08x CC=%x %s DI=%d %s %s\n", tmp,
 282                        TD_CC_GET(tmp), /* EC, */ toggle,
 283                        (tmp & TD_DI) >> 21, pid,
 284                        (tmp & TD_R) ? "R" : "");
 285                cbp = hc32_to_cpup (ohci, &td->hwCBP);
 286                be = hc32_to_cpup (ohci, &td->hwBE);
 287                ohci_dbg (ohci, "     cbp %08x be %08x (len %d)\n", cbp, be,
 288                        cbp ? (be + 1 - cbp) : 0);
 289        } else {
 290                unsigned        i;
 291                ohci_dbg (ohci, "  info %08x CC=%x FC=%d DI=%d SF=%04x\n", tmp,
 292                        TD_CC_GET(tmp),
 293                        (tmp >> 24) & 0x07,
 294                        (tmp & TD_DI) >> 21,
 295                        tmp & 0x0000ffff);
 296                ohci_dbg (ohci, "  bp0 %08x be %08x\n",
 297                        hc32_to_cpup (ohci, &td->hwCBP) & ~0x0fff,
 298                        hc32_to_cpup (ohci, &td->hwBE));
 299                for (i = 0; i < MAXPSW; i++) {
 300                        u16     psw = ohci_hwPSW (ohci, td, i);
 301                        int     cc = (psw >> 12) & 0x0f;
 302                        ohci_dbg (ohci, "    psw [%d] = %2x, CC=%x %s=%d\n", i,
 303                                psw, cc,
 304                                (cc >= 0x0e) ? "OFFSET" : "SIZE",
 305                                psw & 0x0fff);
 306                }
 307        }
 308}
 309
 310/* caller MUST own hcd spinlock if verbose is set! */
 311static void __maybe_unused
 312ohci_dump_ed (const struct ohci_hcd *ohci, const char *label,
 313                const struct ed *ed, int verbose)
 314{
 315        u32     tmp = hc32_to_cpu (ohci, ed->hwINFO);
 316        char    *type = "";
 317
 318        ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x\n",
 319                label,
 320                ed, ed->state, edstring (ed->type),
 321                hc32_to_cpup (ohci, &ed->hwNextED));
 322        switch (tmp & (ED_IN|ED_OUT)) {
 323        case ED_OUT: type = "-OUT"; break;
 324        case ED_IN: type = "-IN"; break;
 325        /* else from TDs ... control */
 326        }
 327        ohci_dbg (ohci,
 328                "  info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d\n", tmp,
 329                0x03ff & (tmp >> 16),
 330                (tmp & ED_DEQUEUE) ? " DQ" : "",
 331                (tmp & ED_ISO) ? " ISO" : "",
 332                (tmp & ED_SKIP) ? " SKIP" : "",
 333                (tmp & ED_LOWSPEED) ? " LOW" : "",
 334                0x000f & (tmp >> 7),
 335                type,
 336                0x007f & tmp);
 337        tmp = hc32_to_cpup (ohci, &ed->hwHeadP);
 338        ohci_dbg (ohci, "  tds: head %08x %s%s tail %08x%s\n",
 339                tmp,
 340                (tmp & ED_C) ? data1 : data0,
 341                (tmp & ED_H) ? " HALT" : "",
 342                hc32_to_cpup (ohci, &ed->hwTailP),
 343                verbose ? "" : " (not listing)");
 344        if (verbose) {
 345                struct list_head        *tmp;
 346
 347                /* use ed->td_list because HC concurrently modifies
 348                 * hwNextTD as it accumulates ed_donelist.
 349                 */
 350                list_for_each (tmp, &ed->td_list) {
 351                        struct td               *td;
 352                        td = list_entry (tmp, struct td, td_list);
 353                        ohci_dump_td (ohci, "  ->", td);
 354                }
 355        }
 356}
 357
 358/*-------------------------------------------------------------------------*/
 359
 360static int debug_async_open(struct inode *, struct file *);
 361static int debug_periodic_open(struct inode *, struct file *);
 362static int debug_registers_open(struct inode *, struct file *);
 363static int debug_async_open(struct inode *, struct file *);
 364static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
 365static int debug_close(struct inode *, struct file *);
 366
 367static const struct file_operations debug_async_fops = {
 368        .owner          = THIS_MODULE,
 369        .open           = debug_async_open,
 370        .read           = debug_output,
 371        .release        = debug_close,
 372        .llseek         = default_llseek,
 373};
 374static const struct file_operations debug_periodic_fops = {
 375        .owner          = THIS_MODULE,
 376        .open           = debug_periodic_open,
 377        .read           = debug_output,
 378        .release        = debug_close,
 379        .llseek         = default_llseek,
 380};
 381static const struct file_operations debug_registers_fops = {
 382        .owner          = THIS_MODULE,
 383        .open           = debug_registers_open,
 384        .read           = debug_output,
 385        .release        = debug_close,
 386        .llseek         = default_llseek,
 387};
 388
 389static struct dentry *ohci_debug_root;
 390
 391struct debug_buffer {
 392        ssize_t (*fill_func)(struct debug_buffer *);    /* fill method */
 393        struct ohci_hcd *ohci;
 394        struct mutex mutex;     /* protect filling of buffer */
 395        size_t count;           /* number of characters filled into buffer */
 396        char *page;
 397};
 398
 399static ssize_t
 400show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
 401{
 402        unsigned                temp, size = count;
 403
 404        if (!ed)
 405                return 0;
 406
 407        /* print first --> last */
 408        while (ed->ed_prev)
 409                ed = ed->ed_prev;
 410
 411        /* dump a snapshot of the bulk or control schedule */
 412        while (ed) {
 413                u32             info = hc32_to_cpu (ohci, ed->hwINFO);
 414                u32             headp = hc32_to_cpu (ohci, ed->hwHeadP);
 415                struct list_head *entry;
 416                struct td       *td;
 417
 418                temp = scnprintf (buf, size,
 419                        "ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s",
 420                        ed,
 421                        (info & ED_LOWSPEED) ? 'l' : 'f',
 422                        info & 0x7f,
 423                        (info >> 7) & 0xf,
 424                        (info & ED_IN) ? "in" : "out",
 425                        0x03ff & (info >> 16),
 426                        info,
 427                        (info & ED_SKIP) ? " s" : "",
 428                        (headp & ED_H) ? " H" : "",
 429                        (headp & ED_C) ? data1 : data0);
 430                size -= temp;
 431                buf += temp;
 432
 433                list_for_each (entry, &ed->td_list) {
 434                        u32             cbp, be;
 435
 436                        td = list_entry (entry, struct td, td_list);
 437                        info = hc32_to_cpup (ohci, &td->hwINFO);
 438                        cbp = hc32_to_cpup (ohci, &td->hwCBP);
 439                        be = hc32_to_cpup (ohci, &td->hwBE);
 440                        temp = scnprintf (buf, size,
 441                                        "\n\ttd %p %s %d cc=%x urb %p (%08x)",
 442                                        td,
 443                                        ({ char *pid;
 444                                        switch (info & TD_DP) {
 445                                        case TD_DP_SETUP: pid = "setup"; break;
 446                                        case TD_DP_IN: pid = "in"; break;
 447                                        case TD_DP_OUT: pid = "out"; break;
 448                                        default: pid = "(?)"; break;
 449                                         } pid;}),
 450                                        cbp ? (be + 1 - cbp) : 0,
 451                                        TD_CC_GET (info), td->urb, info);
 452                        size -= temp;
 453                        buf += temp;
 454                }
 455
 456                temp = scnprintf (buf, size, "\n");
 457                size -= temp;
 458                buf += temp;
 459
 460                ed = ed->ed_next;
 461        }
 462        return count - size;
 463}
 464
 465static ssize_t fill_async_buffer(struct debug_buffer *buf)
 466{
 467        struct ohci_hcd         *ohci;
 468        size_t                  temp, size;
 469        unsigned long           flags;
 470
 471        ohci = buf->ohci;
 472        size = PAGE_SIZE;
 473
 474        /* display control and bulk lists together, for simplicity */
 475        spin_lock_irqsave (&ohci->lock, flags);
 476        temp = show_list(ohci, buf->page, size, ohci->ed_controltail);
 477        temp += show_list(ohci, buf->page + temp, size - temp,
 478                          ohci->ed_bulktail);
 479        spin_unlock_irqrestore (&ohci->lock, flags);
 480
 481        return temp;
 482}
 483
 484#define DBG_SCHED_LIMIT 64
 485
 486static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
 487{
 488        struct ohci_hcd         *ohci;
 489        struct ed               **seen, *ed;
 490        unsigned long           flags;
 491        unsigned                temp, size, seen_count;
 492        char                    *next;
 493        unsigned                i;
 494
 495        seen = kmalloc_array(DBG_SCHED_LIMIT, sizeof(*seen), GFP_ATOMIC);
 496        if (!seen)
 497                return 0;
 498        seen_count = 0;
 499
 500        ohci = buf->ohci;
 501        next = buf->page;
 502        size = PAGE_SIZE;
 503
 504        temp = scnprintf (next, size, "size = %d\n", NUM_INTS);
 505        size -= temp;
 506        next += temp;
 507
 508        /* dump a snapshot of the periodic schedule (and load) */
 509        spin_lock_irqsave (&ohci->lock, flags);
 510        for (i = 0; i < NUM_INTS; i++) {
 511                ed = ohci->periodic[i];
 512                if (!ed)
 513                        continue;
 514
 515                temp = scnprintf (next, size, "%2d [%3d]:", i, ohci->load [i]);
 516                size -= temp;
 517                next += temp;
 518
 519                do {
 520                        temp = scnprintf (next, size, " ed%d/%p",
 521                                ed->interval, ed);
 522                        size -= temp;
 523                        next += temp;
 524                        for (temp = 0; temp < seen_count; temp++) {
 525                                if (seen [temp] == ed)
 526                                        break;
 527                        }
 528
 529                        /* show more info the first time around */
 530                        if (temp == seen_count) {
 531                                u32     info = hc32_to_cpu (ohci, ed->hwINFO);
 532                                struct list_head        *entry;
 533                                unsigned                qlen = 0;
 534
 535                                /* qlen measured here in TDs, not urbs */
 536                                list_for_each (entry, &ed->td_list)
 537                                        qlen++;
 538
 539                                temp = scnprintf (next, size,
 540                                        " (%cs dev%d ep%d%s-%s qlen %u"
 541                                        " max %d %08x%s%s)",
 542                                        (info & ED_LOWSPEED) ? 'l' : 'f',
 543                                        info & 0x7f,
 544                                        (info >> 7) & 0xf,
 545                                        (info & ED_IN) ? "in" : "out",
 546                                        (info & ED_ISO) ? "iso" : "int",
 547                                        qlen,
 548                                        0x03ff & (info >> 16),
 549                                        info,
 550                                        (info & ED_SKIP) ? " K" : "",
 551                                        (ed->hwHeadP &
 552                                                cpu_to_hc32(ohci, ED_H)) ?
 553                                                        " H" : "");
 554                                size -= temp;
 555                                next += temp;
 556
 557                                if (seen_count < DBG_SCHED_LIMIT)
 558                                        seen [seen_count++] = ed;
 559
 560                                ed = ed->ed_next;
 561
 562                        } else {
 563                                /* we've seen it and what's after */
 564                                temp = 0;
 565                                ed = NULL;
 566                        }
 567
 568                } while (ed);
 569
 570                temp = scnprintf (next, size, "\n");
 571                size -= temp;
 572                next += temp;
 573        }
 574        spin_unlock_irqrestore (&ohci->lock, flags);
 575        kfree (seen);
 576
 577        return PAGE_SIZE - size;
 578}
 579#undef DBG_SCHED_LIMIT
 580
 581static ssize_t fill_registers_buffer(struct debug_buffer *buf)
 582{
 583        struct usb_hcd          *hcd;
 584        struct ohci_hcd         *ohci;
 585        struct ohci_regs __iomem *regs;
 586        unsigned long           flags;
 587        unsigned                temp, size;
 588        char                    *next;
 589        u32                     rdata;
 590
 591        ohci = buf->ohci;
 592        hcd = ohci_to_hcd(ohci);
 593        regs = ohci->regs;
 594        next = buf->page;
 595        size = PAGE_SIZE;
 596
 597        spin_lock_irqsave (&ohci->lock, flags);
 598
 599        /* dump driver info, then registers in spec order */
 600
 601        ohci_dbg_nosw(ohci, &next, &size,
 602                "bus %s, device %s\n"
 603                "%s\n"
 604                "%s\n",
 605                hcd->self.controller->bus->name,
 606                dev_name(hcd->self.controller),
 607                hcd->product_desc,
 608                hcd_name);
 609
 610        if (!HCD_HW_ACCESSIBLE(hcd)) {
 611                size -= scnprintf (next, size,
 612                        "SUSPENDED (no register access)\n");
 613                goto done;
 614        }
 615
 616        ohci_dump_status(ohci, &next, &size);
 617
 618        /* hcca */
 619        if (ohci->hcca)
 620                ohci_dbg_nosw(ohci, &next, &size,
 621                        "hcca frame 0x%04x\n", ohci_frame_no(ohci));
 622
 623        /* other registers mostly affect frame timings */
 624        rdata = ohci_readl (ohci, &regs->fminterval);
 625        temp = scnprintf (next, size,
 626                        "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n",
 627                        rdata, (rdata >> 31) ? "FIT " : "",
 628                        (rdata >> 16) & 0xefff, rdata & 0xffff);
 629        size -= temp;
 630        next += temp;
 631
 632        rdata = ohci_readl (ohci, &regs->fmremaining);
 633        temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
 634                        rdata, (rdata >> 31) ? "FRT " : "",
 635                        rdata & 0x3fff);
 636        size -= temp;
 637        next += temp;
 638
 639        rdata = ohci_readl (ohci, &regs->periodicstart);
 640        temp = scnprintf (next, size, "periodicstart 0x%04x\n",
 641                        rdata & 0x3fff);
 642        size -= temp;
 643        next += temp;
 644
 645        rdata = ohci_readl (ohci, &regs->lsthresh);
 646        temp = scnprintf (next, size, "lsthresh 0x%04x\n",
 647                        rdata & 0x3fff);
 648        size -= temp;
 649        next += temp;
 650
 651        temp = scnprintf (next, size, "hub poll timer %s\n",
 652                        HCD_POLL_RH(ohci_to_hcd(ohci)) ? "ON" : "off");
 653        size -= temp;
 654        next += temp;
 655
 656        /* roothub */
 657        ohci_dump_roothub (ohci, 1, &next, &size);
 658
 659done:
 660        spin_unlock_irqrestore (&ohci->lock, flags);
 661
 662        return PAGE_SIZE - size;
 663}
 664
 665static struct debug_buffer *alloc_buffer(struct ohci_hcd *ohci,
 666                                ssize_t (*fill_func)(struct debug_buffer *))
 667{
 668        struct debug_buffer *buf;
 669
 670        buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
 671
 672        if (buf) {
 673                buf->ohci = ohci;
 674                buf->fill_func = fill_func;
 675                mutex_init(&buf->mutex);
 676        }
 677
 678        return buf;
 679}
 680
 681static int fill_buffer(struct debug_buffer *buf)
 682{
 683        int ret = 0;
 684
 685        if (!buf->page)
 686                buf->page = (char *)get_zeroed_page(GFP_KERNEL);
 687
 688        if (!buf->page) {
 689                ret = -ENOMEM;
 690                goto out;
 691        }
 692
 693        ret = buf->fill_func(buf);
 694
 695        if (ret >= 0) {
 696                buf->count = ret;
 697                ret = 0;
 698        }
 699
 700out:
 701        return ret;
 702}
 703
 704static ssize_t debug_output(struct file *file, char __user *user_buf,
 705                        size_t len, loff_t *offset)
 706{
 707        struct debug_buffer *buf = file->private_data;
 708        int ret = 0;
 709
 710        mutex_lock(&buf->mutex);
 711        if (buf->count == 0) {
 712                ret = fill_buffer(buf);
 713                if (ret != 0) {
 714                        mutex_unlock(&buf->mutex);
 715                        goto out;
 716                }
 717        }
 718        mutex_unlock(&buf->mutex);
 719
 720        ret = simple_read_from_buffer(user_buf, len, offset,
 721                                      buf->page, buf->count);
 722
 723out:
 724        return ret;
 725
 726}
 727
 728static int debug_close(struct inode *inode, struct file *file)
 729{
 730        struct debug_buffer *buf = file->private_data;
 731
 732        if (buf) {
 733                if (buf->page)
 734                        free_page((unsigned long)buf->page);
 735                kfree(buf);
 736        }
 737
 738        return 0;
 739}
 740static int debug_async_open(struct inode *inode, struct file *file)
 741{
 742        file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
 743
 744        return file->private_data ? 0 : -ENOMEM;
 745}
 746
 747static int debug_periodic_open(struct inode *inode, struct file *file)
 748{
 749        file->private_data = alloc_buffer(inode->i_private,
 750                                          fill_periodic_buffer);
 751
 752        return file->private_data ? 0 : -ENOMEM;
 753}
 754
 755static int debug_registers_open(struct inode *inode, struct file *file)
 756{
 757        file->private_data = alloc_buffer(inode->i_private,
 758                                          fill_registers_buffer);
 759
 760        return file->private_data ? 0 : -ENOMEM;
 761}
 762static inline void create_debug_files (struct ohci_hcd *ohci)
 763{
 764        struct usb_bus *bus = &ohci_to_hcd(ohci)->self;
 765        struct dentry *root;
 766
 767        root = debugfs_create_dir(bus->bus_name, ohci_debug_root);
 768        ohci->debug_dir = root;
 769
 770        debugfs_create_file("async", S_IRUGO, root, ohci, &debug_async_fops);
 771        debugfs_create_file("periodic", S_IRUGO, root, ohci,
 772                            &debug_periodic_fops);
 773        debugfs_create_file("registers", S_IRUGO, root, ohci,
 774                            &debug_registers_fops);
 775
 776        ohci_dbg (ohci, "created debug files\n");
 777}
 778
 779static inline void remove_debug_files (struct ohci_hcd *ohci)
 780{
 781        debugfs_remove_recursive(ohci->debug_dir);
 782}
 783
 784/*-------------------------------------------------------------------------*/
 785
 786