summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-debug.c
diff options
context:
space:
mode:
authorNiklas Cassel <cassel@kernel.org>2026-09-18 16:06:42 +0200
committerJens Axboe <axboe@kernel.dk>2026-09-29 12:54:47 -0600
commit684b413b5483f57c890c171b9400076a0143b918 (patch)
treef167daddad3dce9af44773541373eafbccc9ac61 /drivers/usb/host/uhci-debug.c
downloadlinux-stable-684b413b5483f57c890c171b9400076a0143b918.tar.gz
linux-stable-684b413b5483f57c890c171b9400076a0143b918.zip
virtio_blk: set the zone write granularitygrafted
virtblk_read_zoned_limits() reads the write granularity that the device reports in virtio_blk_zoned_characteristics and assigns it to the physical block size and to io_min, but never to the limit that is named after it. queue_limits.zone_write_granularity is left at zero, so blk_validate_zoned_limits() raises it to the logical block size: if (lim->zone_write_granularity < lim->logical_block_size) lim->zone_write_granularity = lim->logical_block_size; A device that reports a granularity coarser than its logical block size, which is what the field exists to express, therefore has it silently reduced. A 512e host managed disk passed through to a guest reports a logical block size of 512 and a write granularity of 4096, and the guest ends up with a zone write granularity of 512. bio_split_alignment() returns lim->zone_write_granularity if it is non-zero and bio_split_io_at() may split a bio with as per bio_split_alignment(). This can real to the write getting rejected by the host drive, as the write is not aligned to the physical block size. zonefs also takes its block size from bdev_zone_write_granularity(), so it would incorrectly use 512 on a disk that requires 4096. sd_zbc_read_zones() sets the limit from the physical block size for the same reason. NVMe ZNS and null_blk leave it unset, but the fallback gives the right answer for them, as their write granularity is the logical block size. virtio carries a separate value that may exceed it. Set the zone write granularity from the value that the device reports. Fixes: 95bfec41bd3d ("virtio-blk: add support for zoned block devices") Signed-off-by: Niklas Cassel <cassel@kernel.org> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Link: https://patch.msgid.link/20260918140641.2031075-2-cassel@kernel.org Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/usb/host/uhci-debug.c')
-rw-r--r--drivers/usb/host/uhci-debug.c637
1 files changed, 637 insertions, 0 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
new file mode 100644
index 000000000..e91ec6a4f
--- /dev/null
+++ b/drivers/usb/host/uhci-debug.c
@@ -0,0 +1,637 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UHCI-specific debugging code. Invaluable when something
+ * goes wrong, but don't get in my face.
+ *
+ * Kernel visible pointers are surrounded in []s and bus
+ * visible pointers are surrounded in ()s
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2001 Johannes Erdfelt
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <asm/io.h>
+
+#include "uhci-hcd.h"
+
+#define EXTRA_SPACE 1024
+
+static struct dentry *uhci_debugfs_root;
+
+#ifdef CONFIG_DYNAMIC_DEBUG
+
+/* Handle REALLY large printks so we don't overflow buffers */
+static void lprintk(char *buf)
+{
+ char *p;
+
+ /* Just write one line at a time */
+ while (buf) {
+ p = strchr(buf, '\n');
+ if (p)
+ *p = 0;
+ printk(KERN_DEBUG "%s\n", buf);
+ buf = p;
+ if (buf)
+ buf++;
+ }
+}
+
+static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
+ int len, int space)
+{
+ char *out = buf;
+ char *spid;
+ u32 status, token;
+
+ status = td_status(uhci, td);
+ out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td,
+ hc32_to_cpu(uhci, td->link));
+ out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
+ ((status >> 27) & 3),
+ (status & TD_CTRL_SPD) ? "SPD " : "",
+ (status & TD_CTRL_LS) ? "LS " : "",
+ (status & TD_CTRL_IOC) ? "IOC " : "",
+ (status & TD_CTRL_ACTIVE) ? "Active " : "",
+ (status & TD_CTRL_STALLED) ? "Stalled " : "",
+ (status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
+ (status & TD_CTRL_BABBLE) ? "Babble " : "",
+ (status & TD_CTRL_NAK) ? "NAK " : "",
+ (status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+ (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
+ status & 0x7ff);
+ if (out - buf > len)
+ goto done;
+
+ token = td_token(uhci, td);
+ switch (uhci_packetid(token)) {
+ case USB_PID_SETUP:
+ spid = "SETUP";
+ break;
+ case USB_PID_OUT:
+ spid = "OUT";
+ break;
+ case USB_PID_IN:
+ spid = "IN";
+ break;
+ default:
+ spid = "?";
+ break;
+ }
+
+ out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
+ token >> 21,
+ ((token >> 19) & 1),
+ (token >> 15) & 15,
+ (token >> 8) & 127,
+ (token & 0xff),
+ spid);
+ out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer));
+
+done:
+ if (out - buf > len)
+ out += sprintf(out, " ...\n");
+ return out - buf;
+}
+
+static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
+ char *buf, int len, int space)
+{
+ char *out = buf;
+ struct uhci_td *td;
+ int i, nactive, ninactive;
+ char *ptype;
+
+
+ out += sprintf(out, "urb_priv [%p] ", urbp);
+ out += sprintf(out, "urb [%p] ", urbp->urb);
+ out += sprintf(out, "qh [%p] ", urbp->qh);
+ out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
+ out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe),
+ (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
+ if (out - buf > len)
+ goto done;
+
+ switch (usb_pipetype(urbp->urb->pipe)) {
+ case PIPE_ISOCHRONOUS: ptype = "ISO"; break;
+ case PIPE_INTERRUPT: ptype = "INT"; break;
+ case PIPE_BULK: ptype = "BLK"; break;
+ default:
+ case PIPE_CONTROL: ptype = "CTL"; break;
+ }
+
+ out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
+ out += sprintf(out, " Actlen=%d%s", urbp->urb->actual_length,
+ (urbp->qh->type == USB_ENDPOINT_XFER_CONTROL ?
+ "-8" : ""));
+
+ if (urbp->urb->unlinked)
+ out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
+ out += sprintf(out, "\n");
+
+ if (out - buf > len)
+ goto done;
+
+ i = nactive = ninactive = 0;
+ list_for_each_entry(td, &urbp->td_list, list) {
+ if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
+ (++i <= 10 || debug > 2)) {
+ out += sprintf(out, "%*s%d: ", space + 2, "", i);
+ out += uhci_show_td(uhci, td, out,
+ len - (out - buf), 0);
+ if (out - buf > len)
+ goto tail;
+ } else {
+ if (td_status(uhci, td) & TD_CTRL_ACTIVE)
+ ++nactive;
+ else
+ ++ninactive;
+ }
+ }
+ if (nactive + ninactive > 0)
+ out += sprintf(out,
+ "%*s[skipped %d inactive and %d active TDs]\n",
+ space, "", ninactive, nactive);
+done:
+ if (out - buf > len)
+ out += sprintf(out, " ...\n");
+tail:
+ return out - buf;
+}
+
+static int uhci_show_qh(struct uhci_hcd *uhci,
+ struct uhci_qh *qh, char *buf, int len, int space)
+{
+ char *out = buf;
+ int i, nurbs;
+ __hc32 element = qh_element(qh);
+ char *qtype;
+
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_ISOC: qtype = "ISO"; break;
+ case USB_ENDPOINT_XFER_INT: qtype = "INT"; break;
+ case USB_ENDPOINT_XFER_BULK: qtype = "BLK"; break;
+ case USB_ENDPOINT_XFER_CONTROL: qtype = "CTL"; break;
+ default: qtype = "Skel" ; break;
+ }
+
+ out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
+ space, "", qh, qtype,
+ hc32_to_cpu(uhci, qh->link),
+ hc32_to_cpu(uhci, element));
+ if (qh->type == USB_ENDPOINT_XFER_ISOC)
+ out += sprintf(out,
+ "%*s period %d phase %d load %d us, frame %x desc [%p]\n",
+ space, "", qh->period, qh->phase, qh->load,
+ qh->iso_frame, qh->iso_packet_desc);
+ else if (qh->type == USB_ENDPOINT_XFER_INT)
+ out += sprintf(out, "%*s period %d phase %d load %d us\n",
+ space, "", qh->period, qh->phase, qh->load);
+ if (out - buf > len)
+ goto done;
+
+ if (element & UHCI_PTR_QH(uhci))
+ out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
+
+ if (element & UHCI_PTR_DEPTH(uhci))
+ out += sprintf(out, "%*s Depth traverse\n", space, "");
+
+ if (element & cpu_to_hc32(uhci, 8))
+ out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, "");
+
+ if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci))))
+ out += sprintf(out, "%*s Element is NULL (bug?)\n", space, "");
+
+ if (out - buf > len)
+ goto done;
+
+ if (list_empty(&qh->queue)) {
+ out += sprintf(out, "%*s queue is empty\n", space, "");
+ if (qh == uhci->skel_async_qh) {
+ out += uhci_show_td(uhci, uhci->term_td, out,
+ len - (out - buf), 0);
+ if (out - buf > len)
+ goto tail;
+ }
+ } else {
+ struct urb_priv *urbp = list_entry(qh->queue.next,
+ struct urb_priv, node);
+ struct uhci_td *td = list_entry(urbp->td_list.next,
+ struct uhci_td, list);
+
+ if (element != LINK_TO_TD(uhci, td))
+ out += sprintf(out, "%*s Element != First TD\n",
+ space, "");
+ i = nurbs = 0;
+ list_for_each_entry(urbp, &qh->queue, node) {
+ if (++i <= 10) {
+ out += uhci_show_urbp(uhci, urbp, out,
+ len - (out - buf), space + 2);
+ if (out - buf > len)
+ goto tail;
+ }
+ else
+ ++nurbs;
+ }
+ if (nurbs > 0)
+ out += sprintf(out, "%*s Skipped %d URBs\n",
+ space, "", nurbs);
+ }
+
+ if (out - buf > len)
+ goto done;
+
+ if (qh->dummy_td) {
+ out += sprintf(out, "%*s Dummy TD\n", space, "");
+ out += uhci_show_td(uhci, qh->dummy_td, out,
+ len - (out - buf), 0);
+ if (out - buf > len)
+ goto tail;
+ }
+
+done:
+ if (out - buf > len)
+ out += sprintf(out, " ...\n");
+tail:
+ return out - buf;
+}
+
+static int uhci_show_sc(int port, unsigned short status, char *buf)
+{
+ return sprintf(buf, " stat%d = %04x %s%s%s%s%s%s%s%s%s%s\n",
+ port,
+ status,
+ (status & USBPORTSC_SUSP) ? " Suspend" : "",
+ (status & USBPORTSC_OCC) ? " OverCurrentChange" : "",
+ (status & USBPORTSC_OC) ? " OverCurrent" : "",
+ (status & USBPORTSC_PR) ? " Reset" : "",
+ (status & USBPORTSC_LSDA) ? " LowSpeed" : "",
+ (status & USBPORTSC_RD) ? " ResumeDetect" : "",
+ (status & USBPORTSC_PEC) ? " EnableChange" : "",
+ (status & USBPORTSC_PE) ? " Enabled" : "",
+ (status & USBPORTSC_CSC) ? " ConnectChange" : "",
+ (status & USBPORTSC_CCS) ? " Connected" : "");
+}
+
+static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf)
+{
+ char *rh_state;
+
+ switch (uhci->rh_state) {
+ case UHCI_RH_RESET:
+ rh_state = "reset"; break;
+ case UHCI_RH_SUSPENDED:
+ rh_state = "suspended"; break;
+ case UHCI_RH_AUTO_STOPPED:
+ rh_state = "auto-stopped"; break;
+ case UHCI_RH_RESUMING:
+ rh_state = "resuming"; break;
+ case UHCI_RH_SUSPENDING:
+ rh_state = "suspending"; break;
+ case UHCI_RH_RUNNING:
+ rh_state = "running"; break;
+ case UHCI_RH_RUNNING_NODEVS:
+ rh_state = "running, no devs"; break;
+ default:
+ rh_state = "?"; break;
+ }
+ return sprintf(buf, "Root-hub state: %s FSBR: %d\n",
+ rh_state, uhci->fsbr_is_on);
+}
+
+static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
+{
+ char *out = buf;
+ unsigned short usbcmd, usbstat, usbint, usbfrnum;
+ unsigned int flbaseadd;
+ unsigned char sof;
+ unsigned short portsc1, portsc2;
+
+
+ usbcmd = uhci_readw(uhci, USBCMD);
+ usbstat = uhci_readw(uhci, USBSTS);
+ usbint = uhci_readw(uhci, USBINTR);
+ usbfrnum = uhci_readw(uhci, USBFRNUM);
+ flbaseadd = uhci_readl(uhci, USBFLBASEADD);
+ sof = uhci_readb(uhci, USBSOF);
+ portsc1 = uhci_readw(uhci, USBPORTSC1);
+ portsc2 = uhci_readw(uhci, USBPORTSC2);
+
+ out += sprintf(out, " usbcmd = %04x %s%s%s%s%s%s%s%s\n",
+ usbcmd,
+ (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
+ (usbcmd & USBCMD_CF) ? "CF " : "",
+ (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
+ (usbcmd & USBCMD_FGR) ? "FGR " : "",
+ (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
+ (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
+ (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+ (usbcmd & USBCMD_RS) ? "RS " : "");
+ if (out - buf > len)
+ goto done;
+
+ out += sprintf(out, " usbstat = %04x %s%s%s%s%s%s\n",
+ usbstat,
+ (usbstat & USBSTS_HCH) ? "HCHalted " : "",
+ (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
+ (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
+ (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
+ (usbstat & USBSTS_ERROR) ? "USBError " : "",
+ (usbstat & USBSTS_USBINT) ? "USBINT " : "");
+ if (out - buf > len)
+ goto done;
+
+ out += sprintf(out, " usbint = %04x\n", usbint);
+ out += sprintf(out, " usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1,
+ 0xfff & (4*(unsigned int)usbfrnum));
+ out += sprintf(out, " flbaseadd = %08x\n", flbaseadd);
+ out += sprintf(out, " sof = %02x\n", sof);
+ if (out - buf > len)
+ goto done;
+
+ out += uhci_show_sc(1, portsc1, out);
+ if (out - buf > len)
+ goto done;
+
+ out += uhci_show_sc(2, portsc2, out);
+ if (out - buf > len)
+ goto done;
+
+ out += sprintf(out,
+ "Most recent frame: %x (%d) Last ISO frame: %x (%d)\n",
+ uhci->frame_number, uhci->frame_number & 1023,
+ uhci->last_iso_frame, uhci->last_iso_frame & 1023);
+
+done:
+ if (out - buf > len)
+ out += sprintf(out, " ...\n");
+ return out - buf;
+}
+
+static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
+{
+ char *out = buf;
+ int i, j;
+ struct uhci_qh *qh;
+ struct uhci_td *td;
+ struct list_head *tmp, *head;
+ int nframes, nerrs;
+ __hc32 link;
+ __hc32 fsbr_link;
+
+ static const char * const qh_names[] = {
+ "unlink", "iso", "int128", "int64", "int32", "int16",
+ "int8", "int4", "int2", "async", "term"
+ };
+
+ out += uhci_show_root_hub_state(uhci, out);
+ if (out - buf > len)
+ goto done;
+ out += sprintf(out, "HC status\n");
+ out += uhci_show_status(uhci, out, len - (out - buf));
+ if (out - buf > len)
+ goto tail;
+
+ out += sprintf(out, "Periodic load table\n");
+ for (i = 0; i < MAX_PHASE; ++i) {
+ out += sprintf(out, "\t%d", uhci->load[i]);
+ if (i % 8 == 7)
+ *out++ = '\n';
+ }
+ out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
+ uhci->total_load,
+ uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
+ uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
+ if (debug <= 1)
+ goto tail;
+
+ out += sprintf(out, "Frame List\n");
+ nframes = 10;
+ nerrs = 0;
+ for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+ __hc32 qh_dma;
+
+ if (out - buf > len)
+ goto done;
+ j = 0;
+ td = uhci->frame_cpu[i];
+ link = uhci->frame[i];
+ if (!td)
+ goto check_link;
+
+ if (nframes > 0) {
+ out += sprintf(out, "- Frame %d -> (%08x)\n",
+ i, hc32_to_cpu(uhci, link));
+ j = 1;
+ }
+
+ head = &td->fl_list;
+ tmp = head;
+ do {
+ td = list_entry(tmp, struct uhci_td, fl_list);
+ tmp = tmp->next;
+ if (link != LINK_TO_TD(uhci, td)) {
+ if (nframes > 0) {
+ out += sprintf(out,
+ " link does not match list entry!\n");
+ if (out - buf > len)
+ goto done;
+ } else
+ ++nerrs;
+ }
+ if (nframes > 0) {
+ out += uhci_show_td(uhci, td, out,
+ len - (out - buf), 4);
+ if (out - buf > len)
+ goto tail;
+ }
+ link = td->link;
+ } while (tmp != head);
+
+check_link:
+ qh_dma = uhci_frame_skel_link(uhci, i);
+ if (link != qh_dma) {
+ if (nframes > 0) {
+ if (!j) {
+ out += sprintf(out,
+ "- Frame %d -> (%08x)\n",
+ i, hc32_to_cpu(uhci, link));
+ j = 1;
+ }
+ out += sprintf(out,
+ " link does not match QH (%08x)!\n",
+ hc32_to_cpu(uhci, qh_dma));
+ if (out - buf > len)
+ goto done;
+ } else
+ ++nerrs;
+ }
+ nframes -= j;
+ }
+ if (nerrs > 0)
+ out += sprintf(out, "Skipped %d bad links\n", nerrs);
+
+ out += sprintf(out, "Skeleton QHs\n");
+
+ if (out - buf > len)
+ goto done;
+
+ fsbr_link = 0;
+ for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
+ int cnt = 0;
+
+ qh = uhci->skelqh[i];
+ out += sprintf(out, "- skel_%s_qh\n", qh_names[i]);
+ out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4);
+ if (out - buf > len)
+ goto tail;
+
+ /* Last QH is the Terminating QH, it's different */
+ if (i == SKEL_TERM) {
+ if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td)) {
+ out += sprintf(out,
+ " skel_term_qh element is not set to term_td!\n");
+ if (out - buf > len)
+ goto done;
+ }
+ link = fsbr_link;
+ if (!link)
+ link = LINK_TO_QH(uhci, uhci->skel_term_qh);
+ goto check_qh_link;
+ }
+
+ head = &qh->node;
+ tmp = head->next;
+
+ while (tmp != head) {
+ qh = list_entry(tmp, struct uhci_qh, node);
+ tmp = tmp->next;
+ if (++cnt <= 10) {
+ out += uhci_show_qh(uhci, qh, out,
+ len - (out - buf), 4);
+ if (out - buf > len)
+ goto tail;
+ }
+ if (!fsbr_link && qh->skel >= SKEL_FSBR)
+ fsbr_link = LINK_TO_QH(uhci, qh);
+ }
+ if ((cnt -= 10) > 0)
+ out += sprintf(out, " Skipped %d QHs\n", cnt);
+
+ link = UHCI_PTR_TERM(uhci);
+ if (i <= SKEL_ISO)
+ ;
+ else if (i < SKEL_ASYNC)
+ link = LINK_TO_QH(uhci, uhci->skel_async_qh);
+ else if (!uhci->fsbr_is_on)
+ ;
+ else
+ link = LINK_TO_QH(uhci, uhci->skel_term_qh);
+check_qh_link:
+ if (qh->link != link)
+ out += sprintf(out,
+ " last QH not linked to next skeleton!\n");
+
+ if (out - buf > len)
+ goto done;
+ }
+
+done:
+ if (out - buf > len)
+ out += sprintf(out, " ...\n");
+tail:
+ return out - buf;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#define MAX_OUTPUT (64 * 1024)
+
+struct uhci_debug {
+ int size;
+ char *data;
+};
+
+static int uhci_debug_open(struct inode *inode, struct file *file)
+{
+ struct uhci_hcd *uhci = inode->i_private;
+ struct uhci_debug *up;
+ unsigned long flags;
+
+ up = kmalloc_obj(*up);
+ if (!up)
+ return -ENOMEM;
+
+ up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
+ if (!up->data) {
+ kfree(up);
+ return -ENOMEM;
+ }
+
+ up->size = 0;
+ spin_lock_irqsave(&uhci->lock, flags);
+ if (uhci->is_initialized)
+ up->size = uhci_sprint_schedule(uhci, up->data,
+ MAX_OUTPUT - EXTRA_SPACE);
+ spin_unlock_irqrestore(&uhci->lock, flags);
+
+ file->private_data = up;
+
+ return 0;
+}
+
+static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence)
+{
+ struct uhci_debug *up = file->private_data;
+ return no_seek_end_llseek_size(file, off, whence, up->size);
+}
+
+static ssize_t uhci_debug_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct uhci_debug *up = file->private_data;
+ return simple_read_from_buffer(buf, nbytes, ppos, up->data, up->size);
+}
+
+static int uhci_debug_release(struct inode *inode, struct file *file)
+{
+ struct uhci_debug *up = file->private_data;
+
+ kfree(up->data);
+ kfree(up);
+
+ return 0;
+}
+
+static const struct file_operations uhci_debug_operations = {
+ .owner = THIS_MODULE,
+ .open = uhci_debug_open,
+ .llseek = uhci_debug_lseek,
+ .read = uhci_debug_read,
+ .release = uhci_debug_release,
+};
+#define UHCI_DEBUG_OPS
+
+#endif /* CONFIG_DEBUG_FS */
+
+#else /* CONFIG_DYNAMIC_DEBUG*/
+
+static inline void lprintk(char *buf)
+{}
+
+static inline int uhci_show_qh(struct uhci_hcd *uhci,
+ struct uhci_qh *qh, char *buf, int len, int space)
+{
+ return 0;
+}
+
+static inline int uhci_sprint_schedule(struct uhci_hcd *uhci,
+ char *buf, int len)
+{
+ return 0;
+}
+
+#endif