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.
14 #define S3C_USB_FIFO_LEN 4096
16 struct s3c_udc_state_s
{
17 target_phys_addr_t base
;
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. */
26 uint8_t fifo
[S3C_USB_FIFO_LEN
];
36 uint8_t fifo
[S3C_USB_FIFO_LEN
];
60 void s3c_udc_reset(struct s3c_udc_state_s
*s
)
66 s
->ep_mask
= (1 << S3C_EPS
) - 1;
73 s
->ep0
.maxpacket
= 0x01;
75 for (i
= 0; i
< S3C_EPS
- 1; i
++) {
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;
90 static void s3c_udc_interrupt(struct s3c_udc_state_s
*s
, int ep
)
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
)
106 fstart
&= S3C_USB_FIFO_LEN
- 1;
107 chunk
= MIN(len
, S3C_USB_FIFO_LEN
- fstart
);
108 memcpy(dst
+ fstart
, src
, chunk
);
115 static void s3c_udc_dequeue_packet(uint8_t *dst
, uint8_t *src
,
116 int *fstart
, int *flen
)
120 chunk
= MIN(*flen
, S3C_USB_FIFO_LEN
- *fstart
);
121 memcpy(dst
, src
+ *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
;
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);
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
);
147 /* Signal completion of IN token */
148 s
->ep0
.csr
&= ~(1 << 3);
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
;
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
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);
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
;
223 while (addr
< s3c_udc_ep_reg
[-- ep
]);
224 addr
-= s3c_udc_ep_reg
[ep
];
238 return s
->usb_mask
& ~(1 << 1);
240 return s
->frame
& 0xff;
242 return s
->frame
>> 8;
247 if (s
->index
>= S3C_EPS
)
252 return s
->ep1
[s
->index
- 1].in_csr
[0];
254 if (s
->index
>= S3C_EPS
|| s
->index
== 0)
256 return s
->ep1
[s
->index
- 1].in_csr
[1];
258 if (s
->index
>= S3C_EPS
|| s
->index
== 0)
260 return s
->ep1
[s
->index
- 1].out_csr
[0];
262 if (s
->index
>= S3C_EPS
|| s
->index
== 0)
264 return s
->ep1
[s
->index
- 1].out_csr
[1];
266 if (unlikely(!s
->ep0
.len
))
267 printf("%s: Endpoint0 underrun\n", __FUNCTION__
);
269 ret
= s
->ep0
.fifo
[s
->ep0
.start
++];
272 s
->ep0
.start
&= S3C_USB_FIFO_LEN
- 1;
274 case S3C_EP4_FIFO
: ep
++;
275 case S3C_EP3_FIFO
: ep
++;
276 case S3C_EP2_FIFO
: ep
++;
278 if (unlikely(s
->ep1
[ep
].in_csr
[1] & (1 << 5))) /* MODE_IN */
280 if (unlikely(!s
->ep1
[ep
].len
))
281 printf("%s: Endpoint%i underrun\n", __FUNCTION__
, ep
+ 1);
283 ret
= s
->ep1
[ep
].fifo
[s
->ep1
[ep
].start
++];
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 */
293 if (s
->index
>= S3C_EPS
)
296 return s
->ep0
.maxpacket
;
298 return s
->ep1
[s
->index
- 1].maxpacket
;
300 if (s
->index
>= S3C_EPS
)
303 return s
->ep0
.len
& 0xff;
305 return s
->ep1
[s
->index
- 1].len
& 0xff;
307 if (s
->index
>= S3C_EPS
)
310 return s
->ep0
.len
>> 8;
312 return s
->ep1
[s
->index
- 1].len
>> 8;
317 return s
->ep1
[ep
].control
;
318 case S3C_EP_DMA_UNIT
:
321 return s
->ep1
[ep
].unit_cnt
;
322 case S3C_EP_DMA_FIFO
:
325 return s
->ep1
[ep
].fifo_cnt
;
326 case S3C_EP_DMA_TTC_L
:
329 return (s
->ep1
[ep
].dma_size
>> 0) & 0xff;
330 case S3C_EP_DMA_TTC_M
:
333 return (s
->ep1
[ep
].dma_size
>> 8) & 0xff;
334 case S3C_EP_DMA_TTC_H
:
337 return (s
->ep1
[ep
].dma_size
>> 16) & 0xf;
340 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
346 static void s3c_udc_write(void *opaque
, target_phys_addr_t addr
,
349 struct s3c_udc_state_s
*s
= (struct s3c_udc_state_s
*) opaque
;
352 while (addr
< s3c_udc_ep_reg
[-- ep
]);
353 addr
-= s3c_udc_ep_reg
[ep
];
357 s
->address
= value
| (1 << 7); /* ADDR_UPDATE */
358 s
->dev
.addr
= value
& 0x7f;
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. */
369 s
->ep_intr
&= ~value
;
373 s
->usb_intr
&= ~value
;
377 s
->ep_mask
= value
& ((1 << S3C_EPS
) - 1);
381 s
->usb_mask
= (value
& 0x5) | (1 << 1);
389 if (s
->index
>= S3C_EPS
)
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
);
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
);
412 if (s
->index
>= S3C_EPS
|| s
->index
== 0)
414 s
->ep1
[s
->index
- 1].in_csr
[1] = value
& 0xf0;
418 if (s
->index
>= S3C_EPS
|| s
->index
== 0)
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));
434 if (s
->index
>= S3C_EPS
|| s
->index
== 0)
436 s
->ep1
[s
->index
- 1].out_csr
[1] = value
& 0xe0;
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
;
446 case S3C_EP4_FIFO
: ep
++;
447 case S3C_EP3_FIFO
: ep
++;
448 case S3C_EP2_FIFO
: ep
++;
450 if (unlikely(!(s
->ep1
[ep
].in_csr
[1] & (1 << 5)))) /* MODE_IN */
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]);
464 if (s
->index
>= S3C_EPS
)
467 s
->ep0
.maxpacket
= value
& 0xf;
469 s
->ep1
[s
->index
- 1].maxpacket
= value
& 0xf;
475 s
->ep1
[ep
].control
= value
;
478 case S3C_EP_DMA_UNIT
:
481 s
->ep1
[ep
].unit_cnt
= value
;
484 case S3C_EP_DMA_FIFO
:
487 s
->ep1
[ep
].fifo_cnt
= value
;
490 case S3C_EP_DMA_TTC_L
:
493 s
->ep1
[ep
].dma_size
&= 0xfff00;
494 s
->ep1
[ep
].dma_size
|= (value
& 0xff) << 0;
497 case S3C_EP_DMA_TTC_M
:
500 s
->ep1
[ep
].dma_size
&= 0xf00ff;
501 s
->ep1
[ep
].dma_size
|= (value
& 0xff) << 8;
504 case S3C_EP_DMA_TTC_H
:
507 s
->ep1
[ep
].dma_size
&= 0x0ffff;
508 s
->ep1
[ep
].dma_size
|= (value
& 0xf) << 16;
513 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
517 static CPUReadMemoryFunc
*s3c_udc_readfn
[] = {
523 static CPUWriteMemoryFunc
*s3c_udc_writefn
[] = {
529 static void s3c_udc_save(QEMUFile
*f
, void *opaque
)
531 struct s3c_udc_state_s
*s
= (struct s3c_udc_state_s
*) opaque
;
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
;
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
);
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
;
595 s
->power
&= ~(1 << 3); /* USB_RESET */
599 dev
->state
= USB_STATE_ATTACHED
;
602 dev
->state
= USB_STATE_NOTATTACHED
;
605 s
->power
|= 1 << 3; /* USB_RESET */
607 s
->usb_intr
|= 1 << 2; /* RESET */
609 s3c_udc_interrupt(s
, -1);
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 */
616 s
->ep0
.csr
|= 1 << 2; /* SENT_STALL */
617 s3c_udc_interrupt(s
, 0);
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);
628 if (unlikely(ep
>= 0 &&
629 !(s
->ep1
[ep
].in_csr
[1] & (1 << 5)))) /* MODE_IN */
632 if (unlikely(s
->ep0
.packet
))
633 printf("%s: EP0 overrun\n", __FUNCTION__
);
634 if (s
->ep0
.csr
& (1 << 5)) { /* SEND_STALL */
636 s
->ep0
.csr
|= 1 << 2; /* SENT_STALL */
637 s3c_udc_interrupt(s
, 0);
640 s
->ep0
.csr
&= ~(1 << 1); /* IN_PKT_RDY */
641 s3c_udc_interrupt(s
, p
->devep
);
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 */
648 s
->ep1
[ep
].in_csr
[0] |= 1 << 5; /* SENT_STALL */
649 s3c_udc_interrupt(s
, 0);
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
);
659 s
->ep1
[ep
].packet
= p
;
666 if (unlikely(ep
>= 0 &&
667 s
->ep1
[ep
].in_csr
[1] & (1 << 5))) /* MODE_IN */
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 */
676 s
->ep0
.csr
|= 1 << 2; /* SENT_STALL */
677 s3c_udc_interrupt(s
, 0);
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
);
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 */
690 s
->ep1
[ep
].out_csr
[0] |= 1 << 6; /* SENT_STALL */
691 s3c_udc_interrupt(s
, 0);
694 s3c_udc_queue_packet(s
->ep1
[ep
].fifo
, p
->data
,
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
);
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). */
718 static void s3c_udc_handle_destroy(USBDevice
*dev
)
720 struct s3c_udc_state_s
*s
= (struct s3c_udc_state_s
*) dev
->opaque
;
725 for (i
= 0; i
< S3C_EPS
- 1; i
++) {
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
)
739 struct s3c_udc_state_s
*s
= (struct s3c_udc_state_s
*)
740 qemu_mallocz(sizeof(struct s3c_udc_state_s
));
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
;
753 iomemtype
= cpu_register_io_memory(0, s3c_udc_readfn
,
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);