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