📄 ohci-dbg.c
字号:
case ED_OUT: type = "-OUT"; break; case ED_IN: type = "-IN"; break; /* else from TDs ... control */ } ohci_dbg (ohci, " info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d\n", tmp, 0x03ff & (tmp >> 16), (tmp & ED_DEQUEUE) ? " DQ" : "", (tmp & ED_ISO) ? " ISO" : "", (tmp & ED_SKIP) ? " SKIP" : "", (tmp & ED_LOWSPEED) ? " LOW" : "", 0x000f & (tmp >> 7), type, 0x007f & tmp); tmp = hc32_to_cpup (ohci, &ed->hwHeadP); ohci_dbg (ohci, " tds: head %08x %s%s tail %08x%s\n", tmp, (tmp & ED_C) ? data1 : data0, (tmp & ED_H) ? " HALT" : "", hc32_to_cpup (ohci, &ed->hwTailP), verbose ? "" : " (not listing)"); if (verbose) { struct list_head *tmp; /* use ed->td_list because HC concurrently modifies * hwNextTD as it accumulates ed_donelist. */ list_for_each (tmp, &ed->td_list) { struct td *td; td = list_entry (tmp, struct td, td_list); ohci_dump_td (ohci, " ->", td); } }}#elsestatic inline void ohci_dump (struct ohci_hcd *controller, int verbose) {}#undef OHCI_VERBOSE_DEBUG#endif /* DEBUG *//*-------------------------------------------------------------------------*/#ifdef STUB_DEBUG_FILESstatic inline void create_debug_files (struct ohci_hcd *bus) { }static inline void remove_debug_files (struct ohci_hcd *bus) { }#elsestatic ssize_tshow_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed){ unsigned temp, size = count; if (!ed) return 0; /* print first --> last */ while (ed->ed_prev) ed = ed->ed_prev; /* dump a snapshot of the bulk or control schedule */ while (ed) { u32 info = hc32_to_cpu (ohci, ed->hwINFO); u32 headp = hc32_to_cpu (ohci, ed->hwHeadP); struct list_head *entry; struct td *td; temp = scnprintf (buf, size, "ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s", ed, (info & ED_LOWSPEED) ? 'l' : 'f', info & 0x7f, (info >> 7) & 0xf, (info & ED_IN) ? "in" : "out", 0x03ff & (info >> 16), info, (info & ED_SKIP) ? " s" : "", (headp & ED_H) ? " H" : "", (headp & ED_C) ? data1 : data0); size -= temp; buf += temp; list_for_each (entry, &ed->td_list) { u32 cbp, be; td = list_entry (entry, struct td, td_list); info = hc32_to_cpup (ohci, &td->hwINFO); cbp = hc32_to_cpup (ohci, &td->hwCBP); be = hc32_to_cpup (ohci, &td->hwBE); temp = scnprintf (buf, size, "\n\ttd %p %s %d cc=%x urb %p (%08x)", td, ({ char *pid; switch (info & TD_DP) { case TD_DP_SETUP: pid = "setup"; break; case TD_DP_IN: pid = "in"; break; case TD_DP_OUT: pid = "out"; break; default: pid = "(?)"; break; } pid;}), cbp ? (be + 1 - cbp) : 0, TD_CC_GET (info), td->urb, info); size -= temp; buf += temp; } temp = scnprintf (buf, size, "\n"); size -= temp; buf += temp; ed = ed->ed_next; } return count - size;}static ssize_tshow_async (struct class_device *class_dev, char *buf){ struct usb_bus *bus; struct usb_hcd *hcd; struct ohci_hcd *ohci; size_t temp; unsigned long flags; bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ohci = hcd_to_ohci(hcd); /* display control and bulk lists together, for simplicity */ spin_lock_irqsave (&ohci->lock, flags); temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail); temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail); spin_unlock_irqrestore (&ohci->lock, flags); return temp;}static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL);#define DBG_SCHED_LIMIT 64static ssize_tshow_periodic (struct class_device *class_dev, char *buf){ struct usb_bus *bus; struct usb_hcd *hcd; struct ohci_hcd *ohci; struct ed **seen, *ed; unsigned long flags; unsigned temp, size, seen_count; char *next; unsigned i; if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC))) return 0; seen_count = 0; bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ohci = hcd_to_ohci(hcd); next = buf; size = PAGE_SIZE; temp = scnprintf (next, size, "size = %d\n", NUM_INTS); size -= temp; next += temp; /* dump a snapshot of the periodic schedule (and load) */ spin_lock_irqsave (&ohci->lock, flags); for (i = 0; i < NUM_INTS; i++) { if (!(ed = ohci->periodic [i])) continue; temp = scnprintf (next, size, "%2d [%3d]:", i, ohci->load [i]); size -= temp; next += temp; do { temp = scnprintf (next, size, " ed%d/%p", ed->interval, ed); size -= temp; next += temp; for (temp = 0; temp < seen_count; temp++) { if (seen [temp] == ed) break; } /* show more info the first time around */ if (temp == seen_count) { u32 info = hc32_to_cpu (ohci, ed->hwINFO); struct list_head *entry; unsigned qlen = 0; /* qlen measured here in TDs, not urbs */ list_for_each (entry, &ed->td_list) qlen++; temp = scnprintf (next, size, " (%cs dev%d ep%d%s-%s qlen %u" " max %d %08x%s%s)", (info & ED_LOWSPEED) ? 'l' : 'f', info & 0x7f, (info >> 7) & 0xf, (info & ED_IN) ? "in" : "out", (info & ED_ISO) ? "iso" : "int", qlen, 0x03ff & (info >> 16), info, (info & ED_SKIP) ? " K" : "", (ed->hwHeadP & cpu_to_hc32(ohci, ED_H)) ? " H" : ""); size -= temp; next += temp; if (seen_count < DBG_SCHED_LIMIT) seen [seen_count++] = ed; ed = ed->ed_next; } else { /* we've seen it and what's after */ temp = 0; ed = NULL; } } while (ed); temp = scnprintf (next, size, "\n"); size -= temp; next += temp; } spin_unlock_irqrestore (&ohci->lock, flags); kfree (seen); return PAGE_SIZE - size;}static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);#undef DBG_SCHED_LIMITstatic ssize_tshow_registers (struct class_device *class_dev, char *buf){ struct usb_bus *bus; struct usb_hcd *hcd; struct ohci_hcd *ohci; struct ohci_regs __iomem *regs; unsigned long flags; unsigned temp, size; char *next; u32 rdata; bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ohci = hcd_to_ohci(hcd); regs = ohci->regs; next = buf; size = PAGE_SIZE; spin_lock_irqsave (&ohci->lock, flags); /* dump driver info, then registers in spec order */ ohci_dbg_sw (ohci, &next, &size, "bus %s, device %s\n" "%s\n" "%s version " DRIVER_VERSION "\n", hcd->self.controller->bus->name, hcd->self.controller->bus_id, hcd->product_desc, hcd_name); if (bus->controller->power.power_state.event) { size -= scnprintf (next, size, "SUSPENDED (no register access)\n"); goto done; } ohci_dump_status(ohci, &next, &size); /* hcca */ if (ohci->hcca) ohci_dbg_sw (ohci, &next, &size, "hcca frame 0x%04x\n", ohci_frame_no(ohci)); /* other registers mostly affect frame timings */ rdata = ohci_readl (ohci, ®s->fminterval); temp = scnprintf (next, size, "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n", rdata, (rdata >> 31) ? "FIT " : "", (rdata >> 16) & 0xefff, rdata & 0xffff); size -= temp; next += temp; rdata = ohci_readl (ohci, ®s->fmremaining); temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n", rdata, (rdata >> 31) ? "FRT " : "", rdata & 0x3fff); size -= temp; next += temp; rdata = ohci_readl (ohci, ®s->periodicstart); temp = scnprintf (next, size, "periodicstart 0x%04x\n", rdata & 0x3fff); size -= temp; next += temp; rdata = ohci_readl (ohci, ®s->lsthresh); temp = scnprintf (next, size, "lsthresh 0x%04x\n", rdata & 0x3fff); size -= temp; next += temp; /* roothub */ ohci_dump_roothub (ohci, 1, &next, &size);done: spin_unlock_irqrestore (&ohci->lock, flags); return PAGE_SIZE - size;}static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);static inline void create_debug_files (struct ohci_hcd *ohci){ struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; class_device_create_file(cldev, &class_device_attr_async); class_device_create_file(cldev, &class_device_attr_periodic); class_device_create_file(cldev, &class_device_attr_registers); ohci_dbg (ohci, "created debug files\n");}static inline void remove_debug_files (struct ohci_hcd *ohci){ struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; class_device_remove_file(cldev, &class_device_attr_async); class_device_remove_file(cldev, &class_device_attr_periodic); class_device_remove_file(cldev, &class_device_attr_registers);}#endif/*-------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -