1 | /* |
---|
2 | * USB UHCI controller emulation |
---|
3 | * |
---|
4 | * Copyright (c) 2005 Fabrice Bellard |
---|
5 | * |
---|
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
---|
7 | * of this software and associated documentation files (the "Software"), to deal |
---|
8 | * in the Software without restriction, including without limitation the rights |
---|
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
---|
10 | * copies of the Software, and to permit persons to whom the Software is |
---|
11 | * furnished to do so, subject to the following conditions: |
---|
12 | * |
---|
13 | * The above copyright notice and this permission notice shall be included in |
---|
14 | * all copies or substantial portions of the Software. |
---|
15 | * |
---|
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
---|
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
---|
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
---|
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
---|
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
---|
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
---|
22 | * THE SOFTWARE. |
---|
23 | */ |
---|
24 | #include "vl.h" |
---|
25 | |
---|
26 | //#define DEBUG |
---|
27 | //#define DEBUG_PACKET |
---|
28 | |
---|
29 | #define UHCI_CMD_GRESET (1 << 2) |
---|
30 | #define UHCI_CMD_HCRESET (1 << 1) |
---|
31 | #define UHCI_CMD_RS (1 << 0) |
---|
32 | |
---|
33 | #define UHCI_STS_HCHALTED (1 << 5) |
---|
34 | #define UHCI_STS_HCPERR (1 << 4) |
---|
35 | #define UHCI_STS_HSERR (1 << 3) |
---|
36 | #define UHCI_STS_RD (1 << 2) |
---|
37 | #define UHCI_STS_USBERR (1 << 1) |
---|
38 | #define UHCI_STS_USBINT (1 << 0) |
---|
39 | |
---|
40 | #define TD_CTRL_SPD (1 << 29) |
---|
41 | #define TD_CTRL_ERROR_SHIFT 27 |
---|
42 | #define TD_CTRL_IOS (1 << 25) |
---|
43 | #define TD_CTRL_IOC (1 << 24) |
---|
44 | #define TD_CTRL_ACTIVE (1 << 23) |
---|
45 | #define TD_CTRL_STALL (1 << 22) |
---|
46 | #define TD_CTRL_BUFFER (1 << 21) |
---|
47 | #define TD_CTRL_BABBLE (1 << 20) |
---|
48 | #define TD_CTRL_NAK (1 << 19) |
---|
49 | #define TD_CTRL_TIMEOUT (1 << 18) |
---|
50 | #define TD_CTRL_BITSTUFF \ |
---|
51 | (1 << 17) |
---|
52 | #define TD_CTRL_MASK \ |
---|
53 | (TD_CTRL_BITSTUFF | TD_CTRL_TIMEOUT | TD_CTRL_NAK \ |
---|
54 | | TD_CTRL_BABBLE | TD_CTRL_BUFFER | TD_CTRL_STALL) |
---|
55 | |
---|
56 | #define UHCI_PORT_RESET (1 << 9) |
---|
57 | #define UHCI_PORT_LSDA (1 << 8) |
---|
58 | #define UHCI_PORT_ENC (1 << 3) |
---|
59 | #define UHCI_PORT_EN (1 << 2) |
---|
60 | #define UHCI_PORT_CSC (1 << 1) |
---|
61 | #define UHCI_PORT_CCS (1 << 0) |
---|
62 | |
---|
63 | #define FRAME_TIMER_FREQ 1000 |
---|
64 | |
---|
65 | #define FRAME_MAX_LOOPS 100 |
---|
66 | |
---|
67 | #define NB_PORTS 2 |
---|
68 | |
---|
69 | typedef struct UHCIPort { |
---|
70 | USBPort port; |
---|
71 | uint16_t ctrl; |
---|
72 | } UHCIPort; |
---|
73 | |
---|
74 | typedef struct UHCIState { |
---|
75 | PCIDevice dev; |
---|
76 | uint16_t cmd; /* cmd register */ |
---|
77 | uint16_t status; |
---|
78 | uint16_t intr; /* interrupt enable register */ |
---|
79 | uint16_t frnum; /* frame number */ |
---|
80 | uint32_t fl_base_addr; /* frame list base address */ |
---|
81 | uint8_t sof_timing; |
---|
82 | uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ |
---|
83 | QEMUTimer *frame_timer; |
---|
84 | UHCIPort ports[NB_PORTS]; |
---|
85 | } UHCIState; |
---|
86 | |
---|
87 | typedef struct UHCI_TD { |
---|
88 | uint32_t link; |
---|
89 | uint32_t ctrl; /* see TD_CTRL_xxx */ |
---|
90 | uint32_t token; |
---|
91 | uint32_t buffer; |
---|
92 | } UHCI_TD; |
---|
93 | |
---|
94 | typedef struct UHCI_QH { |
---|
95 | uint32_t link; |
---|
96 | uint32_t el_link; |
---|
97 | } UHCI_QH; |
---|
98 | |
---|
99 | static void uhci_attach(USBPort *port1, USBDevice *dev); |
---|
100 | |
---|
101 | static void uhci_update_irq(UHCIState *s) |
---|
102 | { |
---|
103 | int level; |
---|
104 | if (((s->status2 & 1) && (s->intr & (1 << 2))) || |
---|
105 | ((s->status2 & 2) && (s->intr & (1 << 3))) || |
---|
106 | ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) || |
---|
107 | ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) || |
---|
108 | (s->status & UHCI_STS_HSERR) || |
---|
109 | (s->status & UHCI_STS_HCPERR)) { |
---|
110 | level = 1; |
---|
111 | } else { |
---|
112 | level = 0; |
---|
113 | } |
---|
114 | pci_set_irq(&s->dev, 3, level); |
---|
115 | } |
---|
116 | |
---|
117 | static void uhci_reset(UHCIState *s) |
---|
118 | { |
---|
119 | uint8_t *pci_conf; |
---|
120 | int i; |
---|
121 | UHCIPort *port; |
---|
122 | |
---|
123 | pci_conf = s->dev.config; |
---|
124 | |
---|
125 | pci_conf[0x6a] = 0x01; /* usb clock */ |
---|
126 | pci_conf[0x6b] = 0x00; |
---|
127 | s->cmd = 0; |
---|
128 | s->status = 0; |
---|
129 | s->status2 = 0; |
---|
130 | s->intr = 0; |
---|
131 | s->fl_base_addr = 0; |
---|
132 | s->sof_timing = 64; |
---|
133 | for(i = 0; i < NB_PORTS; i++) { |
---|
134 | port = &s->ports[i]; |
---|
135 | port->ctrl = 0x0080; |
---|
136 | if (port->port.dev) |
---|
137 | uhci_attach(&port->port, port->port.dev); |
---|
138 | } |
---|
139 | } |
---|
140 | |
---|
141 | static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) |
---|
142 | { |
---|
143 | UHCIState *s = opaque; |
---|
144 | |
---|
145 | addr &= 0x1f; |
---|
146 | switch(addr) { |
---|
147 | case 0x0c: |
---|
148 | s->sof_timing = val; |
---|
149 | break; |
---|
150 | } |
---|
151 | } |
---|
152 | |
---|
153 | static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr) |
---|
154 | { |
---|
155 | UHCIState *s = opaque; |
---|
156 | uint32_t val; |
---|
157 | |
---|
158 | addr &= 0x1f; |
---|
159 | switch(addr) { |
---|
160 | case 0x0c: |
---|
161 | val = s->sof_timing; |
---|
162 | break; |
---|
163 | default: |
---|
164 | val = 0xff; |
---|
165 | break; |
---|
166 | } |
---|
167 | return val; |
---|
168 | } |
---|
169 | |
---|
170 | static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) |
---|
171 | { |
---|
172 | UHCIState *s = opaque; |
---|
173 | |
---|
174 | addr &= 0x1f; |
---|
175 | #ifdef DEBUG |
---|
176 | printf("uhci writew port=0x%04x val=0x%04x\n", addr, val); |
---|
177 | #endif |
---|
178 | switch(addr) { |
---|
179 | case 0x00: |
---|
180 | if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) { |
---|
181 | /* start frame processing */ |
---|
182 | qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock)); |
---|
183 | s->status &= ~UHCI_STS_HCHALTED; |
---|
184 | } else if (!(val & UHCI_CMD_RS)) { |
---|
185 | s->status |= UHCI_STS_HCHALTED; |
---|
186 | } |
---|
187 | if (val & UHCI_CMD_GRESET) { |
---|
188 | UHCIPort *port; |
---|
189 | USBDevice *dev; |
---|
190 | int i; |
---|
191 | |
---|
192 | /* send reset on the USB bus */ |
---|
193 | for(i = 0; i < NB_PORTS; i++) { |
---|
194 | port = &s->ports[i]; |
---|
195 | dev = port->port.dev; |
---|
196 | if (dev) { |
---|
197 | dev->handle_packet(dev, |
---|
198 | USB_MSG_RESET, 0, 0, NULL, 0); |
---|
199 | } |
---|
200 | } |
---|
201 | uhci_reset(s); |
---|
202 | return; |
---|
203 | } |
---|
204 | if (val & UHCI_CMD_HCRESET) { |
---|
205 | uhci_reset(s); |
---|
206 | return; |
---|
207 | } |
---|
208 | s->cmd = val; |
---|
209 | break; |
---|
210 | case 0x02: |
---|
211 | s->status &= ~val; |
---|
212 | /* XXX: the chip spec is not coherent, so we add a hidden |
---|
213 | register to distinguish between IOC and SPD */ |
---|
214 | if (val & UHCI_STS_USBINT) |
---|
215 | s->status2 = 0; |
---|
216 | uhci_update_irq(s); |
---|
217 | break; |
---|
218 | case 0x04: |
---|
219 | s->intr = val; |
---|
220 | uhci_update_irq(s); |
---|
221 | break; |
---|
222 | case 0x06: |
---|
223 | if (s->status & UHCI_STS_HCHALTED) |
---|
224 | s->frnum = val & 0x7ff; |
---|
225 | break; |
---|
226 | case 0x10 ... 0x1f: |
---|
227 | { |
---|
228 | UHCIPort *port; |
---|
229 | USBDevice *dev; |
---|
230 | int n; |
---|
231 | |
---|
232 | n = (addr >> 1) & 7; |
---|
233 | if (n >= NB_PORTS) |
---|
234 | return; |
---|
235 | port = &s->ports[n]; |
---|
236 | dev = port->port.dev; |
---|
237 | if (dev) { |
---|
238 | /* port reset */ |
---|
239 | if ( (val & UHCI_PORT_RESET) && |
---|
240 | !(port->ctrl & UHCI_PORT_RESET) ) { |
---|
241 | dev->handle_packet(dev, |
---|
242 | USB_MSG_RESET, 0, 0, NULL, 0); |
---|
243 | } |
---|
244 | } |
---|
245 | port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb); |
---|
246 | /* some bits are reset when a '1' is written to them */ |
---|
247 | port->ctrl &= ~(val & 0x000a); |
---|
248 | } |
---|
249 | break; |
---|
250 | } |
---|
251 | } |
---|
252 | |
---|
253 | static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) |
---|
254 | { |
---|
255 | UHCIState *s = opaque; |
---|
256 | uint32_t val; |
---|
257 | |
---|
258 | addr &= 0x1f; |
---|
259 | switch(addr) { |
---|
260 | case 0x00: |
---|
261 | val = s->cmd; |
---|
262 | break; |
---|
263 | case 0x02: |
---|
264 | val = s->status; |
---|
265 | break; |
---|
266 | case 0x04: |
---|
267 | val = s->intr; |
---|
268 | break; |
---|
269 | case 0x06: |
---|
270 | val = s->frnum; |
---|
271 | break; |
---|
272 | case 0x10 ... 0x1f: |
---|
273 | { |
---|
274 | UHCIPort *port; |
---|
275 | int n; |
---|
276 | n = (addr >> 1) & 7; |
---|
277 | if (n >= NB_PORTS) |
---|
278 | goto read_default; |
---|
279 | port = &s->ports[n]; |
---|
280 | val = port->ctrl; |
---|
281 | } |
---|
282 | break; |
---|
283 | default: |
---|
284 | read_default: |
---|
285 | val = 0xff7f; /* disabled port */ |
---|
286 | break; |
---|
287 | } |
---|
288 | #ifdef DEBUG |
---|
289 | printf("uhci readw port=0x%04x val=0x%04x\n", addr, val); |
---|
290 | #endif |
---|
291 | return val; |
---|
292 | } |
---|
293 | |
---|
294 | static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val) |
---|
295 | { |
---|
296 | UHCIState *s = opaque; |
---|
297 | |
---|
298 | addr &= 0x1f; |
---|
299 | #ifdef DEBUG |
---|
300 | printf("uhci writel port=0x%04x val=0x%08x\n", addr, val); |
---|
301 | #endif |
---|
302 | switch(addr) { |
---|
303 | case 0x08: |
---|
304 | s->fl_base_addr = val & ~0xfff; |
---|
305 | break; |
---|
306 | } |
---|
307 | } |
---|
308 | |
---|
309 | static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr) |
---|
310 | { |
---|
311 | UHCIState *s = opaque; |
---|
312 | uint32_t val; |
---|
313 | |
---|
314 | addr &= 0x1f; |
---|
315 | switch(addr) { |
---|
316 | case 0x08: |
---|
317 | val = s->fl_base_addr; |
---|
318 | break; |
---|
319 | default: |
---|
320 | val = 0xffffffff; |
---|
321 | break; |
---|
322 | } |
---|
323 | return val; |
---|
324 | } |
---|
325 | |
---|
326 | static void uhci_attach(USBPort *port1, USBDevice *dev) |
---|
327 | { |
---|
328 | UHCIState *s = port1->opaque; |
---|
329 | UHCIPort *port = &s->ports[port1->index]; |
---|
330 | |
---|
331 | if (dev) { |
---|
332 | if (port->port.dev) { |
---|
333 | usb_attach(port1, NULL); |
---|
334 | } |
---|
335 | /* set connect status */ |
---|
336 | port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; |
---|
337 | |
---|
338 | /* update speed */ |
---|
339 | if (dev->speed == USB_SPEED_LOW) |
---|
340 | port->ctrl |= UHCI_PORT_LSDA; |
---|
341 | else |
---|
342 | port->ctrl &= ~UHCI_PORT_LSDA; |
---|
343 | port->port.dev = dev; |
---|
344 | /* send the attach message */ |
---|
345 | dev->handle_packet(dev, |
---|
346 | USB_MSG_ATTACH, 0, 0, NULL, 0); |
---|
347 | } else { |
---|
348 | /* set connect status */ |
---|
349 | if (port->ctrl & UHCI_PORT_CCS) { |
---|
350 | port->ctrl &= ~UHCI_PORT_CCS; |
---|
351 | port->ctrl |= UHCI_PORT_CSC; |
---|
352 | } |
---|
353 | /* disable port */ |
---|
354 | if (port->ctrl & UHCI_PORT_EN) { |
---|
355 | port->ctrl &= ~UHCI_PORT_EN; |
---|
356 | port->ctrl |= UHCI_PORT_ENC; |
---|
357 | } |
---|
358 | dev = port->port.dev; |
---|
359 | if (dev) { |
---|
360 | /* send the detach message */ |
---|
361 | dev->handle_packet(dev, |
---|
362 | USB_MSG_DETACH, 0, 0, NULL, 0); |
---|
363 | } |
---|
364 | port->port.dev = NULL; |
---|
365 | } |
---|
366 | } |
---|
367 | |
---|
368 | static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, |
---|
369 | uint8_t devaddr, uint8_t devep, |
---|
370 | uint8_t *data, int len) |
---|
371 | { |
---|
372 | UHCIPort *port; |
---|
373 | USBDevice *dev; |
---|
374 | int i, ret; |
---|
375 | |
---|
376 | #ifdef DEBUG_PACKET |
---|
377 | { |
---|
378 | const char *pidstr; |
---|
379 | switch(pid) { |
---|
380 | case USB_TOKEN_SETUP: pidstr = "SETUP"; break; |
---|
381 | case USB_TOKEN_IN: pidstr = "IN"; break; |
---|
382 | case USB_TOKEN_OUT: pidstr = "OUT"; break; |
---|
383 | default: pidstr = "?"; break; |
---|
384 | } |
---|
385 | printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n", |
---|
386 | s->frnum, pidstr, devaddr, devep, len); |
---|
387 | if (pid != USB_TOKEN_IN) { |
---|
388 | printf(" data_out="); |
---|
389 | for(i = 0; i < len; i++) { |
---|
390 | printf(" %02x", data[i]); |
---|
391 | } |
---|
392 | printf("\n"); |
---|
393 | } |
---|
394 | } |
---|
395 | #endif |
---|
396 | for(i = 0; i < NB_PORTS; i++) { |
---|
397 | port = &s->ports[i]; |
---|
398 | dev = port->port.dev; |
---|
399 | if (dev && (port->ctrl & UHCI_PORT_EN)) { |
---|
400 | ret = dev->handle_packet(dev, pid, |
---|
401 | devaddr, devep, |
---|
402 | data, len); |
---|
403 | if (ret != USB_RET_NODEV) { |
---|
404 | #ifdef DEBUG_PACKET |
---|
405 | { |
---|
406 | printf(" ret=%d ", ret); |
---|
407 | if (pid == USB_TOKEN_IN && ret > 0) { |
---|
408 | printf("data_in="); |
---|
409 | for(i = 0; i < ret; i++) { |
---|
410 | printf(" %02x", data[i]); |
---|
411 | } |
---|
412 | } |
---|
413 | printf("\n"); |
---|
414 | } |
---|
415 | #endif |
---|
416 | return ret; |
---|
417 | } |
---|
418 | } |
---|
419 | } |
---|
420 | return USB_RET_NODEV; |
---|
421 | } |
---|
422 | |
---|
423 | /* return -1 if fatal error (frame must be stopped) |
---|
424 | 0 if TD successful |
---|
425 | 1 if TD unsuccessful or inactive |
---|
426 | */ |
---|
427 | static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) |
---|
428 | { |
---|
429 | uint8_t pid; |
---|
430 | uint8_t buf[2048]; |
---|
431 | int len, max_len, err, ret; |
---|
432 | |
---|
433 | if (!(td->ctrl & TD_CTRL_ACTIVE)){ |
---|
434 | ret = 1; |
---|
435 | goto out; |
---|
436 | } |
---|
437 | /* Clear TD's status field explicitly */ |
---|
438 | td->ctrl = td->ctrl & (~TD_CTRL_MASK); |
---|
439 | |
---|
440 | /* TD is active */ |
---|
441 | max_len = ((td->token >> 21) + 1) & 0x7ff; |
---|
442 | pid = td->token & 0xff; |
---|
443 | switch(pid) { |
---|
444 | case USB_TOKEN_OUT: |
---|
445 | case USB_TOKEN_SETUP: |
---|
446 | cpu_physical_memory_read(td->buffer, buf, max_len); |
---|
447 | ret = uhci_broadcast_packet(s, pid, |
---|
448 | (td->token >> 8) & 0x7f, |
---|
449 | (td->token >> 15) & 0xf, |
---|
450 | buf, max_len); |
---|
451 | len = max_len; |
---|
452 | break; |
---|
453 | case USB_TOKEN_IN: |
---|
454 | ret = uhci_broadcast_packet(s, pid, |
---|
455 | (td->token >> 8) & 0x7f, |
---|
456 | (td->token >> 15) & 0xf, |
---|
457 | buf, max_len); |
---|
458 | if (ret >= 0) { |
---|
459 | len = ret; |
---|
460 | if (len > max_len) { |
---|
461 | len = max_len; |
---|
462 | ret = USB_RET_BABBLE; |
---|
463 | } |
---|
464 | if (len > 0) { |
---|
465 | /* write the data back */ |
---|
466 | cpu_physical_memory_write(td->buffer, buf, len); |
---|
467 | } |
---|
468 | } else { |
---|
469 | len = 0; |
---|
470 | } |
---|
471 | break; |
---|
472 | default: |
---|
473 | /* invalid pid : frame interrupted */ |
---|
474 | s->status |= UHCI_STS_HCPERR; |
---|
475 | uhci_update_irq(s); |
---|
476 | ret = -1; |
---|
477 | goto out; |
---|
478 | } |
---|
479 | if (td->ctrl & TD_CTRL_IOS) |
---|
480 | td->ctrl &= ~TD_CTRL_ACTIVE; |
---|
481 | if (ret >= 0) { |
---|
482 | td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); |
---|
483 | td->ctrl &= ~TD_CTRL_ACTIVE; |
---|
484 | if (pid == USB_TOKEN_IN && |
---|
485 | (td->ctrl & TD_CTRL_SPD) && |
---|
486 | len < max_len) { |
---|
487 | *int_mask |= 0x02; |
---|
488 | /* short packet: do not update QH */ |
---|
489 | ret = 1; |
---|
490 | goto out; |
---|
491 | } else { |
---|
492 | /* success */ |
---|
493 | ret = 0; |
---|
494 | goto out; |
---|
495 | } |
---|
496 | } else { |
---|
497 | switch(ret) { |
---|
498 | default: |
---|
499 | case USB_RET_NODEV: |
---|
500 | do_timeout: |
---|
501 | td->ctrl |= TD_CTRL_TIMEOUT; |
---|
502 | err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3; |
---|
503 | if (err != 0) { |
---|
504 | err--; |
---|
505 | if (err == 0) { |
---|
506 | td->ctrl &= ~TD_CTRL_ACTIVE; |
---|
507 | s->status |= UHCI_STS_USBERR; |
---|
508 | uhci_update_irq(s); |
---|
509 | } |
---|
510 | } |
---|
511 | td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | |
---|
512 | (err << TD_CTRL_ERROR_SHIFT); |
---|
513 | ret = 1; |
---|
514 | goto out; |
---|
515 | case USB_RET_NAK: |
---|
516 | td->ctrl |= TD_CTRL_NAK; |
---|
517 | if (pid == USB_TOKEN_SETUP) |
---|
518 | goto do_timeout; |
---|
519 | ret = 1; |
---|
520 | goto out; |
---|
521 | case USB_RET_STALL: |
---|
522 | td->ctrl |= TD_CTRL_STALL; |
---|
523 | td->ctrl &= ~TD_CTRL_ACTIVE; |
---|
524 | ret = 1; |
---|
525 | goto out; |
---|
526 | case USB_RET_BABBLE: |
---|
527 | td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; |
---|
528 | td->ctrl &= ~TD_CTRL_ACTIVE; |
---|
529 | /* frame interrupted */ |
---|
530 | ret = -1; |
---|
531 | goto out; |
---|
532 | } |
---|
533 | } |
---|
534 | |
---|
535 | out: |
---|
536 | /* If TD is inactive and IOC bit set to 1 then update int_mask */ |
---|
537 | if ((td->ctrl & TD_CTRL_IOC) && (!(td->ctrl & TD_CTRL_ACTIVE))) { |
---|
538 | *int_mask |= 0x01; |
---|
539 | } |
---|
540 | return ret; |
---|
541 | } |
---|
542 | |
---|
543 | static void uhci_frame_timer(void *opaque) |
---|
544 | { |
---|
545 | UHCIState *s = opaque; |
---|
546 | int64_t expire_time; |
---|
547 | uint32_t frame_addr, link, old_td_ctrl, val; |
---|
548 | int int_mask, cnt, ret; |
---|
549 | UHCI_TD td; |
---|
550 | UHCI_QH qh; |
---|
551 | |
---|
552 | if (!(s->cmd & UHCI_CMD_RS)) { |
---|
553 | qemu_del_timer(s->frame_timer); |
---|
554 | /* set hchalted bit in status - UHCI11D 2.1.2 */ |
---|
555 | s->status |= UHCI_STS_HCHALTED; |
---|
556 | return; |
---|
557 | } |
---|
558 | frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2); |
---|
559 | cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); |
---|
560 | le32_to_cpus(&link); |
---|
561 | int_mask = 0; |
---|
562 | cnt = FRAME_MAX_LOOPS; |
---|
563 | while ((link & 1) == 0) { |
---|
564 | if (--cnt == 0) |
---|
565 | break; |
---|
566 | /* valid frame */ |
---|
567 | if (link & 2) { |
---|
568 | /* QH */ |
---|
569 | cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh)); |
---|
570 | le32_to_cpus(&qh.link); |
---|
571 | le32_to_cpus(&qh.el_link); |
---|
572 | depth_first: |
---|
573 | if (qh.el_link & 1) { |
---|
574 | /* no element : go to next entry */ |
---|
575 | link = qh.link; |
---|
576 | } else if (qh.el_link & 2) { |
---|
577 | /* QH */ |
---|
578 | link = qh.el_link; |
---|
579 | } else { |
---|
580 | /* TD */ |
---|
581 | if (--cnt == 0) |
---|
582 | break; |
---|
583 | cpu_physical_memory_read(qh.el_link & ~0xf, |
---|
584 | (uint8_t *)&td, sizeof(td)); |
---|
585 | le32_to_cpus(&td.link); |
---|
586 | le32_to_cpus(&td.ctrl); |
---|
587 | le32_to_cpus(&td.token); |
---|
588 | le32_to_cpus(&td.buffer); |
---|
589 | old_td_ctrl = td.ctrl; |
---|
590 | ret = uhci_handle_td(s, &td, &int_mask); |
---|
591 | /* update the status bits of the TD */ |
---|
592 | if (old_td_ctrl != td.ctrl) { |
---|
593 | val = cpu_to_le32(td.ctrl); |
---|
594 | cpu_physical_memory_write((qh.el_link & ~0xf) + 4, |
---|
595 | (const uint8_t *)&val, |
---|
596 | sizeof(val)); |
---|
597 | } |
---|
598 | if (ret < 0) |
---|
599 | break; /* interrupted frame */ |
---|
600 | if (ret == 0) { |
---|
601 | /* update qh element link */ |
---|
602 | qh.el_link = td.link; |
---|
603 | val = cpu_to_le32(qh.el_link); |
---|
604 | cpu_physical_memory_write((link & ~0xf) + 4, |
---|
605 | (const uint8_t *)&val, |
---|
606 | sizeof(val)); |
---|
607 | if (qh.el_link & 4) { |
---|
608 | /* depth first */ |
---|
609 | goto depth_first; |
---|
610 | } |
---|
611 | } |
---|
612 | /* go to next entry */ |
---|
613 | link = qh.link; |
---|
614 | } |
---|
615 | } else { |
---|
616 | /* TD */ |
---|
617 | cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td)); |
---|
618 | le32_to_cpus(&td.link); |
---|
619 | le32_to_cpus(&td.ctrl); |
---|
620 | le32_to_cpus(&td.token); |
---|
621 | le32_to_cpus(&td.buffer); |
---|
622 | old_td_ctrl = td.ctrl; |
---|
623 | ret = uhci_handle_td(s, &td, &int_mask); |
---|
624 | /* update the status bits of the TD */ |
---|
625 | if (old_td_ctrl != td.ctrl) { |
---|
626 | val = cpu_to_le32(td.ctrl); |
---|
627 | cpu_physical_memory_write((link & ~0xf) + 4, |
---|
628 | (const uint8_t *)&val, |
---|
629 | sizeof(val)); |
---|
630 | } |
---|
631 | if (ret < 0) |
---|
632 | break; /* interrupted frame */ |
---|
633 | link = td.link; |
---|
634 | } |
---|
635 | } |
---|
636 | s->frnum = (s->frnum + 1) & 0x7ff; |
---|
637 | if (int_mask) { |
---|
638 | s->status2 |= int_mask; |
---|
639 | s->status |= UHCI_STS_USBINT; |
---|
640 | uhci_update_irq(s); |
---|
641 | } |
---|
642 | /* prepare the timer for the next frame */ |
---|
643 | expire_time = qemu_get_clock(vm_clock) + |
---|
644 | (ticks_per_sec / FRAME_TIMER_FREQ); |
---|
645 | qemu_mod_timer(s->frame_timer, expire_time); |
---|
646 | } |
---|
647 | |
---|
648 | static void uhci_map(PCIDevice *pci_dev, int region_num, |
---|
649 | uint32_t addr, uint32_t size, int type) |
---|
650 | { |
---|
651 | UHCIState *s = (UHCIState *)pci_dev; |
---|
652 | |
---|
653 | register_ioport_write(addr, 32, 2, uhci_ioport_writew, s); |
---|
654 | register_ioport_read(addr, 32, 2, uhci_ioport_readw, s); |
---|
655 | register_ioport_write(addr, 32, 4, uhci_ioport_writel, s); |
---|
656 | register_ioport_read(addr, 32, 4, uhci_ioport_readl, s); |
---|
657 | register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s); |
---|
658 | register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); |
---|
659 | } |
---|
660 | |
---|
661 | void uhci_usb_save(QEMUFile *f, void *opaque) |
---|
662 | { |
---|
663 | int i; |
---|
664 | UHCIState *s = (UHCIState*)opaque; |
---|
665 | |
---|
666 | qemu_put_be16s(f, &s->cmd); |
---|
667 | qemu_put_be16s(f, &s->status); |
---|
668 | qemu_put_be16s(f, &s->intr); |
---|
669 | qemu_put_be16s(f, &s->frnum); |
---|
670 | qemu_put_be32s(f, &s->fl_base_addr); |
---|
671 | qemu_put_8s(f, &s->sof_timing); |
---|
672 | qemu_put_8s(f, &s->status2); |
---|
673 | |
---|
674 | for(i = 0; i < NB_PORTS; i++) { |
---|
675 | qemu_put_be16s(f, &s->ports[i].ctrl); |
---|
676 | } |
---|
677 | |
---|
678 | qemu_put_timer(f, s->frame_timer); |
---|
679 | } |
---|
680 | |
---|
681 | int uhci_usb_load(QEMUFile *f, void *opaque, int version_id) |
---|
682 | { |
---|
683 | int i; |
---|
684 | UHCIState *s = (UHCIState*)opaque; |
---|
685 | |
---|
686 | if (version_id != 1) |
---|
687 | return -EINVAL; |
---|
688 | |
---|
689 | qemu_get_be16s(f, &s->cmd); |
---|
690 | qemu_get_be16s(f, &s->status); |
---|
691 | qemu_get_be16s(f, &s->intr); |
---|
692 | qemu_get_be16s(f, &s->frnum); |
---|
693 | qemu_get_be32s(f, &s->fl_base_addr); |
---|
694 | qemu_get_8s(f, &s->sof_timing); |
---|
695 | qemu_get_8s(f, &s->status2); |
---|
696 | |
---|
697 | for(i = 0; i < NB_PORTS; i++) { |
---|
698 | qemu_get_be16s(f, &s->ports[i].ctrl); |
---|
699 | } |
---|
700 | |
---|
701 | qemu_get_timer(f, s->frame_timer); |
---|
702 | |
---|
703 | return 0; |
---|
704 | } |
---|
705 | |
---|
706 | void usb_uhci_init(PCIBus *bus, int devfn) |
---|
707 | { |
---|
708 | UHCIState *s; |
---|
709 | uint8_t *pci_conf; |
---|
710 | int i; |
---|
711 | |
---|
712 | s = (UHCIState *)pci_register_device(bus, |
---|
713 | "USB-UHCI", sizeof(UHCIState), |
---|
714 | devfn, NULL, NULL); |
---|
715 | pci_conf = s->dev.config; |
---|
716 | pci_conf[0x00] = 0x86; |
---|
717 | pci_conf[0x01] = 0x80; |
---|
718 | pci_conf[0x02] = 0x20; |
---|
719 | pci_conf[0x03] = 0x70; |
---|
720 | pci_conf[0x08] = 0x01; // revision number |
---|
721 | pci_conf[0x09] = 0x00; |
---|
722 | pci_conf[0x0a] = 0x03; |
---|
723 | pci_conf[0x0b] = 0x0c; |
---|
724 | pci_conf[0x0e] = 0x00; // header_type |
---|
725 | pci_conf[0x3d] = 4; // interrupt pin 3 |
---|
726 | pci_conf[0x60] = 0x10; // release number |
---|
727 | pci_conf[0x2c] = pci_conf[0x00]; // same as Vendor ID |
---|
728 | pci_conf[0x2d] = pci_conf[0x01]; |
---|
729 | |
---|
730 | for(i = 0; i < NB_PORTS; i++) { |
---|
731 | qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach); |
---|
732 | } |
---|
733 | s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); |
---|
734 | |
---|
735 | uhci_reset(s); |
---|
736 | |
---|
737 | /* Use region 4 for consistency with real hardware. BSD guests seem |
---|
738 | to rely on this. */ |
---|
739 | pci_register_io_region(&s->dev, 4, 0x20, |
---|
740 | PCI_ADDRESS_SPACE_IO, uhci_map); |
---|
741 | |
---|
742 | register_savevm("UHCI_usb_pci", 0, 1, generic_pci_save, generic_pci_load, s); |
---|
743 | |
---|
744 | register_savevm("UHCI usb controller", 0, 1, uhci_usb_save, uhci_usb_load, s); |
---|
745 | } |
---|