~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/usb/host/uhci-debug.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * UHCI-specific debugging code. Invaluable when something
 
3
 * goes wrong, but don't get in my face.
 
4
 *
 
5
 * Kernel visible pointers are surrounded in []s and bus
 
6
 * visible pointers are surrounded in ()s
 
7
 *
 
8
 * (C) Copyright 1999 Linus Torvalds
 
9
 * (C) Copyright 1999-2001 Johannes Erdfelt
 
10
 */
 
11
 
 
12
#include <linux/slab.h>
 
13
#include <linux/kernel.h>
 
14
#include <linux/debugfs.h>
 
15
#include <asm/io.h>
 
16
 
 
17
#include "uhci-hcd.h"
 
18
 
 
19
static struct dentry *uhci_debugfs_root;
 
20
 
 
21
#ifdef DEBUG
 
22
 
 
23
/* Handle REALLY large printks so we don't overflow buffers */
 
24
static void lprintk(char *buf)
 
25
{
 
26
        char *p;
 
27
 
 
28
        /* Just write one line at a time */
 
29
        while (buf) {
 
30
                p = strchr(buf, '\n');
 
31
                if (p)
 
32
                        *p = 0;
 
33
                printk(KERN_DEBUG "%s\n", buf);
 
34
                buf = p;
 
35
                if (buf)
 
36
                        buf++;
 
37
        }
 
38
}
 
39
 
 
40
static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
 
41
                        int len, int space)
 
42
{
 
43
        char *out = buf;
 
44
        char *spid;
 
45
        u32 status, token;
 
46
 
 
47
        /* Try to make sure there's enough memory */
 
48
        if (len < 160)
 
49
                return 0;
 
50
 
 
51
        status = td_status(uhci, td);
 
52
        out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td,
 
53
                hc32_to_cpu(uhci, td->link));
 
54
        out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
 
55
                ((status >> 27) & 3),
 
56
                (status & TD_CTRL_SPD) ?      "SPD " : "",
 
57
                (status & TD_CTRL_LS) ?       "LS " : "",
 
58
                (status & TD_CTRL_IOC) ?      "IOC " : "",
 
59
                (status & TD_CTRL_ACTIVE) ?   "Active " : "",
 
60
                (status & TD_CTRL_STALLED) ?  "Stalled " : "",
 
61
                (status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
 
62
                (status & TD_CTRL_BABBLE) ?   "Babble " : "",
 
63
                (status & TD_CTRL_NAK) ?      "NAK " : "",
 
64
                (status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
 
65
                (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
 
66
                status & 0x7ff);
 
67
 
 
68
        token = td_token(uhci, td);
 
69
        switch (uhci_packetid(token)) {
 
70
                case USB_PID_SETUP:
 
71
                        spid = "SETUP";
 
72
                        break;
 
73
                case USB_PID_OUT:
 
74
                        spid = "OUT";
 
75
                        break;
 
76
                case USB_PID_IN:
 
77
                        spid = "IN";
 
78
                        break;
 
79
                default:
 
80
                        spid = "?";
 
81
                        break;
 
82
        }
 
83
 
 
84
        out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
 
85
                token >> 21,
 
86
                ((token >> 19) & 1),
 
87
                (token >> 15) & 15,
 
88
                (token >> 8) & 127,
 
89
                (token & 0xff),
 
90
                spid);
 
91
        out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer));
 
92
 
 
93
        return out - buf;
 
94
}
 
95
 
 
96
static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
 
97
                        char *buf, int len, int space)
 
98
{
 
99
        char *out = buf;
 
100
        struct uhci_td *td;
 
101
        int i, nactive, ninactive;
 
102
        char *ptype;
 
103
 
 
104
        if (len < 200)
 
105
                return 0;
 
106
 
 
107
        out += sprintf(out, "urb_priv [%p] ", urbp);
 
108
        out += sprintf(out, "urb [%p] ", urbp->urb);
 
109
        out += sprintf(out, "qh [%p] ", urbp->qh);
 
110
        out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
 
111
        out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe),
 
112
                        (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
 
113
 
 
114
        switch (usb_pipetype(urbp->urb->pipe)) {
 
115
        case PIPE_ISOCHRONOUS: ptype = "ISO"; break;
 
116
        case PIPE_INTERRUPT: ptype = "INT"; break;
 
117
        case PIPE_BULK: ptype = "BLK"; break;
 
118
        default:
 
119
        case PIPE_CONTROL: ptype = "CTL"; break;
 
120
        }
 
121
 
 
122
        out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
 
123
        out += sprintf(out, " Actlen=%d%s", urbp->urb->actual_length,
 
124
                        (urbp->qh->type == USB_ENDPOINT_XFER_CONTROL ?
 
125
                                "-8" : ""));
 
126
 
 
127
        if (urbp->urb->unlinked)
 
128
                out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
 
129
        out += sprintf(out, "\n");
 
130
 
 
131
        i = nactive = ninactive = 0;
 
132
        list_for_each_entry(td, &urbp->td_list, list) {
 
133
                if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
 
134
                                (++i <= 10 || debug > 2)) {
 
135
                        out += sprintf(out, "%*s%d: ", space + 2, "", i);
 
136
                        out += uhci_show_td(uhci, td, out,
 
137
                                        len - (out - buf), 0);
 
138
                } else {
 
139
                        if (td_status(uhci, td) & TD_CTRL_ACTIVE)
 
140
                                ++nactive;
 
141
                        else
 
142
                                ++ninactive;
 
143
                }
 
144
        }
 
145
        if (nactive + ninactive > 0)
 
146
                out += sprintf(out, "%*s[skipped %d inactive and %d active "
 
147
                                "TDs]\n",
 
148
                                space, "", ninactive, nactive);
 
149
 
 
150
        return out - buf;
 
151
}
 
152
 
 
153
static int uhci_show_qh(struct uhci_hcd *uhci,
 
154
                struct uhci_qh *qh, char *buf, int len, int space)
 
155
{
 
156
        char *out = buf;
 
157
        int i, nurbs;
 
158
        __hc32 element = qh_element(qh);
 
159
        char *qtype;
 
160
 
 
161
        /* Try to make sure there's enough memory */
 
162
        if (len < 80 * 7)
 
163
                return 0;
 
164
 
 
165
        switch (qh->type) {
 
166
        case USB_ENDPOINT_XFER_ISOC: qtype = "ISO"; break;
 
167
        case USB_ENDPOINT_XFER_INT: qtype = "INT"; break;
 
168
        case USB_ENDPOINT_XFER_BULK: qtype = "BLK"; break;
 
169
        case USB_ENDPOINT_XFER_CONTROL: qtype = "CTL"; break;
 
170
        default: qtype = "Skel" ; break;
 
171
        }
 
172
 
 
173
        out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
 
174
                        space, "", qh, qtype,
 
175
                        hc32_to_cpu(uhci, qh->link),
 
176
                        hc32_to_cpu(uhci, element));
 
177
        if (qh->type == USB_ENDPOINT_XFER_ISOC)
 
178
                out += sprintf(out, "%*s    period %d phase %d load %d us, "
 
179
                                "frame %x desc [%p]\n",
 
180
                                space, "", qh->period, qh->phase, qh->load,
 
181
                                qh->iso_frame, qh->iso_packet_desc);
 
182
        else if (qh->type == USB_ENDPOINT_XFER_INT)
 
183
                out += sprintf(out, "%*s    period %d phase %d load %d us\n",
 
184
                                space, "", qh->period, qh->phase, qh->load);
 
185
 
 
186
        if (element & UHCI_PTR_QH(uhci))
 
187
                out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
 
188
 
 
189
        if (element & UHCI_PTR_DEPTH(uhci))
 
190
                out += sprintf(out, "%*s  Depth traverse\n", space, "");
 
191
 
 
192
        if (element & cpu_to_hc32(uhci, 8))
 
193
                out += sprintf(out, "%*s  Bit 3 set (bug?)\n", space, "");
 
194
 
 
195
        if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci))))
 
196
                out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
 
197
 
 
198
        if (list_empty(&qh->queue)) {
 
199
                out += sprintf(out, "%*s  queue is empty\n", space, "");
 
200
                if (qh == uhci->skel_async_qh)
 
201
                        out += uhci_show_td(uhci, uhci->term_td, out,
 
202
                                        len - (out - buf), 0);
 
203
        } else {
 
204
                struct urb_priv *urbp = list_entry(qh->queue.next,
 
205
                                struct urb_priv, node);
 
206
                struct uhci_td *td = list_entry(urbp->td_list.next,
 
207
                                struct uhci_td, list);
 
208
 
 
209
                if (element != LINK_TO_TD(uhci, td))
 
210
                        out += sprintf(out, "%*s Element != First TD\n",
 
211
                                        space, "");
 
212
                i = nurbs = 0;
 
213
                list_for_each_entry(urbp, &qh->queue, node) {
 
214
                        if (++i <= 10)
 
215
                                out += uhci_show_urbp(uhci, urbp, out,
 
216
                                                len - (out - buf), space + 2);
 
217
                        else
 
218
                                ++nurbs;
 
219
                }
 
220
                if (nurbs > 0)
 
221
                        out += sprintf(out, "%*s Skipped %d URBs\n",
 
222
                                        space, "", nurbs);
 
223
        }
 
224
 
 
225
        if (qh->dummy_td) {
 
226
                out += sprintf(out, "%*s  Dummy TD\n", space, "");
 
227
                out += uhci_show_td(uhci, qh->dummy_td, out,
 
228
                                len - (out - buf), 0);
 
229
        }
 
230
 
 
231
        return out - buf;
 
232
}
 
233
 
 
234
static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
 
235
{
 
236
        char *out = buf;
 
237
 
 
238
        /* Try to make sure there's enough memory */
 
239
        if (len < 160)
 
240
                return 0;
 
241
 
 
242
        out += sprintf(out, "  stat%d     =     %04x  %s%s%s%s%s%s%s%s%s%s\n",
 
243
                port,
 
244
                status,
 
245
                (status & USBPORTSC_SUSP) ?     " Suspend" : "",
 
246
                (status & USBPORTSC_OCC) ?      " OverCurrentChange" : "",
 
247
                (status & USBPORTSC_OC) ?       " OverCurrent" : "",
 
248
                (status & USBPORTSC_PR) ?       " Reset" : "",
 
249
                (status & USBPORTSC_LSDA) ?     " LowSpeed" : "",
 
250
                (status & USBPORTSC_RD) ?       " ResumeDetect" : "",
 
251
                (status & USBPORTSC_PEC) ?      " EnableChange" : "",
 
252
                (status & USBPORTSC_PE) ?       " Enabled" : "",
 
253
                (status & USBPORTSC_CSC) ?      " ConnectChange" : "",
 
254
                (status & USBPORTSC_CCS) ?      " Connected" : "");
 
255
 
 
256
        return out - buf;
 
257
}
 
258
 
 
259
static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len)
 
260
{
 
261
        char *out = buf;
 
262
        char *rh_state;
 
263
 
 
264
        /* Try to make sure there's enough memory */
 
265
        if (len < 60)
 
266
                return 0;
 
267
 
 
268
        switch (uhci->rh_state) {
 
269
            case UHCI_RH_RESET:
 
270
                rh_state = "reset";             break;
 
271
            case UHCI_RH_SUSPENDED:
 
272
                rh_state = "suspended";         break;
 
273
            case UHCI_RH_AUTO_STOPPED:
 
274
                rh_state = "auto-stopped";      break;
 
275
            case UHCI_RH_RESUMING:
 
276
                rh_state = "resuming";          break;
 
277
            case UHCI_RH_SUSPENDING:
 
278
                rh_state = "suspending";        break;
 
279
            case UHCI_RH_RUNNING:
 
280
                rh_state = "running";           break;
 
281
            case UHCI_RH_RUNNING_NODEVS:
 
282
                rh_state = "running, no devs";  break;
 
283
            default:
 
284
                rh_state = "?";                 break;
 
285
        }
 
286
        out += sprintf(out, "Root-hub state: %s   FSBR: %d\n",
 
287
                        rh_state, uhci->fsbr_is_on);
 
288
        return out - buf;
 
289
}
 
290
 
 
291
static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
 
292
{
 
293
        char *out = buf;
 
294
        unsigned short usbcmd, usbstat, usbint, usbfrnum;
 
295
        unsigned int flbaseadd;
 
296
        unsigned char sof;
 
297
        unsigned short portsc1, portsc2;
 
298
 
 
299
        /* Try to make sure there's enough memory */
 
300
        if (len < 80 * 9)
 
301
                return 0;
 
302
 
 
303
        usbcmd    = uhci_readw(uhci, 0);
 
304
        usbstat   = uhci_readw(uhci, 2);
 
305
        usbint    = uhci_readw(uhci, 4);
 
306
        usbfrnum  = uhci_readw(uhci, 6);
 
307
        flbaseadd = uhci_readl(uhci, 8);
 
308
        sof       = uhci_readb(uhci, 12);
 
309
        portsc1   = uhci_readw(uhci, 16);
 
310
        portsc2   = uhci_readw(uhci, 18);
 
311
 
 
312
        out += sprintf(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
 
313
                usbcmd,
 
314
                (usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
 
315
                (usbcmd & USBCMD_CF) ?      "CF " : "",
 
316
                (usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
 
317
                (usbcmd & USBCMD_FGR) ?     "FGR " : "",
 
318
                (usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
 
319
                (usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
 
320
                (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
 
321
                (usbcmd & USBCMD_RS) ?      "RS " : "");
 
322
 
 
323
        out += sprintf(out, "  usbstat   =     %04x   %s%s%s%s%s%s\n",
 
324
                usbstat,
 
325
                (usbstat & USBSTS_HCH) ?    "HCHalted " : "",
 
326
                (usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
 
327
                (usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
 
328
                (usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
 
329
                (usbstat & USBSTS_ERROR) ?  "USBError " : "",
 
330
                (usbstat & USBSTS_USBINT) ? "USBINT " : "");
 
331
 
 
332
        out += sprintf(out, "  usbint    =     %04x\n", usbint);
 
333
        out += sprintf(out, "  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
 
334
                0xfff & (4*(unsigned int)usbfrnum));
 
335
        out += sprintf(out, "  flbaseadd = %08x\n", flbaseadd);
 
336
        out += sprintf(out, "  sof       =       %02x\n", sof);
 
337
        out += uhci_show_sc(1, portsc1, out, len - (out - buf));
 
338
        out += uhci_show_sc(2, portsc2, out, len - (out - buf));
 
339
        out += sprintf(out, "Most recent frame: %x (%d)   "
 
340
                        "Last ISO frame: %x (%d)\n",
 
341
                        uhci->frame_number, uhci->frame_number & 1023,
 
342
                        uhci->last_iso_frame, uhci->last_iso_frame & 1023);
 
343
 
 
344
        return out - buf;
 
345
}
 
346
 
 
347
static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 
348
{
 
349
        char *out = buf;
 
350
        int i, j;
 
351
        struct uhci_qh *qh;
 
352
        struct uhci_td *td;
 
353
        struct list_head *tmp, *head;
 
354
        int nframes, nerrs;
 
355
        __hc32 link;
 
356
        __hc32 fsbr_link;
 
357
 
 
358
        static const char * const qh_names[] = {
 
359
                "unlink", "iso", "int128", "int64", "int32", "int16",
 
360
                "int8", "int4", "int2", "async", "term"
 
361
        };
 
362
 
 
363
        out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
 
364
        out += sprintf(out, "HC status\n");
 
365
        out += uhci_show_status(uhci, out, len - (out - buf));
 
366
 
 
367
        out += sprintf(out, "Periodic load table\n");
 
368
        for (i = 0; i < MAX_PHASE; ++i) {
 
369
                out += sprintf(out, "\t%d", uhci->load[i]);
 
370
                if (i % 8 == 7)
 
371
                        *out++ = '\n';
 
372
        }
 
373
        out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
 
374
                        uhci->total_load,
 
375
                        uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
 
376
                        uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
 
377
        if (debug <= 1)
 
378
                return out - buf;
 
379
 
 
380
        out += sprintf(out, "Frame List\n");
 
381
        nframes = 10;
 
382
        nerrs = 0;
 
383
        for (i = 0; i < UHCI_NUMFRAMES; ++i) {
 
384
                __hc32 qh_dma;
 
385
 
 
386
                j = 0;
 
387
                td = uhci->frame_cpu[i];
 
388
                link = uhci->frame[i];
 
389
                if (!td)
 
390
                        goto check_link;
 
391
 
 
392
                if (nframes > 0) {
 
393
                        out += sprintf(out, "- Frame %d -> (%08x)\n",
 
394
                                        i, hc32_to_cpu(uhci, link));
 
395
                        j = 1;
 
396
                }
 
397
 
 
398
                head = &td->fl_list;
 
399
                tmp = head;
 
400
                do {
 
401
                        td = list_entry(tmp, struct uhci_td, fl_list);
 
402
                        tmp = tmp->next;
 
403
                        if (link != LINK_TO_TD(uhci, td)) {
 
404
                                if (nframes > 0)
 
405
                                        out += sprintf(out, "    link does "
 
406
                                                "not match list entry!\n");
 
407
                                else
 
408
                                        ++nerrs;
 
409
                        }
 
410
                        if (nframes > 0)
 
411
                                out += uhci_show_td(uhci, td, out,
 
412
                                                len - (out - buf), 4);
 
413
                        link = td->link;
 
414
                } while (tmp != head);
 
415
 
 
416
check_link:
 
417
                qh_dma = uhci_frame_skel_link(uhci, i);
 
418
                if (link != qh_dma) {
 
419
                        if (nframes > 0) {
 
420
                                if (!j) {
 
421
                                        out += sprintf(out,
 
422
                                                "- Frame %d -> (%08x)\n",
 
423
                                                i, hc32_to_cpu(uhci, link));
 
424
                                        j = 1;
 
425
                                }
 
426
                                out += sprintf(out, "   link does not match "
 
427
                                        "QH (%08x)!\n",
 
428
                                        hc32_to_cpu(uhci, qh_dma));
 
429
                        } else
 
430
                                ++nerrs;
 
431
                }
 
432
                nframes -= j;
 
433
        }
 
434
        if (nerrs > 0)
 
435
                out += sprintf(out, "Skipped %d bad links\n", nerrs);
 
436
 
 
437
        out += sprintf(out, "Skeleton QHs\n");
 
438
 
 
439
        fsbr_link = 0;
 
440
        for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
 
441
                int cnt = 0;
 
442
 
 
443
                qh = uhci->skelqh[i];
 
444
                out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \
 
445
                out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4);
 
446
 
 
447
                /* Last QH is the Terminating QH, it's different */
 
448
                if (i == SKEL_TERM) {
 
449
                        if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td))
 
450
                                out += sprintf(out, "    skel_term_qh element is not set to term_td!\n");
 
451
                        link = fsbr_link;
 
452
                        if (!link)
 
453
                                link = LINK_TO_QH(uhci, uhci->skel_term_qh);
 
454
                        goto check_qh_link;
 
455
                }
 
456
 
 
457
                head = &qh->node;
 
458
                tmp = head->next;
 
459
 
 
460
                while (tmp != head) {
 
461
                        qh = list_entry(tmp, struct uhci_qh, node);
 
462
                        tmp = tmp->next;
 
463
                        if (++cnt <= 10)
 
464
                                out += uhci_show_qh(uhci, qh, out,
 
465
                                                len - (out - buf), 4);
 
466
                        if (!fsbr_link && qh->skel >= SKEL_FSBR)
 
467
                                fsbr_link = LINK_TO_QH(uhci, qh);
 
468
                }
 
469
                if ((cnt -= 10) > 0)
 
470
                        out += sprintf(out, "    Skipped %d QHs\n", cnt);
 
471
 
 
472
                link = UHCI_PTR_TERM(uhci);
 
473
                if (i <= SKEL_ISO)
 
474
                        ;
 
475
                else if (i < SKEL_ASYNC)
 
476
                        link = LINK_TO_QH(uhci, uhci->skel_async_qh);
 
477
                else if (!uhci->fsbr_is_on)
 
478
                        ;
 
479
                else
 
480
                        link = LINK_TO_QH(uhci, uhci->skel_term_qh);
 
481
check_qh_link:
 
482
                if (qh->link != link)
 
483
                        out += sprintf(out, "    last QH not linked to next skeleton!\n");
 
484
        }
 
485
 
 
486
        return out - buf;
 
487
}
 
488
 
 
489
#ifdef CONFIG_DEBUG_FS
 
490
 
 
491
#define MAX_OUTPUT      (64 * 1024)
 
492
 
 
493
struct uhci_debug {
 
494
        int size;
 
495
        char *data;
 
496
};
 
497
 
 
498
static int uhci_debug_open(struct inode *inode, struct file *file)
 
499
{
 
500
        struct uhci_hcd *uhci = inode->i_private;
 
501
        struct uhci_debug *up;
 
502
        unsigned long flags;
 
503
 
 
504
        up = kmalloc(sizeof(*up), GFP_KERNEL);
 
505
        if (!up)
 
506
                return -ENOMEM;
 
507
 
 
508
        up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
 
509
        if (!up->data) {
 
510
                kfree(up);
 
511
                return -ENOMEM;
 
512
        }
 
513
 
 
514
        up->size = 0;
 
515
        spin_lock_irqsave(&uhci->lock, flags);
 
516
        if (uhci->is_initialized)
 
517
                up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
 
518
        spin_unlock_irqrestore(&uhci->lock, flags);
 
519
 
 
520
        file->private_data = up;
 
521
 
 
522
        return 0;
 
523
}
 
524
 
 
525
static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence)
 
526
{
 
527
        struct uhci_debug *up;
 
528
        loff_t new = -1;
 
529
 
 
530
        up = file->private_data;
 
531
 
 
532
        /* XXX: atomic 64bit seek access, but that needs to be fixed in the VFS */
 
533
        switch (whence) {
 
534
        case 0:
 
535
                new = off;
 
536
                break;
 
537
        case 1:
 
538
                new = file->f_pos + off;
 
539
                break;
 
540
        }
 
541
 
 
542
        if (new < 0 || new > up->size)
 
543
                return -EINVAL;
 
544
 
 
545
        return (file->f_pos = new);
 
546
}
 
547
 
 
548
static ssize_t uhci_debug_read(struct file *file, char __user *buf,
 
549
                                size_t nbytes, loff_t *ppos)
 
550
{
 
551
        struct uhci_debug *up = file->private_data;
 
552
        return simple_read_from_buffer(buf, nbytes, ppos, up->data, up->size);
 
553
}
 
554
 
 
555
static int uhci_debug_release(struct inode *inode, struct file *file)
 
556
{
 
557
        struct uhci_debug *up = file->private_data;
 
558
 
 
559
        kfree(up->data);
 
560
        kfree(up);
 
561
 
 
562
        return 0;
 
563
}
 
564
 
 
565
static const struct file_operations uhci_debug_operations = {
 
566
        .owner =        THIS_MODULE,
 
567
        .open =         uhci_debug_open,
 
568
        .llseek =       uhci_debug_lseek,
 
569
        .read =         uhci_debug_read,
 
570
        .release =      uhci_debug_release,
 
571
};
 
572
#define UHCI_DEBUG_OPS
 
573
 
 
574
#endif  /* CONFIG_DEBUG_FS */
 
575
 
 
576
#else   /* DEBUG */
 
577
 
 
578
static inline void lprintk(char *buf)
 
579
{}
 
580
 
 
581
static inline int uhci_show_qh(struct uhci_hcd *uhci,
 
582
                struct uhci_qh *qh, char *buf, int len, int space)
 
583
{
 
584
        return 0;
 
585
}
 
586
 
 
587
static inline int uhci_sprint_schedule(struct uhci_hcd *uhci,
 
588
                char *buf, int len)
 
589
{
 
590
        return 0;
 
591
}
 
592
 
 
593
#endif