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 "%s: setup(8):", __FILE__);
  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 "%s: data(%d/%d):", __FILE__,
  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        .llseek         = default_llseek,
 417};
 418static const struct file_operations debug_periodic_fops = {
 419        .owner          = THIS_MODULE,
 420        .open           = debug_periodic_open,
 421        .read           = debug_output,
 422        .release        = debug_close,
 423        .llseek         = default_llseek,
 424};
 425static const struct file_operations debug_registers_fops = {
 426        .owner          = THIS_MODULE,
 427        .open           = debug_registers_open,
 428        .read           = debug_output,
 429        .release        = debug_close,
 430        .llseek         = default_llseek,
 431};
 432
 433static struct dentry *ohci_debug_root;
 434
 435struct debug_buffer {
 436        ssize_t (*fill_func)(struct debug_buffer *);    /* fill method */
 437        struct ohci_hcd *ohci;
 438        struct mutex mutex;     /* protect filling of buffer */
 439        size_t count;           /* number of characters filled into buffer */
 440        char *page;
 441};
 442
 443static ssize_t
 444show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
 445{
 446        unsigned                temp, size = count;
 447
 448        if (!ed)
 449                return 0;
 450
 451        /* print first --> last */
 452        while (ed->ed_prev)
 453                ed = ed->ed_prev;
 454
 455        /* dump a snapshot of the bulk or control schedule */
 456        while (ed) {
 457                u32             info = hc32_to_cpu (ohci, ed->hwINFO);
 458                u32             headp = hc32_to_cpu (ohci, ed->hwHeadP);
 459                struct list_head *entry;
 460                struct td       *td;
 461
 462                temp = scnprintf (buf, size,
 463                        "ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s",
 464                        ed,
 465                        (info & ED_LOWSPEED) ? 'l' : 'f',
 466                        info & 0x7f,
 467                        (info >> 7) & 0xf,
 468                        (info & ED_IN) ? "in" : "out",
 469                        0x03ff & (info >> 16),
 470                        info,
 471                        (info & ED_SKIP) ? " s" : "",
 472                        (headp & ED_H) ? " H" : "",
 473                        (headp & ED_C) ? data1 : data0);
 474                size -= temp;
 475                buf += temp;
 476
 477                list_for_each (entry, &ed->td_list) {
 478                        u32             cbp, be;
 479
 480                        td = list_entry (entry, struct td, td_list);
 481                        info = hc32_to_cpup (ohci, &td->hwINFO);
 482                        cbp = hc32_to_cpup (ohci, &td->hwCBP);
 483                        be = hc32_to_cpup (ohci, &td->hwBE);
 484                        temp = scnprintf (buf, size,
 485                                        "\n\ttd %p %s %d cc=%x urb %p (%08x)",
 486                                        td,
 487                                        ({ char *pid;
 488                                        switch (info & TD_DP) {
 489                                        case TD_DP_SETUP: pid = "setup"; break;
 490                                        case TD_DP_IN: pid = "in"; break;
 491                                        case TD_DP_OUT: pid = "out"; break;
 492                                        default: pid = "(?)"; break;
 493                                         } pid;}),
 494                                        cbp ? (be + 1 - cbp) : 0,
 495                                        TD_CC_GET (info), td->urb, info);
 496                        size -= temp;
 497                        buf += temp;
 498                }
 499
 500                temp = scnprintf (buf, size, "\n");
 501                size -= temp;
 502                buf += temp;
 503
 504                ed = ed->ed_next;
 505        }
 506        return count - size;
 507}
 508
 509static ssize_t fill_async_buffer(struct debug_buffer *buf)
 510{
 511        struct ohci_hcd         *ohci;
 512        size_t                  temp;
 513        unsigned long           flags;
 514
 515        ohci = buf->ohci;
 516
 517        /* display control and bulk lists together, for simplicity */
 518        spin_lock_irqsave (&ohci->lock, flags);
 519        temp = show_list(ohci, buf->page, buf->count, ohci->ed_controltail);
 520        temp += show_list(ohci, buf->page + temp, buf->count - temp,
 521                          ohci->ed_bulktail);
 522        spin_unlock_irqrestore (&ohci->lock, flags);
 523
 524        return temp;
 525}
 526
 527#define DBG_SCHED_LIMIT 64
 528
 529static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
 530{
 531        struct ohci_hcd         *ohci;
 532        struct ed               **seen, *ed;
 533        unsigned long           flags;
 534        unsigned                temp, size, seen_count;
 535        char                    *next;
 536        unsigned                i;
 537
 538        if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
 539                return 0;
 540        seen_count = 0;
 541
 542        ohci = buf->ohci;
 543        next = buf->page;
 544        size = PAGE_SIZE;
 545
 546        temp = scnprintf (next, size, "size = %d\n", NUM_INTS);
 547        size -= temp;
 548        next += temp;
 549
 550        /* dump a snapshot of the periodic schedule (and load) */
 551        spin_lock_irqsave (&ohci->lock, flags);
 552        for (i = 0; i < NUM_INTS; i++) {
 553                if (!(ed = ohci->periodic [i]))
 554                        continue;
 555
 556                temp = scnprintf (next, size, "%2d [%3d]:", i, ohci->load [i]);
 557                size -= temp;
 558                next += temp;
 559
 560                do {
 561                        temp = scnprintf (next, size, " ed%d/%p",
 562                                ed->interval, ed);
 563                        size -= temp;
 564                        next += temp;
 565                        for (temp = 0; temp < seen_count; temp++) {
 566                                if (seen [temp] == ed)
 567                                        break;
 568                        }
 569
 570                        /* show more info the first time around */
 571                        if (temp == seen_count) {
 572                                u32     info = hc32_to_cpu (ohci, ed->hwINFO);
 573                                struct list_head        *entry;
 574                                unsigned                qlen = 0;
 575
 576                                /* qlen measured here in TDs, not urbs */
 577                                list_for_each (entry, &ed->td_list)
 578                                        qlen++;
 579
 580                                temp = scnprintf (next, size,
 581                                        " (%cs dev%d ep%d%s-%s qlen %u"
 582                                        " max %d %08x%s%s)",
 583                                        (info & ED_LOWSPEED) ? 'l' : 'f',
 584                                        info & 0x7f,
 585                                        (info >> 7) & 0xf,
 586                                        (info & ED_IN) ? "in" : "out",
 587                                        (info & ED_ISO) ? "iso" : "int",
 588                                        qlen,
 589                                        0x03ff & (info >> 16),
 590                                        info,
 591                                        (info & ED_SKIP) ? " K" : "",
 592                                        (ed->hwHeadP &
 593                                                cpu_to_hc32(ohci, ED_H)) ?
 594                                                        " H" : "");
 595                                size -= temp;
 596                                next += temp;
 597
 598                                if (seen_count < DBG_SCHED_LIMIT)
 599                                        seen [seen_count++] = ed;
 600
 601                                ed = ed->ed_next;
 602
 603                        } else {
 604                                /* we've seen it and what's after */
 605                                temp = 0;
 606                                ed = NULL;
 607                        }
 608
 609                } while (ed);
 610
 611                temp = scnprintf (next, size, "\n");
 612                size -= temp;
 613                next += temp;
 614        }
 615        spin_unlock_irqrestore (&ohci->lock, flags);
 616        kfree (seen);
 617
 618        return PAGE_SIZE - size;
 619}
 620#undef DBG_SCHED_LIMIT
 621
 622static ssize_t fill_registers_buffer(struct debug_buffer *buf)
 623{
 624        struct usb_hcd          *hcd;
 625        struct ohci_hcd         *ohci;
 626        struct ohci_regs __iomem *regs;
 627        unsigned long           flags;
 628        unsigned                temp, size;
 629        char                    *next;
 630        u32                     rdata;
 631
 632        ohci = buf->ohci;
 633        hcd = ohci_to_hcd(ohci);
 634        regs = ohci->regs;
 635        next = buf->page;
 636        size = PAGE_SIZE;
 637
 638        spin_lock_irqsave (&ohci->lock, flags);
 639
 640        /* dump driver info, then registers in spec order */
 641
 642        ohci_dbg_sw (ohci, &next, &size,
 643                "bus %s, device %s\n"
 644                "%s\n"
 645                "%s\n",
 646                hcd->self.controller->bus->name,
 647                dev_name(hcd->self.controller),
 648                hcd->product_desc,
 649                hcd_name);
 650
 651        if (!HCD_HW_ACCESSIBLE(hcd)) {
 652                size -= scnprintf (next, size,
 653                        "SUSPENDED (no register access)\n");
 654                goto done;
 655        }
 656
 657        ohci_dump_status(ohci, &next, &size);
 658
 659        /* hcca */
 660        if (ohci->hcca)
 661                ohci_dbg_sw (ohci, &next, &size,
 662                        "hcca frame 0x%04x\n", ohci_frame_no(ohci));
 663
 664        /* other registers mostly affect frame timings */
 665        rdata = ohci_readl (ohci, &regs->fminterval);
 666        temp = scnprintf (next, size,
 667                        "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n",
 668                        rdata, (rdata >> 31) ? "FIT " : "",
 669                        (rdata >> 16) & 0xefff, rdata & 0xffff);
 670        size -= temp;
 671        next += temp;
 672
 673        rdata = ohci_readl (ohci, &regs->fmremaining);
 674        temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
 675                        rdata, (rdata >> 31) ? "FRT " : "",
 676                        rdata & 0x3fff);
 677        size -= temp;
 678        next += temp;
 679
 680        rdata = ohci_readl (ohci, &regs->periodicstart);
 681        temp = scnprintf (next, size, "periodicstart 0x%04x\n",
 682                        rdata & 0x3fff);
 683        size -= temp;
 684        next += temp;
 685
 686        rdata = ohci_readl (ohci, &regs->lsthresh);
 687        temp = scnprintf (next, size, "lsthresh 0x%04x\n",
 688                        rdata & 0x3fff);
 689        size -= temp;
 690        next += temp;
 691
 692        temp = scnprintf (next, size, "hub poll timer %s\n",
 693                        HCD_POLL_RH(ohci_to_hcd(ohci)) ? "ON" : "off");
 694        size -= temp;
 695        next += temp;
 696
 697        /* roothub */
 698        ohci_dump_roothub (ohci, 1, &next, &size);
 699
 700done:
 701        spin_unlock_irqrestore (&ohci->lock, flags);
 702
 703        return PAGE_SIZE - size;
 704}
 705
 706static struct debug_buffer *alloc_buffer(struct ohci_hcd *ohci,
 707                                ssize_t (*fill_func)(struct debug_buffer *))
 708{
 709        struct debug_buffer *buf;
 710
 711        buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
 712
 713        if (buf) {
 714                buf->ohci = ohci;
 715                buf->fill_func = fill_func;
 716                mutex_init(&buf->mutex);
 717        }
 718
 719        return buf;
 720}
 721
 722static int fill_buffer(struct debug_buffer *buf)
 723{
 724        int ret = 0;
 725
 726        if (!buf->page)
 727                buf->page = (char *)get_zeroed_page(GFP_KERNEL);
 728
 729        if (!buf->page) {
 730                ret = -ENOMEM;
 731                goto out;
 732        }
 733
 734        ret = buf->fill_func(buf);
 735
 736        if (ret >= 0) {
 737                buf->count = ret;
 738                ret = 0;
 739        }
 740
 741out:
 742        return ret;
 743}
 744
 745static ssize_t debug_output(struct file *file, char __user *user_buf,
 746                        size_t len, loff_t *offset)
 747{
 748        struct debug_buffer *buf = file->private_data;
 749        int ret = 0;
 750
 751        mutex_lock(&buf->mutex);
 752        if (buf->count == 0) {
 753                ret = fill_buffer(buf);
 754                if (ret != 0) {
 755                        mutex_unlock(&buf->mutex);
 756                        goto out;
 757                }
 758        }
 759        mutex_unlock(&buf->mutex);
 760
 761        ret = simple_read_from_buffer(user_buf, len, offset,
 762                                      buf->page, buf->count);
 763
 764out:
 765        return ret;
 766
 767}
 768
 769static int debug_close(struct inode *inode, struct file *file)
 770{
 771        struct debug_buffer *buf = file->private_data;
 772
 773        if (buf) {
 774                if (buf->page)
 775                        free_page((unsigned long)buf->page);
 776                kfree(buf);
 777        }
 778
 779        return 0;
 780}
 781static int debug_async_open(struct inode *inode, struct file *file)
 782{
 783        file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
 784
 785        return file->private_data ? 0 : -ENOMEM;
 786}
 787
 788static int debug_periodic_open(struct inode *inode, struct file *file)
 789{
 790        file->private_data = alloc_buffer(inode->i_private,
 791                                          fill_periodic_buffer);
 792
 793        return file->private_data ? 0 : -ENOMEM;
 794}
 795
 796static int debug_registers_open(struct inode *inode, struct file *file)
 797{
 798        file->private_data = alloc_buffer(inode->i_private,
 799                                          fill_registers_buffer);
 800
 801        return file->private_data ? 0 : -ENOMEM;
 802}
 803static inline void create_debug_files (struct ohci_hcd *ohci)
 804{
 805        struct usb_bus *bus = &ohci_to_hcd(ohci)->self;
 806
 807        ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root);
 808        if (!ohci->debug_dir)
 809                goto dir_error;
 810
 811        ohci->debug_async = debugfs_create_file("async", S_IRUGO,
 812                                                ohci->debug_dir, ohci,
 813                                                &debug_async_fops);
 814        if (!ohci->debug_async)
 815                goto async_error;
 816
 817        ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
 818                                                   ohci->debug_dir, ohci,
 819                                                   &debug_periodic_fops);
 820        if (!ohci->debug_periodic)
 821                goto periodic_error;
 822
 823        ohci->debug_registers = debugfs_create_file("registers", S_IRUGO,
 824                                                    ohci->debug_dir, ohci,
 825                                                    &debug_registers_fops);
 826        if (!ohci->debug_registers)
 827                goto registers_error;
 828
 829        ohci_dbg (ohci, "created debug files\n");
 830        return;
 831
 832registers_error:
 833        debugfs_remove(ohci->debug_periodic);
 834periodic_error:
 835        debugfs_remove(ohci->debug_async);
 836async_error:
 837        debugfs_remove(ohci->debug_dir);
 838dir_error:
 839        ohci->debug_periodic = NULL;
 840        ohci->debug_async = NULL;
 841        ohci->debug_dir = NULL;
 842}
 843
 844static inline void remove_debug_files (struct ohci_hcd *ohci)
 845{
 846        debugfs_remove(ohci->debug_registers);
 847        debugfs_remove(ohci->debug_periodic);
 848        debugfs_remove(ohci->debug_async);
 849        debugfs_remove(ohci->debug_dir);
 850}
 851
 852#endif
 853
 854/*-------------------------------------------------------------------------*/
 855
 856