Commit d76630386d59d203ad4594d7e91be1f2e258ab93
1 parent
be7ed2533d
Exists in
master
and in
55 other branches
usb: mv_udc: Clean up the initial variable check
Clean up the code that checks the validity of a USB gadget driver in usb_gadget_register_driver(). Moreover, limit the speed of the driver to either FULL or HIGH, this is more precise and once we have xHCI support, also more correct. Signed-off-by: Marek Vasut <marex@denx.de> Cc: Fabio Estevam <fabio.estevam@freescale.com> Cc: Lei Wen <leiwen@marvell.com> Cc: Otavio Salvador <otavio@ossystems.com.br> Cc: Stefano Babic <sbabic@denx.de>
Showing 1 changed file with 5 additions and 6 deletions Inline Diff
drivers/usb/gadget/mv_udc.c
1 | /* | 1 | /* |
2 | * Copyright 2011, Marvell Semiconductor Inc. | 2 | * Copyright 2011, Marvell Semiconductor Inc. |
3 | * Lei Wen <leiwen@marvell.com> | 3 | * Lei Wen <leiwen@marvell.com> |
4 | * | 4 | * |
5 | * SPDX-License-Identifier: GPL-2.0+ | 5 | * SPDX-License-Identifier: GPL-2.0+ |
6 | * | 6 | * |
7 | * Back ported to the 8xx platform (from the 8260 platform) by | 7 | * Back ported to the 8xx platform (from the 8260 platform) by |
8 | * Murray.Jensen@cmst.csiro.au, 27-Jan-01. | 8 | * Murray.Jensen@cmst.csiro.au, 27-Jan-01. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <common.h> | 11 | #include <common.h> |
12 | #include <command.h> | 12 | #include <command.h> |
13 | #include <config.h> | 13 | #include <config.h> |
14 | #include <net.h> | 14 | #include <net.h> |
15 | #include <malloc.h> | 15 | #include <malloc.h> |
16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
18 | #include <usb/mv_udc.h> | 18 | #include <usb/mv_udc.h> |
19 | 19 | ||
20 | #if CONFIG_USB_MAX_CONTROLLER_COUNT > 1 | 20 | #if CONFIG_USB_MAX_CONTROLLER_COUNT > 1 |
21 | #error This driver only supports one single controller. | 21 | #error This driver only supports one single controller. |
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | #ifndef DEBUG | 24 | #ifndef DEBUG |
25 | #define DBG(x...) do {} while (0) | 25 | #define DBG(x...) do {} while (0) |
26 | #else | 26 | #else |
27 | #define DBG(x...) printf(x) | 27 | #define DBG(x...) printf(x) |
28 | static const char *reqname(unsigned r) | 28 | static const char *reqname(unsigned r) |
29 | { | 29 | { |
30 | switch (r) { | 30 | switch (r) { |
31 | case USB_REQ_GET_STATUS: return "GET_STATUS"; | 31 | case USB_REQ_GET_STATUS: return "GET_STATUS"; |
32 | case USB_REQ_CLEAR_FEATURE: return "CLEAR_FEATURE"; | 32 | case USB_REQ_CLEAR_FEATURE: return "CLEAR_FEATURE"; |
33 | case USB_REQ_SET_FEATURE: return "SET_FEATURE"; | 33 | case USB_REQ_SET_FEATURE: return "SET_FEATURE"; |
34 | case USB_REQ_SET_ADDRESS: return "SET_ADDRESS"; | 34 | case USB_REQ_SET_ADDRESS: return "SET_ADDRESS"; |
35 | case USB_REQ_GET_DESCRIPTOR: return "GET_DESCRIPTOR"; | 35 | case USB_REQ_GET_DESCRIPTOR: return "GET_DESCRIPTOR"; |
36 | case USB_REQ_SET_DESCRIPTOR: return "SET_DESCRIPTOR"; | 36 | case USB_REQ_SET_DESCRIPTOR: return "SET_DESCRIPTOR"; |
37 | case USB_REQ_GET_CONFIGURATION: return "GET_CONFIGURATION"; | 37 | case USB_REQ_GET_CONFIGURATION: return "GET_CONFIGURATION"; |
38 | case USB_REQ_SET_CONFIGURATION: return "SET_CONFIGURATION"; | 38 | case USB_REQ_SET_CONFIGURATION: return "SET_CONFIGURATION"; |
39 | case USB_REQ_GET_INTERFACE: return "GET_INTERFACE"; | 39 | case USB_REQ_GET_INTERFACE: return "GET_INTERFACE"; |
40 | case USB_REQ_SET_INTERFACE: return "SET_INTERFACE"; | 40 | case USB_REQ_SET_INTERFACE: return "SET_INTERFACE"; |
41 | default: return "*UNKNOWN*"; | 41 | default: return "*UNKNOWN*"; |
42 | } | 42 | } |
43 | } | 43 | } |
44 | #endif | 44 | #endif |
45 | 45 | ||
46 | #define PAGE_SIZE 4096 | 46 | #define PAGE_SIZE 4096 |
47 | #define QH_MAXNUM 32 | 47 | #define QH_MAXNUM 32 |
48 | static struct usb_endpoint_descriptor ep0_out_desc = { | 48 | static struct usb_endpoint_descriptor ep0_out_desc = { |
49 | .bLength = sizeof(struct usb_endpoint_descriptor), | 49 | .bLength = sizeof(struct usb_endpoint_descriptor), |
50 | .bDescriptorType = USB_DT_ENDPOINT, | 50 | .bDescriptorType = USB_DT_ENDPOINT, |
51 | .bEndpointAddress = 0, | 51 | .bEndpointAddress = 0, |
52 | .bmAttributes = USB_ENDPOINT_XFER_CONTROL, | 52 | .bmAttributes = USB_ENDPOINT_XFER_CONTROL, |
53 | }; | 53 | }; |
54 | 54 | ||
55 | static struct usb_endpoint_descriptor ep0_in_desc = { | 55 | static struct usb_endpoint_descriptor ep0_in_desc = { |
56 | .bLength = sizeof(struct usb_endpoint_descriptor), | 56 | .bLength = sizeof(struct usb_endpoint_descriptor), |
57 | .bDescriptorType = USB_DT_ENDPOINT, | 57 | .bDescriptorType = USB_DT_ENDPOINT, |
58 | .bEndpointAddress = USB_DIR_IN, | 58 | .bEndpointAddress = USB_DIR_IN, |
59 | .bmAttributes = USB_ENDPOINT_XFER_CONTROL, | 59 | .bmAttributes = USB_ENDPOINT_XFER_CONTROL, |
60 | }; | 60 | }; |
61 | 61 | ||
62 | struct ept_queue_head *epts; | 62 | struct ept_queue_head *epts; |
63 | struct ept_queue_item *items[2 * NUM_ENDPOINTS]; | 63 | struct ept_queue_item *items[2 * NUM_ENDPOINTS]; |
64 | static int mv_pullup(struct usb_gadget *gadget, int is_on); | 64 | static int mv_pullup(struct usb_gadget *gadget, int is_on); |
65 | static int mv_ep_enable(struct usb_ep *ep, | 65 | static int mv_ep_enable(struct usb_ep *ep, |
66 | const struct usb_endpoint_descriptor *desc); | 66 | const struct usb_endpoint_descriptor *desc); |
67 | static int mv_ep_disable(struct usb_ep *ep); | 67 | static int mv_ep_disable(struct usb_ep *ep); |
68 | static int mv_ep_queue(struct usb_ep *ep, | 68 | static int mv_ep_queue(struct usb_ep *ep, |
69 | struct usb_request *req, gfp_t gfp_flags); | 69 | struct usb_request *req, gfp_t gfp_flags); |
70 | static struct usb_request * | 70 | static struct usb_request * |
71 | mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags); | 71 | mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags); |
72 | static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req); | 72 | static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req); |
73 | 73 | ||
74 | static struct usb_gadget_ops mv_udc_ops = { | 74 | static struct usb_gadget_ops mv_udc_ops = { |
75 | .pullup = mv_pullup, | 75 | .pullup = mv_pullup, |
76 | }; | 76 | }; |
77 | 77 | ||
78 | static struct usb_ep_ops mv_ep_ops = { | 78 | static struct usb_ep_ops mv_ep_ops = { |
79 | .enable = mv_ep_enable, | 79 | .enable = mv_ep_enable, |
80 | .disable = mv_ep_disable, | 80 | .disable = mv_ep_disable, |
81 | .queue = mv_ep_queue, | 81 | .queue = mv_ep_queue, |
82 | .alloc_request = mv_ep_alloc_request, | 82 | .alloc_request = mv_ep_alloc_request, |
83 | .free_request = mv_ep_free_request, | 83 | .free_request = mv_ep_free_request, |
84 | }; | 84 | }; |
85 | 85 | ||
86 | /* Init values for USB endpoints. */ | 86 | /* Init values for USB endpoints. */ |
87 | static const struct usb_ep mv_ep_init[2] = { | 87 | static const struct usb_ep mv_ep_init[2] = { |
88 | [0] = { /* EP 0 */ | 88 | [0] = { /* EP 0 */ |
89 | .maxpacket = 64, | 89 | .maxpacket = 64, |
90 | .name = "ep0", | 90 | .name = "ep0", |
91 | .ops = &mv_ep_ops, | 91 | .ops = &mv_ep_ops, |
92 | }, | 92 | }, |
93 | [1] = { /* EP 1..n */ | 93 | [1] = { /* EP 1..n */ |
94 | .maxpacket = 512, | 94 | .maxpacket = 512, |
95 | .name = "ep-", | 95 | .name = "ep-", |
96 | .ops = &mv_ep_ops, | 96 | .ops = &mv_ep_ops, |
97 | }, | 97 | }, |
98 | }; | 98 | }; |
99 | 99 | ||
100 | static struct mv_drv controller = { | 100 | static struct mv_drv controller = { |
101 | .gadget = { | 101 | .gadget = { |
102 | .name = "mv_udc", | 102 | .name = "mv_udc", |
103 | }, | 103 | }, |
104 | }; | 104 | }; |
105 | 105 | ||
106 | static struct usb_request * | 106 | static struct usb_request * |
107 | mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags) | 107 | mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags) |
108 | { | 108 | { |
109 | struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep); | 109 | struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep); |
110 | return &mv_ep->req; | 110 | return &mv_ep->req; |
111 | } | 111 | } |
112 | 112 | ||
113 | static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req) | 113 | static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req) |
114 | { | 114 | { |
115 | return; | 115 | return; |
116 | } | 116 | } |
117 | 117 | ||
118 | static void ep_enable(int num, int in) | 118 | static void ep_enable(int num, int in) |
119 | { | 119 | { |
120 | struct ept_queue_head *head; | 120 | struct ept_queue_head *head; |
121 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; | 121 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; |
122 | unsigned n; | 122 | unsigned n; |
123 | head = epts + 2*num + in; | 123 | head = epts + 2*num + in; |
124 | 124 | ||
125 | n = readl(&udc->epctrl[num]); | 125 | n = readl(&udc->epctrl[num]); |
126 | if (in) | 126 | if (in) |
127 | n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK); | 127 | n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK); |
128 | else | 128 | else |
129 | n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK); | 129 | n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK); |
130 | 130 | ||
131 | if (num != 0) | 131 | if (num != 0) |
132 | head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE) | CONFIG_ZLT; | 132 | head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE) | CONFIG_ZLT; |
133 | writel(n, &udc->epctrl[num]); | 133 | writel(n, &udc->epctrl[num]); |
134 | } | 134 | } |
135 | 135 | ||
136 | static int mv_ep_enable(struct usb_ep *ep, | 136 | static int mv_ep_enable(struct usb_ep *ep, |
137 | const struct usb_endpoint_descriptor *desc) | 137 | const struct usb_endpoint_descriptor *desc) |
138 | { | 138 | { |
139 | struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep); | 139 | struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep); |
140 | int num, in; | 140 | int num, in; |
141 | num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; | 141 | num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; |
142 | in = (desc->bEndpointAddress & USB_DIR_IN) != 0; | 142 | in = (desc->bEndpointAddress & USB_DIR_IN) != 0; |
143 | ep_enable(num, in); | 143 | ep_enable(num, in); |
144 | mv_ep->desc = desc; | 144 | mv_ep->desc = desc; |
145 | return 0; | 145 | return 0; |
146 | } | 146 | } |
147 | 147 | ||
148 | static int mv_ep_disable(struct usb_ep *ep) | 148 | static int mv_ep_disable(struct usb_ep *ep) |
149 | { | 149 | { |
150 | return 0; | 150 | return 0; |
151 | } | 151 | } |
152 | 152 | ||
153 | static int mv_ep_queue(struct usb_ep *ep, | 153 | static int mv_ep_queue(struct usb_ep *ep, |
154 | struct usb_request *req, gfp_t gfp_flags) | 154 | struct usb_request *req, gfp_t gfp_flags) |
155 | { | 155 | { |
156 | struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep); | 156 | struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep); |
157 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; | 157 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; |
158 | struct ept_queue_item *item; | 158 | struct ept_queue_item *item; |
159 | struct ept_queue_head *head; | 159 | struct ept_queue_head *head; |
160 | unsigned phys; | 160 | unsigned phys; |
161 | int bit, num, len, in; | 161 | int bit, num, len, in; |
162 | num = mv_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; | 162 | num = mv_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; |
163 | in = (mv_ep->desc->bEndpointAddress & USB_DIR_IN) != 0; | 163 | in = (mv_ep->desc->bEndpointAddress & USB_DIR_IN) != 0; |
164 | item = items[2 * num + in]; | 164 | item = items[2 * num + in]; |
165 | head = epts + 2 * num + in; | 165 | head = epts + 2 * num + in; |
166 | phys = (unsigned)req->buf; | 166 | phys = (unsigned)req->buf; |
167 | len = req->length; | 167 | len = req->length; |
168 | 168 | ||
169 | item->next = TERMINATE; | 169 | item->next = TERMINATE; |
170 | item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE; | 170 | item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE; |
171 | item->page0 = phys; | 171 | item->page0 = phys; |
172 | item->page1 = (phys & 0xfffff000) + 0x1000; | 172 | item->page1 = (phys & 0xfffff000) + 0x1000; |
173 | 173 | ||
174 | head->next = (unsigned) item; | 174 | head->next = (unsigned) item; |
175 | head->info = 0; | 175 | head->info = 0; |
176 | 176 | ||
177 | DBG("ept%d %s queue len %x, buffer %x\n", | 177 | DBG("ept%d %s queue len %x, buffer %x\n", |
178 | num, in ? "in" : "out", len, phys); | 178 | num, in ? "in" : "out", len, phys); |
179 | 179 | ||
180 | if (in) | 180 | if (in) |
181 | bit = EPT_TX(num); | 181 | bit = EPT_TX(num); |
182 | else | 182 | else |
183 | bit = EPT_RX(num); | 183 | bit = EPT_RX(num); |
184 | 184 | ||
185 | flush_cache(phys, len); | 185 | flush_cache(phys, len); |
186 | flush_cache((unsigned long)item, sizeof(struct ept_queue_item)); | 186 | flush_cache((unsigned long)item, sizeof(struct ept_queue_item)); |
187 | writel(bit, &udc->epprime); | 187 | writel(bit, &udc->epprime); |
188 | 188 | ||
189 | return 0; | 189 | return 0; |
190 | } | 190 | } |
191 | 191 | ||
192 | static void handle_ep_complete(struct mv_ep *ep) | 192 | static void handle_ep_complete(struct mv_ep *ep) |
193 | { | 193 | { |
194 | struct ept_queue_item *item; | 194 | struct ept_queue_item *item; |
195 | int num, in, len; | 195 | int num, in, len; |
196 | num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; | 196 | num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; |
197 | in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0; | 197 | in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0; |
198 | if (num == 0) | 198 | if (num == 0) |
199 | ep->desc = &ep0_out_desc; | 199 | ep->desc = &ep0_out_desc; |
200 | item = items[2 * num + in]; | 200 | item = items[2 * num + in]; |
201 | 201 | ||
202 | if (item->info & 0xff) | 202 | if (item->info & 0xff) |
203 | printf("EP%d/%s FAIL nfo=%x pg0=%x\n", | 203 | printf("EP%d/%s FAIL nfo=%x pg0=%x\n", |
204 | num, in ? "in" : "out", item->info, item->page0); | 204 | num, in ? "in" : "out", item->info, item->page0); |
205 | 205 | ||
206 | len = (item->info >> 16) & 0x7fff; | 206 | len = (item->info >> 16) & 0x7fff; |
207 | ep->req.length -= len; | 207 | ep->req.length -= len; |
208 | DBG("ept%d %s complete %x\n", | 208 | DBG("ept%d %s complete %x\n", |
209 | num, in ? "in" : "out", len); | 209 | num, in ? "in" : "out", len); |
210 | ep->req.complete(&ep->ep, &ep->req); | 210 | ep->req.complete(&ep->ep, &ep->req); |
211 | if (num == 0) { | 211 | if (num == 0) { |
212 | ep->req.length = 0; | 212 | ep->req.length = 0; |
213 | usb_ep_queue(&ep->ep, &ep->req, 0); | 213 | usb_ep_queue(&ep->ep, &ep->req, 0); |
214 | ep->desc = &ep0_in_desc; | 214 | ep->desc = &ep0_in_desc; |
215 | } | 215 | } |
216 | } | 216 | } |
217 | 217 | ||
218 | #define SETUP(type, request) (((type) << 8) | (request)) | 218 | #define SETUP(type, request) (((type) << 8) | (request)) |
219 | 219 | ||
220 | static void handle_setup(void) | 220 | static void handle_setup(void) |
221 | { | 221 | { |
222 | struct usb_request *req = &controller.ep[0].req; | 222 | struct usb_request *req = &controller.ep[0].req; |
223 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; | 223 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; |
224 | struct ept_queue_head *head; | 224 | struct ept_queue_head *head; |
225 | struct usb_ctrlrequest r; | 225 | struct usb_ctrlrequest r; |
226 | int status = 0; | 226 | int status = 0; |
227 | int num, in, _num, _in, i; | 227 | int num, in, _num, _in, i; |
228 | char *buf; | 228 | char *buf; |
229 | head = epts; | 229 | head = epts; |
230 | 230 | ||
231 | flush_cache((unsigned long)head, sizeof(struct ept_queue_head)); | 231 | flush_cache((unsigned long)head, sizeof(struct ept_queue_head)); |
232 | memcpy(&r, head->setup_data, sizeof(struct usb_ctrlrequest)); | 232 | memcpy(&r, head->setup_data, sizeof(struct usb_ctrlrequest)); |
233 | writel(EPT_RX(0), &udc->epstat); | 233 | writel(EPT_RX(0), &udc->epstat); |
234 | DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest), | 234 | DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest), |
235 | r.bRequestType, r.bRequest, r.wIndex, r.wValue); | 235 | r.bRequestType, r.bRequest, r.wIndex, r.wValue); |
236 | 236 | ||
237 | switch (SETUP(r.bRequestType, r.bRequest)) { | 237 | switch (SETUP(r.bRequestType, r.bRequest)) { |
238 | case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE): | 238 | case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE): |
239 | _num = r.wIndex & 15; | 239 | _num = r.wIndex & 15; |
240 | _in = !!(r.wIndex & 0x80); | 240 | _in = !!(r.wIndex & 0x80); |
241 | 241 | ||
242 | if ((r.wValue == 0) && (r.wLength == 0)) { | 242 | if ((r.wValue == 0) && (r.wLength == 0)) { |
243 | req->length = 0; | 243 | req->length = 0; |
244 | for (i = 0; i < NUM_ENDPOINTS; i++) { | 244 | for (i = 0; i < NUM_ENDPOINTS; i++) { |
245 | if (!controller.ep[i].desc) | 245 | if (!controller.ep[i].desc) |
246 | continue; | 246 | continue; |
247 | num = controller.ep[i].desc->bEndpointAddress | 247 | num = controller.ep[i].desc->bEndpointAddress |
248 | & USB_ENDPOINT_NUMBER_MASK; | 248 | & USB_ENDPOINT_NUMBER_MASK; |
249 | in = (controller.ep[i].desc->bEndpointAddress | 249 | in = (controller.ep[i].desc->bEndpointAddress |
250 | & USB_DIR_IN) != 0; | 250 | & USB_DIR_IN) != 0; |
251 | if ((num == _num) && (in == _in)) { | 251 | if ((num == _num) && (in == _in)) { |
252 | ep_enable(num, in); | 252 | ep_enable(num, in); |
253 | usb_ep_queue(controller.gadget.ep0, | 253 | usb_ep_queue(controller.gadget.ep0, |
254 | req, 0); | 254 | req, 0); |
255 | break; | 255 | break; |
256 | } | 256 | } |
257 | } | 257 | } |
258 | } | 258 | } |
259 | return; | 259 | return; |
260 | 260 | ||
261 | case SETUP(USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS): | 261 | case SETUP(USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS): |
262 | /* | 262 | /* |
263 | * write address delayed (will take effect | 263 | * write address delayed (will take effect |
264 | * after the next IN txn) | 264 | * after the next IN txn) |
265 | */ | 265 | */ |
266 | writel((r.wValue << 25) | (1 << 24), &udc->devaddr); | 266 | writel((r.wValue << 25) | (1 << 24), &udc->devaddr); |
267 | req->length = 0; | 267 | req->length = 0; |
268 | usb_ep_queue(controller.gadget.ep0, req, 0); | 268 | usb_ep_queue(controller.gadget.ep0, req, 0); |
269 | return; | 269 | return; |
270 | 270 | ||
271 | case SETUP(USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_STATUS): | 271 | case SETUP(USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_STATUS): |
272 | req->length = 2; | 272 | req->length = 2; |
273 | buf = (char *)req->buf; | 273 | buf = (char *)req->buf; |
274 | buf[0] = 1 << USB_DEVICE_SELF_POWERED; | 274 | buf[0] = 1 << USB_DEVICE_SELF_POWERED; |
275 | buf[1] = 0; | 275 | buf[1] = 0; |
276 | usb_ep_queue(controller.gadget.ep0, req, 0); | 276 | usb_ep_queue(controller.gadget.ep0, req, 0); |
277 | return; | 277 | return; |
278 | } | 278 | } |
279 | /* pass request up to the gadget driver */ | 279 | /* pass request up to the gadget driver */ |
280 | if (controller.driver) | 280 | if (controller.driver) |
281 | status = controller.driver->setup(&controller.gadget, &r); | 281 | status = controller.driver->setup(&controller.gadget, &r); |
282 | else | 282 | else |
283 | status = -ENODEV; | 283 | status = -ENODEV; |
284 | 284 | ||
285 | if (!status) | 285 | if (!status) |
286 | return; | 286 | return; |
287 | DBG("STALL reqname %s type %x value %x, index %x\n", | 287 | DBG("STALL reqname %s type %x value %x, index %x\n", |
288 | reqname(r.bRequest), r.bRequestType, r.wValue, r.wIndex); | 288 | reqname(r.bRequest), r.bRequestType, r.wValue, r.wIndex); |
289 | writel((1<<16) | (1 << 0), &udc->epctrl[0]); | 289 | writel((1<<16) | (1 << 0), &udc->epctrl[0]); |
290 | } | 290 | } |
291 | 291 | ||
292 | static void stop_activity(void) | 292 | static void stop_activity(void) |
293 | { | 293 | { |
294 | int i, num, in; | 294 | int i, num, in; |
295 | struct ept_queue_head *head; | 295 | struct ept_queue_head *head; |
296 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; | 296 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; |
297 | writel(readl(&udc->epcomp), &udc->epcomp); | 297 | writel(readl(&udc->epcomp), &udc->epcomp); |
298 | writel(readl(&udc->epstat), &udc->epstat); | 298 | writel(readl(&udc->epstat), &udc->epstat); |
299 | writel(0xffffffff, &udc->epflush); | 299 | writel(0xffffffff, &udc->epflush); |
300 | 300 | ||
301 | /* error out any pending reqs */ | 301 | /* error out any pending reqs */ |
302 | for (i = 0; i < NUM_ENDPOINTS; i++) { | 302 | for (i = 0; i < NUM_ENDPOINTS; i++) { |
303 | if (i != 0) | 303 | if (i != 0) |
304 | writel(0, &udc->epctrl[i]); | 304 | writel(0, &udc->epctrl[i]); |
305 | if (controller.ep[i].desc) { | 305 | if (controller.ep[i].desc) { |
306 | num = controller.ep[i].desc->bEndpointAddress | 306 | num = controller.ep[i].desc->bEndpointAddress |
307 | & USB_ENDPOINT_NUMBER_MASK; | 307 | & USB_ENDPOINT_NUMBER_MASK; |
308 | in = (controller.ep[i].desc->bEndpointAddress | 308 | in = (controller.ep[i].desc->bEndpointAddress |
309 | & USB_DIR_IN) != 0; | 309 | & USB_DIR_IN) != 0; |
310 | head = epts + (num * 2) + (in); | 310 | head = epts + (num * 2) + (in); |
311 | head->info = INFO_ACTIVE; | 311 | head->info = INFO_ACTIVE; |
312 | } | 312 | } |
313 | } | 313 | } |
314 | } | 314 | } |
315 | 315 | ||
316 | void udc_irq(void) | 316 | void udc_irq(void) |
317 | { | 317 | { |
318 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; | 318 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; |
319 | unsigned n = readl(&udc->usbsts); | 319 | unsigned n = readl(&udc->usbsts); |
320 | writel(n, &udc->usbsts); | 320 | writel(n, &udc->usbsts); |
321 | int bit, i, num, in; | 321 | int bit, i, num, in; |
322 | 322 | ||
323 | n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI); | 323 | n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI); |
324 | if (n == 0) | 324 | if (n == 0) |
325 | return; | 325 | return; |
326 | 326 | ||
327 | if (n & STS_URI) { | 327 | if (n & STS_URI) { |
328 | DBG("-- reset --\n"); | 328 | DBG("-- reset --\n"); |
329 | stop_activity(); | 329 | stop_activity(); |
330 | } | 330 | } |
331 | if (n & STS_SLI) | 331 | if (n & STS_SLI) |
332 | DBG("-- suspend --\n"); | 332 | DBG("-- suspend --\n"); |
333 | 333 | ||
334 | if (n & STS_PCI) { | 334 | if (n & STS_PCI) { |
335 | DBG("-- portchange --\n"); | 335 | DBG("-- portchange --\n"); |
336 | bit = (readl(&udc->portsc) >> 26) & 3; | 336 | bit = (readl(&udc->portsc) >> 26) & 3; |
337 | if (bit == 2) { | 337 | if (bit == 2) { |
338 | controller.gadget.speed = USB_SPEED_HIGH; | 338 | controller.gadget.speed = USB_SPEED_HIGH; |
339 | for (i = 1; i < NUM_ENDPOINTS && n; i++) | 339 | for (i = 1; i < NUM_ENDPOINTS && n; i++) |
340 | if (controller.ep[i].desc) | 340 | if (controller.ep[i].desc) |
341 | controller.ep[i].ep.maxpacket = 512; | 341 | controller.ep[i].ep.maxpacket = 512; |
342 | } else { | 342 | } else { |
343 | controller.gadget.speed = USB_SPEED_FULL; | 343 | controller.gadget.speed = USB_SPEED_FULL; |
344 | } | 344 | } |
345 | } | 345 | } |
346 | 346 | ||
347 | if (n & STS_UEI) | 347 | if (n & STS_UEI) |
348 | printf("<UEI %x>\n", readl(&udc->epcomp)); | 348 | printf("<UEI %x>\n", readl(&udc->epcomp)); |
349 | 349 | ||
350 | if ((n & STS_UI) || (n & STS_UEI)) { | 350 | if ((n & STS_UI) || (n & STS_UEI)) { |
351 | n = readl(&udc->epstat); | 351 | n = readl(&udc->epstat); |
352 | if (n & EPT_RX(0)) | 352 | if (n & EPT_RX(0)) |
353 | handle_setup(); | 353 | handle_setup(); |
354 | 354 | ||
355 | n = readl(&udc->epcomp); | 355 | n = readl(&udc->epcomp); |
356 | if (n != 0) | 356 | if (n != 0) |
357 | writel(n, &udc->epcomp); | 357 | writel(n, &udc->epcomp); |
358 | 358 | ||
359 | for (i = 0; i < NUM_ENDPOINTS && n; i++) { | 359 | for (i = 0; i < NUM_ENDPOINTS && n; i++) { |
360 | if (controller.ep[i].desc) { | 360 | if (controller.ep[i].desc) { |
361 | num = controller.ep[i].desc->bEndpointAddress | 361 | num = controller.ep[i].desc->bEndpointAddress |
362 | & USB_ENDPOINT_NUMBER_MASK; | 362 | & USB_ENDPOINT_NUMBER_MASK; |
363 | in = (controller.ep[i].desc->bEndpointAddress | 363 | in = (controller.ep[i].desc->bEndpointAddress |
364 | & USB_DIR_IN) != 0; | 364 | & USB_DIR_IN) != 0; |
365 | bit = (in) ? EPT_TX(num) : EPT_RX(num); | 365 | bit = (in) ? EPT_TX(num) : EPT_RX(num); |
366 | if (n & bit) | 366 | if (n & bit) |
367 | handle_ep_complete(&controller.ep[i]); | 367 | handle_ep_complete(&controller.ep[i]); |
368 | } | 368 | } |
369 | } | 369 | } |
370 | } | 370 | } |
371 | } | 371 | } |
372 | 372 | ||
373 | int usb_gadget_handle_interrupts(void) | 373 | int usb_gadget_handle_interrupts(void) |
374 | { | 374 | { |
375 | u32 value; | 375 | u32 value; |
376 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; | 376 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; |
377 | 377 | ||
378 | value = readl(&udc->usbsts); | 378 | value = readl(&udc->usbsts); |
379 | if (value) | 379 | if (value) |
380 | udc_irq(); | 380 | udc_irq(); |
381 | 381 | ||
382 | return value; | 382 | return value; |
383 | } | 383 | } |
384 | 384 | ||
385 | static int mv_pullup(struct usb_gadget *gadget, int is_on) | 385 | static int mv_pullup(struct usb_gadget *gadget, int is_on) |
386 | { | 386 | { |
387 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; | 387 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; |
388 | if (is_on) { | 388 | if (is_on) { |
389 | /* RESET */ | 389 | /* RESET */ |
390 | writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RST, &udc->usbcmd); | 390 | writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RST, &udc->usbcmd); |
391 | udelay(200); | 391 | udelay(200); |
392 | 392 | ||
393 | writel((unsigned) epts, &udc->epinitaddr); | 393 | writel((unsigned) epts, &udc->epinitaddr); |
394 | 394 | ||
395 | /* select DEVICE mode */ | 395 | /* select DEVICE mode */ |
396 | writel(USBMODE_DEVICE, &udc->usbmode); | 396 | writel(USBMODE_DEVICE, &udc->usbmode); |
397 | 397 | ||
398 | writel(0xffffffff, &udc->epflush); | 398 | writel(0xffffffff, &udc->epflush); |
399 | 399 | ||
400 | /* Turn on the USB connection by enabling the pullup resistor */ | 400 | /* Turn on the USB connection by enabling the pullup resistor */ |
401 | writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RUN, &udc->usbcmd); | 401 | writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RUN, &udc->usbcmd); |
402 | } else { | 402 | } else { |
403 | stop_activity(); | 403 | stop_activity(); |
404 | writel(USBCMD_FS2, &udc->usbcmd); | 404 | writel(USBCMD_FS2, &udc->usbcmd); |
405 | udelay(800); | 405 | udelay(800); |
406 | if (controller.driver) | 406 | if (controller.driver) |
407 | controller.driver->disconnect(gadget); | 407 | controller.driver->disconnect(gadget); |
408 | } | 408 | } |
409 | 409 | ||
410 | return 0; | 410 | return 0; |
411 | } | 411 | } |
412 | 412 | ||
413 | void udc_disconnect(void) | 413 | void udc_disconnect(void) |
414 | { | 414 | { |
415 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; | 415 | struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor; |
416 | /* disable pullup */ | 416 | /* disable pullup */ |
417 | stop_activity(); | 417 | stop_activity(); |
418 | writel(USBCMD_FS2, &udc->usbcmd); | 418 | writel(USBCMD_FS2, &udc->usbcmd); |
419 | udelay(800); | 419 | udelay(800); |
420 | if (controller.driver) | 420 | if (controller.driver) |
421 | controller.driver->disconnect(&controller.gadget); | 421 | controller.driver->disconnect(&controller.gadget); |
422 | } | 422 | } |
423 | 423 | ||
424 | static int mvudc_probe(void) | 424 | static int mvudc_probe(void) |
425 | { | 425 | { |
426 | struct ept_queue_head *head; | 426 | struct ept_queue_head *head; |
427 | int i; | 427 | int i; |
428 | 428 | ||
429 | controller.gadget.ops = &mv_udc_ops; | 429 | controller.gadget.ops = &mv_udc_ops; |
430 | epts = memalign(PAGE_SIZE, QH_MAXNUM * sizeof(struct ept_queue_head)); | 430 | epts = memalign(PAGE_SIZE, QH_MAXNUM * sizeof(struct ept_queue_head)); |
431 | memset(epts, 0, QH_MAXNUM * sizeof(struct ept_queue_head)); | 431 | memset(epts, 0, QH_MAXNUM * sizeof(struct ept_queue_head)); |
432 | for (i = 0; i < 2 * NUM_ENDPOINTS; i++) { | 432 | for (i = 0; i < 2 * NUM_ENDPOINTS; i++) { |
433 | /* | 433 | /* |
434 | * For item0 and item1, they are served as ep0 | 434 | * For item0 and item1, they are served as ep0 |
435 | * out&in seperately | 435 | * out&in seperately |
436 | */ | 436 | */ |
437 | head = epts + i; | 437 | head = epts + i; |
438 | if (i < 2) | 438 | if (i < 2) |
439 | head->config = CONFIG_MAX_PKT(EP0_MAX_PACKET_SIZE) | 439 | head->config = CONFIG_MAX_PKT(EP0_MAX_PACKET_SIZE) |
440 | | CONFIG_ZLT | CONFIG_IOS; | 440 | | CONFIG_ZLT | CONFIG_IOS; |
441 | else | 441 | else |
442 | head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE) | 442 | head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE) |
443 | | CONFIG_ZLT; | 443 | | CONFIG_ZLT; |
444 | head->next = TERMINATE; | 444 | head->next = TERMINATE; |
445 | head->info = 0; | 445 | head->info = 0; |
446 | 446 | ||
447 | items[i] = memalign(PAGE_SIZE, sizeof(struct ept_queue_item)); | 447 | items[i] = memalign(PAGE_SIZE, sizeof(struct ept_queue_item)); |
448 | } | 448 | } |
449 | 449 | ||
450 | INIT_LIST_HEAD(&controller.gadget.ep_list); | 450 | INIT_LIST_HEAD(&controller.gadget.ep_list); |
451 | 451 | ||
452 | /* Init EP 0 */ | 452 | /* Init EP 0 */ |
453 | memcpy(&controller.ep[0].ep, &mv_ep_init[0], sizeof(*mv_ep_init)); | 453 | memcpy(&controller.ep[0].ep, &mv_ep_init[0], sizeof(*mv_ep_init)); |
454 | controller.ep[0].desc = &ep0_in_desc; | 454 | controller.ep[0].desc = &ep0_in_desc; |
455 | controller.gadget.ep0 = &controller.ep[0].ep; | 455 | controller.gadget.ep0 = &controller.ep[0].ep; |
456 | INIT_LIST_HEAD(&controller.gadget.ep0->ep_list); | 456 | INIT_LIST_HEAD(&controller.gadget.ep0->ep_list); |
457 | 457 | ||
458 | /* Init EP 1..n */ | 458 | /* Init EP 1..n */ |
459 | for (i = 1; i < NUM_ENDPOINTS; i++) { | 459 | for (i = 1; i < NUM_ENDPOINTS; i++) { |
460 | memcpy(&controller.ep[i].ep, &mv_ep_init[1], | 460 | memcpy(&controller.ep[i].ep, &mv_ep_init[1], |
461 | sizeof(*mv_ep_init)); | 461 | sizeof(*mv_ep_init)); |
462 | list_add_tail(&controller.ep[i].ep.ep_list, | 462 | list_add_tail(&controller.ep[i].ep.ep_list, |
463 | &controller.gadget.ep_list); | 463 | &controller.gadget.ep_list); |
464 | } | 464 | } |
465 | 465 | ||
466 | return 0; | 466 | return 0; |
467 | } | 467 | } |
468 | 468 | ||
469 | int usb_gadget_register_driver(struct usb_gadget_driver *driver) | 469 | int usb_gadget_register_driver(struct usb_gadget_driver *driver) |
470 | { | 470 | { |
471 | struct mv_udc *udc; | 471 | struct mv_udc *udc; |
472 | int ret; | 472 | int ret; |
473 | 473 | ||
474 | if (!driver | 474 | if (!driver) |
475 | || driver->speed < USB_SPEED_FULL | ||
476 | || !driver->bind | ||
477 | || !driver->setup) { | ||
478 | DBG("bad parameter.\n"); | ||
479 | return -EINVAL; | 475 | return -EINVAL; |
480 | } | 476 | if (!driver->bind || !driver->setup || !driver->disconnect) |
477 | return -EINVAL; | ||
478 | if (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH) | ||
479 | return -EINVAL; | ||
481 | 480 | ||
482 | ret = usb_lowlevel_init(0, (void **)&controller.ctrl); | 481 | ret = usb_lowlevel_init(0, (void **)&controller.ctrl); |
483 | if (ret) | 482 | if (ret) |
484 | return ret; | 483 | return ret; |
485 | 484 | ||
486 | ret = mvudc_probe(); | 485 | ret = mvudc_probe(); |
487 | if (!ret) { | 486 | if (!ret) { |
488 | udc = (struct mv_udc *)controller.ctrl->hcor; | 487 | udc = (struct mv_udc *)controller.ctrl->hcor; |
489 | 488 | ||
490 | /* select ULPI phy */ | 489 | /* select ULPI phy */ |
491 | writel(PTS(PTS_ENABLE) | PFSC, &udc->portsc); | 490 | writel(PTS(PTS_ENABLE) | PFSC, &udc->portsc); |
492 | } | 491 | } |
493 | 492 | ||
494 | ret = driver->bind(&controller.gadget); | 493 | ret = driver->bind(&controller.gadget); |
495 | if (ret) { | 494 | if (ret) { |
496 | DBG("driver->bind() returned %d\n", ret); | 495 | DBG("driver->bind() returned %d\n", ret); |
497 | return ret; | 496 | return ret; |
498 | } | 497 | } |
499 | controller.driver = driver; | 498 | controller.driver = driver; |
500 | 499 | ||
501 | return 0; | 500 | return 0; |
502 | } | 501 | } |
503 | 502 | ||
504 | int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) | 503 | int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) |
505 | { | 504 | { |