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