MINI2440: General update
[qemu/mini2440.git] / hw / s3c24xx_udc.c
blob5e5fc8c220b1f37413e4efa850dd52f7be9be2c7
1 /*
2 * Samsung S3C2410A USB Device Controller emulation.
4 * Copyright (c) 2007 OpenMoko, Inc.
5 * Author: Andrzej Zaborowski <andrew@openedhand.com>
7 * This code is licenced under the GNU GPL v2.
8 */
10 #include "s3c.h"
11 #include "usb.h"
12 #include "hw.h"
14 #define S3C_USB_FIFO_LEN 4096
16 struct s3c_udc_state_s {
17 target_phys_addr_t base;
18 USBDevice dev;
19 qemu_irq irq;
20 qemu_irq *dma;
22 /* Use FIFOs big enough to hold entire packets, just don't report
23 * lengths greater than 16 and 64 bytes for EP0 and EP1-4 respectively. */
24 struct {
25 int start, len;
26 uint8_t fifo[S3C_USB_FIFO_LEN];
27 USBPacket *packet;
29 uint8_t csr;
30 uint8_t maxpacket;
31 } ep0;
33 #define S3C_EPS 5
34 struct {
35 int start, len;
36 uint8_t fifo[S3C_USB_FIFO_LEN];
37 USBPacket *packet;
38 int packet_len;
40 uint8_t in_csr[2];
41 uint8_t out_csr[2];
42 uint8_t maxpacket;
44 uint8_t control;
45 uint8_t unit_cnt;
46 uint8_t fifo_cnt;
47 uint32_t dma_size;
48 } ep1[S3C_EPS - 1];
50 uint8_t index;
51 uint8_t power;
52 uint8_t ep_intr;
53 uint8_t ep_mask;
54 uint8_t usb_intr;
55 uint8_t usb_mask;
56 uint16_t frame;
57 uint8_t address;
60 void s3c_udc_reset(struct s3c_udc_state_s *s)
62 int i;
63 s->address = 0x00;
64 s->power = 0x00;
65 s->ep_intr = 0x00;
66 s->ep_mask = (1 << S3C_EPS) - 1;
67 s->usb_intr = 0x00;
68 s->usb_mask = 0x06;
69 s->frame = 0x0000;
70 s->index = 0x00;
71 s->ep0.len = 0;
72 s->ep0.csr = 0x00;
73 s->ep0.maxpacket = 0x01;
74 s->ep0.packet = 0;
75 for (i = 0; i < S3C_EPS - 1; i ++) {
76 s->ep1[i].len = 0;
77 s->ep1[i].in_csr[0] = 0;
78 s->ep1[i].in_csr[1] = 0;
79 s->ep1[i].out_csr[0] = 0;
80 s->ep1[i].out_csr[1] = 0;
81 s->ep1[i].maxpacket = 0x01;
82 s->ep1[i].control = 0x00;
83 s->ep1[i].unit_cnt = 0x00;
84 s->ep1[i].fifo_cnt = 0x00;
85 s->ep1[i].dma_size = 0;
86 s->ep1[i].packet = 0;
90 static void s3c_udc_interrupt(struct s3c_udc_state_s *s, int ep)
92 if (ep >= 0)
93 s->ep_intr |= 1 << ep;
94 s->ep_intr &= s->ep_mask;
95 s->usb_intr &= s->usb_mask;
96 qemu_set_irq(s->irq, s->ep_intr | s->usb_intr);
99 static void s3c_udc_queue_packet(uint8_t *dst, uint8_t *src,
100 int fstart, int *flen, int len)
102 int chunk;
103 fstart += *flen;
104 *flen += len;
105 while (len) {
106 fstart &= S3C_USB_FIFO_LEN - 1;
107 chunk = MIN(len, S3C_USB_FIFO_LEN - fstart);
108 memcpy(dst + fstart, src, chunk);
109 len -= chunk;
110 src += chunk;
111 fstart += chunk;
115 static void s3c_udc_dequeue_packet(uint8_t *dst, uint8_t *src,
116 int *fstart, int *flen)
118 int chunk;
119 while (*flen) {
120 chunk = MIN(*flen, S3C_USB_FIFO_LEN - *fstart);
121 memcpy(dst, src + *fstart, chunk);
122 *flen -= chunk;
123 dst += chunk;
124 *fstart += chunk;
125 *fstart &= S3C_USB_FIFO_LEN - 1;
129 static void s3c_udc_ep0_rdy(struct s3c_udc_state_s *s, uint8_t value)
131 USBPacket *packet = s->ep0.packet;
132 if (packet) {
133 if (s->ep0.len < packet->len &&
134 !(value & (1 << 3))) { /* DATA_END */
135 s->ep0.csr &= ~(1 << 1); /* IN_PKT_RDY */
136 s3c_udc_interrupt(s, 0);
137 return;
140 if (value & (1 << 1)) {
141 packet->len = s->ep0.len;
142 s3c_udc_dequeue_packet(packet->data, s->ep0.fifo,
143 &s->ep0.start, &s->ep0.len);
144 } else
145 packet->len = 0;
147 /* Signal completion of IN token */
148 s->ep0.csr &= ~(1 << 3);
149 s->ep0.packet = 0;
150 packet->complete_cb(packet, packet->complete_opaque);
154 static void s3c_udc_ep1_rdy(struct s3c_udc_state_s *s, int ep, uint8_t value)
156 USBPacket *packet = s->ep1[ep].packet;
157 if (packet) {
158 /* HACK: there's no simple (timing independent) way to know when
159 * a packet ends. We will terminate packets only when the OS
160 * writes less than 64 bytes (the FIFO size), thus the OS has to
161 * make a final zero length write if the packet is 64 multiple
162 * sized. */
163 if (!((s->ep1[ep].len - s->ep1[ep].packet_len) & 63) &&
164 (s->ep1[ep].len > s->ep1[ep].packet_len ||
165 s->ep1[ep].len == 0)) {
166 s->ep1[ep].packet_len = s->ep1[ep].len;
167 s->ep1[ep].in_csr[0] &= ~(1 << 0); /* IN_PKT_RDY */
168 s->ep1[ep].in_csr[0] &= ~(1 << 3); /* FIFO_FLUSH */
169 s3c_udc_interrupt(s, ep + 1);
170 return;
173 /* TODO: check that packet->len >= s->ep1[ep].len */
174 packet->len = s->ep1[ep].len;
175 s3c_udc_dequeue_packet(packet->data, s->ep1[ep].fifo,
176 &s->ep1[ep].start, &s->ep1[ep].len);
178 /* Signal completion of IN token */
179 s->ep1[ep].packet = 0;
180 s->ep1[ep].packet_len = 0;
181 packet->complete_cb(packet, packet->complete_opaque);
185 #define S3C_FUNC_ADDR 0x140 /* Function address register */
186 #define S3C_PWR 0x144 /* Power management register */
187 #define S3C_EP_INT 0x148 /* Endpoint interrupt register */
188 #define S3C_USB_INT 0x158 /* USB interrupt register */
189 #define S3C_EP_INT_EN 0x15c /* Endpoint interrupt enable register */
190 #define S3C_USB_INT_EN 0x16c /* USB interrupt enable register */
191 #define S3C_FRAME_NUM1 0x170 /* Frame number 1 register */
192 #define S3C_FRAME_NUM2 0x174 /* Frame number 2 register */
193 #define S3C_INDEX 0x178 /* Index register */
194 #define S3C_MAXP 0x180 /* MAX packet register */
195 #define S3C_IN_CSR1 0x184 /* EP In control status register 1 */
196 #define S3C_IN_CSR2 0x188 /* EP In control status register 2 */
197 #define S3C_OUT_CSR1 0x190 /* EP Out control status register 1 */
198 #define S3C_OUT_CSR2 0x194 /* EP Out control status register 2 */
199 #define S3C_FIFO_CNT1 0x198 /* EP Out write count register 1 */
200 #define S3C_FIFO_CNT2 0x19c /* EP Out write count register 2 */
201 #define S3C_EP0_FIFO 0x1c0 /* Endpoint0 FIFO register */
202 #define S3C_EP1_FIFO 0x1c4 /* Endpoint1 FIFO register */
203 #define S3C_EP2_FIFO 0x1c8 /* Endpoint2 FIFO register */
204 #define S3C_EP3_FIFO 0x1cc /* Endpoint3 FIFO register */
205 #define S3C_EP4_FIFO 0x1d0 /* Endpoint4 FIFO register */
207 static const target_phys_addr_t s3c_udc_ep_reg[S3C_EPS] = {
208 0x000, 0x200, 0x218, 0x240, 0x258
210 #define S3C_EP_DMA_CON 0x00 /* DMA control register */
211 #define S3C_EP_DMA_UNIT 0x04 /* DMA unit counter register */
212 #define S3C_EP_DMA_FIFO 0x08 /* DMA FIFO counter register */
213 #define S3C_EP_DMA_TTC_L 0x0c /* DMA transfer counter low-byte */
214 #define S3C_EP_DMA_TTC_M 0x10 /* DMA transfer counter middle-byte */
215 #define S3C_EP_DMA_TTC_H 0x14 /* DMA transfer counter high-byte */
217 static uint32_t s3c_udc_read(void *opaque, target_phys_addr_t addr)
219 struct s3c_udc_state_s *s = (struct s3c_udc_state_s *) opaque;
220 int ep = S3C_EPS;
221 uint8_t ret = 0;
223 while (addr < s3c_udc_ep_reg[-- ep]);
224 addr -= s3c_udc_ep_reg[ep];
226 switch (addr) {
227 case S3C_FUNC_ADDR:
228 return s->address;
229 case S3C_PWR:
230 return s->power;
231 case S3C_EP_INT:
232 return s->ep_intr;
233 case S3C_USB_INT:
234 return s->usb_intr;
235 case S3C_EP_INT_EN:
236 return s->ep_mask;
237 case S3C_USB_INT_EN:
238 return s->usb_mask & ~(1 << 1);
239 case S3C_FRAME_NUM1:
240 return s->frame & 0xff;
241 case S3C_FRAME_NUM2:
242 return s->frame >> 8;
243 case S3C_INDEX:
244 return s->index;
246 case S3C_IN_CSR1:
247 if (s->index >= S3C_EPS)
248 goto bad_reg;
249 if (s->index == 0)
250 return s->ep0.csr;
251 else
252 return s->ep1[s->index - 1].in_csr[0];
253 case S3C_IN_CSR2:
254 if (s->index >= S3C_EPS || s->index == 0)
255 goto bad_reg;
256 return s->ep1[s->index - 1].in_csr[1];
257 case S3C_OUT_CSR1:
258 if (s->index >= S3C_EPS || s->index == 0)
259 goto bad_reg;
260 return s->ep1[s->index - 1].out_csr[0];
261 case S3C_OUT_CSR2:
262 if (s->index >= S3C_EPS || s->index == 0)
263 goto bad_reg;
264 return s->ep1[s->index - 1].out_csr[1];
265 case S3C_EP0_FIFO:
266 if (unlikely(!s->ep0.len))
267 printf("%s: Endpoint0 underrun\n", __FUNCTION__);
268 else {
269 ret = s->ep0.fifo[s->ep0.start ++];
270 s->ep0.len --;
272 s->ep0.start &= S3C_USB_FIFO_LEN - 1;
273 return ret;
274 case S3C_EP4_FIFO: ep ++;
275 case S3C_EP3_FIFO: ep ++;
276 case S3C_EP2_FIFO: ep ++;
277 case S3C_EP1_FIFO:
278 if (unlikely(s->ep1[ep].in_csr[1] & (1 << 5))) /* MODE_IN */
279 goto bad_reg;
280 if (unlikely(!s->ep1[ep].len))
281 printf("%s: Endpoint%i underrun\n", __FUNCTION__, ep + 1);
282 else {
283 ret = s->ep1[ep].fifo[s->ep1[ep].start ++];
284 s->ep1[ep].len --;
286 s->ep1[ep].start &= S3C_USB_FIFO_LEN - 1;
287 if (s->ep1[ep].out_csr[1] & (1 << 7)) /* AUTO_CLR */
288 if (s->ep1[ep].len <= 0) {
289 s->ep1[ep].out_csr[0] &= ~(1 << 0); /* OUT_PKT_READY */
291 return ret;
292 case S3C_MAXP:
293 if (s->index >= S3C_EPS)
294 goto bad_reg;
295 if (s->index == 0)
296 return s->ep0.maxpacket;
297 else
298 return s->ep1[s->index - 1].maxpacket;
299 case S3C_FIFO_CNT1:
300 if (s->index >= S3C_EPS)
301 goto bad_reg;
302 if (s->index == 0)
303 return s->ep0.len & 0xff;
304 else
305 return s->ep1[s->index - 1].len & 0xff;
306 case S3C_FIFO_CNT2:
307 if (s->index >= S3C_EPS)
308 goto bad_reg;
309 if (s->index == 0)
310 return s->ep0.len >> 8;
311 else
312 return s->ep1[s->index - 1].len >> 8;
314 case S3C_EP_DMA_CON:
315 if (!ep --)
316 goto bad_reg;
317 return s->ep1[ep].control;
318 case S3C_EP_DMA_UNIT:
319 if (!ep --)
320 goto bad_reg;
321 return s->ep1[ep].unit_cnt;
322 case S3C_EP_DMA_FIFO:
323 if (!ep --)
324 goto bad_reg;
325 return s->ep1[ep].fifo_cnt;
326 case S3C_EP_DMA_TTC_L:
327 if (!ep --)
328 goto bad_reg;
329 return (s->ep1[ep].dma_size >> 0) & 0xff;
330 case S3C_EP_DMA_TTC_M:
331 if (!ep --)
332 goto bad_reg;
333 return (s->ep1[ep].dma_size >> 8) & 0xff;
334 case S3C_EP_DMA_TTC_H:
335 if (!ep --)
336 goto bad_reg;
337 return (s->ep1[ep].dma_size >> 16) & 0xf;
338 bad_reg:
339 default:
340 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
341 break;
343 return 0;
346 static void s3c_udc_write(void *opaque, target_phys_addr_t addr,
347 uint32_t value)
349 struct s3c_udc_state_s *s = (struct s3c_udc_state_s *) opaque;
350 int ep = S3C_EPS;
352 while (addr < s3c_udc_ep_reg[-- ep]);
353 addr -= s3c_udc_ep_reg[ep];
355 switch (addr) {
356 case S3C_FUNC_ADDR:
357 s->address = value | (1 << 7); /* ADDR_UPDATE */
358 s->dev.addr = value & 0x7f;
359 break;
361 case S3C_PWR:
362 if (!(value & (1 << 2))) /* MCU_RESUME */
363 s->power &= ~(1 << 1); /* SUSPEND_MODE */
364 s->power = (value & 5) | (s->power & 10);
365 /* Should send a SUSPEND interrupt every 3ms if SUSPEND is enabled. */
366 break;
368 case S3C_EP_INT:
369 s->ep_intr &= ~value;
370 break;
372 case S3C_USB_INT:
373 s->usb_intr &= ~value;
374 break;
376 case S3C_EP_INT_EN:
377 s->ep_mask = value & ((1 << S3C_EPS) - 1);
378 break;
380 case S3C_USB_INT_EN:
381 s->usb_mask = (value & 0x5) | (1 << 1);
382 break;
384 case S3C_INDEX:
385 s->index = value;
386 break;
388 case S3C_IN_CSR1:
389 if (s->index >= S3C_EPS)
390 goto bad_reg;
391 if (s->index == 0) {
392 s->ep0.csr = (value | (s->ep0.csr & 0xa)) & (s->ep0.csr | ~0x4);
393 if (value & (1 << 7)) /* SERVICED_SETUP_EN */
394 s->ep0.csr &= ~(1 << 4); /* SETUP_END */
395 if (value & (1 << 6)) /* SERVICED_OUT_PKT_ */
396 s->ep0.csr &= ~(1 << 0); /* OUT_PKT_RDY */
397 if (value & (1 << 1)) /* IN_PKT_RDY */
398 s3c_udc_ep0_rdy(s, value);
399 else if (value & (1 << 3)) /* DATA_END */
400 s3c_udc_ep0_rdy(s, value);
401 } else {
402 ep = s->index - 1;
403 s->ep1[ep].in_csr[0] = (value | (s->ep1[ep].in_csr[0] & 1)) & 0x19;
404 if (value & (1 << 3)) /* FIFO_FLUSH */
405 s3c_udc_ep1_rdy(s, ep, value);
406 else if (value & (1 << 0)) /* IN_PKT_RDY */
407 s3c_udc_ep1_rdy(s, ep, value);
409 break;
411 case S3C_IN_CSR2:
412 if (s->index >= S3C_EPS || s->index == 0)
413 goto bad_reg;
414 s->ep1[s->index - 1].in_csr[1] = value & 0xf0;
415 break;
417 case S3C_OUT_CSR1:
418 if (s->index >= S3C_EPS || s->index == 0)
419 goto bad_reg;
420 if (s->ep1[s->index - 1].out_csr[0] & (1 << 0)) { /* OUT_PKT_R */
421 if (value & (1 << 4)) /* FIFO_FLUSH */
422 s->ep1[s->index - 1].len = 0;
423 else if (!(value & (1 << 0)) && /* OUT_PKT_RDY */
424 s->ep1[s->index - 1].len) {
425 value |= 1 << 0; /* OUT_PKT_RDY */
426 s3c_udc_interrupt(s, s->index);
429 s->ep1[s->index - 1].out_csr[0] = value &
430 (0xa0 | (s->ep1[s->index - 1].out_csr[0] & 0x41));
431 break;
433 case S3C_OUT_CSR2:
434 if (s->index >= S3C_EPS || s->index == 0)
435 goto bad_reg;
436 s->ep1[s->index - 1].out_csr[1] = value & 0xe0;
437 break;
439 case S3C_EP0_FIFO:
440 if (unlikely(s->ep0.len >= S3C_USB_FIFO_LEN))
441 printf("%s: Endpoint0 overrun\n", __FUNCTION__);
442 s->ep0.fifo[(s->ep0.start + s->ep0.len ++) &
443 (S3C_USB_FIFO_LEN - 1)] = value;
444 break;
446 case S3C_EP4_FIFO: ep ++;
447 case S3C_EP3_FIFO: ep ++;
448 case S3C_EP2_FIFO: ep ++;
449 case S3C_EP1_FIFO:
450 if (unlikely(!(s->ep1[ep].in_csr[1] & (1 << 5)))) /* MODE_IN */
451 goto bad_reg;
452 if (unlikely(s->ep1[ep].len >= S3C_USB_FIFO_LEN))
453 printf("%s: Endpoint%i overrun\n", __FUNCTION__, ep + 1);
454 s->ep1[ep].fifo[(s->ep1[ep].start + s->ep1[ep].len ++) &
455 (S3C_USB_FIFO_LEN - 1)] = value;
456 if (s->ep1[ep].in_csr[1] & (1 << 7)) /* AUTO_SET */
457 if (s->ep1[ep].len >= (s->ep1[ep].maxpacket << 3)) {
458 s->ep1[ep].in_csr[0] |= 1 << 0; /* IN_PKT_RDY */
459 s3c_udc_ep1_rdy(s, ep, s->ep1[ep].in_csr[0]);
461 break;
463 case S3C_MAXP:
464 if (s->index >= S3C_EPS)
465 goto bad_reg;
466 if (s->index == 0)
467 s->ep0.maxpacket = value & 0xf;
468 else
469 s->ep1[s->index - 1].maxpacket = value & 0xf;
470 break;
472 case S3C_EP_DMA_CON:
473 if (!ep --)
474 goto bad_reg;
475 s->ep1[ep].control = value;
476 break;
478 case S3C_EP_DMA_UNIT:
479 if (!ep --)
480 goto bad_reg;
481 s->ep1[ep].unit_cnt = value;
482 break;
484 case S3C_EP_DMA_FIFO:
485 if (!ep --)
486 goto bad_reg;
487 s->ep1[ep].fifo_cnt = value;
488 break;
490 case S3C_EP_DMA_TTC_L:
491 if (!ep --)
492 goto bad_reg;
493 s->ep1[ep].dma_size &= 0xfff00;
494 s->ep1[ep].dma_size |= (value & 0xff) << 0;
495 break;
497 case S3C_EP_DMA_TTC_M:
498 if (!ep --)
499 goto bad_reg;
500 s->ep1[ep].dma_size &= 0xf00ff;
501 s->ep1[ep].dma_size |= (value & 0xff) << 8;
502 break;
504 case S3C_EP_DMA_TTC_H:
505 if (!ep --)
506 goto bad_reg;
507 s->ep1[ep].dma_size &= 0x0ffff;
508 s->ep1[ep].dma_size |= (value & 0xf) << 16;
509 break;
511 bad_reg:
512 default:
513 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
517 static CPUReadMemoryFunc *s3c_udc_readfn[] = {
518 s3c_udc_read,
519 s3c_udc_read,
520 s3c_udc_read,
523 static CPUWriteMemoryFunc *s3c_udc_writefn[] = {
524 s3c_udc_write,
525 s3c_udc_write,
526 s3c_udc_write,
529 static void s3c_udc_save(QEMUFile *f, void *opaque)
531 struct s3c_udc_state_s *s = (struct s3c_udc_state_s *) opaque;
532 int i;
533 qemu_put_8s(f, &s->ep0.csr);
534 qemu_put_8s(f, &s->ep0.maxpacket);
536 for (i = 0; i < S3C_EPS - 1; i ++) {
537 qemu_put_8s(f, &s->ep1[i].in_csr[0]);
538 qemu_put_8s(f, &s->ep1[i].in_csr[1]);
539 qemu_put_8s(f, &s->ep1[i].out_csr[0]);
540 qemu_put_8s(f, &s->ep1[i].out_csr[1]);
541 qemu_put_8s(f, &s->ep1[i].maxpacket);
542 qemu_put_8s(f, &s->ep1[i].control);
543 qemu_put_8s(f, &s->ep1[i].unit_cnt);
544 qemu_put_8s(f, &s->ep1[i].fifo_cnt);
545 qemu_put_be32s(f, &s->ep1[i].dma_size);
548 qemu_put_8s(f, &s->index);
549 qemu_put_8s(f, &s->power);
550 qemu_put_8s(f, &s->ep_intr);
551 qemu_put_8s(f, &s->ep_mask);
552 qemu_put_8s(f, &s->usb_intr);
553 qemu_put_8s(f, &s->usb_mask);
554 qemu_put_be16s(f, &s->frame);
555 qemu_put_8s(f, &s->address);
558 static int s3c_udc_load(QEMUFile *f, void *opaque, int version_id)
560 struct s3c_udc_state_s *s = (struct s3c_udc_state_s *) opaque;
561 int i;
562 /* TODO: Make it look more like a disconnect */
563 qemu_put_8s(f, &s->ep0.csr);
564 qemu_put_8s(f, &s->ep0.maxpacket);
566 for (i = 0; i < S3C_EPS - 1; i ++) {
567 qemu_put_8s(f, &s->ep1[i].in_csr[0]);
568 qemu_put_8s(f, &s->ep1[i].in_csr[1]);
569 qemu_put_8s(f, &s->ep1[i].out_csr[0]);
570 qemu_put_8s(f, &s->ep1[i].out_csr[1]);
571 qemu_put_8s(f, &s->ep1[i].maxpacket);
572 qemu_put_8s(f, &s->ep1[i].control);
573 qemu_put_8s(f, &s->ep1[i].unit_cnt);
574 qemu_put_8s(f, &s->ep1[i].fifo_cnt);
575 qemu_put_be32s(f, &s->ep1[i].dma_size);
578 qemu_put_8s(f, &s->index);
579 qemu_put_8s(f, &s->power);
580 qemu_put_8s(f, &s->ep_intr);
581 qemu_put_8s(f, &s->ep_mask);
582 qemu_put_8s(f, &s->usb_intr);
583 qemu_put_8s(f, &s->usb_mask);
584 qemu_put_be16s(f, &s->frame);
585 qemu_put_8s(f, &s->address);
587 return 0;
590 static int s3c_udc_handle_packet(USBDevice *dev, USBPacket *p)
592 struct s3c_udc_state_s *s = (struct s3c_udc_state_s *) dev->opaque;
593 int ep;
594 int ret = 0;
595 s->power &= ~(1 << 3); /* USB_RESET */
597 switch (p->pid) {
598 case USB_MSG_ATTACH:
599 dev->state = USB_STATE_ATTACHED;
600 break;
601 case USB_MSG_DETACH:
602 dev->state = USB_STATE_NOTATTACHED;
603 break;
604 case USB_MSG_RESET:
605 s->power |= 1 << 3; /* USB_RESET */
606 #if 0
607 s->usb_intr |= 1 << 2; /* RESET */
608 #endif
609 s3c_udc_interrupt(s, -1);
610 break;
611 case USB_TOKEN_SETUP:
612 if (unlikely(s->ep0.packet || (s->ep0.csr & (1 << 0)))) /* OUT_PKT_R */
613 printf("%s: EP0 overrun\n", __FUNCTION__);
614 if (s->ep0.csr & (1 << 5)) { /* SEND_STALL */
615 ret = USB_RET_STALL;
616 s->ep0.csr |= 1 << 2; /* SENT_STALL */
617 s3c_udc_interrupt(s, 0);
618 break;
620 s->frame ++;
621 s3c_udc_queue_packet(s->ep0.fifo, p->data,
622 s->ep0.start, &s->ep0.len, p->len);
623 s->ep0.csr |= 1 << 0; /* OUT_PKT_RDY */
624 s3c_udc_interrupt(s, 0);
625 break;
626 case USB_TOKEN_IN:
627 ep = p->devep - 1;
628 if (unlikely(ep >= 0 &&
629 !(s->ep1[ep].in_csr[1] & (1 << 5)))) /* MODE_IN */
630 goto fail;
631 if (p->devep == 0) {
632 if (unlikely(s->ep0.packet))
633 printf("%s: EP0 overrun\n", __FUNCTION__);
634 if (s->ep0.csr & (1 << 5)) { /* SEND_STALL */
635 ret = USB_RET_STALL;
636 s->ep0.csr |= 1 << 2; /* SENT_STALL */
637 s3c_udc_interrupt(s, 0);
638 break;
640 s->ep0.csr &= ~(1 << 1); /* IN_PKT_RDY */
641 s3c_udc_interrupt(s, p->devep);
642 s->ep0.packet = p;
643 } else {
644 if (unlikely(s->ep1[ep].packet))
645 printf("%s: EP%i overrun\n", __FUNCTION__, ep + 1);
646 if (s->ep1[ep].in_csr[0] & (1 << 4)) { /* SEND_STALL */
647 ret = USB_RET_STALL;
648 s->ep1[ep].in_csr[0] |= 1 << 5; /* SENT_STALL */
649 s3c_udc_interrupt(s, 0);
650 break;
652 if (!(s->ep1[ep].in_csr[1] & (1 << 4)) || /* IN_DMA_INT_MASK */
653 !(s->ep1[ep].control & (1 << 0))) { /* DMA_MODE_EN */
654 s->ep1[ep].in_csr[0] &= ~(1 << 0); /* IN_PKT_RDY */
655 s->ep1[ep].in_csr[0] &= ~(1 << 3); /* FIFO_FLUSH */
656 s3c_udc_interrupt(s, p->devep);
658 /* TODO: DMA */
659 s->ep1[ep].packet = p;
661 s->frame ++;
662 ret = USB_RET_ASYNC;
663 break;
664 case USB_TOKEN_OUT:
665 ep = p->devep - 1;
666 if (unlikely(ep >= 0 &&
667 s->ep1[ep].in_csr[1] & (1 << 5))) /* MODE_IN */
668 goto fail;
669 s->frame ++;
670 if (p->devep == 0) {
671 if (unlikely(s->ep0.packet || (s->ep0.csr &
672 (1 << 0)))) /* OUT_PKT_RDY */
673 printf("%s: EP0 overrun\n", __FUNCTION__);
674 if (s->ep0.csr & (1 << 5)) { /* SEND_STALL */
675 ret = USB_RET_STALL;
676 s->ep0.csr |= 1 << 2; /* SENT_STALL */
677 s3c_udc_interrupt(s, 0);
678 break;
680 s3c_udc_queue_packet(s->ep0.fifo, p->data,
681 s->ep0.start, &s->ep0.len, p->len);
682 s->ep0.csr |= 1 << 0; /* OUT_PKT_RDY */
683 s3c_udc_interrupt(s, p->devep);
684 } else {
685 if (unlikely(s->ep1[ep].packet || (s->ep1[ep].out_csr[0] &
686 (1 << 0)))) /* OUT_PKT_R */
687 printf("%s: EP%i overrun\n", __FUNCTION__, ep + 1);
688 if (s->ep1[ep].out_csr[0] & (1 << 5)) { /* SEND_STALL */
689 ret = USB_RET_STALL;
690 s->ep1[ep].out_csr[0] |= 1 << 6; /* SENT_STALL */
691 s3c_udc_interrupt(s, 0);
692 break;
694 s3c_udc_queue_packet(s->ep1[ep].fifo, p->data,
695 s->ep1[ep].start,
696 &s->ep1[ep].len, p->len);
697 if (!(s->ep1[ep].out_csr[1] & (1 << 5)) || /* OUT_DMA_INT_MASK */
698 !(s->ep1[ep].control & (1 << 0))) { /* DMA_MODE_EN */
699 s->ep1[ep].out_csr[0] |= 1 << 0; /* OUT_PKT_RDY */
700 s3c_udc_interrupt(s, p->devep);
702 /* TODO: DMA */
704 /* Perhaps it is a good idea to return USB_RET_ASYNC here and in
705 * USB_TOKEN_SETUP and trigger completion only after OUT_PKT_RDY
706 * condition is serviced by the guest to avoid potential overruns
707 * and so that the host can know about timeouts (seems there's no
708 * way to indicate other errors asynchronously). */
709 break;
710 default:
711 fail:
712 ret = USB_RET_STALL;
713 break;
715 return ret;
718 static void s3c_udc_handle_destroy(USBDevice *dev)
720 struct s3c_udc_state_s *s = (struct s3c_udc_state_s *) dev->opaque;
721 int i;
722 s->ep0.len = 0;
723 s->ep0.csr = 0x00;
724 s->ep0.packet = 0;
725 for (i = 0; i < S3C_EPS - 1; i ++) {
726 s->ep1[i].len = 0;
727 s->ep1[i].in_csr[0] = 0;
728 s->ep1[i].in_csr[1] = 0;
729 s->ep1[i].out_csr[0] = 0;
730 s->ep1[i].out_csr[1] = 0;
731 s->ep1[i].packet = 0;
735 struct s3c_udc_state_s *s3c_udc_init(target_phys_addr_t base,
736 qemu_irq irq, qemu_irq *dma)
738 int iomemtype;
739 struct s3c_udc_state_s *s = (struct s3c_udc_state_s *)
740 qemu_mallocz(sizeof(struct s3c_udc_state_s));
742 s->base = base;
743 s->irq = irq;
744 s->dma = dma;
746 s->dev.speed = USB_SPEED_FULL;
747 s->dev.handle_packet = s3c_udc_handle_packet;
748 s->dev.handle_destroy = s3c_udc_handle_destroy;
749 s->dev.opaque = s;
751 s3c_udc_reset(s);
753 iomemtype = cpu_register_io_memory(0, s3c_udc_readfn,
754 s3c_udc_writefn, s);
755 cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
757 register_savevm("s3c24xx_udc", 0, 0, s3c_udc_save, s3c_udc_load, s);
759 // TODO import usb gadget code from openmoko
760 // qemu_register_usb_gadget(&s->dev);
762 return s;