]>
Commit | Line | Data |
---|---|---|
38517a78 ŁM |
1 | /* |
2 | * drivers/usb/gadget/s3c_udc_otg_xfer_dma.c | |
3 | * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers | |
4 | * | |
5 | * Copyright (C) 2009 for Samsung Electronics | |
6 | * | |
7 | * BSP Support for Samsung's UDC driver | |
8 | * available at: | |
9 | * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git | |
10 | * | |
11 | * State machine bugfixes: | |
12 | * Marek Szyprowski <m.szyprowski@samsung.com> | |
13 | * | |
14 | * Ported to u-boot: | |
15 | * Marek Szyprowski <m.szyprowski@samsung.com> | |
16 | * Lukasz Majewski <l.majewski@samsumg.com> | |
17 | * | |
1a459660 | 18 | * SPDX-License-Identifier: GPL-2.0+ |
38517a78 ŁM |
19 | */ |
20 | ||
21 | static u8 clear_feature_num; | |
22 | int clear_feature_flag; | |
23 | ||
24 | /* Bulk-Only Mass Storage Reset (class-specific request) */ | |
25 | #define GET_MAX_LUN_REQUEST 0xFE | |
26 | #define BOT_RESET_REQUEST 0xFF | |
27 | ||
28 | static inline void s3c_udc_ep0_zlp(struct s3c_udc *dev) | |
29 | { | |
30 | u32 ep_ctrl; | |
31 | ||
32 | flush_dcache_range((unsigned long) usb_ctrl_dma_addr, | |
33 | (unsigned long) usb_ctrl_dma_addr | |
34 | + DMA_BUFFER_SIZE); | |
35 | ||
36 | writel(usb_ctrl_dma_addr, ®->in_endp[EP0_CON].diepdma); | |
37 | writel(DIEPT_SIZ_PKT_CNT(1), ®->in_endp[EP0_CON].dieptsiz); | |
38 | ||
39 | ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); | |
40 | writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, | |
41 | ®->in_endp[EP0_CON].diepctl); | |
42 | ||
f3b05ca5 | 43 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", |
38517a78 ŁM |
44 | __func__, readl(®->in_endp[EP0_CON].diepctl)); |
45 | dev->ep0state = WAIT_FOR_IN_COMPLETE; | |
46 | } | |
47 | ||
48 | void s3c_udc_pre_setup(void) | |
49 | { | |
50 | u32 ep_ctrl; | |
51 | ||
f3b05ca5 ŁM |
52 | debug_cond(DEBUG_IN_EP, |
53 | "%s : Prepare Setup packets.\n", __func__); | |
38517a78 ŁM |
54 | |
55 | invalidate_dcache_range((unsigned long) usb_ctrl_dma_addr, | |
56 | (unsigned long) usb_ctrl_dma_addr | |
57 | + DMA_BUFFER_SIZE); | |
58 | ||
59 | writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest), | |
60 | ®->out_endp[EP0_CON].doeptsiz); | |
61 | writel(usb_ctrl_dma_addr, ®->out_endp[EP0_CON].doepdma); | |
62 | ||
63 | ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); | |
64 | writel(ep_ctrl|DEPCTL_EPENA, ®->out_endp[EP0_CON].doepctl); | |
65 | ||
f3b05ca5 | 66 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", |
38517a78 | 67 | __func__, readl(®->in_endp[EP0_CON].diepctl)); |
f3b05ca5 | 68 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", |
38517a78 ŁM |
69 | __func__, readl(®->out_endp[EP0_CON].doepctl)); |
70 | ||
71 | } | |
72 | ||
73 | static inline void s3c_ep0_complete_out(void) | |
74 | { | |
75 | u32 ep_ctrl; | |
76 | ||
f3b05ca5 | 77 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", |
38517a78 | 78 | __func__, readl(®->in_endp[EP0_CON].diepctl)); |
f3b05ca5 | 79 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", |
38517a78 ŁM |
80 | __func__, readl(®->out_endp[EP0_CON].doepctl)); |
81 | ||
ea2d9159 AG |
82 | debug_cond(DEBUG_IN_EP, |
83 | "%s : Prepare Complete Out packet.\n", __func__); | |
38517a78 ŁM |
84 | |
85 | invalidate_dcache_range((unsigned long) usb_ctrl_dma_addr, | |
86 | (unsigned long) usb_ctrl_dma_addr | |
87 | + DMA_BUFFER_SIZE); | |
88 | ||
89 | writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest), | |
90 | ®->out_endp[EP0_CON].doeptsiz); | |
91 | writel(usb_ctrl_dma_addr, ®->out_endp[EP0_CON].doepdma); | |
92 | ||
93 | ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); | |
94 | writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, | |
95 | ®->out_endp[EP0_CON].doepctl); | |
96 | ||
f3b05ca5 | 97 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", |
38517a78 | 98 | __func__, readl(®->in_endp[EP0_CON].diepctl)); |
f3b05ca5 | 99 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", |
38517a78 ŁM |
100 | __func__, readl(®->out_endp[EP0_CON].doepctl)); |
101 | ||
102 | } | |
103 | ||
104 | ||
105 | static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req) | |
106 | { | |
107 | u32 *buf, ctrl; | |
108 | u32 length, pktcnt; | |
109 | u32 ep_num = ep_index(ep); | |
110 | ||
111 | buf = req->req.buf + req->req.actual; | |
112 | ||
113 | length = min(req->req.length - req->req.actual, (int)ep->ep.maxpacket); | |
114 | ||
115 | ep->len = length; | |
116 | ep->dma_buf = buf; | |
117 | ||
118 | invalidate_dcache_range((unsigned long) ep->dev->dma_buf[ep_num], | |
119 | (unsigned long) ep->dev->dma_buf[ep_num] | |
120 | + DMA_BUFFER_SIZE); | |
121 | ||
122 | if (length == 0) | |
123 | pktcnt = 1; | |
124 | else | |
125 | pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; | |
126 | ||
127 | pktcnt = 1; | |
128 | ctrl = readl(®->out_endp[ep_num].doepctl); | |
129 | ||
130 | writel(the_controller->dma_addr[ep_index(ep)+1], | |
131 | ®->out_endp[ep_num].doepdma); | |
132 | writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length), | |
133 | ®->out_endp[ep_num].doeptsiz); | |
134 | writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->out_endp[ep_num].doepctl); | |
135 | ||
f3b05ca5 ŁM |
136 | debug_cond(DEBUG_OUT_EP != 0, |
137 | "%s: EP%d RX DMA start : DOEPDMA = 0x%x," | |
138 | "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n" | |
139 | "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", | |
140 | __func__, ep_num, | |
141 | readl(®->out_endp[ep_num].doepdma), | |
142 | readl(®->out_endp[ep_num].doeptsiz), | |
143 | readl(®->out_endp[ep_num].doepctl), | |
144 | buf, pktcnt, length); | |
38517a78 ŁM |
145 | return 0; |
146 | ||
147 | } | |
148 | ||
149 | int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) | |
150 | { | |
151 | u32 *buf, ctrl = 0; | |
152 | u32 length, pktcnt; | |
153 | u32 ep_num = ep_index(ep); | |
154 | u32 *p = the_controller->dma_buf[ep_index(ep)+1]; | |
155 | ||
156 | buf = req->req.buf + req->req.actual; | |
157 | length = req->req.length - req->req.actual; | |
158 | ||
159 | if (ep_num == EP0_CON) | |
6777a3cf | 160 | length = min(length, (u32)ep_maxpacket(ep)); |
38517a78 ŁM |
161 | |
162 | ep->len = length; | |
163 | ep->dma_buf = buf; | |
164 | memcpy(p, ep->dma_buf, length); | |
165 | ||
166 | flush_dcache_range((unsigned long) p , | |
167 | (unsigned long) p + DMA_BUFFER_SIZE); | |
168 | ||
169 | if (length == 0) | |
170 | pktcnt = 1; | |
171 | else | |
172 | pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; | |
173 | ||
174 | /* Flush the endpoint's Tx FIFO */ | |
175 | writel(TX_FIFO_NUMBER(ep->fifo_num), ®->grstctl); | |
176 | writel(TX_FIFO_NUMBER(ep->fifo_num) | TX_FIFO_FLUSH, ®->grstctl); | |
177 | while (readl(®->grstctl) & TX_FIFO_FLUSH) | |
178 | ; | |
179 | ||
180 | writel(the_controller->dma_addr[ep_index(ep)+1], | |
181 | ®->in_endp[ep_num].diepdma); | |
182 | writel(DIEPT_SIZ_PKT_CNT(pktcnt) | DIEPT_SIZ_XFER_SIZE(length), | |
183 | ®->in_endp[ep_num].dieptsiz); | |
184 | ||
185 | ctrl = readl(®->in_endp[ep_num].diepctl); | |
186 | ||
187 | /* Write the FIFO number to be used for this endpoint */ | |
188 | ctrl &= DIEPCTL_TX_FIFO_NUM_MASK; | |
189 | ctrl |= DIEPCTL_TX_FIFO_NUM(ep->fifo_num); | |
190 | ||
191 | /* Clear reserved (Next EP) bits */ | |
192 | ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT)); | |
193 | ||
194 | writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->in_endp[ep_num].diepctl); | |
195 | ||
ea2d9159 AG |
196 | debug_cond(DEBUG_IN_EP, |
197 | "%s:EP%d TX DMA start : DIEPDMA0 = 0x%x," | |
198 | "DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" | |
199 | "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", | |
200 | __func__, ep_num, | |
201 | readl(®->in_endp[ep_num].diepdma), | |
202 | readl(®->in_endp[ep_num].dieptsiz), | |
203 | readl(®->in_endp[ep_num].diepctl), | |
204 | buf, pktcnt, length); | |
38517a78 ŁM |
205 | |
206 | return length; | |
207 | } | |
208 | ||
209 | static void complete_rx(struct s3c_udc *dev, u8 ep_num) | |
210 | { | |
211 | struct s3c_ep *ep = &dev->ep[ep_num]; | |
212 | struct s3c_request *req = NULL; | |
213 | u32 ep_tsr = 0, xfer_size = 0, is_short = 0; | |
214 | u32 *p = the_controller->dma_buf[ep_index(ep)+1]; | |
215 | ||
216 | if (list_empty(&ep->queue)) { | |
f3b05ca5 ŁM |
217 | debug_cond(DEBUG_OUT_EP != 0, |
218 | "%s: RX DMA done : NULL REQ on OUT EP-%d\n", | |
219 | __func__, ep_num); | |
38517a78 ŁM |
220 | return; |
221 | ||
222 | } | |
223 | ||
224 | req = list_entry(ep->queue.next, struct s3c_request, queue); | |
225 | ep_tsr = readl(®->out_endp[ep_num].doeptsiz); | |
226 | ||
227 | if (ep_num == EP0_CON) | |
228 | xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP0); | |
229 | else | |
230 | xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP); | |
231 | ||
232 | xfer_size = ep->len - xfer_size; | |
233 | ||
234 | invalidate_dcache_range((unsigned long) p, | |
235 | (unsigned long) p + DMA_BUFFER_SIZE); | |
236 | ||
237 | memcpy(ep->dma_buf, p, ep->len); | |
238 | ||
239 | req->req.actual += min(xfer_size, req->req.length - req->req.actual); | |
240 | is_short = (xfer_size < ep->ep.maxpacket); | |
241 | ||
f3b05ca5 ŁM |
242 | debug_cond(DEBUG_OUT_EP != 0, |
243 | "%s: RX DMA done : ep = %d, rx bytes = %d/%d, " | |
244 | "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n", | |
245 | __func__, ep_num, req->req.actual, req->req.length, | |
246 | is_short, ep_tsr, xfer_size); | |
38517a78 ŁM |
247 | |
248 | if (is_short || req->req.actual == req->req.length) { | |
249 | if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) { | |
f3b05ca5 | 250 | debug_cond(DEBUG_OUT_EP != 0, " => Send ZLP\n"); |
38517a78 ŁM |
251 | s3c_udc_ep0_zlp(dev); |
252 | /* packet will be completed in complete_tx() */ | |
253 | dev->ep0state = WAIT_FOR_IN_COMPLETE; | |
254 | } else { | |
255 | done(ep, req, 0); | |
256 | ||
257 | if (!list_empty(&ep->queue)) { | |
258 | req = list_entry(ep->queue.next, | |
259 | struct s3c_request, queue); | |
f3b05ca5 ŁM |
260 | debug_cond(DEBUG_OUT_EP != 0, |
261 | "%s: Next Rx request start...\n", | |
262 | __func__); | |
38517a78 ŁM |
263 | setdma_rx(ep, req); |
264 | } | |
265 | } | |
266 | } else | |
267 | setdma_rx(ep, req); | |
268 | } | |
269 | ||
270 | static void complete_tx(struct s3c_udc *dev, u8 ep_num) | |
271 | { | |
272 | struct s3c_ep *ep = &dev->ep[ep_num]; | |
273 | struct s3c_request *req; | |
274 | u32 ep_tsr = 0, xfer_size = 0, is_short = 0; | |
275 | u32 last; | |
276 | ||
277 | if (dev->ep0state == WAIT_FOR_NULL_COMPLETE) { | |
278 | dev->ep0state = WAIT_FOR_OUT_COMPLETE; | |
279 | s3c_ep0_complete_out(); | |
280 | return; | |
281 | } | |
282 | ||
283 | if (list_empty(&ep->queue)) { | |
ea2d9159 AG |
284 | debug_cond(DEBUG_IN_EP, |
285 | "%s: TX DMA done : NULL REQ on IN EP-%d\n", | |
286 | __func__, ep_num); | |
38517a78 ŁM |
287 | return; |
288 | ||
289 | } | |
290 | ||
291 | req = list_entry(ep->queue.next, struct s3c_request, queue); | |
292 | ||
293 | ep_tsr = readl(®->in_endp[ep_num].dieptsiz); | |
294 | ||
295 | xfer_size = ep->len; | |
296 | is_short = (xfer_size < ep->ep.maxpacket); | |
297 | req->req.actual += min(xfer_size, req->req.length - req->req.actual); | |
298 | ||
ea2d9159 AG |
299 | debug_cond(DEBUG_IN_EP, |
300 | "%s: TX DMA done : ep = %d, tx bytes = %d/%d, " | |
301 | "is_short = %d, DIEPTSIZ = 0x%x, remained bytes = %d\n", | |
302 | __func__, ep_num, req->req.actual, req->req.length, | |
303 | is_short, ep_tsr, xfer_size); | |
38517a78 ŁM |
304 | |
305 | if (ep_num == 0) { | |
306 | if (dev->ep0state == DATA_STATE_XMIT) { | |
ea2d9159 AG |
307 | debug_cond(DEBUG_IN_EP, |
308 | "%s: ep_num = %d, ep0stat ==" | |
309 | "DATA_STATE_XMIT\n", | |
310 | __func__, ep_num); | |
38517a78 ŁM |
311 | last = write_fifo_ep0(ep, req); |
312 | if (last) | |
313 | dev->ep0state = WAIT_FOR_COMPLETE; | |
314 | } else if (dev->ep0state == WAIT_FOR_IN_COMPLETE) { | |
ea2d9159 AG |
315 | debug_cond(DEBUG_IN_EP, |
316 | "%s: ep_num = %d, completing request\n", | |
317 | __func__, ep_num); | |
38517a78 ŁM |
318 | done(ep, req, 0); |
319 | dev->ep0state = WAIT_FOR_SETUP; | |
320 | } else if (dev->ep0state == WAIT_FOR_COMPLETE) { | |
ea2d9159 AG |
321 | debug_cond(DEBUG_IN_EP, |
322 | "%s: ep_num = %d, completing request\n", | |
323 | __func__, ep_num); | |
38517a78 ŁM |
324 | done(ep, req, 0); |
325 | dev->ep0state = WAIT_FOR_OUT_COMPLETE; | |
326 | s3c_ep0_complete_out(); | |
327 | } else { | |
ea2d9159 AG |
328 | debug_cond(DEBUG_IN_EP, |
329 | "%s: ep_num = %d, invalid ep state\n", | |
330 | __func__, ep_num); | |
38517a78 ŁM |
331 | } |
332 | return; | |
333 | } | |
334 | ||
335 | if (req->req.actual == req->req.length) | |
336 | done(ep, req, 0); | |
337 | ||
338 | if (!list_empty(&ep->queue)) { | |
339 | req = list_entry(ep->queue.next, struct s3c_request, queue); | |
ea2d9159 AG |
340 | debug_cond(DEBUG_IN_EP, |
341 | "%s: Next Tx request start...\n", __func__); | |
38517a78 ŁM |
342 | setdma_tx(ep, req); |
343 | } | |
344 | } | |
345 | ||
346 | static inline void s3c_udc_check_tx_queue(struct s3c_udc *dev, u8 ep_num) | |
347 | { | |
348 | struct s3c_ep *ep = &dev->ep[ep_num]; | |
349 | struct s3c_request *req; | |
350 | ||
ea2d9159 AG |
351 | debug_cond(DEBUG_IN_EP, |
352 | "%s: Check queue, ep_num = %d\n", __func__, ep_num); | |
38517a78 ŁM |
353 | |
354 | if (!list_empty(&ep->queue)) { | |
355 | req = list_entry(ep->queue.next, struct s3c_request, queue); | |
ea2d9159 AG |
356 | debug_cond(DEBUG_IN_EP, |
357 | "%s: Next Tx request(0x%p) start...\n", | |
358 | __func__, req); | |
38517a78 ŁM |
359 | |
360 | if (ep_is_in(ep)) | |
361 | setdma_tx(ep, req); | |
362 | else | |
363 | setdma_rx(ep, req); | |
364 | } else { | |
ea2d9159 AG |
365 | debug_cond(DEBUG_IN_EP, |
366 | "%s: NULL REQ on IN EP-%d\n", __func__, ep_num); | |
38517a78 ŁM |
367 | |
368 | return; | |
369 | } | |
370 | ||
371 | } | |
372 | ||
373 | static void process_ep_in_intr(struct s3c_udc *dev) | |
374 | { | |
375 | u32 ep_intr, ep_intr_status; | |
376 | u8 ep_num = 0; | |
377 | ||
378 | ep_intr = readl(®->daint); | |
ea2d9159 AG |
379 | debug_cond(DEBUG_IN_EP, |
380 | "*** %s: EP In interrupt : DAINT = 0x%x\n", __func__, ep_intr); | |
38517a78 ŁM |
381 | |
382 | ep_intr &= DAINT_MASK; | |
383 | ||
384 | while (ep_intr) { | |
385 | if (ep_intr & DAINT_IN_EP_INT(1)) { | |
386 | ep_intr_status = readl(®->in_endp[ep_num].diepint); | |
f3b05ca5 ŁM |
387 | debug_cond(DEBUG_IN_EP, |
388 | "\tEP%d-IN : DIEPINT = 0x%x\n", | |
389 | ep_num, ep_intr_status); | |
38517a78 ŁM |
390 | |
391 | /* Interrupt Clear */ | |
392 | writel(ep_intr_status, ®->in_endp[ep_num].diepint); | |
393 | ||
394 | if (ep_intr_status & TRANSFER_DONE) { | |
395 | complete_tx(dev, ep_num); | |
396 | ||
397 | if (ep_num == 0) { | |
398 | if (dev->ep0state == | |
399 | WAIT_FOR_IN_COMPLETE) | |
400 | dev->ep0state = WAIT_FOR_SETUP; | |
401 | ||
402 | if (dev->ep0state == WAIT_FOR_SETUP) | |
403 | s3c_udc_pre_setup(); | |
404 | ||
405 | /* continue transfer after | |
406 | set_clear_halt for DMA mode */ | |
407 | if (clear_feature_flag == 1) { | |
408 | s3c_udc_check_tx_queue(dev, | |
409 | clear_feature_num); | |
410 | clear_feature_flag = 0; | |
411 | } | |
412 | } | |
413 | } | |
414 | } | |
415 | ep_num++; | |
416 | ep_intr >>= 1; | |
417 | } | |
418 | } | |
419 | ||
420 | static void process_ep_out_intr(struct s3c_udc *dev) | |
421 | { | |
422 | u32 ep_intr, ep_intr_status; | |
423 | u8 ep_num = 0; | |
424 | ||
425 | ep_intr = readl(®->daint); | |
f3b05ca5 ŁM |
426 | debug_cond(DEBUG_OUT_EP != 0, |
427 | "*** %s: EP OUT interrupt : DAINT = 0x%x\n", | |
428 | __func__, ep_intr); | |
38517a78 ŁM |
429 | |
430 | ep_intr = (ep_intr >> DAINT_OUT_BIT) & DAINT_MASK; | |
431 | ||
432 | while (ep_intr) { | |
433 | if (ep_intr & 0x1) { | |
434 | ep_intr_status = readl(®->out_endp[ep_num].doepint); | |
f3b05ca5 ŁM |
435 | debug_cond(DEBUG_OUT_EP != 0, |
436 | "\tEP%d-OUT : DOEPINT = 0x%x\n", | |
437 | ep_num, ep_intr_status); | |
38517a78 ŁM |
438 | |
439 | /* Interrupt Clear */ | |
440 | writel(ep_intr_status, ®->out_endp[ep_num].doepint); | |
441 | ||
442 | if (ep_num == 0) { | |
443 | if (ep_intr_status & TRANSFER_DONE) { | |
444 | if (dev->ep0state != | |
445 | WAIT_FOR_OUT_COMPLETE) | |
446 | complete_rx(dev, ep_num); | |
447 | else { | |
448 | dev->ep0state = WAIT_FOR_SETUP; | |
449 | s3c_udc_pre_setup(); | |
450 | } | |
451 | } | |
452 | ||
453 | if (ep_intr_status & | |
454 | CTRL_OUT_EP_SETUP_PHASE_DONE) { | |
f3b05ca5 ŁM |
455 | debug_cond(DEBUG_OUT_EP != 0, |
456 | "SETUP packet arrived\n"); | |
38517a78 ŁM |
457 | s3c_handle_ep0(dev); |
458 | } | |
459 | } else { | |
460 | if (ep_intr_status & TRANSFER_DONE) | |
461 | complete_rx(dev, ep_num); | |
462 | } | |
463 | } | |
464 | ep_num++; | |
465 | ep_intr >>= 1; | |
466 | } | |
467 | } | |
468 | ||
469 | /* | |
470 | * usb client interrupt handler. | |
471 | */ | |
472 | static int s3c_udc_irq(int irq, void *_dev) | |
473 | { | |
474 | struct s3c_udc *dev = _dev; | |
475 | u32 intr_status; | |
476 | u32 usb_status, gintmsk; | |
477 | unsigned long flags; | |
478 | ||
479 | spin_lock_irqsave(&dev->lock, flags); | |
480 | ||
481 | intr_status = readl(®->gintsts); | |
482 | gintmsk = readl(®->gintmsk); | |
483 | ||
ea2d9159 AG |
484 | debug_cond(DEBUG_ISR, |
485 | "\n*** %s : GINTSTS=0x%x(on state %s), GINTMSK : 0x%x," | |
38517a78 ŁM |
486 | "DAINT : 0x%x, DAINTMSK : 0x%x\n", |
487 | __func__, intr_status, state_names[dev->ep0state], gintmsk, | |
488 | readl(®->daint), readl(®->daintmsk)); | |
489 | ||
490 | if (!intr_status) { | |
491 | spin_unlock_irqrestore(&dev->lock, flags); | |
492 | return IRQ_HANDLED; | |
493 | } | |
494 | ||
495 | if (intr_status & INT_ENUMDONE) { | |
ea2d9159 | 496 | debug_cond(DEBUG_ISR, "\tSpeed Detection interrupt\n"); |
38517a78 ŁM |
497 | |
498 | writel(INT_ENUMDONE, ®->gintsts); | |
499 | usb_status = (readl(®->dsts) & 0x6); | |
500 | ||
501 | if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) { | |
f3b05ca5 ŁM |
502 | debug_cond(DEBUG_ISR, |
503 | "\t\tFull Speed Detection\n"); | |
38517a78 ŁM |
504 | set_max_pktsize(dev, USB_SPEED_FULL); |
505 | ||
506 | } else { | |
ea2d9159 AG |
507 | debug_cond(DEBUG_ISR, |
508 | "\t\tHigh Speed Detection : 0x%x\n", | |
509 | usb_status); | |
38517a78 ŁM |
510 | set_max_pktsize(dev, USB_SPEED_HIGH); |
511 | } | |
512 | } | |
513 | ||
514 | if (intr_status & INT_EARLY_SUSPEND) { | |
ea2d9159 | 515 | debug_cond(DEBUG_ISR, "\tEarly suspend interrupt\n"); |
38517a78 ŁM |
516 | writel(INT_EARLY_SUSPEND, ®->gintsts); |
517 | } | |
518 | ||
519 | if (intr_status & INT_SUSPEND) { | |
520 | usb_status = readl(®->dsts); | |
ea2d9159 AG |
521 | debug_cond(DEBUG_ISR, |
522 | "\tSuspend interrupt :(DSTS):0x%x\n", usb_status); | |
38517a78 ŁM |
523 | writel(INT_SUSPEND, ®->gintsts); |
524 | ||
525 | if (dev->gadget.speed != USB_SPEED_UNKNOWN | |
526 | && dev->driver) { | |
527 | if (dev->driver->suspend) | |
528 | dev->driver->suspend(&dev->gadget); | |
529 | ||
530 | /* HACK to let gadget detect disconnected state */ | |
531 | if (dev->driver->disconnect) { | |
532 | spin_unlock_irqrestore(&dev->lock, flags); | |
533 | dev->driver->disconnect(&dev->gadget); | |
534 | spin_lock_irqsave(&dev->lock, flags); | |
535 | } | |
536 | } | |
537 | } | |
538 | ||
539 | if (intr_status & INT_RESUME) { | |
ea2d9159 | 540 | debug_cond(DEBUG_ISR, "\tResume interrupt\n"); |
38517a78 ŁM |
541 | writel(INT_RESUME, ®->gintsts); |
542 | ||
543 | if (dev->gadget.speed != USB_SPEED_UNKNOWN | |
544 | && dev->driver | |
545 | && dev->driver->resume) { | |
546 | ||
547 | dev->driver->resume(&dev->gadget); | |
548 | } | |
549 | } | |
550 | ||
551 | if (intr_status & INT_RESET) { | |
552 | usb_status = readl(®->gotgctl); | |
ea2d9159 AG |
553 | debug_cond(DEBUG_ISR, |
554 | "\tReset interrupt - (GOTGCTL):0x%x\n", usb_status); | |
38517a78 ŁM |
555 | writel(INT_RESET, ®->gintsts); |
556 | ||
557 | if ((usb_status & 0xc0000) == (0x3 << 18)) { | |
558 | if (reset_available) { | |
ea2d9159 AG |
559 | debug_cond(DEBUG_ISR, |
560 | "\t\tOTG core got reset (%d)!!\n", | |
561 | reset_available); | |
38517a78 ŁM |
562 | reconfig_usbd(); |
563 | dev->ep0state = WAIT_FOR_SETUP; | |
564 | reset_available = 0; | |
565 | s3c_udc_pre_setup(); | |
566 | } else | |
567 | reset_available = 1; | |
568 | ||
569 | } else { | |
570 | reset_available = 1; | |
f3b05ca5 ŁM |
571 | debug_cond(DEBUG_ISR, |
572 | "\t\tRESET handling skipped\n"); | |
38517a78 ŁM |
573 | } |
574 | } | |
575 | ||
576 | if (intr_status & INT_IN_EP) | |
577 | process_ep_in_intr(dev); | |
578 | ||
579 | if (intr_status & INT_OUT_EP) | |
580 | process_ep_out_intr(dev); | |
581 | ||
582 | spin_unlock_irqrestore(&dev->lock, flags); | |
583 | ||
584 | return IRQ_HANDLED; | |
585 | } | |
586 | ||
587 | /** Queue one request | |
588 | * Kickstart transfer if needed | |
589 | */ | |
590 | static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req, | |
591 | gfp_t gfp_flags) | |
592 | { | |
593 | struct s3c_request *req; | |
594 | struct s3c_ep *ep; | |
595 | struct s3c_udc *dev; | |
596 | unsigned long flags; | |
597 | u32 ep_num, gintsts; | |
598 | ||
599 | req = container_of(_req, struct s3c_request, req); | |
600 | if (unlikely(!_req || !_req->complete || !_req->buf | |
601 | || !list_empty(&req->queue))) { | |
602 | ||
ea2d9159 | 603 | debug("%s: bad params\n", __func__); |
38517a78 ŁM |
604 | return -EINVAL; |
605 | } | |
606 | ||
607 | ep = container_of(_ep, struct s3c_ep, ep); | |
608 | ||
609 | if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { | |
610 | ||
ea2d9159 | 611 | debug("%s: bad ep: %s, %d, %p\n", __func__, |
38517a78 ŁM |
612 | ep->ep.name, !ep->desc, _ep); |
613 | return -EINVAL; | |
614 | } | |
615 | ||
616 | ep_num = ep_index(ep); | |
617 | dev = ep->dev; | |
618 | if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { | |
619 | ||
ea2d9159 | 620 | debug("%s: bogus device state %p\n", __func__, dev->driver); |
38517a78 ŁM |
621 | return -ESHUTDOWN; |
622 | } | |
623 | ||
624 | spin_lock_irqsave(&dev->lock, flags); | |
625 | ||
626 | _req->status = -EINPROGRESS; | |
627 | _req->actual = 0; | |
628 | ||
629 | /* kickstart this i/o queue? */ | |
ea2d9159 | 630 | debug("\n*** %s: %s-%s req = %p, len = %d, buf = %p" |
38517a78 ŁM |
631 | "Q empty = %d, stopped = %d\n", |
632 | __func__, _ep->name, ep_is_in(ep) ? "in" : "out", | |
633 | _req, _req->length, _req->buf, | |
634 | list_empty(&ep->queue), ep->stopped); | |
635 | ||
f3b05ca5 | 636 | #ifdef DEBUG |
38517a78 ŁM |
637 | { |
638 | int i, len = _req->length; | |
639 | ||
640 | printf("pkt = "); | |
641 | if (len > 64) | |
642 | len = 64; | |
643 | for (i = 0; i < len; i++) { | |
644 | printf("%02x", ((u8 *)_req->buf)[i]); | |
645 | if ((i & 7) == 7) | |
646 | printf(" "); | |
647 | } | |
648 | printf("\n"); | |
649 | } | |
650 | #endif | |
651 | ||
652 | if (list_empty(&ep->queue) && !ep->stopped) { | |
653 | ||
654 | if (ep_num == 0) { | |
655 | /* EP0 */ | |
656 | list_add_tail(&req->queue, &ep->queue); | |
657 | s3c_ep0_kick(dev, ep); | |
658 | req = 0; | |
659 | ||
660 | } else if (ep_is_in(ep)) { | |
661 | gintsts = readl(®->gintsts); | |
ea2d9159 | 662 | debug_cond(DEBUG_IN_EP, |
f3b05ca5 ŁM |
663 | "%s: ep_is_in, S3C_UDC_OTG_GINTSTS=0x%x\n", |
664 | __func__, gintsts); | |
38517a78 ŁM |
665 | |
666 | setdma_tx(ep, req); | |
667 | } else { | |
668 | gintsts = readl(®->gintsts); | |
f3b05ca5 ŁM |
669 | debug_cond(DEBUG_OUT_EP != 0, |
670 | "%s:ep_is_out, S3C_UDC_OTG_GINTSTS=0x%x\n", | |
671 | __func__, gintsts); | |
38517a78 ŁM |
672 | |
673 | setdma_rx(ep, req); | |
674 | } | |
675 | } | |
676 | ||
677 | /* pio or dma irq handler advances the queue. */ | |
678 | if (likely(req != 0)) | |
679 | list_add_tail(&req->queue, &ep->queue); | |
680 | ||
681 | spin_unlock_irqrestore(&dev->lock, flags); | |
682 | ||
683 | return 0; | |
684 | } | |
685 | ||
686 | /****************************************************************/ | |
687 | /* End Point 0 related functions */ | |
688 | /****************************************************************/ | |
689 | ||
690 | /* return: 0 = still running, 1 = completed, negative = errno */ | |
691 | static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req) | |
692 | { | |
693 | u32 max; | |
694 | unsigned count; | |
695 | int is_last; | |
696 | ||
697 | max = ep_maxpacket(ep); | |
698 | ||
f3b05ca5 | 699 | debug_cond(DEBUG_EP0 != 0, "%s: max = %d\n", __func__, max); |
38517a78 ŁM |
700 | |
701 | count = setdma_tx(ep, req); | |
702 | ||
703 | /* last packet is usually short (or a zlp) */ | |
704 | if (likely(count != max)) | |
705 | is_last = 1; | |
706 | else { | |
707 | if (likely(req->req.length != req->req.actual + count) | |
708 | || req->req.zero) | |
709 | is_last = 0; | |
710 | else | |
711 | is_last = 1; | |
712 | } | |
713 | ||
f3b05ca5 ŁM |
714 | debug_cond(DEBUG_EP0 != 0, |
715 | "%s: wrote %s %d bytes%s %d left %p\n", __func__, | |
716 | ep->ep.name, count, | |
717 | is_last ? "/L" : "", | |
718 | req->req.length - req->req.actual - count, req); | |
38517a78 ŁM |
719 | |
720 | /* requests complete when all IN data is in the FIFO */ | |
721 | if (is_last) { | |
722 | ep->dev->ep0state = WAIT_FOR_SETUP; | |
723 | return 1; | |
724 | } | |
725 | ||
726 | return 0; | |
727 | } | |
728 | ||
729 | int s3c_fifo_read(struct s3c_ep *ep, u32 *cp, int max) | |
730 | { | |
731 | u32 bytes; | |
732 | ||
733 | bytes = sizeof(struct usb_ctrlrequest); | |
734 | ||
735 | invalidate_dcache_range((unsigned long) ep->dev->dma_buf[ep_index(ep)], | |
736 | (unsigned long) ep->dev->dma_buf[ep_index(ep)] | |
737 | + DMA_BUFFER_SIZE); | |
738 | ||
f3b05ca5 ŁM |
739 | debug_cond(DEBUG_EP0 != 0, |
740 | "%s: bytes=%d, ep_index=%d %p\n", __func__, | |
741 | bytes, ep_index(ep), ep->dev->dma_buf[ep_index(ep)]); | |
38517a78 ŁM |
742 | |
743 | return bytes; | |
744 | } | |
745 | ||
746 | /** | |
747 | * udc_set_address - set the USB address for this device | |
748 | * @address: | |
749 | * | |
750 | * Called from control endpoint function | |
751 | * after it decodes a set address setup packet. | |
752 | */ | |
753 | static void udc_set_address(struct s3c_udc *dev, unsigned char address) | |
754 | { | |
755 | u32 ctrl = readl(®->dcfg); | |
756 | writel(DEVICE_ADDRESS(address) | ctrl, ®->dcfg); | |
757 | ||
758 | s3c_udc_ep0_zlp(dev); | |
759 | ||
f3b05ca5 ŁM |
760 | debug_cond(DEBUG_EP0 != 0, |
761 | "%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n", | |
762 | __func__, address, readl(®->dcfg)); | |
38517a78 ŁM |
763 | |
764 | dev->usb_address = address; | |
765 | } | |
766 | ||
767 | static inline void s3c_udc_ep0_set_stall(struct s3c_ep *ep) | |
768 | { | |
769 | struct s3c_udc *dev; | |
770 | u32 ep_ctrl = 0; | |
771 | ||
772 | dev = ep->dev; | |
773 | ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); | |
774 | ||
775 | /* set the disable and stall bits */ | |
776 | if (ep_ctrl & DEPCTL_EPENA) | |
777 | ep_ctrl |= DEPCTL_EPDIS; | |
778 | ||
779 | ep_ctrl |= DEPCTL_STALL; | |
780 | ||
781 | writel(ep_ctrl, ®->in_endp[EP0_CON].diepctl); | |
782 | ||
f3b05ca5 ŁM |
783 | debug_cond(DEBUG_EP0 != 0, |
784 | "%s: set ep%d stall, DIEPCTL0 = 0x%p\n", | |
785 | __func__, ep_index(ep), ®->in_endp[EP0_CON].diepctl); | |
38517a78 ŁM |
786 | /* |
787 | * The application can only set this bit, and the core clears it, | |
788 | * when a SETUP token is received for this endpoint | |
789 | */ | |
790 | dev->ep0state = WAIT_FOR_SETUP; | |
791 | ||
792 | s3c_udc_pre_setup(); | |
793 | } | |
794 | ||
795 | static void s3c_ep0_read(struct s3c_udc *dev) | |
796 | { | |
797 | struct s3c_request *req; | |
798 | struct s3c_ep *ep = &dev->ep[0]; | |
38517a78 ŁM |
799 | |
800 | if (!list_empty(&ep->queue)) { | |
801 | req = list_entry(ep->queue.next, struct s3c_request, queue); | |
802 | ||
803 | } else { | |
ea2d9159 | 804 | debug("%s: ---> BUG\n", __func__); |
38517a78 ŁM |
805 | BUG(); |
806 | return; | |
807 | } | |
808 | ||
f3b05ca5 ŁM |
809 | debug_cond(DEBUG_EP0 != 0, |
810 | "%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n", | |
811 | __func__, req, req->req.length, req->req.actual); | |
38517a78 ŁM |
812 | |
813 | if (req->req.length == 0) { | |
814 | /* zlp for Set_configuration, Set_interface, | |
815 | * or Bulk-Only mass storge reset */ | |
816 | ||
817 | ep->len = 0; | |
818 | s3c_udc_ep0_zlp(dev); | |
819 | ||
f3b05ca5 ŁM |
820 | debug_cond(DEBUG_EP0 != 0, |
821 | "%s: req.length = 0, bRequest = %d\n", | |
822 | __func__, usb_ctrl->bRequest); | |
38517a78 ŁM |
823 | return; |
824 | } | |
825 | ||
ea2d9159 | 826 | setdma_rx(ep, req); |
38517a78 ŁM |
827 | } |
828 | ||
829 | /* | |
830 | * DATA_STATE_XMIT | |
831 | */ | |
832 | static int s3c_ep0_write(struct s3c_udc *dev) | |
833 | { | |
834 | struct s3c_request *req; | |
835 | struct s3c_ep *ep = &dev->ep[0]; | |
836 | int ret, need_zlp = 0; | |
837 | ||
838 | if (list_empty(&ep->queue)) | |
839 | req = 0; | |
840 | else | |
841 | req = list_entry(ep->queue.next, struct s3c_request, queue); | |
842 | ||
843 | if (!req) { | |
f3b05ca5 | 844 | debug_cond(DEBUG_EP0 != 0, "%s: NULL REQ\n", __func__); |
38517a78 ŁM |
845 | return 0; |
846 | } | |
847 | ||
f3b05ca5 ŁM |
848 | debug_cond(DEBUG_EP0 != 0, |
849 | "%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n", | |
850 | __func__, req, req->req.length, req->req.actual); | |
38517a78 ŁM |
851 | |
852 | if (req->req.length - req->req.actual == ep0_fifo_size) { | |
853 | /* Next write will end with the packet size, */ | |
854 | /* so we need Zero-length-packet */ | |
855 | need_zlp = 1; | |
856 | } | |
857 | ||
858 | ret = write_fifo_ep0(ep, req); | |
859 | ||
860 | if ((ret == 1) && !need_zlp) { | |
861 | /* Last packet */ | |
862 | dev->ep0state = WAIT_FOR_COMPLETE; | |
f3b05ca5 ŁM |
863 | debug_cond(DEBUG_EP0 != 0, |
864 | "%s: finished, waiting for status\n", __func__); | |
38517a78 ŁM |
865 | |
866 | } else { | |
867 | dev->ep0state = DATA_STATE_XMIT; | |
f3b05ca5 ŁM |
868 | debug_cond(DEBUG_EP0 != 0, |
869 | "%s: not finished\n", __func__); | |
38517a78 ŁM |
870 | } |
871 | ||
872 | return 1; | |
873 | } | |
874 | ||
875 | u16 g_status; | |
876 | ||
877 | int s3c_udc_get_status(struct s3c_udc *dev, | |
878 | struct usb_ctrlrequest *crq) | |
879 | { | |
880 | u8 ep_num = crq->wIndex & 0x7F; | |
881 | u32 ep_ctrl; | |
882 | u32 *p = the_controller->dma_buf[1]; | |
883 | ||
f3b05ca5 ŁM |
884 | debug_cond(DEBUG_SETUP != 0, |
885 | "%s: *** USB_REQ_GET_STATUS\n", __func__); | |
38517a78 ŁM |
886 | printf("crq->brequest:0x%x\n", crq->bRequestType & USB_RECIP_MASK); |
887 | switch (crq->bRequestType & USB_RECIP_MASK) { | |
888 | case USB_RECIP_INTERFACE: | |
889 | g_status = 0; | |
f3b05ca5 ŁM |
890 | debug_cond(DEBUG_SETUP != 0, |
891 | "\tGET_STATUS:USB_RECIP_INTERFACE, g_stauts = %d\n", | |
892 | g_status); | |
38517a78 ŁM |
893 | break; |
894 | ||
895 | case USB_RECIP_DEVICE: | |
896 | g_status = 0x1; /* Self powered */ | |
f3b05ca5 ŁM |
897 | debug_cond(DEBUG_SETUP != 0, |
898 | "\tGET_STATUS: USB_RECIP_DEVICE, g_stauts = %d\n", | |
899 | g_status); | |
38517a78 ŁM |
900 | break; |
901 | ||
902 | case USB_RECIP_ENDPOINT: | |
903 | if (crq->wLength > 2) { | |
f3b05ca5 ŁM |
904 | debug_cond(DEBUG_SETUP != 0, |
905 | "\tGET_STATUS:Not support EP or wLength\n"); | |
38517a78 ŁM |
906 | return 1; |
907 | } | |
908 | ||
909 | g_status = dev->ep[ep_num].stopped; | |
f3b05ca5 ŁM |
910 | debug_cond(DEBUG_SETUP != 0, |
911 | "\tGET_STATUS: USB_RECIP_ENDPOINT, g_stauts = %d\n", | |
912 | g_status); | |
38517a78 ŁM |
913 | |
914 | break; | |
915 | ||
916 | default: | |
917 | return 1; | |
918 | } | |
919 | ||
920 | memcpy(p, &g_status, sizeof(g_status)); | |
921 | ||
922 | flush_dcache_range((unsigned long) p, | |
923 | (unsigned long) p + DMA_BUFFER_SIZE); | |
924 | ||
925 | writel(the_controller->dma_addr[1], ®->in_endp[EP0_CON].diepdma); | |
926 | writel(DIEPT_SIZ_PKT_CNT(1) | DIEPT_SIZ_XFER_SIZE(2), | |
927 | ®->in_endp[EP0_CON].dieptsiz); | |
928 | ||
929 | ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); | |
930 | writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, | |
931 | ®->in_endp[EP0_CON].diepctl); | |
932 | dev->ep0state = WAIT_FOR_NULL_COMPLETE; | |
933 | ||
934 | return 0; | |
935 | } | |
936 | ||
937 | static void s3c_udc_set_nak(struct s3c_ep *ep) | |
938 | { | |
939 | u8 ep_num; | |
940 | u32 ep_ctrl = 0; | |
941 | ||
942 | ep_num = ep_index(ep); | |
ea2d9159 | 943 | debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); |
38517a78 ŁM |
944 | |
945 | if (ep_is_in(ep)) { | |
946 | ep_ctrl = readl(®->in_endp[ep_num].diepctl); | |
947 | ep_ctrl |= DEPCTL_SNAK; | |
948 | writel(ep_ctrl, ®->in_endp[ep_num].diepctl); | |
ea2d9159 | 949 | debug("%s: set NAK, DIEPCTL%d = 0x%x\n", |
38517a78 ŁM |
950 | __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); |
951 | } else { | |
952 | ep_ctrl = readl(®->out_endp[ep_num].doepctl); | |
953 | ep_ctrl |= DEPCTL_SNAK; | |
954 | writel(ep_ctrl, ®->out_endp[ep_num].doepctl); | |
ea2d9159 | 955 | debug("%s: set NAK, DOEPCTL%d = 0x%x\n", |
38517a78 ŁM |
956 | __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); |
957 | } | |
958 | ||
959 | return; | |
960 | } | |
961 | ||
962 | ||
963 | void s3c_udc_ep_set_stall(struct s3c_ep *ep) | |
964 | { | |
965 | u8 ep_num; | |
966 | u32 ep_ctrl = 0; | |
967 | ||
968 | ep_num = ep_index(ep); | |
ea2d9159 | 969 | debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); |
38517a78 ŁM |
970 | |
971 | if (ep_is_in(ep)) { | |
972 | ep_ctrl = readl(®->in_endp[ep_num].diepctl); | |
973 | ||
974 | /* set the disable and stall bits */ | |
975 | if (ep_ctrl & DEPCTL_EPENA) | |
976 | ep_ctrl |= DEPCTL_EPDIS; | |
977 | ||
978 | ep_ctrl |= DEPCTL_STALL; | |
979 | ||
980 | writel(ep_ctrl, ®->in_endp[ep_num].diepctl); | |
ea2d9159 | 981 | debug("%s: set stall, DIEPCTL%d = 0x%x\n", |
38517a78 ŁM |
982 | __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); |
983 | ||
984 | } else { | |
985 | ep_ctrl = readl(®->out_endp[ep_num].doepctl); | |
986 | ||
987 | /* set the stall bit */ | |
988 | ep_ctrl |= DEPCTL_STALL; | |
989 | ||
990 | writel(ep_ctrl, ®->out_endp[ep_num].doepctl); | |
ea2d9159 | 991 | debug("%s: set stall, DOEPCTL%d = 0x%x\n", |
38517a78 ŁM |
992 | __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); |
993 | } | |
994 | ||
995 | return; | |
996 | } | |
997 | ||
998 | void s3c_udc_ep_clear_stall(struct s3c_ep *ep) | |
999 | { | |
1000 | u8 ep_num; | |
1001 | u32 ep_ctrl = 0; | |
1002 | ||
1003 | ep_num = ep_index(ep); | |
ea2d9159 | 1004 | debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); |
38517a78 ŁM |
1005 | |
1006 | if (ep_is_in(ep)) { | |
1007 | ep_ctrl = readl(®->in_endp[ep_num].diepctl); | |
1008 | ||
1009 | /* clear stall bit */ | |
1010 | ep_ctrl &= ~DEPCTL_STALL; | |
1011 | ||
1012 | /* | |
1013 | * USB Spec 9.4.5: For endpoints using data toggle, regardless | |
1014 | * of whether an endpoint has the Halt feature set, a | |
1015 | * ClearFeature(ENDPOINT_HALT) request always results in the | |
1016 | * data toggle being reinitialized to DATA0. | |
1017 | */ | |
1018 | if (ep->bmAttributes == USB_ENDPOINT_XFER_INT | |
1019 | || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { | |
1020 | ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */ | |
1021 | } | |
1022 | ||
1023 | writel(ep_ctrl, ®->in_endp[ep_num].diepctl); | |
ea2d9159 | 1024 | debug("%s: cleared stall, DIEPCTL%d = 0x%x\n", |
38517a78 ŁM |
1025 | __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); |
1026 | ||
1027 | } else { | |
1028 | ep_ctrl = readl(®->out_endp[ep_num].doepctl); | |
1029 | ||
1030 | /* clear stall bit */ | |
1031 | ep_ctrl &= ~DEPCTL_STALL; | |
1032 | ||
1033 | if (ep->bmAttributes == USB_ENDPOINT_XFER_INT | |
1034 | || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { | |
1035 | ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */ | |
1036 | } | |
1037 | ||
1038 | writel(ep_ctrl, ®->out_endp[ep_num].doepctl); | |
ea2d9159 | 1039 | debug("%s: cleared stall, DOEPCTL%d = 0x%x\n", |
38517a78 ŁM |
1040 | __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); |
1041 | } | |
1042 | ||
1043 | return; | |
1044 | } | |
1045 | ||
1046 | static int s3c_udc_set_halt(struct usb_ep *_ep, int value) | |
1047 | { | |
1048 | struct s3c_ep *ep; | |
1049 | struct s3c_udc *dev; | |
1050 | unsigned long flags; | |
1051 | u8 ep_num; | |
1052 | ||
1053 | ep = container_of(_ep, struct s3c_ep, ep); | |
1054 | ep_num = ep_index(ep); | |
1055 | ||
1056 | if (unlikely(!_ep || !ep->desc || ep_num == EP0_CON || | |
1057 | ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC)) { | |
ea2d9159 | 1058 | debug("%s: %s bad ep or descriptor\n", __func__, ep->ep.name); |
38517a78 ŁM |
1059 | return -EINVAL; |
1060 | } | |
1061 | ||
1062 | /* Attempt to halt IN ep will fail if any transfer requests | |
1063 | * are still queue */ | |
1064 | if (value && ep_is_in(ep) && !list_empty(&ep->queue)) { | |
ea2d9159 | 1065 | debug("%s: %s queue not empty, req = %p\n", |
38517a78 ŁM |
1066 | __func__, ep->ep.name, |
1067 | list_entry(ep->queue.next, struct s3c_request, queue)); | |
1068 | ||
1069 | return -EAGAIN; | |
1070 | } | |
1071 | ||
1072 | dev = ep->dev; | |
ea2d9159 | 1073 | debug("%s: ep_num = %d, value = %d\n", __func__, ep_num, value); |
38517a78 ŁM |
1074 | |
1075 | spin_lock_irqsave(&dev->lock, flags); | |
1076 | ||
1077 | if (value == 0) { | |
1078 | ep->stopped = 0; | |
1079 | s3c_udc_ep_clear_stall(ep); | |
1080 | } else { | |
1081 | if (ep_num == 0) | |
1082 | dev->ep0state = WAIT_FOR_SETUP; | |
1083 | ||
1084 | ep->stopped = 1; | |
1085 | s3c_udc_ep_set_stall(ep); | |
1086 | } | |
1087 | ||
1088 | spin_unlock_irqrestore(&dev->lock, flags); | |
1089 | ||
1090 | return 0; | |
1091 | } | |
1092 | ||
1093 | void s3c_udc_ep_activate(struct s3c_ep *ep) | |
1094 | { | |
1095 | u8 ep_num; | |
1096 | u32 ep_ctrl = 0, daintmsk = 0; | |
1097 | ||
1098 | ep_num = ep_index(ep); | |
1099 | ||
1100 | /* Read DEPCTLn register */ | |
1101 | if (ep_is_in(ep)) { | |
1102 | ep_ctrl = readl(®->in_endp[ep_num].diepctl); | |
1103 | daintmsk = 1 << ep_num; | |
1104 | } else { | |
1105 | ep_ctrl = readl(®->out_endp[ep_num].doepctl); | |
1106 | daintmsk = (1 << ep_num) << DAINT_OUT_BIT; | |
1107 | } | |
1108 | ||
ea2d9159 | 1109 | debug("%s: EPCTRL%d = 0x%x, ep_is_in = %d\n", |
38517a78 ŁM |
1110 | __func__, ep_num, ep_ctrl, ep_is_in(ep)); |
1111 | ||
1112 | /* If the EP is already active don't change the EP Control | |
1113 | * register. */ | |
1114 | if (!(ep_ctrl & DEPCTL_USBACTEP)) { | |
1115 | ep_ctrl = (ep_ctrl & ~DEPCTL_TYPE_MASK) | | |
1116 | (ep->bmAttributes << DEPCTL_TYPE_BIT); | |
1117 | ep_ctrl = (ep_ctrl & ~DEPCTL_MPS_MASK) | | |
1118 | (ep->ep.maxpacket << DEPCTL_MPS_BIT); | |
1119 | ep_ctrl |= (DEPCTL_SETD0PID | DEPCTL_USBACTEP | DEPCTL_SNAK); | |
1120 | ||
1121 | if (ep_is_in(ep)) { | |
1122 | writel(ep_ctrl, ®->in_endp[ep_num].diepctl); | |
ea2d9159 | 1123 | debug("%s: USB Ative EP%d, DIEPCTRL%d = 0x%x\n", |
38517a78 ŁM |
1124 | __func__, ep_num, ep_num, |
1125 | readl(®->in_endp[ep_num].diepctl)); | |
1126 | } else { | |
1127 | writel(ep_ctrl, ®->out_endp[ep_num].doepctl); | |
ea2d9159 | 1128 | debug("%s: USB Ative EP%d, DOEPCTRL%d = 0x%x\n", |
38517a78 ŁM |
1129 | __func__, ep_num, ep_num, |
1130 | readl(®->out_endp[ep_num].doepctl)); | |
1131 | } | |
1132 | } | |
1133 | ||
1134 | /* Unmask EP Interrtupt */ | |
1135 | writel(readl(®->daintmsk)|daintmsk, ®->daintmsk); | |
ea2d9159 | 1136 | debug("%s: DAINTMSK = 0x%x\n", __func__, readl(®->daintmsk)); |
38517a78 ŁM |
1137 | |
1138 | } | |
1139 | ||
1140 | static int s3c_udc_clear_feature(struct usb_ep *_ep) | |
1141 | { | |
1142 | struct s3c_udc *dev; | |
1143 | struct s3c_ep *ep; | |
1144 | u8 ep_num; | |
1145 | ||
1146 | ep = container_of(_ep, struct s3c_ep, ep); | |
1147 | ep_num = ep_index(ep); | |
1148 | ||
1149 | dev = ep->dev; | |
f3b05ca5 ŁM |
1150 | debug_cond(DEBUG_SETUP != 0, |
1151 | "%s: ep_num = %d, is_in = %d, clear_feature_flag = %d\n", | |
1152 | __func__, ep_num, ep_is_in(ep), clear_feature_flag); | |
38517a78 ŁM |
1153 | |
1154 | if (usb_ctrl->wLength != 0) { | |
f3b05ca5 ŁM |
1155 | debug_cond(DEBUG_SETUP != 0, |
1156 | "\tCLEAR_FEATURE: wLength is not zero.....\n"); | |
38517a78 ŁM |
1157 | return 1; |
1158 | } | |
1159 | ||
1160 | switch (usb_ctrl->bRequestType & USB_RECIP_MASK) { | |
1161 | case USB_RECIP_DEVICE: | |
1162 | switch (usb_ctrl->wValue) { | |
1163 | case USB_DEVICE_REMOTE_WAKEUP: | |
f3b05ca5 ŁM |
1164 | debug_cond(DEBUG_SETUP != 0, |
1165 | "\tOFF:USB_DEVICE_REMOTE_WAKEUP\n"); | |
38517a78 ŁM |
1166 | break; |
1167 | ||
1168 | case USB_DEVICE_TEST_MODE: | |
f3b05ca5 ŁM |
1169 | debug_cond(DEBUG_SETUP != 0, |
1170 | "\tCLEAR_FEATURE: USB_DEVICE_TEST_MODE\n"); | |
38517a78 ŁM |
1171 | /** @todo Add CLEAR_FEATURE for TEST modes. */ |
1172 | break; | |
1173 | } | |
1174 | ||
1175 | s3c_udc_ep0_zlp(dev); | |
1176 | break; | |
1177 | ||
1178 | case USB_RECIP_ENDPOINT: | |
f3b05ca5 ŁM |
1179 | debug_cond(DEBUG_SETUP != 0, |
1180 | "\tCLEAR_FEATURE:USB_RECIP_ENDPOINT, wValue = %d\n", | |
1181 | usb_ctrl->wValue); | |
38517a78 ŁM |
1182 | |
1183 | if (usb_ctrl->wValue == USB_ENDPOINT_HALT) { | |
1184 | if (ep_num == 0) { | |
1185 | s3c_udc_ep0_set_stall(ep); | |
1186 | return 0; | |
1187 | } | |
1188 | ||
1189 | s3c_udc_ep0_zlp(dev); | |
1190 | ||
1191 | s3c_udc_ep_clear_stall(ep); | |
1192 | s3c_udc_ep_activate(ep); | |
1193 | ep->stopped = 0; | |
1194 | ||
1195 | clear_feature_num = ep_num; | |
1196 | clear_feature_flag = 1; | |
1197 | } | |
1198 | break; | |
1199 | } | |
1200 | ||
1201 | return 0; | |
1202 | } | |
1203 | ||
1204 | static int s3c_udc_set_feature(struct usb_ep *_ep) | |
1205 | { | |
1206 | struct s3c_udc *dev; | |
1207 | struct s3c_ep *ep; | |
1208 | u8 ep_num; | |
1209 | ||
1210 | ep = container_of(_ep, struct s3c_ep, ep); | |
1211 | ep_num = ep_index(ep); | |
1212 | dev = ep->dev; | |
1213 | ||
f3b05ca5 ŁM |
1214 | debug_cond(DEBUG_SETUP != 0, |
1215 | "%s: *** USB_REQ_SET_FEATURE , ep_num = %d\n", | |
38517a78 ŁM |
1216 | __func__, ep_num); |
1217 | ||
1218 | if (usb_ctrl->wLength != 0) { | |
f3b05ca5 ŁM |
1219 | debug_cond(DEBUG_SETUP != 0, |
1220 | "\tSET_FEATURE: wLength is not zero.....\n"); | |
38517a78 ŁM |
1221 | return 1; |
1222 | } | |
1223 | ||
1224 | switch (usb_ctrl->bRequestType & USB_RECIP_MASK) { | |
1225 | case USB_RECIP_DEVICE: | |
1226 | switch (usb_ctrl->wValue) { | |
1227 | case USB_DEVICE_REMOTE_WAKEUP: | |
f3b05ca5 ŁM |
1228 | debug_cond(DEBUG_SETUP != 0, |
1229 | "\tSET_FEATURE:USB_DEVICE_REMOTE_WAKEUP\n"); | |
38517a78 ŁM |
1230 | break; |
1231 | case USB_DEVICE_B_HNP_ENABLE: | |
f3b05ca5 ŁM |
1232 | debug_cond(DEBUG_SETUP != 0, |
1233 | "\tSET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n"); | |
38517a78 ŁM |
1234 | break; |
1235 | ||
1236 | case USB_DEVICE_A_HNP_SUPPORT: | |
1237 | /* RH port supports HNP */ | |
f3b05ca5 ŁM |
1238 | debug_cond(DEBUG_SETUP != 0, |
1239 | "\tSET_FEATURE:USB_DEVICE_A_HNP_SUPPORT\n"); | |
38517a78 ŁM |
1240 | break; |
1241 | ||
1242 | case USB_DEVICE_A_ALT_HNP_SUPPORT: | |
1243 | /* other RH port does */ | |
f3b05ca5 ŁM |
1244 | debug_cond(DEBUG_SETUP != 0, |
1245 | "\tSET: USB_DEVICE_A_ALT_HNP_SUPPORT\n"); | |
38517a78 ŁM |
1246 | break; |
1247 | } | |
1248 | ||
1249 | s3c_udc_ep0_zlp(dev); | |
1250 | return 0; | |
1251 | ||
1252 | case USB_RECIP_INTERFACE: | |
f3b05ca5 ŁM |
1253 | debug_cond(DEBUG_SETUP != 0, |
1254 | "\tSET_FEATURE: USB_RECIP_INTERFACE\n"); | |
38517a78 ŁM |
1255 | break; |
1256 | ||
1257 | case USB_RECIP_ENDPOINT: | |
f3b05ca5 ŁM |
1258 | debug_cond(DEBUG_SETUP != 0, |
1259 | "\tSET_FEATURE: USB_RECIP_ENDPOINT\n"); | |
38517a78 ŁM |
1260 | if (usb_ctrl->wValue == USB_ENDPOINT_HALT) { |
1261 | if (ep_num == 0) { | |
1262 | s3c_udc_ep0_set_stall(ep); | |
1263 | return 0; | |
1264 | } | |
1265 | ep->stopped = 1; | |
1266 | s3c_udc_ep_set_stall(ep); | |
1267 | } | |
1268 | ||
1269 | s3c_udc_ep0_zlp(dev); | |
1270 | return 0; | |
1271 | } | |
1272 | ||
1273 | return 1; | |
1274 | } | |
1275 | ||
1276 | /* | |
1277 | * WAIT_FOR_SETUP (OUT_PKT_RDY) | |
1278 | */ | |
1279 | void s3c_ep0_setup(struct s3c_udc *dev) | |
1280 | { | |
1281 | struct s3c_ep *ep = &dev->ep[0]; | |
ea2d9159 | 1282 | int i; |
38517a78 ŁM |
1283 | u8 ep_num; |
1284 | ||
1285 | /* Nuke all previous transfers */ | |
1286 | nuke(ep, -EPROTO); | |
1287 | ||
1288 | /* read control req from fifo (8 bytes) */ | |
ea2d9159 | 1289 | s3c_fifo_read(ep, (u32 *)usb_ctrl, 8); |
38517a78 | 1290 | |
f3b05ca5 ŁM |
1291 | debug_cond(DEBUG_SETUP != 0, |
1292 | "%s: bRequestType = 0x%x(%s), bRequest = 0x%x" | |
1293 | "\twLength = 0x%x, wValue = 0x%x, wIndex= 0x%x\n", | |
1294 | __func__, usb_ctrl->bRequestType, | |
1295 | (usb_ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT", | |
1296 | usb_ctrl->bRequest, | |
1297 | usb_ctrl->wLength, usb_ctrl->wValue, usb_ctrl->wIndex); | |
38517a78 | 1298 | |
f3b05ca5 | 1299 | #ifdef DEBUG |
38517a78 ŁM |
1300 | { |
1301 | int i, len = sizeof(*usb_ctrl); | |
ea2d9159 | 1302 | char *p = (char *)usb_ctrl; |
38517a78 ŁM |
1303 | |
1304 | printf("pkt = "); | |
1305 | for (i = 0; i < len; i++) { | |
1306 | printf("%02x", ((u8 *)p)[i]); | |
1307 | if ((i & 7) == 7) | |
1308 | printf(" "); | |
1309 | } | |
1310 | printf("\n"); | |
1311 | } | |
1312 | #endif | |
1313 | ||
1314 | if (usb_ctrl->bRequest == GET_MAX_LUN_REQUEST && | |
1315 | usb_ctrl->wLength != 1) { | |
f3b05ca5 ŁM |
1316 | debug_cond(DEBUG_SETUP != 0, |
1317 | "\t%s:GET_MAX_LUN_REQUEST:invalid", | |
1318 | __func__); | |
1319 | debug_cond(DEBUG_SETUP != 0, | |
1320 | "wLength = %d, setup returned\n", | |
1321 | usb_ctrl->wLength); | |
38517a78 ŁM |
1322 | |
1323 | s3c_udc_ep0_set_stall(ep); | |
1324 | dev->ep0state = WAIT_FOR_SETUP; | |
1325 | ||
1326 | return; | |
1327 | } else if (usb_ctrl->bRequest == BOT_RESET_REQUEST && | |
1328 | usb_ctrl->wLength != 0) { | |
1329 | /* Bulk-Only *mass storge reset of class-specific request */ | |
f3b05ca5 ŁM |
1330 | debug_cond(DEBUG_SETUP != 0, |
1331 | "%s:BOT Rest:invalid wLength =%d, setup returned\n", | |
1332 | __func__, usb_ctrl->wLength); | |
38517a78 ŁM |
1333 | |
1334 | s3c_udc_ep0_set_stall(ep); | |
1335 | dev->ep0state = WAIT_FOR_SETUP; | |
1336 | ||
1337 | return; | |
1338 | } | |
1339 | ||
1340 | /* Set direction of EP0 */ | |
1341 | if (likely(usb_ctrl->bRequestType & USB_DIR_IN)) { | |
1342 | ep->bEndpointAddress |= USB_DIR_IN; | |
38517a78 ŁM |
1343 | } else { |
1344 | ep->bEndpointAddress &= ~USB_DIR_IN; | |
38517a78 ŁM |
1345 | } |
1346 | /* cope with automagic for some standard requests. */ | |
1347 | dev->req_std = (usb_ctrl->bRequestType & USB_TYPE_MASK) | |
1348 | == USB_TYPE_STANDARD; | |
7cf7beff | 1349 | |
38517a78 ŁM |
1350 | dev->req_pending = 1; |
1351 | ||
1352 | /* Handle some SETUP packets ourselves */ | |
1353 | if (dev->req_std) { | |
1354 | switch (usb_ctrl->bRequest) { | |
1355 | case USB_REQ_SET_ADDRESS: | |
f3b05ca5 ŁM |
1356 | debug_cond(DEBUG_SETUP != 0, |
1357 | "%s: *** USB_REQ_SET_ADDRESS (%d)\n", | |
1358 | __func__, usb_ctrl->wValue); | |
38517a78 ŁM |
1359 | if (usb_ctrl->bRequestType |
1360 | != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) | |
1361 | break; | |
1362 | ||
1363 | udc_set_address(dev, usb_ctrl->wValue); | |
1364 | return; | |
1365 | ||
1366 | case USB_REQ_SET_CONFIGURATION: | |
f3b05ca5 ŁM |
1367 | debug_cond(DEBUG_SETUP != 0, |
1368 | "=====================================\n"); | |
1369 | debug_cond(DEBUG_SETUP != 0, | |
1370 | "%s: USB_REQ_SET_CONFIGURATION (%d)\n", | |
1371 | __func__, usb_ctrl->wValue); | |
38517a78 | 1372 | |
7cf7beff | 1373 | if (usb_ctrl->bRequestType == USB_RECIP_DEVICE) |
38517a78 | 1374 | reset_available = 1; |
7cf7beff | 1375 | |
38517a78 ŁM |
1376 | break; |
1377 | ||
1378 | case USB_REQ_GET_DESCRIPTOR: | |
f3b05ca5 ŁM |
1379 | debug_cond(DEBUG_SETUP != 0, |
1380 | "%s: *** USB_REQ_GET_DESCRIPTOR\n", | |
1381 | __func__); | |
38517a78 ŁM |
1382 | break; |
1383 | ||
1384 | case USB_REQ_SET_INTERFACE: | |
f3b05ca5 ŁM |
1385 | debug_cond(DEBUG_SETUP != 0, |
1386 | "%s: *** USB_REQ_SET_INTERFACE (%d)\n", | |
1387 | __func__, usb_ctrl->wValue); | |
38517a78 | 1388 | |
7cf7beff | 1389 | if (usb_ctrl->bRequestType == USB_RECIP_INTERFACE) |
38517a78 | 1390 | reset_available = 1; |
7cf7beff | 1391 | |
38517a78 ŁM |
1392 | break; |
1393 | ||
1394 | case USB_REQ_GET_CONFIGURATION: | |
f3b05ca5 ŁM |
1395 | debug_cond(DEBUG_SETUP != 0, |
1396 | "%s: *** USB_REQ_GET_CONFIGURATION\n", | |
1397 | __func__); | |
38517a78 ŁM |
1398 | break; |
1399 | ||
1400 | case USB_REQ_GET_STATUS: | |
1401 | if (!s3c_udc_get_status(dev, usb_ctrl)) | |
1402 | return; | |
1403 | ||
1404 | break; | |
1405 | ||
1406 | case USB_REQ_CLEAR_FEATURE: | |
1407 | ep_num = usb_ctrl->wIndex & 0x7f; | |
1408 | ||
1409 | if (!s3c_udc_clear_feature(&dev->ep[ep_num].ep)) | |
1410 | return; | |
1411 | ||
1412 | break; | |
1413 | ||
1414 | case USB_REQ_SET_FEATURE: | |
1415 | ep_num = usb_ctrl->wIndex & 0x7f; | |
1416 | ||
1417 | if (!s3c_udc_set_feature(&dev->ep[ep_num].ep)) | |
1418 | return; | |
1419 | ||
1420 | break; | |
1421 | ||
1422 | default: | |
f3b05ca5 ŁM |
1423 | debug_cond(DEBUG_SETUP != 0, |
1424 | "%s: *** Default of usb_ctrl->bRequest=0x%x" | |
1425 | "happened.\n", __func__, usb_ctrl->bRequest); | |
38517a78 ŁM |
1426 | break; |
1427 | } | |
1428 | } | |
1429 | ||
1430 | ||
1431 | if (likely(dev->driver)) { | |
1432 | /* device-2-host (IN) or no data setup command, | |
1433 | * process immediately */ | |
f3b05ca5 ŁM |
1434 | debug_cond(DEBUG_SETUP != 0, |
1435 | "%s:usb_ctrlreq will be passed to fsg_setup()\n", | |
38517a78 ŁM |
1436 | __func__); |
1437 | ||
1438 | spin_unlock(&dev->lock); | |
1439 | i = dev->driver->setup(&dev->gadget, usb_ctrl); | |
1440 | spin_lock(&dev->lock); | |
1441 | ||
1442 | if (i < 0) { | |
38517a78 ŁM |
1443 | /* setup processing failed, force stall */ |
1444 | s3c_udc_ep0_set_stall(ep); | |
1445 | dev->ep0state = WAIT_FOR_SETUP; | |
1446 | ||
f3b05ca5 ŁM |
1447 | debug_cond(DEBUG_SETUP != 0, |
1448 | "\tdev->driver->setup failed (%d)," | |
38517a78 ŁM |
1449 | " bRequest = %d\n", |
1450 | i, usb_ctrl->bRequest); | |
1451 | ||
1452 | ||
1453 | } else if (dev->req_pending) { | |
1454 | dev->req_pending = 0; | |
f3b05ca5 ŁM |
1455 | debug_cond(DEBUG_SETUP != 0, |
1456 | "\tdev->req_pending...\n"); | |
38517a78 ŁM |
1457 | } |
1458 | ||
f3b05ca5 ŁM |
1459 | debug_cond(DEBUG_SETUP != 0, |
1460 | "\tep0state = %s\n", state_names[dev->ep0state]); | |
38517a78 ŁM |
1461 | |
1462 | } | |
1463 | } | |
1464 | ||
1465 | /* | |
1466 | * handle ep0 interrupt | |
1467 | */ | |
1468 | static void s3c_handle_ep0(struct s3c_udc *dev) | |
1469 | { | |
1470 | if (dev->ep0state == WAIT_FOR_SETUP) { | |
f3b05ca5 ŁM |
1471 | debug_cond(DEBUG_OUT_EP != 0, |
1472 | "%s: WAIT_FOR_SETUP\n", __func__); | |
38517a78 ŁM |
1473 | s3c_ep0_setup(dev); |
1474 | ||
1475 | } else { | |
f3b05ca5 ŁM |
1476 | debug_cond(DEBUG_OUT_EP != 0, |
1477 | "%s: strange state!!(state = %s)\n", | |
38517a78 ŁM |
1478 | __func__, state_names[dev->ep0state]); |
1479 | } | |
1480 | } | |
1481 | ||
1482 | static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep) | |
1483 | { | |
f3b05ca5 ŁM |
1484 | debug_cond(DEBUG_EP0 != 0, |
1485 | "%s: ep_is_in = %d\n", __func__, ep_is_in(ep)); | |
38517a78 ŁM |
1486 | if (ep_is_in(ep)) { |
1487 | dev->ep0state = DATA_STATE_XMIT; | |
1488 | s3c_ep0_write(dev); | |
1489 | ||
1490 | } else { | |
1491 | dev->ep0state = DATA_STATE_RECV; | |
1492 | s3c_ep0_read(dev); | |
1493 | } | |
1494 | } |