root/drivers/usb/host/ohci-dbg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ohci_dump_intr_mask
  2. maybe_print_eds
  3. hcfs2string
  4. rh_state_string
  5. ohci_dump_status
  6. ohci_dump_roothub
  7. ohci_dump
  8. ohci_dump_td
  9. ohci_dump_ed
  10. show_list
  11. fill_async_buffer
  12. fill_periodic_buffer
  13. fill_registers_buffer
  14. alloc_buffer
  15. fill_buffer
  16. debug_output
  17. debug_close
  18. debug_async_open
  19. debug_periodic_open
  20. debug_registers_open
  21. create_debug_files
  22. remove_debug_files

   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 
  42 static 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 
  64 static 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 
  75 static 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 
  86 static 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
 100 static void
 101 ohci_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 
 190 static void
 191 ohci_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 
 240 static 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 
 252 static const char data0 [] = "DATA0";
 253 static const char data1 [] = "DATA1";
 254 
 255 static 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! */
 311 static void __maybe_unused
 312 ohci_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 
 360 static int debug_async_open(struct inode *, struct file *);
 361 static int debug_periodic_open(struct inode *, struct file *);
 362 static int debug_registers_open(struct inode *, struct file *);
 363 static int debug_async_open(struct inode *, struct file *);
 364 static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
 365 static int debug_close(struct inode *, struct file *);
 366 
 367 static 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 };
 374 static 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 };
 381 static 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 
 389 static struct dentry *ohci_debug_root;
 390 
 391 struct 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 
 399 static ssize_t
 400 show_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 
 465 static 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 
 486 static 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 
 581 static 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 
 659 done:
 660         spin_unlock_irqrestore (&ohci->lock, flags);
 661 
 662         return PAGE_SIZE - size;
 663 }
 664 
 665 static 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 
 681 static 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 
 700 out:
 701         return ret;
 702 }
 703 
 704 static 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 
 723 out:
 724         return ret;
 725 
 726 }
 727 
 728 static 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 }
 740 static 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 
 747 static 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 
 755 static 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 }
 762 static 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 
 779 static inline void remove_debug_files (struct ohci_hcd *ohci)
 780 {
 781         debugfs_remove_recursive(ohci->debug_dir);
 782 }
 783 
 784 /*-------------------------------------------------------------------------*/
 785 

/* [<][>][^][v][top][bottom][index][help] */