aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-debug.c
diff options
context:
space:
mode:
authorChen Gang <gang.chen@asianux.com>2013-01-23 03:13:41 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-24 16:42:09 -0500
commit13996ca7afd5b5d7980ea013b00e3ef7cf2cefd0 (patch)
tree5819c68b358a7c9fe44eee44b5e884e1bfe335ea /drivers/usb/host/uhci-debug.c
parentd2123fd9e1a56b8006986ed37e0aaf93ef0dd978 (diff)
USB: uhci: check buffer length to avoid memory overflow
for function uhci_sprint_schedule: the buffer len is MAX_OUTPUT: 64 * 1024, which may not be enough: may loop UHCI_NUMFRAMES times (UHCI_NUMFRAMES is 1024) each time of loop may get more than 64 bytes so need check the buffer length to avoid memory overflow this patch fix it like this: at first, make enough room for buffering the exceeding contents judge the contents which written whether bigger than buffer length if bigger (the exceeding contents will be in the exceeding buffer) break current work flow, and return. Signed-off-by: Chen Gang <gang.chen@asianux.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/uhci-debug.c')
-rw-r--r--drivers/usb/host/uhci-debug.c150
1 files changed, 104 insertions, 46 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index fc0b0daac93d..8a55bb25315b 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -16,6 +16,8 @@
16 16
17#include "uhci-hcd.h" 17#include "uhci-hcd.h"
18 18
19#define EXTRA_SPACE 1024
20
19static struct dentry *uhci_debugfs_root; 21static struct dentry *uhci_debugfs_root;
20 22
21#ifdef DEBUG 23#ifdef DEBUG
@@ -44,10 +46,6 @@ static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
44 char *spid; 46 char *spid;
45 u32 status, token; 47 u32 status, token;
46 48
47 /* Try to make sure there's enough memory */
48 if (len < 160)
49 return 0;
50
51 status = td_status(uhci, td); 49 status = td_status(uhci, td);
52 out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, 50 out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td,
53 hc32_to_cpu(uhci, td->link)); 51 hc32_to_cpu(uhci, td->link));
@@ -64,6 +62,8 @@ static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
64 (status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "", 62 (status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
65 (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "", 63 (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
66 status & 0x7ff); 64 status & 0x7ff);
65 if (out - buf > len)
66 goto done;
67 67
68 token = td_token(uhci, td); 68 token = td_token(uhci, td);
69 switch (uhci_packetid(token)) { 69 switch (uhci_packetid(token)) {
@@ -90,6 +90,9 @@ static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
90 spid); 90 spid);
91 out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer)); 91 out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer));
92 92
93done:
94 if (out - buf > len)
95 out += sprintf(out, " ...\n");
93 return out - buf; 96 return out - buf;
94} 97}
95 98
@@ -101,8 +104,6 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
101 int i, nactive, ninactive; 104 int i, nactive, ninactive;
102 char *ptype; 105 char *ptype;
103 106
104 if (len < 200)
105 return 0;
106 107
107 out += sprintf(out, "urb_priv [%p] ", urbp); 108 out += sprintf(out, "urb_priv [%p] ", urbp);
108 out += sprintf(out, "urb [%p] ", urbp->urb); 109 out += sprintf(out, "urb [%p] ", urbp->urb);
@@ -110,6 +111,8 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
110 out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe)); 111 out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
111 out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), 112 out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe),
112 (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT")); 113 (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
114 if (out - buf > len)
115 goto done;
113 116
114 switch (usb_pipetype(urbp->urb->pipe)) { 117 switch (usb_pipetype(urbp->urb->pipe)) {
115 case PIPE_ISOCHRONOUS: ptype = "ISO"; break; 118 case PIPE_ISOCHRONOUS: ptype = "ISO"; break;
@@ -128,6 +131,9 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
128 out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked); 131 out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
129 out += sprintf(out, "\n"); 132 out += sprintf(out, "\n");
130 133
134 if (out - buf > len)
135 goto done;
136
131 i = nactive = ninactive = 0; 137 i = nactive = ninactive = 0;
132 list_for_each_entry(td, &urbp->td_list, list) { 138 list_for_each_entry(td, &urbp->td_list, list) {
133 if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC && 139 if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
@@ -135,6 +141,8 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
135 out += sprintf(out, "%*s%d: ", space + 2, "", i); 141 out += sprintf(out, "%*s%d: ", space + 2, "", i);
136 out += uhci_show_td(uhci, td, out, 142 out += uhci_show_td(uhci, td, out,
137 len - (out - buf), 0); 143 len - (out - buf), 0);
144 if (out - buf > len)
145 goto tail;
138 } else { 146 } else {
139 if (td_status(uhci, td) & TD_CTRL_ACTIVE) 147 if (td_status(uhci, td) & TD_CTRL_ACTIVE)
140 ++nactive; 148 ++nactive;
@@ -146,7 +154,10 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
146 out += sprintf(out, "%*s[skipped %d inactive and %d active " 154 out += sprintf(out, "%*s[skipped %d inactive and %d active "
147 "TDs]\n", 155 "TDs]\n",
148 space, "", ninactive, nactive); 156 space, "", ninactive, nactive);
149 157done:
158 if (out - buf > len)
159 out += sprintf(out, " ...\n");
160tail:
150 return out - buf; 161 return out - buf;
151} 162}
152 163
@@ -158,10 +169,6 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
158 __hc32 element = qh_element(qh); 169 __hc32 element = qh_element(qh);
159 char *qtype; 170 char *qtype;
160 171
161 /* Try to make sure there's enough memory */
162 if (len < 80 * 7)
163 return 0;
164
165 switch (qh->type) { 172 switch (qh->type) {
166 case USB_ENDPOINT_XFER_ISOC: qtype = "ISO"; break; 173 case USB_ENDPOINT_XFER_ISOC: qtype = "ISO"; break;
167 case USB_ENDPOINT_XFER_INT: qtype = "INT"; break; 174 case USB_ENDPOINT_XFER_INT: qtype = "INT"; break;
@@ -182,6 +189,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
182 else if (qh->type == USB_ENDPOINT_XFER_INT) 189 else if (qh->type == USB_ENDPOINT_XFER_INT)
183 out += sprintf(out, "%*s period %d phase %d load %d us\n", 190 out += sprintf(out, "%*s period %d phase %d load %d us\n",
184 space, "", qh->period, qh->phase, qh->load); 191 space, "", qh->period, qh->phase, qh->load);
192 if (out - buf > len)
193 goto done;
185 194
186 if (element & UHCI_PTR_QH(uhci)) 195 if (element & UHCI_PTR_QH(uhci))
187 out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); 196 out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
@@ -195,11 +204,17 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
195 if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci)))) 204 if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci))))
196 out += sprintf(out, "%*s Element is NULL (bug?)\n", space, ""); 205 out += sprintf(out, "%*s Element is NULL (bug?)\n", space, "");
197 206
207 if (out - buf > len)
208 goto done;
209
198 if (list_empty(&qh->queue)) { 210 if (list_empty(&qh->queue)) {
199 out += sprintf(out, "%*s queue is empty\n", space, ""); 211 out += sprintf(out, "%*s queue is empty\n", space, "");
200 if (qh == uhci->skel_async_qh) 212 if (qh == uhci->skel_async_qh) {
201 out += uhci_show_td(uhci, uhci->term_td, out, 213 out += uhci_show_td(uhci, uhci->term_td, out,
202 len - (out - buf), 0); 214 len - (out - buf), 0);
215 if (out - buf > len)
216 goto tail;
217 }
203 } else { 218 } else {
204 struct urb_priv *urbp = list_entry(qh->queue.next, 219 struct urb_priv *urbp = list_entry(qh->queue.next,
205 struct urb_priv, node); 220 struct urb_priv, node);
@@ -211,9 +226,12 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
211 space, ""); 226 space, "");
212 i = nurbs = 0; 227 i = nurbs = 0;
213 list_for_each_entry(urbp, &qh->queue, node) { 228 list_for_each_entry(urbp, &qh->queue, node) {
214 if (++i <= 10) 229 if (++i <= 10) {
215 out += uhci_show_urbp(uhci, urbp, out, 230 out += uhci_show_urbp(uhci, urbp, out,
216 len - (out - buf), space + 2); 231 len - (out - buf), space + 2);
232 if (out - buf > len)
233 goto tail;
234 }
217 else 235 else
218 ++nurbs; 236 ++nurbs;
219 } 237 }
@@ -222,24 +240,27 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
222 space, "", nurbs); 240 space, "", nurbs);
223 } 241 }
224 242
243 if (out - buf > len)
244 goto done;
245
225 if (qh->dummy_td) { 246 if (qh->dummy_td) {
226 out += sprintf(out, "%*s Dummy TD\n", space, ""); 247 out += sprintf(out, "%*s Dummy TD\n", space, "");
227 out += uhci_show_td(uhci, qh->dummy_td, out, 248 out += uhci_show_td(uhci, qh->dummy_td, out,
228 len - (out - buf), 0); 249 len - (out - buf), 0);
250 if (out - buf > len)
251 goto tail;
229 } 252 }
230 253
254done:
255 if (out - buf > len)
256 out += sprintf(out, " ...\n");
257tail:
231 return out - buf; 258 return out - buf;
232} 259}
233 260
234static int uhci_show_sc(int port, unsigned short status, char *buf, int len) 261static int uhci_show_sc(int port, unsigned short status, char *buf)
235{ 262{
236 char *out = buf; 263 return sprintf(buf, " stat%d = %04x %s%s%s%s%s%s%s%s%s%s\n",
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, 264 port,
244 status, 265 status,
245 (status & USBPORTSC_SUSP) ? " Suspend" : "", 266 (status & USBPORTSC_SUSP) ? " Suspend" : "",
@@ -252,19 +273,12 @@ static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
252 (status & USBPORTSC_PE) ? " Enabled" : "", 273 (status & USBPORTSC_PE) ? " Enabled" : "",
253 (status & USBPORTSC_CSC) ? " ConnectChange" : "", 274 (status & USBPORTSC_CSC) ? " ConnectChange" : "",
254 (status & USBPORTSC_CCS) ? " Connected" : ""); 275 (status & USBPORTSC_CCS) ? " Connected" : "");
255
256 return out - buf;
257} 276}
258 277
259static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len) 278static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf)
260{ 279{
261 char *out = buf;
262 char *rh_state; 280 char *rh_state;
263 281
264 /* Try to make sure there's enough memory */
265 if (len < 60)
266 return 0;
267
268 switch (uhci->rh_state) { 282 switch (uhci->rh_state) {
269 case UHCI_RH_RESET: 283 case UHCI_RH_RESET:
270 rh_state = "reset"; break; 284 rh_state = "reset"; break;
@@ -283,9 +297,8 @@ static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len)
283 default: 297 default:
284 rh_state = "?"; break; 298 rh_state = "?"; break;
285 } 299 }
286 out += sprintf(out, "Root-hub state: %s FSBR: %d\n", 300 return sprintf(buf, "Root-hub state: %s FSBR: %d\n",
287 rh_state, uhci->fsbr_is_on); 301 rh_state, uhci->fsbr_is_on);
288 return out - buf;
289} 302}
290 303
291static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) 304static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
@@ -296,9 +309,6 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
296 unsigned char sof; 309 unsigned char sof;
297 unsigned short portsc1, portsc2; 310 unsigned short portsc1, portsc2;
298 311
299 /* Try to make sure there's enough memory */
300 if (len < 80 * 9)
301 return 0;
302 312
303 usbcmd = uhci_readw(uhci, 0); 313 usbcmd = uhci_readw(uhci, 0);
304 usbstat = uhci_readw(uhci, 2); 314 usbstat = uhci_readw(uhci, 2);
@@ -319,6 +329,8 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
319 (usbcmd & USBCMD_GRESET) ? "GRESET " : "", 329 (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
320 (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "", 330 (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
321 (usbcmd & USBCMD_RS) ? "RS " : ""); 331 (usbcmd & USBCMD_RS) ? "RS " : "");
332 if (out - buf > len)
333 goto done;
322 334
323 out += sprintf(out, " usbstat = %04x %s%s%s%s%s%s\n", 335 out += sprintf(out, " usbstat = %04x %s%s%s%s%s%s\n",
324 usbstat, 336 usbstat,
@@ -328,19 +340,33 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
328 (usbstat & USBSTS_RD) ? "ResumeDetect " : "", 340 (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
329 (usbstat & USBSTS_ERROR) ? "USBError " : "", 341 (usbstat & USBSTS_ERROR) ? "USBError " : "",
330 (usbstat & USBSTS_USBINT) ? "USBINT " : ""); 342 (usbstat & USBSTS_USBINT) ? "USBINT " : "");
343 if (out - buf > len)
344 goto done;
331 345
332 out += sprintf(out, " usbint = %04x\n", usbint); 346 out += sprintf(out, " usbint = %04x\n", usbint);
333 out += sprintf(out, " usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, 347 out += sprintf(out, " usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1,
334 0xfff & (4*(unsigned int)usbfrnum)); 348 0xfff & (4*(unsigned int)usbfrnum));
335 out += sprintf(out, " flbaseadd = %08x\n", flbaseadd); 349 out += sprintf(out, " flbaseadd = %08x\n", flbaseadd);
336 out += sprintf(out, " sof = %02x\n", sof); 350 out += sprintf(out, " sof = %02x\n", sof);
337 out += uhci_show_sc(1, portsc1, out, len - (out - buf)); 351 if (out - buf > len)
338 out += uhci_show_sc(2, portsc2, out, len - (out - buf)); 352 goto done;
339 out += sprintf(out, "Most recent frame: %x (%d) " 353
340 "Last ISO frame: %x (%d)\n", 354 out += uhci_show_sc(1, portsc1, out);
355 if (out - buf > len)
356 goto done;
357
358 out += uhci_show_sc(2, portsc2, out);
359 if (out - buf > len)
360 goto done;
361
362 out += sprintf(out,
363 "Most recent frame: %x (%d) Last ISO frame: %x (%d)\n",
341 uhci->frame_number, uhci->frame_number & 1023, 364 uhci->frame_number, uhci->frame_number & 1023,
342 uhci->last_iso_frame, uhci->last_iso_frame & 1023); 365 uhci->last_iso_frame, uhci->last_iso_frame & 1023);
343 366
367done:
368 if (out - buf > len)
369 out += sprintf(out, " ...\n");
344 return out - buf; 370 return out - buf;
345} 371}
346 372
@@ -360,9 +386,13 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
360 "int8", "int4", "int2", "async", "term" 386 "int8", "int4", "int2", "async", "term"
361 }; 387 };
362 388
363 out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); 389 out += uhci_show_root_hub_state(uhci, out);
390 if (out - buf > len)
391 goto done;
364 out += sprintf(out, "HC status\n"); 392 out += sprintf(out, "HC status\n");
365 out += uhci_show_status(uhci, out, len - (out - buf)); 393 out += uhci_show_status(uhci, out, len - (out - buf));
394 if (out - buf > len)
395 goto tail;
366 396
367 out += sprintf(out, "Periodic load table\n"); 397 out += sprintf(out, "Periodic load table\n");
368 for (i = 0; i < MAX_PHASE; ++i) { 398 for (i = 0; i < MAX_PHASE; ++i) {
@@ -375,7 +405,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
375 uhci_to_hcd(uhci)->self.bandwidth_int_reqs, 405 uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
376 uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs); 406 uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
377 if (debug <= 1) 407 if (debug <= 1)
378 return out - buf; 408 goto tail;
379 409
380 out += sprintf(out, "Frame List\n"); 410 out += sprintf(out, "Frame List\n");
381 nframes = 10; 411 nframes = 10;
@@ -383,6 +413,8 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
383 for (i = 0; i < UHCI_NUMFRAMES; ++i) { 413 for (i = 0; i < UHCI_NUMFRAMES; ++i) {
384 __hc32 qh_dma; 414 __hc32 qh_dma;
385 415
416 if (out - buf > len)
417 goto done;
386 j = 0; 418 j = 0;
387 td = uhci->frame_cpu[i]; 419 td = uhci->frame_cpu[i];
388 link = uhci->frame[i]; 420 link = uhci->frame[i];
@@ -401,15 +433,20 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
401 td = list_entry(tmp, struct uhci_td, fl_list); 433 td = list_entry(tmp, struct uhci_td, fl_list);
402 tmp = tmp->next; 434 tmp = tmp->next;
403 if (link != LINK_TO_TD(uhci, td)) { 435 if (link != LINK_TO_TD(uhci, td)) {
404 if (nframes > 0) 436 if (nframes > 0) {
405 out += sprintf(out, " link does " 437 out += sprintf(out, " link does "
406 "not match list entry!\n"); 438 "not match list entry!\n");
407 else 439 if (out - buf > len)
440 goto done;
441 } else
408 ++nerrs; 442 ++nerrs;
409 } 443 }
410 if (nframes > 0) 444 if (nframes > 0) {
411 out += uhci_show_td(uhci, td, out, 445 out += uhci_show_td(uhci, td, out,
412 len - (out - buf), 4); 446 len - (out - buf), 4);
447 if (out - buf > len)
448 goto tail;
449 }
413 link = td->link; 450 link = td->link;
414 } while (tmp != head); 451 } while (tmp != head);
415 452
@@ -426,6 +463,8 @@ check_link:
426 out += sprintf(out, " link does not match " 463 out += sprintf(out, " link does not match "
427 "QH (%08x)!\n", 464 "QH (%08x)!\n",
428 hc32_to_cpu(uhci, qh_dma)); 465 hc32_to_cpu(uhci, qh_dma));
466 if (out - buf > len)
467 goto done;
429 } else 468 } else
430 ++nerrs; 469 ++nerrs;
431 } 470 }
@@ -436,6 +475,9 @@ check_link:
436 475
437 out += sprintf(out, "Skeleton QHs\n"); 476 out += sprintf(out, "Skeleton QHs\n");
438 477
478 if (out - buf > len)
479 goto done;
480
439 fsbr_link = 0; 481 fsbr_link = 0;
440 for (i = 0; i < UHCI_NUM_SKELQH; ++i) { 482 for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
441 int cnt = 0; 483 int cnt = 0;
@@ -443,11 +485,16 @@ check_link:
443 qh = uhci->skelqh[i]; 485 qh = uhci->skelqh[i];
444 out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \ 486 out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \
445 out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4); 487 out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4);
488 if (out - buf > len)
489 goto tail;
446 490
447 /* Last QH is the Terminating QH, it's different */ 491 /* Last QH is the Terminating QH, it's different */
448 if (i == SKEL_TERM) { 492 if (i == SKEL_TERM) {
449 if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td)) 493 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"); 494 out += sprintf(out, " skel_term_qh element is not set to term_td!\n");
495 if (out - buf > len)
496 goto done;
497 }
451 link = fsbr_link; 498 link = fsbr_link;
452 if (!link) 499 if (!link)
453 link = LINK_TO_QH(uhci, uhci->skel_term_qh); 500 link = LINK_TO_QH(uhci, uhci->skel_term_qh);
@@ -460,9 +507,12 @@ check_link:
460 while (tmp != head) { 507 while (tmp != head) {
461 qh = list_entry(tmp, struct uhci_qh, node); 508 qh = list_entry(tmp, struct uhci_qh, node);
462 tmp = tmp->next; 509 tmp = tmp->next;
463 if (++cnt <= 10) 510 if (++cnt <= 10) {
464 out += uhci_show_qh(uhci, qh, out, 511 out += uhci_show_qh(uhci, qh, out,
465 len - (out - buf), 4); 512 len - (out - buf), 4);
513 if (out - buf > len)
514 goto tail;
515 }
466 if (!fsbr_link && qh->skel >= SKEL_FSBR) 516 if (!fsbr_link && qh->skel >= SKEL_FSBR)
467 fsbr_link = LINK_TO_QH(uhci, qh); 517 fsbr_link = LINK_TO_QH(uhci, qh);
468 } 518 }
@@ -481,8 +531,15 @@ check_link:
481check_qh_link: 531check_qh_link:
482 if (qh->link != link) 532 if (qh->link != link)
483 out += sprintf(out, " last QH not linked to next skeleton!\n"); 533 out += sprintf(out, " last QH not linked to next skeleton!\n");
534
535 if (out - buf > len)
536 goto done;
484 } 537 }
485 538
539done:
540 if (out - buf > len)
541 out += sprintf(out, " ...\n");
542tail:
486 return out - buf; 543 return out - buf;
487} 544}
488 545
@@ -514,7 +571,8 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
514 up->size = 0; 571 up->size = 0;
515 spin_lock_irqsave(&uhci->lock, flags); 572 spin_lock_irqsave(&uhci->lock, flags);
516 if (uhci->is_initialized) 573 if (uhci->is_initialized)
517 up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); 574 up->size = uhci_sprint_schedule(uhci, up->data,
575 MAX_OUTPUT - EXTRA_SPACE);
518 spin_unlock_irqrestore(&uhci->lock, flags); 576 spin_unlock_irqrestore(&uhci->lock, flags);
519 577
520 file->private_data = up; 578 file->private_data = up;