diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2005-11-03 11:44:49 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-04 16:48:29 -0500 |
commit | 6912354a895fcd234155273fe8838a0d83259a9b (patch) | |
tree | 6dca4969dda3fb177c62f18b12bfb6d2be4bb567 /drivers/usb | |
parent | 959eea2191e8d74b16ef019b0f4bf875c14f4547 (diff) |
[PATCH] USB: EHCI: fix conflation of buf == 0 with len == 0
When the ehci-hcd driver prepares a control URB, it tests for a
zero-length data stage by looking at the transfer_dma value instead of
the transfer_buffer_length. (In fact it does this even for non-control
URBs, which is an additional aspect of the same bug.)
However, under certain circumstances it's possible for transfer_dma to
be 0 while transfer_buffer_length is non-zero. This can happen when a
freshly allocated page (mapped to address 0 and marked Copy-On-Write,
but never written to) is used as the source buffer for an OUT transfer.
This patch (as598) fixes the problem.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/ehci-q.c | 14 |
1 files changed, 7 insertions, 7 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index bf03ec0d8ee2..9b13bf2fa98d 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
@@ -514,18 +514,18 @@ qh_urb_transaction ( | |||
514 | qtd->urb = urb; | 514 | qtd->urb = urb; |
515 | qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); | 515 | qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); |
516 | list_add_tail (&qtd->qtd_list, head); | 516 | list_add_tail (&qtd->qtd_list, head); |
517 | |||
518 | /* for zero length DATA stages, STATUS is always IN */ | ||
519 | if (len == 0) | ||
520 | token |= (1 /* "in" */ << 8); | ||
517 | } | 521 | } |
518 | 522 | ||
519 | /* | 523 | /* |
520 | * data transfer stage: buffer setup | 524 | * data transfer stage: buffer setup |
521 | */ | 525 | */ |
522 | if (likely (len > 0)) | 526 | buf = urb->transfer_dma; |
523 | buf = urb->transfer_dma; | ||
524 | else | ||
525 | buf = 0; | ||
526 | 527 | ||
527 | /* for zero length DATA stages, STATUS is always IN */ | 528 | if (is_input) |
528 | if (!buf || is_input) | ||
529 | token |= (1 /* "in" */ << 8); | 529 | token |= (1 /* "in" */ << 8); |
530 | /* else it's already initted to "out" pid (0 << 8) */ | 530 | /* else it's already initted to "out" pid (0 << 8) */ |
531 | 531 | ||
@@ -572,7 +572,7 @@ qh_urb_transaction ( | |||
572 | * control requests may need a terminating data "status" ack; | 572 | * control requests may need a terminating data "status" ack; |
573 | * bulk ones may need a terminating short packet (zero length). | 573 | * bulk ones may need a terminating short packet (zero length). |
574 | */ | 574 | */ |
575 | if (likely (buf != 0)) { | 575 | if (likely (urb->transfer_buffer_length != 0)) { |
576 | int one_more = 0; | 576 | int one_more = 0; |
577 | 577 | ||
578 | if (usb_pipecontrol (urb->pipe)) { | 578 | if (usb_pipecontrol (urb->pipe)) { |