diff options
author | Felipe Balbi <balbi@ti.com> | 2011-02-16 05:40:05 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2011-02-17 14:11:46 -0500 |
commit | ad1adb89a0d9410345d573b6995a1fa9f9b7c74a (patch) | |
tree | b07349993d6eec5dff875f5517b0c79667906a8b | |
parent | 63eed2b52494e35aaf38ac2db537d6ea0a55b0da (diff) |
usb: musb: gadget: do not poke with gadget's list_head
struct usb_request's list_head is supposed to be
used only by gadget drivers, but musb is abusing
that. Give struct musb_request its own list_head
and prevent musb from poking into other driver's
business.
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/musb/musb_core.h | 4 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget.c | 37 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget.h | 7 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget_ep0.c | 24 |
4 files changed, 41 insertions, 31 deletions
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index d74a8113ae74..2c8dde6d23e0 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h | |||
@@ -328,7 +328,7 @@ struct musb_hw_ep { | |||
328 | #endif | 328 | #endif |
329 | }; | 329 | }; |
330 | 330 | ||
331 | static inline struct usb_request *next_in_request(struct musb_hw_ep *hw_ep) | 331 | static inline struct musb_request *next_in_request(struct musb_hw_ep *hw_ep) |
332 | { | 332 | { |
333 | #ifdef CONFIG_USB_GADGET_MUSB_HDRC | 333 | #ifdef CONFIG_USB_GADGET_MUSB_HDRC |
334 | return next_request(&hw_ep->ep_in); | 334 | return next_request(&hw_ep->ep_in); |
@@ -337,7 +337,7 @@ static inline struct usb_request *next_in_request(struct musb_hw_ep *hw_ep) | |||
337 | #endif | 337 | #endif |
338 | } | 338 | } |
339 | 339 | ||
340 | static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep) | 340 | static inline struct musb_request *next_out_request(struct musb_hw_ep *hw_ep) |
341 | { | 341 | { |
342 | #ifdef CONFIG_USB_GADGET_MUSB_HDRC | 342 | #ifdef CONFIG_USB_GADGET_MUSB_HDRC |
343 | return next_request(&hw_ep->ep_out); | 343 | return next_request(&hw_ep->ep_out); |
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 86decba48f28..0f59bf935c85 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c | |||
@@ -189,7 +189,7 @@ __acquires(ep->musb->lock) | |||
189 | 189 | ||
190 | req = to_musb_request(request); | 190 | req = to_musb_request(request); |
191 | 191 | ||
192 | list_del(&request->list); | 192 | list_del(&req->list); |
193 | if (req->request.status == -EINPROGRESS) | 193 | if (req->request.status == -EINPROGRESS) |
194 | req->request.status = status; | 194 | req->request.status = status; |
195 | musb = req->musb; | 195 | musb = req->musb; |
@@ -251,9 +251,8 @@ static void nuke(struct musb_ep *ep, const int status) | |||
251 | ep->dma = NULL; | 251 | ep->dma = NULL; |
252 | } | 252 | } |
253 | 253 | ||
254 | while (!list_empty(&(ep->req_list))) { | 254 | while (!list_empty(&ep->req_list)) { |
255 | req = container_of(ep->req_list.next, struct musb_request, | 255 | req = list_first_entry(&ep->req_list, struct musb_request, list); |
256 | request.list); | ||
257 | musb_g_giveback(ep, &req->request, status); | 256 | musb_g_giveback(ep, &req->request, status); |
258 | } | 257 | } |
259 | } | 258 | } |
@@ -485,6 +484,7 @@ static void txstate(struct musb *musb, struct musb_request *req) | |||
485 | void musb_g_tx(struct musb *musb, u8 epnum) | 484 | void musb_g_tx(struct musb *musb, u8 epnum) |
486 | { | 485 | { |
487 | u16 csr; | 486 | u16 csr; |
487 | struct musb_request *req; | ||
488 | struct usb_request *request; | 488 | struct usb_request *request; |
489 | u8 __iomem *mbase = musb->mregs; | 489 | u8 __iomem *mbase = musb->mregs; |
490 | struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_in; | 490 | struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_in; |
@@ -492,7 +492,8 @@ void musb_g_tx(struct musb *musb, u8 epnum) | |||
492 | struct dma_channel *dma; | 492 | struct dma_channel *dma; |
493 | 493 | ||
494 | musb_ep_select(mbase, epnum); | 494 | musb_ep_select(mbase, epnum); |
495 | request = next_request(musb_ep); | 495 | req = next_request(musb_ep); |
496 | request = &req->request; | ||
496 | 497 | ||
497 | csr = musb_readw(epio, MUSB_TXCSR); | 498 | csr = musb_readw(epio, MUSB_TXCSR); |
498 | DBG(4, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr); | 499 | DBG(4, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr); |
@@ -571,15 +572,15 @@ void musb_g_tx(struct musb *musb, u8 epnum) | |||
571 | 572 | ||
572 | if (request->actual == request->length) { | 573 | if (request->actual == request->length) { |
573 | musb_g_giveback(musb_ep, request, 0); | 574 | musb_g_giveback(musb_ep, request, 0); |
574 | request = musb_ep->desc ? next_request(musb_ep) : NULL; | 575 | req = musb_ep->desc ? next_request(musb_ep) : NULL; |
575 | if (!request) { | 576 | if (!req) { |
576 | DBG(4, "%s idle now\n", | 577 | DBG(4, "%s idle now\n", |
577 | musb_ep->end_point.name); | 578 | musb_ep->end_point.name); |
578 | return; | 579 | return; |
579 | } | 580 | } |
580 | } | 581 | } |
581 | 582 | ||
582 | txstate(musb, to_musb_request(request)); | 583 | txstate(musb, req); |
583 | } | 584 | } |
584 | } | 585 | } |
585 | 586 | ||
@@ -821,6 +822,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) | |||
821 | void musb_g_rx(struct musb *musb, u8 epnum) | 822 | void musb_g_rx(struct musb *musb, u8 epnum) |
822 | { | 823 | { |
823 | u16 csr; | 824 | u16 csr; |
825 | struct musb_request *req; | ||
824 | struct usb_request *request; | 826 | struct usb_request *request; |
825 | void __iomem *mbase = musb->mregs; | 827 | void __iomem *mbase = musb->mregs; |
826 | struct musb_ep *musb_ep; | 828 | struct musb_ep *musb_ep; |
@@ -835,10 +837,12 @@ void musb_g_rx(struct musb *musb, u8 epnum) | |||
835 | 837 | ||
836 | musb_ep_select(mbase, epnum); | 838 | musb_ep_select(mbase, epnum); |
837 | 839 | ||
838 | request = next_request(musb_ep); | 840 | req = next_request(musb_ep); |
839 | if (!request) | 841 | if (!req) |
840 | return; | 842 | return; |
841 | 843 | ||
844 | request = &req->request; | ||
845 | |||
842 | csr = musb_readw(epio, MUSB_RXCSR); | 846 | csr = musb_readw(epio, MUSB_RXCSR); |
843 | dma = is_dma_capable() ? musb_ep->dma : NULL; | 847 | dma = is_dma_capable() ? musb_ep->dma : NULL; |
844 | 848 | ||
@@ -914,15 +918,15 @@ void musb_g_rx(struct musb *musb, u8 epnum) | |||
914 | #endif | 918 | #endif |
915 | musb_g_giveback(musb_ep, request, 0); | 919 | musb_g_giveback(musb_ep, request, 0); |
916 | 920 | ||
917 | request = next_request(musb_ep); | 921 | req = next_request(musb_ep); |
918 | if (!request) | 922 | if (!req) |
919 | return; | 923 | return; |
920 | } | 924 | } |
921 | #if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) | 925 | #if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) |
922 | exit: | 926 | exit: |
923 | #endif | 927 | #endif |
924 | /* Analyze request */ | 928 | /* Analyze request */ |
925 | rxstate(musb, to_musb_request(request)); | 929 | rxstate(musb, req); |
926 | } | 930 | } |
927 | 931 | ||
928 | /* ------------------------------------------------------------ */ | 932 | /* ------------------------------------------------------------ */ |
@@ -1171,7 +1175,6 @@ struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) | |||
1171 | return NULL; | 1175 | return NULL; |
1172 | } | 1176 | } |
1173 | 1177 | ||
1174 | INIT_LIST_HEAD(&request->request.list); | ||
1175 | request->request.dma = DMA_ADDR_INVALID; | 1178 | request->request.dma = DMA_ADDR_INVALID; |
1176 | request->epnum = musb_ep->current_epnum; | 1179 | request->epnum = musb_ep->current_epnum; |
1177 | request->ep = musb_ep; | 1180 | request->ep = musb_ep; |
@@ -1257,10 +1260,10 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, | |||
1257 | } | 1260 | } |
1258 | 1261 | ||
1259 | /* add request to the list */ | 1262 | /* add request to the list */ |
1260 | list_add_tail(&(request->request.list), &(musb_ep->req_list)); | 1263 | list_add_tail(&request->list, &musb_ep->req_list); |
1261 | 1264 | ||
1262 | /* it this is the head of the queue, start i/o ... */ | 1265 | /* it this is the head of the queue, start i/o ... */ |
1263 | if (!musb_ep->busy && &request->request.list == musb_ep->req_list.next) | 1266 | if (!musb_ep->busy && &request->list == musb_ep->req_list.next) |
1264 | musb_ep_restart(musb, request); | 1267 | musb_ep_restart(musb, request); |
1265 | 1268 | ||
1266 | cleanup: | 1269 | cleanup: |
@@ -1349,7 +1352,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value) | |||
1349 | 1352 | ||
1350 | musb_ep_select(mbase, epnum); | 1353 | musb_ep_select(mbase, epnum); |
1351 | 1354 | ||
1352 | request = to_musb_request(next_request(musb_ep)); | 1355 | request = next_request(musb_ep); |
1353 | if (value) { | 1356 | if (value) { |
1354 | if (request) { | 1357 | if (request) { |
1355 | DBG(3, "request in progress, cannot halt %s\n", | 1358 | DBG(3, "request in progress, cannot halt %s\n", |
diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h index a55354fbccf5..66b7c5e0fb44 100644 --- a/drivers/usb/musb/musb_gadget.h +++ b/drivers/usb/musb/musb_gadget.h | |||
@@ -35,6 +35,8 @@ | |||
35 | #ifndef __MUSB_GADGET_H | 35 | #ifndef __MUSB_GADGET_H |
36 | #define __MUSB_GADGET_H | 36 | #define __MUSB_GADGET_H |
37 | 37 | ||
38 | #include <linux/list.h> | ||
39 | |||
38 | enum buffer_map_state { | 40 | enum buffer_map_state { |
39 | UN_MAPPED = 0, | 41 | UN_MAPPED = 0, |
40 | PRE_MAPPED, | 42 | PRE_MAPPED, |
@@ -43,6 +45,7 @@ enum buffer_map_state { | |||
43 | 45 | ||
44 | struct musb_request { | 46 | struct musb_request { |
45 | struct usb_request request; | 47 | struct usb_request request; |
48 | struct list_head list; | ||
46 | struct musb_ep *ep; | 49 | struct musb_ep *ep; |
47 | struct musb *musb; | 50 | struct musb *musb; |
48 | u8 tx; /* endpoint direction */ | 51 | u8 tx; /* endpoint direction */ |
@@ -94,13 +97,13 @@ static inline struct musb_ep *to_musb_ep(struct usb_ep *ep) | |||
94 | return ep ? container_of(ep, struct musb_ep, end_point) : NULL; | 97 | return ep ? container_of(ep, struct musb_ep, end_point) : NULL; |
95 | } | 98 | } |
96 | 99 | ||
97 | static inline struct usb_request *next_request(struct musb_ep *ep) | 100 | static inline struct musb_request *next_request(struct musb_ep *ep) |
98 | { | 101 | { |
99 | struct list_head *queue = &ep->req_list; | 102 | struct list_head *queue = &ep->req_list; |
100 | 103 | ||
101 | if (list_empty(queue)) | 104 | if (list_empty(queue)) |
102 | return NULL; | 105 | return NULL; |
103 | return container_of(queue->next, struct usb_request, list); | 106 | return container_of(queue->next, struct musb_request, list); |
104 | } | 107 | } |
105 | 108 | ||
106 | extern void musb_g_tx(struct musb *musb, u8 epnum); | 109 | extern void musb_g_tx(struct musb *musb, u8 epnum); |
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 6dd03f4c5f49..75a542e42fdf 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c | |||
@@ -304,8 +304,7 @@ __acquires(musb->lock) | |||
304 | } | 304 | } |
305 | 305 | ||
306 | /* Maybe start the first request in the queue */ | 306 | /* Maybe start the first request in the queue */ |
307 | request = to_musb_request( | 307 | request = next_request(musb_ep); |
308 | next_request(musb_ep)); | ||
309 | if (!musb_ep->busy && request) { | 308 | if (!musb_ep->busy && request) { |
310 | DBG(3, "restarting the request\n"); | 309 | DBG(3, "restarting the request\n"); |
311 | musb_ep_restart(musb, request); | 310 | musb_ep_restart(musb, request); |
@@ -491,10 +490,12 @@ stall: | |||
491 | static void ep0_rxstate(struct musb *musb) | 490 | static void ep0_rxstate(struct musb *musb) |
492 | { | 491 | { |
493 | void __iomem *regs = musb->control_ep->regs; | 492 | void __iomem *regs = musb->control_ep->regs; |
493 | struct musb_request *request; | ||
494 | struct usb_request *req; | 494 | struct usb_request *req; |
495 | u16 count, csr; | 495 | u16 count, csr; |
496 | 496 | ||
497 | req = next_ep0_request(musb); | 497 | request = next_ep0_request(musb); |
498 | req = &request->request; | ||
498 | 499 | ||
499 | /* read packet and ack; or stall because of gadget driver bug: | 500 | /* read packet and ack; or stall because of gadget driver bug: |
500 | * should have provided the rx buffer before setup() returned. | 501 | * should have provided the rx buffer before setup() returned. |
@@ -544,17 +545,20 @@ static void ep0_rxstate(struct musb *musb) | |||
544 | static void ep0_txstate(struct musb *musb) | 545 | static void ep0_txstate(struct musb *musb) |
545 | { | 546 | { |
546 | void __iomem *regs = musb->control_ep->regs; | 547 | void __iomem *regs = musb->control_ep->regs; |
547 | struct usb_request *request = next_ep0_request(musb); | 548 | struct musb_request *req = next_ep0_request(musb); |
549 | struct usb_request *request; | ||
548 | u16 csr = MUSB_CSR0_TXPKTRDY; | 550 | u16 csr = MUSB_CSR0_TXPKTRDY; |
549 | u8 *fifo_src; | 551 | u8 *fifo_src; |
550 | u8 fifo_count; | 552 | u8 fifo_count; |
551 | 553 | ||
552 | if (!request) { | 554 | if (!req) { |
553 | /* WARN_ON(1); */ | 555 | /* WARN_ON(1); */ |
554 | DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0)); | 556 | DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0)); |
555 | return; | 557 | return; |
556 | } | 558 | } |
557 | 559 | ||
560 | request = &req->request; | ||
561 | |||
558 | /* load the data */ | 562 | /* load the data */ |
559 | fifo_src = (u8 *) request->buf + request->actual; | 563 | fifo_src = (u8 *) request->buf + request->actual; |
560 | fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE, | 564 | fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE, |
@@ -598,7 +602,7 @@ static void ep0_txstate(struct musb *musb) | |||
598 | static void | 602 | static void |
599 | musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req) | 603 | musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req) |
600 | { | 604 | { |
601 | struct usb_request *r; | 605 | struct musb_request *r; |
602 | void __iomem *regs = musb->control_ep->regs; | 606 | void __iomem *regs = musb->control_ep->regs; |
603 | 607 | ||
604 | musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)req); | 608 | musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)req); |
@@ -616,7 +620,7 @@ musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req) | |||
616 | /* clean up any leftover transfers */ | 620 | /* clean up any leftover transfers */ |
617 | r = next_ep0_request(musb); | 621 | r = next_ep0_request(musb); |
618 | if (r) | 622 | if (r) |
619 | musb_g_ep0_giveback(musb, r); | 623 | musb_g_ep0_giveback(musb, &r->request); |
620 | 624 | ||
621 | /* For zero-data requests we want to delay the STATUS stage to | 625 | /* For zero-data requests we want to delay the STATUS stage to |
622 | * avoid SETUPEND errors. If we read data (OUT), delay accepting | 626 | * avoid SETUPEND errors. If we read data (OUT), delay accepting |
@@ -758,11 +762,11 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) | |||
758 | case MUSB_EP0_STAGE_STATUSOUT: | 762 | case MUSB_EP0_STAGE_STATUSOUT: |
759 | /* end of sequence #1: write to host (TX state) */ | 763 | /* end of sequence #1: write to host (TX state) */ |
760 | { | 764 | { |
761 | struct usb_request *req; | 765 | struct musb_request *req; |
762 | 766 | ||
763 | req = next_ep0_request(musb); | 767 | req = next_ep0_request(musb); |
764 | if (req) | 768 | if (req) |
765 | musb_g_ep0_giveback(musb, req); | 769 | musb_g_ep0_giveback(musb, &req->request); |
766 | } | 770 | } |
767 | 771 | ||
768 | /* | 772 | /* |
@@ -961,7 +965,7 @@ musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags) | |||
961 | } | 965 | } |
962 | 966 | ||
963 | /* add request to the list */ | 967 | /* add request to the list */ |
964 | list_add_tail(&(req->request.list), &(ep->req_list)); | 968 | list_add_tail(&req->list, &ep->req_list); |
965 | 969 | ||
966 | DBG(3, "queue to %s (%s), length=%d\n", | 970 | DBG(3, "queue to %s (%s), length=%d\n", |
967 | ep->name, ep->is_in ? "IN/TX" : "OUT/RX", | 971 | ep->name, ep->is_in ? "IN/TX" : "OUT/RX", |