|
|
1.1 ! root 1: /* ! 2: * USB UHCI controller emulation ! 3: * ! 4: * Copyright (c) 2005 Fabrice Bellard ! 5: * ! 6: * Copyright (c) 2008 Max Krasnyansky ! 7: * Magor rewrite of the UHCI data structures parser and frame processor ! 8: * Support for fully async operation and multiple outstanding transactions ! 9: * ! 10: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 11: * of this software and associated documentation files (the "Software"), to deal ! 12: * in the Software without restriction, including without limitation the rights ! 13: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 14: * copies of the Software, and to permit persons to whom the Software is ! 15: * furnished to do so, subject to the following conditions: ! 16: * ! 17: * The above copyright notice and this permission notice shall be included in ! 18: * all copies or substantial portions of the Software. ! 19: * ! 20: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 21: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 22: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 23: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 24: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 25: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 26: * THE SOFTWARE. ! 27: */ ! 28: #include "hw/hw.h" ! 29: #include "hw/usb.h" ! 30: #include "hw/pci.h" ! 31: #include "qemu-timer.h" ! 32: #include "iov.h" ! 33: #include "dma.h" ! 34: #include "trace.h" ! 35: ! 36: //#define DEBUG ! 37: //#define DEBUG_DUMP_DATA ! 38: ! 39: #define UHCI_CMD_FGR (1 << 4) ! 40: #define UHCI_CMD_EGSM (1 << 3) ! 41: #define UHCI_CMD_GRESET (1 << 2) ! 42: #define UHCI_CMD_HCRESET (1 << 1) ! 43: #define UHCI_CMD_RS (1 << 0) ! 44: ! 45: #define UHCI_STS_HCHALTED (1 << 5) ! 46: #define UHCI_STS_HCPERR (1 << 4) ! 47: #define UHCI_STS_HSERR (1 << 3) ! 48: #define UHCI_STS_RD (1 << 2) ! 49: #define UHCI_STS_USBERR (1 << 1) ! 50: #define UHCI_STS_USBINT (1 << 0) ! 51: ! 52: #define TD_CTRL_SPD (1 << 29) ! 53: #define TD_CTRL_ERROR_SHIFT 27 ! 54: #define TD_CTRL_IOS (1 << 25) ! 55: #define TD_CTRL_IOC (1 << 24) ! 56: #define TD_CTRL_ACTIVE (1 << 23) ! 57: #define TD_CTRL_STALL (1 << 22) ! 58: #define TD_CTRL_BABBLE (1 << 20) ! 59: #define TD_CTRL_NAK (1 << 19) ! 60: #define TD_CTRL_TIMEOUT (1 << 18) ! 61: ! 62: #define UHCI_PORT_SUSPEND (1 << 12) ! 63: #define UHCI_PORT_RESET (1 << 9) ! 64: #define UHCI_PORT_LSDA (1 << 8) ! 65: #define UHCI_PORT_RD (1 << 6) ! 66: #define UHCI_PORT_ENC (1 << 3) ! 67: #define UHCI_PORT_EN (1 << 2) ! 68: #define UHCI_PORT_CSC (1 << 1) ! 69: #define UHCI_PORT_CCS (1 << 0) ! 70: ! 71: #define UHCI_PORT_READ_ONLY (0x1bb) ! 72: #define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC) ! 73: ! 74: #define FRAME_TIMER_FREQ 1000 ! 75: ! 76: #define FRAME_MAX_LOOPS 256 ! 77: ! 78: #define NB_PORTS 2 ! 79: ! 80: enum { ! 81: TD_RESULT_STOP_FRAME = 10, ! 82: TD_RESULT_COMPLETE, ! 83: TD_RESULT_NEXT_QH, ! 84: TD_RESULT_ASYNC_START, ! 85: TD_RESULT_ASYNC_CONT, ! 86: }; ! 87: ! 88: typedef struct UHCIState UHCIState; ! 89: typedef struct UHCIAsync UHCIAsync; ! 90: typedef struct UHCIQueue UHCIQueue; ! 91: ! 92: /* ! 93: * Pending async transaction. ! 94: * 'packet' must be the first field because completion ! 95: * handler does "(UHCIAsync *) pkt" cast. ! 96: */ ! 97: ! 98: struct UHCIAsync { ! 99: USBPacket packet; ! 100: QEMUSGList sgl; ! 101: UHCIQueue *queue; ! 102: QTAILQ_ENTRY(UHCIAsync) next; ! 103: uint32_t td; ! 104: uint8_t isoc; ! 105: uint8_t done; ! 106: }; ! 107: ! 108: struct UHCIQueue { ! 109: uint32_t token; ! 110: UHCIState *uhci; ! 111: QTAILQ_ENTRY(UHCIQueue) next; ! 112: QTAILQ_HEAD(, UHCIAsync) asyncs; ! 113: int8_t valid; ! 114: }; ! 115: ! 116: typedef struct UHCIPort { ! 117: USBPort port; ! 118: uint16_t ctrl; ! 119: } UHCIPort; ! 120: ! 121: struct UHCIState { ! 122: PCIDevice dev; ! 123: MemoryRegion io_bar; ! 124: USBBus bus; /* Note unused when we're a companion controller */ ! 125: uint16_t cmd; /* cmd register */ ! 126: uint16_t status; ! 127: uint16_t intr; /* interrupt enable register */ ! 128: uint16_t frnum; /* frame number */ ! 129: uint32_t fl_base_addr; /* frame list base address */ ! 130: uint8_t sof_timing; ! 131: uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ ! 132: int64_t expire_time; ! 133: QEMUTimer *frame_timer; ! 134: UHCIPort ports[NB_PORTS]; ! 135: ! 136: /* Interrupts that should be raised at the end of the current frame. */ ! 137: uint32_t pending_int_mask; ! 138: ! 139: /* Active packets */ ! 140: QTAILQ_HEAD(, UHCIQueue) queues; ! 141: uint8_t num_ports_vmstate; ! 142: ! 143: /* Properties */ ! 144: char *masterbus; ! 145: uint32_t firstport; ! 146: }; ! 147: ! 148: typedef struct UHCI_TD { ! 149: uint32_t link; ! 150: uint32_t ctrl; /* see TD_CTRL_xxx */ ! 151: uint32_t token; ! 152: uint32_t buffer; ! 153: } UHCI_TD; ! 154: ! 155: typedef struct UHCI_QH { ! 156: uint32_t link; ! 157: uint32_t el_link; ! 158: } UHCI_QH; ! 159: ! 160: static inline int32_t uhci_queue_token(UHCI_TD *td) ! 161: { ! 162: /* covers ep, dev, pid -> identifies the endpoint */ ! 163: return td->token & 0x7ffff; ! 164: } ! 165: ! 166: static UHCIQueue *uhci_queue_get(UHCIState *s, UHCI_TD *td) ! 167: { ! 168: uint32_t token = uhci_queue_token(td); ! 169: UHCIQueue *queue; ! 170: ! 171: QTAILQ_FOREACH(queue, &s->queues, next) { ! 172: if (queue->token == token) { ! 173: return queue; ! 174: } ! 175: } ! 176: ! 177: queue = g_new0(UHCIQueue, 1); ! 178: queue->uhci = s; ! 179: queue->token = token; ! 180: QTAILQ_INIT(&queue->asyncs); ! 181: QTAILQ_INSERT_HEAD(&s->queues, queue, next); ! 182: trace_usb_uhci_queue_add(queue->token); ! 183: return queue; ! 184: } ! 185: ! 186: static void uhci_queue_free(UHCIQueue *queue) ! 187: { ! 188: UHCIState *s = queue->uhci; ! 189: ! 190: trace_usb_uhci_queue_del(queue->token); ! 191: QTAILQ_REMOVE(&s->queues, queue, next); ! 192: g_free(queue); ! 193: } ! 194: ! 195: static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t addr) ! 196: { ! 197: UHCIAsync *async = g_new0(UHCIAsync, 1); ! 198: ! 199: async->queue = queue; ! 200: async->td = addr; ! 201: usb_packet_init(&async->packet); ! 202: pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1); ! 203: trace_usb_uhci_packet_add(async->queue->token, async->td); ! 204: ! 205: return async; ! 206: } ! 207: ! 208: static void uhci_async_free(UHCIAsync *async) ! 209: { ! 210: trace_usb_uhci_packet_del(async->queue->token, async->td); ! 211: usb_packet_cleanup(&async->packet); ! 212: qemu_sglist_destroy(&async->sgl); ! 213: g_free(async); ! 214: } ! 215: ! 216: static void uhci_async_link(UHCIAsync *async) ! 217: { ! 218: UHCIQueue *queue = async->queue; ! 219: QTAILQ_INSERT_TAIL(&queue->asyncs, async, next); ! 220: trace_usb_uhci_packet_link_async(async->queue->token, async->td); ! 221: } ! 222: ! 223: static void uhci_async_unlink(UHCIAsync *async) ! 224: { ! 225: UHCIQueue *queue = async->queue; ! 226: QTAILQ_REMOVE(&queue->asyncs, async, next); ! 227: trace_usb_uhci_packet_unlink_async(async->queue->token, async->td); ! 228: } ! 229: ! 230: static void uhci_async_cancel(UHCIAsync *async) ! 231: { ! 232: trace_usb_uhci_packet_cancel(async->queue->token, async->td, async->done); ! 233: if (!async->done) ! 234: usb_cancel_packet(&async->packet); ! 235: uhci_async_free(async); ! 236: } ! 237: ! 238: /* ! 239: * Mark all outstanding async packets as invalid. ! 240: * This is used for canceling them when TDs are removed by the HCD. ! 241: */ ! 242: static void uhci_async_validate_begin(UHCIState *s) ! 243: { ! 244: UHCIQueue *queue; ! 245: ! 246: QTAILQ_FOREACH(queue, &s->queues, next) { ! 247: queue->valid--; ! 248: } ! 249: } ! 250: ! 251: /* ! 252: * Cancel async packets that are no longer valid ! 253: */ ! 254: static void uhci_async_validate_end(UHCIState *s) ! 255: { ! 256: UHCIQueue *queue, *n; ! 257: UHCIAsync *async; ! 258: ! 259: QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) { ! 260: if (queue->valid > 0) { ! 261: continue; ! 262: } ! 263: while (!QTAILQ_EMPTY(&queue->asyncs)) { ! 264: async = QTAILQ_FIRST(&queue->asyncs); ! 265: uhci_async_unlink(async); ! 266: uhci_async_cancel(async); ! 267: } ! 268: uhci_queue_free(queue); ! 269: } ! 270: } ! 271: ! 272: static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev) ! 273: { ! 274: UHCIQueue *queue; ! 275: UHCIAsync *curr, *n; ! 276: ! 277: QTAILQ_FOREACH(queue, &s->queues, next) { ! 278: QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) { ! 279: if (!usb_packet_is_inflight(&curr->packet) || ! 280: curr->packet.ep->dev != dev) { ! 281: continue; ! 282: } ! 283: uhci_async_unlink(curr); ! 284: uhci_async_cancel(curr); ! 285: } ! 286: } ! 287: } ! 288: ! 289: static void uhci_async_cancel_all(UHCIState *s) ! 290: { ! 291: UHCIQueue *queue; ! 292: UHCIAsync *curr, *n; ! 293: ! 294: QTAILQ_FOREACH(queue, &s->queues, next) { ! 295: QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) { ! 296: uhci_async_unlink(curr); ! 297: uhci_async_cancel(curr); ! 298: } ! 299: uhci_queue_free(queue); ! 300: } ! 301: } ! 302: ! 303: static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, UHCI_TD *td) ! 304: { ! 305: uint32_t token = uhci_queue_token(td); ! 306: UHCIQueue *queue; ! 307: UHCIAsync *async; ! 308: ! 309: QTAILQ_FOREACH(queue, &s->queues, next) { ! 310: if (queue->token == token) { ! 311: break; ! 312: } ! 313: } ! 314: if (queue == NULL) { ! 315: return NULL; ! 316: } ! 317: ! 318: QTAILQ_FOREACH(async, &queue->asyncs, next) { ! 319: if (async->td == addr) { ! 320: return async; ! 321: } ! 322: } ! 323: ! 324: return NULL; ! 325: } ! 326: ! 327: static void uhci_update_irq(UHCIState *s) ! 328: { ! 329: int level; ! 330: if (((s->status2 & 1) && (s->intr & (1 << 2))) || ! 331: ((s->status2 & 2) && (s->intr & (1 << 3))) || ! 332: ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) || ! 333: ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) || ! 334: (s->status & UHCI_STS_HSERR) || ! 335: (s->status & UHCI_STS_HCPERR)) { ! 336: level = 1; ! 337: } else { ! 338: level = 0; ! 339: } ! 340: qemu_set_irq(s->dev.irq[3], level); ! 341: } ! 342: ! 343: static void uhci_reset(void *opaque) ! 344: { ! 345: UHCIState *s = opaque; ! 346: uint8_t *pci_conf; ! 347: int i; ! 348: UHCIPort *port; ! 349: ! 350: trace_usb_uhci_reset(); ! 351: ! 352: pci_conf = s->dev.config; ! 353: ! 354: pci_conf[0x6a] = 0x01; /* usb clock */ ! 355: pci_conf[0x6b] = 0x00; ! 356: s->cmd = 0; ! 357: s->status = 0; ! 358: s->status2 = 0; ! 359: s->intr = 0; ! 360: s->fl_base_addr = 0; ! 361: s->sof_timing = 64; ! 362: ! 363: for(i = 0; i < NB_PORTS; i++) { ! 364: port = &s->ports[i]; ! 365: port->ctrl = 0x0080; ! 366: if (port->port.dev && port->port.dev->attached) { ! 367: usb_port_reset(&port->port); ! 368: } ! 369: } ! 370: ! 371: uhci_async_cancel_all(s); ! 372: uhci_update_irq(s); ! 373: } ! 374: ! 375: static void uhci_pre_save(void *opaque) ! 376: { ! 377: UHCIState *s = opaque; ! 378: ! 379: uhci_async_cancel_all(s); ! 380: } ! 381: ! 382: static const VMStateDescription vmstate_uhci_port = { ! 383: .name = "uhci port", ! 384: .version_id = 1, ! 385: .minimum_version_id = 1, ! 386: .minimum_version_id_old = 1, ! 387: .fields = (VMStateField []) { ! 388: VMSTATE_UINT16(ctrl, UHCIPort), ! 389: VMSTATE_END_OF_LIST() ! 390: } ! 391: }; ! 392: ! 393: static const VMStateDescription vmstate_uhci = { ! 394: .name = "uhci", ! 395: .version_id = 2, ! 396: .minimum_version_id = 1, ! 397: .minimum_version_id_old = 1, ! 398: .pre_save = uhci_pre_save, ! 399: .fields = (VMStateField []) { ! 400: VMSTATE_PCI_DEVICE(dev, UHCIState), ! 401: VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState), ! 402: VMSTATE_STRUCT_ARRAY(ports, UHCIState, NB_PORTS, 1, ! 403: vmstate_uhci_port, UHCIPort), ! 404: VMSTATE_UINT16(cmd, UHCIState), ! 405: VMSTATE_UINT16(status, UHCIState), ! 406: VMSTATE_UINT16(intr, UHCIState), ! 407: VMSTATE_UINT16(frnum, UHCIState), ! 408: VMSTATE_UINT32(fl_base_addr, UHCIState), ! 409: VMSTATE_UINT8(sof_timing, UHCIState), ! 410: VMSTATE_UINT8(status2, UHCIState), ! 411: VMSTATE_TIMER(frame_timer, UHCIState), ! 412: VMSTATE_INT64_V(expire_time, UHCIState, 2), ! 413: VMSTATE_END_OF_LIST() ! 414: } ! 415: }; ! 416: ! 417: static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) ! 418: { ! 419: UHCIState *s = opaque; ! 420: ! 421: addr &= 0x1f; ! 422: switch(addr) { ! 423: case 0x0c: ! 424: s->sof_timing = val; ! 425: break; ! 426: } ! 427: } ! 428: ! 429: static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr) ! 430: { ! 431: UHCIState *s = opaque; ! 432: uint32_t val; ! 433: ! 434: addr &= 0x1f; ! 435: switch(addr) { ! 436: case 0x0c: ! 437: val = s->sof_timing; ! 438: break; ! 439: default: ! 440: val = 0xff; ! 441: break; ! 442: } ! 443: return val; ! 444: } ! 445: ! 446: static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) ! 447: { ! 448: UHCIState *s = opaque; ! 449: ! 450: addr &= 0x1f; ! 451: trace_usb_uhci_mmio_writew(addr, val); ! 452: ! 453: switch(addr) { ! 454: case 0x00: ! 455: if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) { ! 456: /* start frame processing */ ! 457: trace_usb_uhci_schedule_start(); ! 458: s->expire_time = qemu_get_clock_ns(vm_clock) + ! 459: (get_ticks_per_sec() / FRAME_TIMER_FREQ); ! 460: qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); ! 461: s->status &= ~UHCI_STS_HCHALTED; ! 462: } else if (!(val & UHCI_CMD_RS)) { ! 463: s->status |= UHCI_STS_HCHALTED; ! 464: } ! 465: if (val & UHCI_CMD_GRESET) { ! 466: UHCIPort *port; ! 467: int i; ! 468: ! 469: /* send reset on the USB bus */ ! 470: for(i = 0; i < NB_PORTS; i++) { ! 471: port = &s->ports[i]; ! 472: usb_device_reset(port->port.dev); ! 473: } ! 474: uhci_reset(s); ! 475: return; ! 476: } ! 477: if (val & UHCI_CMD_HCRESET) { ! 478: uhci_reset(s); ! 479: return; ! 480: } ! 481: s->cmd = val; ! 482: break; ! 483: case 0x02: ! 484: s->status &= ~val; ! 485: /* XXX: the chip spec is not coherent, so we add a hidden ! 486: register to distinguish between IOC and SPD */ ! 487: if (val & UHCI_STS_USBINT) ! 488: s->status2 = 0; ! 489: uhci_update_irq(s); ! 490: break; ! 491: case 0x04: ! 492: s->intr = val; ! 493: uhci_update_irq(s); ! 494: break; ! 495: case 0x06: ! 496: if (s->status & UHCI_STS_HCHALTED) ! 497: s->frnum = val & 0x7ff; ! 498: break; ! 499: case 0x10 ... 0x1f: ! 500: { ! 501: UHCIPort *port; ! 502: USBDevice *dev; ! 503: int n; ! 504: ! 505: n = (addr >> 1) & 7; ! 506: if (n >= NB_PORTS) ! 507: return; ! 508: port = &s->ports[n]; ! 509: dev = port->port.dev; ! 510: if (dev && dev->attached) { ! 511: /* port reset */ ! 512: if ( (val & UHCI_PORT_RESET) && ! 513: !(port->ctrl & UHCI_PORT_RESET) ) { ! 514: usb_device_reset(dev); ! 515: } ! 516: } ! 517: port->ctrl &= UHCI_PORT_READ_ONLY; ! 518: port->ctrl |= (val & ~UHCI_PORT_READ_ONLY); ! 519: /* some bits are reset when a '1' is written to them */ ! 520: port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR); ! 521: } ! 522: break; ! 523: } ! 524: } ! 525: ! 526: static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) ! 527: { ! 528: UHCIState *s = opaque; ! 529: uint32_t val; ! 530: ! 531: addr &= 0x1f; ! 532: switch(addr) { ! 533: case 0x00: ! 534: val = s->cmd; ! 535: break; ! 536: case 0x02: ! 537: val = s->status; ! 538: break; ! 539: case 0x04: ! 540: val = s->intr; ! 541: break; ! 542: case 0x06: ! 543: val = s->frnum; ! 544: break; ! 545: case 0x10 ... 0x1f: ! 546: { ! 547: UHCIPort *port; ! 548: int n; ! 549: n = (addr >> 1) & 7; ! 550: if (n >= NB_PORTS) ! 551: goto read_default; ! 552: port = &s->ports[n]; ! 553: val = port->ctrl; ! 554: } ! 555: break; ! 556: default: ! 557: read_default: ! 558: val = 0xff7f; /* disabled port */ ! 559: break; ! 560: } ! 561: ! 562: trace_usb_uhci_mmio_readw(addr, val); ! 563: ! 564: return val; ! 565: } ! 566: ! 567: static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val) ! 568: { ! 569: UHCIState *s = opaque; ! 570: ! 571: addr &= 0x1f; ! 572: trace_usb_uhci_mmio_writel(addr, val); ! 573: ! 574: switch(addr) { ! 575: case 0x08: ! 576: s->fl_base_addr = val & ~0xfff; ! 577: break; ! 578: } ! 579: } ! 580: ! 581: static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr) ! 582: { ! 583: UHCIState *s = opaque; ! 584: uint32_t val; ! 585: ! 586: addr &= 0x1f; ! 587: switch(addr) { ! 588: case 0x08: ! 589: val = s->fl_base_addr; ! 590: break; ! 591: default: ! 592: val = 0xffffffff; ! 593: break; ! 594: } ! 595: trace_usb_uhci_mmio_readl(addr, val); ! 596: return val; ! 597: } ! 598: ! 599: /* signal resume if controller suspended */ ! 600: static void uhci_resume (void *opaque) ! 601: { ! 602: UHCIState *s = (UHCIState *)opaque; ! 603: ! 604: if (!s) ! 605: return; ! 606: ! 607: if (s->cmd & UHCI_CMD_EGSM) { ! 608: s->cmd |= UHCI_CMD_FGR; ! 609: s->status |= UHCI_STS_RD; ! 610: uhci_update_irq(s); ! 611: } ! 612: } ! 613: ! 614: static void uhci_attach(USBPort *port1) ! 615: { ! 616: UHCIState *s = port1->opaque; ! 617: UHCIPort *port = &s->ports[port1->index]; ! 618: ! 619: /* set connect status */ ! 620: port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; ! 621: ! 622: /* update speed */ ! 623: if (port->port.dev->speed == USB_SPEED_LOW) { ! 624: port->ctrl |= UHCI_PORT_LSDA; ! 625: } else { ! 626: port->ctrl &= ~UHCI_PORT_LSDA; ! 627: } ! 628: ! 629: uhci_resume(s); ! 630: } ! 631: ! 632: static void uhci_detach(USBPort *port1) ! 633: { ! 634: UHCIState *s = port1->opaque; ! 635: UHCIPort *port = &s->ports[port1->index]; ! 636: ! 637: uhci_async_cancel_device(s, port1->dev); ! 638: ! 639: /* set connect status */ ! 640: if (port->ctrl & UHCI_PORT_CCS) { ! 641: port->ctrl &= ~UHCI_PORT_CCS; ! 642: port->ctrl |= UHCI_PORT_CSC; ! 643: } ! 644: /* disable port */ ! 645: if (port->ctrl & UHCI_PORT_EN) { ! 646: port->ctrl &= ~UHCI_PORT_EN; ! 647: port->ctrl |= UHCI_PORT_ENC; ! 648: } ! 649: ! 650: uhci_resume(s); ! 651: } ! 652: ! 653: static void uhci_child_detach(USBPort *port1, USBDevice *child) ! 654: { ! 655: UHCIState *s = port1->opaque; ! 656: ! 657: uhci_async_cancel_device(s, child); ! 658: } ! 659: ! 660: static void uhci_wakeup(USBPort *port1) ! 661: { ! 662: UHCIState *s = port1->opaque; ! 663: UHCIPort *port = &s->ports[port1->index]; ! 664: ! 665: if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) { ! 666: port->ctrl |= UHCI_PORT_RD; ! 667: uhci_resume(s); ! 668: } ! 669: } ! 670: ! 671: static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr) ! 672: { ! 673: USBDevice *dev; ! 674: int i; ! 675: ! 676: for (i = 0; i < NB_PORTS; i++) { ! 677: UHCIPort *port = &s->ports[i]; ! 678: if (!(port->ctrl & UHCI_PORT_EN)) { ! 679: continue; ! 680: } ! 681: dev = usb_find_device(&port->port, addr); ! 682: if (dev != NULL) { ! 683: return dev; ! 684: } ! 685: } ! 686: return NULL; ! 687: } ! 688: ! 689: static void uhci_async_complete(USBPort *port, USBPacket *packet); ! 690: static void uhci_process_frame(UHCIState *s); ! 691: ! 692: /* return -1 if fatal error (frame must be stopped) ! 693: 0 if TD successful ! 694: 1 if TD unsuccessful or inactive ! 695: */ ! 696: static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask) ! 697: { ! 698: int len = 0, max_len, err, ret; ! 699: uint8_t pid; ! 700: ! 701: max_len = ((td->token >> 21) + 1) & 0x7ff; ! 702: pid = td->token & 0xff; ! 703: ! 704: ret = async->packet.result; ! 705: ! 706: if (td->ctrl & TD_CTRL_IOS) ! 707: td->ctrl &= ~TD_CTRL_ACTIVE; ! 708: ! 709: if (ret < 0) ! 710: goto out; ! 711: ! 712: len = async->packet.result; ! 713: td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); ! 714: ! 715: /* The NAK bit may have been set by a previous frame, so clear it ! 716: here. The docs are somewhat unclear, but win2k relies on this ! 717: behavior. */ ! 718: td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK); ! 719: if (td->ctrl & TD_CTRL_IOC) ! 720: *int_mask |= 0x01; ! 721: ! 722: if (pid == USB_TOKEN_IN) { ! 723: if (len > max_len) { ! 724: ret = USB_RET_BABBLE; ! 725: goto out; ! 726: } ! 727: ! 728: if ((td->ctrl & TD_CTRL_SPD) && len < max_len) { ! 729: *int_mask |= 0x02; ! 730: /* short packet: do not update QH */ ! 731: trace_usb_uhci_packet_complete_shortxfer(async->queue->token, ! 732: async->td); ! 733: return TD_RESULT_NEXT_QH; ! 734: } ! 735: } ! 736: ! 737: /* success */ ! 738: trace_usb_uhci_packet_complete_success(async->queue->token, async->td); ! 739: return TD_RESULT_COMPLETE; ! 740: ! 741: out: ! 742: switch(ret) { ! 743: case USB_RET_STALL: ! 744: td->ctrl |= TD_CTRL_STALL; ! 745: td->ctrl &= ~TD_CTRL_ACTIVE; ! 746: s->status |= UHCI_STS_USBERR; ! 747: if (td->ctrl & TD_CTRL_IOC) { ! 748: *int_mask |= 0x01; ! 749: } ! 750: uhci_update_irq(s); ! 751: trace_usb_uhci_packet_complete_stall(async->queue->token, async->td); ! 752: return TD_RESULT_NEXT_QH; ! 753: ! 754: case USB_RET_BABBLE: ! 755: td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; ! 756: td->ctrl &= ~TD_CTRL_ACTIVE; ! 757: s->status |= UHCI_STS_USBERR; ! 758: if (td->ctrl & TD_CTRL_IOC) { ! 759: *int_mask |= 0x01; ! 760: } ! 761: uhci_update_irq(s); ! 762: /* frame interrupted */ ! 763: trace_usb_uhci_packet_complete_babble(async->queue->token, async->td); ! 764: return TD_RESULT_STOP_FRAME; ! 765: ! 766: case USB_RET_NAK: ! 767: td->ctrl |= TD_CTRL_NAK; ! 768: if (pid == USB_TOKEN_SETUP) ! 769: break; ! 770: return TD_RESULT_NEXT_QH; ! 771: ! 772: case USB_RET_IOERROR: ! 773: case USB_RET_NODEV: ! 774: default: ! 775: break; ! 776: } ! 777: ! 778: /* Retry the TD if error count is not zero */ ! 779: ! 780: td->ctrl |= TD_CTRL_TIMEOUT; ! 781: err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3; ! 782: if (err != 0) { ! 783: err--; ! 784: if (err == 0) { ! 785: td->ctrl &= ~TD_CTRL_ACTIVE; ! 786: s->status |= UHCI_STS_USBERR; ! 787: if (td->ctrl & TD_CTRL_IOC) ! 788: *int_mask |= 0x01; ! 789: uhci_update_irq(s); ! 790: trace_usb_uhci_packet_complete_error(async->queue->token, ! 791: async->td); ! 792: } ! 793: } ! 794: td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | ! 795: (err << TD_CTRL_ERROR_SHIFT); ! 796: return TD_RESULT_NEXT_QH; ! 797: } ! 798: ! 799: static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, ! 800: uint32_t *int_mask, bool queuing) ! 801: { ! 802: UHCIAsync *async; ! 803: int len = 0, max_len; ! 804: uint8_t pid; ! 805: USBDevice *dev; ! 806: USBEndpoint *ep; ! 807: ! 808: /* Is active ? */ ! 809: if (!(td->ctrl & TD_CTRL_ACTIVE)) ! 810: return TD_RESULT_NEXT_QH; ! 811: ! 812: async = uhci_async_find_td(s, addr, td); ! 813: if (async) { ! 814: /* Already submitted */ ! 815: async->queue->valid = 32; ! 816: ! 817: if (!async->done) ! 818: return TD_RESULT_ASYNC_CONT; ! 819: if (queuing) { ! 820: /* we are busy filling the queue, we are not prepared ! 821: to consume completed packages then, just leave them ! 822: in async state */ ! 823: return TD_RESULT_ASYNC_CONT; ! 824: } ! 825: ! 826: uhci_async_unlink(async); ! 827: goto done; ! 828: } ! 829: ! 830: /* Allocate new packet */ ! 831: async = uhci_async_alloc(uhci_queue_get(s, td), addr); ! 832: ! 833: /* valid needs to be large enough to handle 10 frame delay ! 834: * for initial isochronous requests ! 835: */ ! 836: async->queue->valid = 32; ! 837: async->isoc = td->ctrl & TD_CTRL_IOS; ! 838: ! 839: max_len = ((td->token >> 21) + 1) & 0x7ff; ! 840: pid = td->token & 0xff; ! 841: ! 842: dev = uhci_find_device(s, (td->token >> 8) & 0x7f); ! 843: ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf); ! 844: usb_packet_setup(&async->packet, pid, ep); ! 845: qemu_sglist_add(&async->sgl, td->buffer, max_len); ! 846: usb_packet_map(&async->packet, &async->sgl); ! 847: ! 848: switch(pid) { ! 849: case USB_TOKEN_OUT: ! 850: case USB_TOKEN_SETUP: ! 851: len = usb_handle_packet(dev, &async->packet); ! 852: if (len >= 0) ! 853: len = max_len; ! 854: break; ! 855: ! 856: case USB_TOKEN_IN: ! 857: len = usb_handle_packet(dev, &async->packet); ! 858: break; ! 859: ! 860: default: ! 861: /* invalid pid : frame interrupted */ ! 862: uhci_async_free(async); ! 863: s->status |= UHCI_STS_HCPERR; ! 864: uhci_update_irq(s); ! 865: return TD_RESULT_STOP_FRAME; ! 866: } ! 867: ! 868: if (len == USB_RET_ASYNC) { ! 869: uhci_async_link(async); ! 870: return TD_RESULT_ASYNC_START; ! 871: } ! 872: ! 873: async->packet.result = len; ! 874: ! 875: done: ! 876: len = uhci_complete_td(s, td, async, int_mask); ! 877: usb_packet_unmap(&async->packet); ! 878: uhci_async_free(async); ! 879: return len; ! 880: } ! 881: ! 882: static void uhci_async_complete(USBPort *port, USBPacket *packet) ! 883: { ! 884: UHCIAsync *async = container_of(packet, UHCIAsync, packet); ! 885: UHCIState *s = async->queue->uhci; ! 886: ! 887: if (async->isoc) { ! 888: UHCI_TD td; ! 889: uint32_t link = async->td; ! 890: uint32_t int_mask = 0, val; ! 891: ! 892: pci_dma_read(&s->dev, link & ~0xf, &td, sizeof(td)); ! 893: le32_to_cpus(&td.link); ! 894: le32_to_cpus(&td.ctrl); ! 895: le32_to_cpus(&td.token); ! 896: le32_to_cpus(&td.buffer); ! 897: ! 898: uhci_async_unlink(async); ! 899: uhci_complete_td(s, &td, async, &int_mask); ! 900: s->pending_int_mask |= int_mask; ! 901: ! 902: /* update the status bits of the TD */ ! 903: val = cpu_to_le32(td.ctrl); ! 904: pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val)); ! 905: uhci_async_free(async); ! 906: } else { ! 907: async->done = 1; ! 908: uhci_process_frame(s); ! 909: } ! 910: } ! 911: ! 912: static int is_valid(uint32_t link) ! 913: { ! 914: return (link & 1) == 0; ! 915: } ! 916: ! 917: static int is_qh(uint32_t link) ! 918: { ! 919: return (link & 2) != 0; ! 920: } ! 921: ! 922: static int depth_first(uint32_t link) ! 923: { ! 924: return (link & 4) != 0; ! 925: } ! 926: ! 927: /* QH DB used for detecting QH loops */ ! 928: #define UHCI_MAX_QUEUES 128 ! 929: typedef struct { ! 930: uint32_t addr[UHCI_MAX_QUEUES]; ! 931: int count; ! 932: } QhDb; ! 933: ! 934: static void qhdb_reset(QhDb *db) ! 935: { ! 936: db->count = 0; ! 937: } ! 938: ! 939: /* Add QH to DB. Returns 1 if already present or DB is full. */ ! 940: static int qhdb_insert(QhDb *db, uint32_t addr) ! 941: { ! 942: int i; ! 943: for (i = 0; i < db->count; i++) ! 944: if (db->addr[i] == addr) ! 945: return 1; ! 946: ! 947: if (db->count >= UHCI_MAX_QUEUES) ! 948: return 1; ! 949: ! 950: db->addr[db->count++] = addr; ! 951: return 0; ! 952: } ! 953: ! 954: static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) ! 955: { ! 956: uint32_t int_mask = 0; ! 957: uint32_t plink = td->link; ! 958: uint32_t token = uhci_queue_token(td); ! 959: UHCI_TD ptd; ! 960: int ret; ! 961: ! 962: while (is_valid(plink)) { ! 963: pci_dma_read(&s->dev, plink & ~0xf, &ptd, sizeof(ptd)); ! 964: le32_to_cpus(&ptd.link); ! 965: le32_to_cpus(&ptd.ctrl); ! 966: le32_to_cpus(&ptd.token); ! 967: le32_to_cpus(&ptd.buffer); ! 968: if (!(ptd.ctrl & TD_CTRL_ACTIVE)) { ! 969: break; ! 970: } ! 971: if (uhci_queue_token(&ptd) != token) { ! 972: break; ! 973: } ! 974: trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token); ! 975: ret = uhci_handle_td(s, plink, &ptd, &int_mask, true); ! 976: if (ret == TD_RESULT_ASYNC_CONT) { ! 977: break; ! 978: } ! 979: assert(ret == TD_RESULT_ASYNC_START); ! 980: assert(int_mask == 0); ! 981: plink = ptd.link; ! 982: } ! 983: } ! 984: ! 985: static void uhci_process_frame(UHCIState *s) ! 986: { ! 987: uint32_t frame_addr, link, old_td_ctrl, val, int_mask; ! 988: uint32_t curr_qh, td_count = 0, bytes_count = 0; ! 989: int cnt, ret; ! 990: UHCI_TD td; ! 991: UHCI_QH qh; ! 992: QhDb qhdb; ! 993: ! 994: frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2); ! 995: ! 996: pci_dma_read(&s->dev, frame_addr, &link, 4); ! 997: le32_to_cpus(&link); ! 998: ! 999: int_mask = 0; ! 1000: curr_qh = 0; ! 1001: ! 1002: qhdb_reset(&qhdb); ! 1003: ! 1004: for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) { ! 1005: if (is_qh(link)) { ! 1006: /* QH */ ! 1007: trace_usb_uhci_qh_load(link & ~0xf); ! 1008: ! 1009: if (qhdb_insert(&qhdb, link)) { ! 1010: /* ! 1011: * We're going in circles. Which is not a bug because ! 1012: * HCD is allowed to do that as part of the BW management. ! 1013: * ! 1014: * Stop processing here if ! 1015: * (a) no transaction has been done since we've been ! 1016: * here last time, or ! 1017: * (b) we've reached the usb 1.1 bandwidth, which is ! 1018: * 1280 bytes/frame. ! 1019: */ ! 1020: if (td_count == 0) { ! 1021: trace_usb_uhci_frame_loop_stop_idle(); ! 1022: break; ! 1023: } else if (bytes_count >= 1280) { ! 1024: trace_usb_uhci_frame_loop_stop_bandwidth(); ! 1025: break; ! 1026: } else { ! 1027: trace_usb_uhci_frame_loop_continue(); ! 1028: td_count = 0; ! 1029: qhdb_reset(&qhdb); ! 1030: qhdb_insert(&qhdb, link); ! 1031: } ! 1032: } ! 1033: ! 1034: pci_dma_read(&s->dev, link & ~0xf, &qh, sizeof(qh)); ! 1035: le32_to_cpus(&qh.link); ! 1036: le32_to_cpus(&qh.el_link); ! 1037: ! 1038: if (!is_valid(qh.el_link)) { ! 1039: /* QH w/o elements */ ! 1040: curr_qh = 0; ! 1041: link = qh.link; ! 1042: } else { ! 1043: /* QH with elements */ ! 1044: curr_qh = link; ! 1045: link = qh.el_link; ! 1046: } ! 1047: continue; ! 1048: } ! 1049: ! 1050: /* TD */ ! 1051: pci_dma_read(&s->dev, link & ~0xf, &td, sizeof(td)); ! 1052: le32_to_cpus(&td.link); ! 1053: le32_to_cpus(&td.ctrl); ! 1054: le32_to_cpus(&td.token); ! 1055: le32_to_cpus(&td.buffer); ! 1056: trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token); ! 1057: ! 1058: old_td_ctrl = td.ctrl; ! 1059: ret = uhci_handle_td(s, link, &td, &int_mask, false); ! 1060: if (old_td_ctrl != td.ctrl) { ! 1061: /* update the status bits of the TD */ ! 1062: val = cpu_to_le32(td.ctrl); ! 1063: pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val)); ! 1064: } ! 1065: ! 1066: switch (ret) { ! 1067: case TD_RESULT_STOP_FRAME: /* interrupted frame */ ! 1068: goto out; ! 1069: ! 1070: case TD_RESULT_NEXT_QH: ! 1071: case TD_RESULT_ASYNC_CONT: ! 1072: trace_usb_uhci_td_nextqh(curr_qh & ~0xf, link & ~0xf); ! 1073: link = curr_qh ? qh.link : td.link; ! 1074: continue; ! 1075: ! 1076: case TD_RESULT_ASYNC_START: ! 1077: trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf); ! 1078: if (is_valid(td.link)) { ! 1079: uhci_fill_queue(s, &td); ! 1080: } ! 1081: link = curr_qh ? qh.link : td.link; ! 1082: continue; ! 1083: ! 1084: case TD_RESULT_COMPLETE: ! 1085: trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf); ! 1086: link = td.link; ! 1087: td_count++; ! 1088: bytes_count += (td.ctrl & 0x7ff) + 1; ! 1089: ! 1090: if (curr_qh) { ! 1091: /* update QH element link */ ! 1092: qh.el_link = link; ! 1093: val = cpu_to_le32(qh.el_link); ! 1094: pci_dma_write(&s->dev, (curr_qh & ~0xf) + 4, &val, sizeof(val)); ! 1095: ! 1096: if (!depth_first(link)) { ! 1097: /* done with this QH */ ! 1098: curr_qh = 0; ! 1099: link = qh.link; ! 1100: } ! 1101: } ! 1102: break; ! 1103: ! 1104: default: ! 1105: assert(!"unknown return code"); ! 1106: } ! 1107: ! 1108: /* go to the next entry */ ! 1109: } ! 1110: ! 1111: out: ! 1112: s->pending_int_mask |= int_mask; ! 1113: } ! 1114: ! 1115: static void uhci_frame_timer(void *opaque) ! 1116: { ! 1117: UHCIState *s = opaque; ! 1118: ! 1119: /* prepare the timer for the next frame */ ! 1120: s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ); ! 1121: ! 1122: if (!(s->cmd & UHCI_CMD_RS)) { ! 1123: /* Full stop */ ! 1124: trace_usb_uhci_schedule_stop(); ! 1125: qemu_del_timer(s->frame_timer); ! 1126: uhci_async_cancel_all(s); ! 1127: /* set hchalted bit in status - UHCI11D 2.1.2 */ ! 1128: s->status |= UHCI_STS_HCHALTED; ! 1129: return; ! 1130: } ! 1131: ! 1132: /* Complete the previous frame */ ! 1133: if (s->pending_int_mask) { ! 1134: s->status2 |= s->pending_int_mask; ! 1135: s->status |= UHCI_STS_USBINT; ! 1136: uhci_update_irq(s); ! 1137: } ! 1138: s->pending_int_mask = 0; ! 1139: ! 1140: /* Start new frame */ ! 1141: s->frnum = (s->frnum + 1) & 0x7ff; ! 1142: ! 1143: trace_usb_uhci_frame_start(s->frnum); ! 1144: ! 1145: uhci_async_validate_begin(s); ! 1146: ! 1147: uhci_process_frame(s); ! 1148: ! 1149: uhci_async_validate_end(s); ! 1150: ! 1151: qemu_mod_timer(s->frame_timer, s->expire_time); ! 1152: } ! 1153: ! 1154: static const MemoryRegionPortio uhci_portio[] = { ! 1155: { 0, 32, 2, .write = uhci_ioport_writew, }, ! 1156: { 0, 32, 2, .read = uhci_ioport_readw, }, ! 1157: { 0, 32, 4, .write = uhci_ioport_writel, }, ! 1158: { 0, 32, 4, .read = uhci_ioport_readl, }, ! 1159: { 0, 32, 1, .write = uhci_ioport_writeb, }, ! 1160: { 0, 32, 1, .read = uhci_ioport_readb, }, ! 1161: PORTIO_END_OF_LIST() ! 1162: }; ! 1163: ! 1164: static const MemoryRegionOps uhci_ioport_ops = { ! 1165: .old_portio = uhci_portio, ! 1166: }; ! 1167: ! 1168: static USBPortOps uhci_port_ops = { ! 1169: .attach = uhci_attach, ! 1170: .detach = uhci_detach, ! 1171: .child_detach = uhci_child_detach, ! 1172: .wakeup = uhci_wakeup, ! 1173: .complete = uhci_async_complete, ! 1174: }; ! 1175: ! 1176: static USBBusOps uhci_bus_ops = { ! 1177: }; ! 1178: ! 1179: static int usb_uhci_common_initfn(PCIDevice *dev) ! 1180: { ! 1181: UHCIState *s = DO_UPCAST(UHCIState, dev, dev); ! 1182: uint8_t *pci_conf = s->dev.config; ! 1183: int i; ! 1184: ! 1185: pci_conf[PCI_CLASS_PROG] = 0x00; ! 1186: /* TODO: reset value should be 0. */ ! 1187: pci_conf[PCI_INTERRUPT_PIN] = 4; /* interrupt pin D */ ! 1188: pci_conf[USB_SBRN] = USB_RELEASE_1; // release number ! 1189: ! 1190: if (s->masterbus) { ! 1191: USBPort *ports[NB_PORTS]; ! 1192: for(i = 0; i < NB_PORTS; i++) { ! 1193: ports[i] = &s->ports[i].port; ! 1194: } ! 1195: if (usb_register_companion(s->masterbus, ports, NB_PORTS, ! 1196: s->firstport, s, &uhci_port_ops, ! 1197: USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) { ! 1198: return -1; ! 1199: } ! 1200: } else { ! 1201: usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev); ! 1202: for (i = 0; i < NB_PORTS; i++) { ! 1203: usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops, ! 1204: USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); ! 1205: } ! 1206: } ! 1207: s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s); ! 1208: s->num_ports_vmstate = NB_PORTS; ! 1209: QTAILQ_INIT(&s->queues); ! 1210: ! 1211: qemu_register_reset(uhci_reset, s); ! 1212: ! 1213: memory_region_init_io(&s->io_bar, &uhci_ioport_ops, s, "uhci", 0x20); ! 1214: /* Use region 4 for consistency with real hardware. BSD guests seem ! 1215: to rely on this. */ ! 1216: pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar); ! 1217: ! 1218: return 0; ! 1219: } ! 1220: ! 1221: static int usb_uhci_vt82c686b_initfn(PCIDevice *dev) ! 1222: { ! 1223: UHCIState *s = DO_UPCAST(UHCIState, dev, dev); ! 1224: uint8_t *pci_conf = s->dev.config; ! 1225: ! 1226: /* USB misc control 1/2 */ ! 1227: pci_set_long(pci_conf + 0x40,0x00001000); ! 1228: /* PM capability */ ! 1229: pci_set_long(pci_conf + 0x80,0x00020001); ! 1230: /* USB legacy support */ ! 1231: pci_set_long(pci_conf + 0xc0,0x00002000); ! 1232: ! 1233: return usb_uhci_common_initfn(dev); ! 1234: } ! 1235: ! 1236: static int usb_uhci_exit(PCIDevice *dev) ! 1237: { ! 1238: UHCIState *s = DO_UPCAST(UHCIState, dev, dev); ! 1239: ! 1240: memory_region_destroy(&s->io_bar); ! 1241: return 0; ! 1242: } ! 1243: ! 1244: static Property uhci_properties[] = { ! 1245: DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), ! 1246: DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), ! 1247: DEFINE_PROP_END_OF_LIST(), ! 1248: }; ! 1249: ! 1250: static void piix3_uhci_class_init(ObjectClass *klass, void *data) ! 1251: { ! 1252: DeviceClass *dc = DEVICE_CLASS(klass); ! 1253: PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); ! 1254: ! 1255: k->init = usb_uhci_common_initfn; ! 1256: k->exit = usb_uhci_exit; ! 1257: k->vendor_id = PCI_VENDOR_ID_INTEL; ! 1258: k->device_id = PCI_DEVICE_ID_INTEL_82371SB_2; ! 1259: k->revision = 0x01; ! 1260: k->class_id = PCI_CLASS_SERIAL_USB; ! 1261: dc->vmsd = &vmstate_uhci; ! 1262: dc->props = uhci_properties; ! 1263: } ! 1264: ! 1265: static TypeInfo piix3_uhci_info = { ! 1266: .name = "piix3-usb-uhci", ! 1267: .parent = TYPE_PCI_DEVICE, ! 1268: .instance_size = sizeof(UHCIState), ! 1269: .class_init = piix3_uhci_class_init, ! 1270: }; ! 1271: ! 1272: static void piix4_uhci_class_init(ObjectClass *klass, void *data) ! 1273: { ! 1274: DeviceClass *dc = DEVICE_CLASS(klass); ! 1275: PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); ! 1276: ! 1277: k->init = usb_uhci_common_initfn; ! 1278: k->exit = usb_uhci_exit; ! 1279: k->vendor_id = PCI_VENDOR_ID_INTEL; ! 1280: k->device_id = PCI_DEVICE_ID_INTEL_82371AB_2; ! 1281: k->revision = 0x01; ! 1282: k->class_id = PCI_CLASS_SERIAL_USB; ! 1283: dc->vmsd = &vmstate_uhci; ! 1284: dc->props = uhci_properties; ! 1285: } ! 1286: ! 1287: static TypeInfo piix4_uhci_info = { ! 1288: .name = "piix4-usb-uhci", ! 1289: .parent = TYPE_PCI_DEVICE, ! 1290: .instance_size = sizeof(UHCIState), ! 1291: .class_init = piix4_uhci_class_init, ! 1292: }; ! 1293: ! 1294: static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data) ! 1295: { ! 1296: DeviceClass *dc = DEVICE_CLASS(klass); ! 1297: PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); ! 1298: ! 1299: k->init = usb_uhci_vt82c686b_initfn; ! 1300: k->exit = usb_uhci_exit; ! 1301: k->vendor_id = PCI_VENDOR_ID_VIA; ! 1302: k->device_id = PCI_DEVICE_ID_VIA_UHCI; ! 1303: k->revision = 0x01; ! 1304: k->class_id = PCI_CLASS_SERIAL_USB; ! 1305: dc->vmsd = &vmstate_uhci; ! 1306: dc->props = uhci_properties; ! 1307: } ! 1308: ! 1309: static TypeInfo vt82c686b_uhci_info = { ! 1310: .name = "vt82c686b-usb-uhci", ! 1311: .parent = TYPE_PCI_DEVICE, ! 1312: .instance_size = sizeof(UHCIState), ! 1313: .class_init = vt82c686b_uhci_class_init, ! 1314: }; ! 1315: ! 1316: static void ich9_uhci1_class_init(ObjectClass *klass, void *data) ! 1317: { ! 1318: DeviceClass *dc = DEVICE_CLASS(klass); ! 1319: PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); ! 1320: ! 1321: k->init = usb_uhci_common_initfn; ! 1322: k->vendor_id = PCI_VENDOR_ID_INTEL; ! 1323: k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1; ! 1324: k->revision = 0x03; ! 1325: k->class_id = PCI_CLASS_SERIAL_USB; ! 1326: dc->vmsd = &vmstate_uhci; ! 1327: dc->props = uhci_properties; ! 1328: } ! 1329: ! 1330: static TypeInfo ich9_uhci1_info = { ! 1331: .name = "ich9-usb-uhci1", ! 1332: .parent = TYPE_PCI_DEVICE, ! 1333: .instance_size = sizeof(UHCIState), ! 1334: .class_init = ich9_uhci1_class_init, ! 1335: }; ! 1336: ! 1337: static void ich9_uhci2_class_init(ObjectClass *klass, void *data) ! 1338: { ! 1339: DeviceClass *dc = DEVICE_CLASS(klass); ! 1340: PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); ! 1341: ! 1342: k->init = usb_uhci_common_initfn; ! 1343: k->vendor_id = PCI_VENDOR_ID_INTEL; ! 1344: k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2; ! 1345: k->revision = 0x03; ! 1346: k->class_id = PCI_CLASS_SERIAL_USB; ! 1347: dc->vmsd = &vmstate_uhci; ! 1348: dc->props = uhci_properties; ! 1349: } ! 1350: ! 1351: static TypeInfo ich9_uhci2_info = { ! 1352: .name = "ich9-usb-uhci2", ! 1353: .parent = TYPE_PCI_DEVICE, ! 1354: .instance_size = sizeof(UHCIState), ! 1355: .class_init = ich9_uhci2_class_init, ! 1356: }; ! 1357: ! 1358: static void ich9_uhci3_class_init(ObjectClass *klass, void *data) ! 1359: { ! 1360: DeviceClass *dc = DEVICE_CLASS(klass); ! 1361: PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); ! 1362: ! 1363: k->init = usb_uhci_common_initfn; ! 1364: k->vendor_id = PCI_VENDOR_ID_INTEL; ! 1365: k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3; ! 1366: k->revision = 0x03; ! 1367: k->class_id = PCI_CLASS_SERIAL_USB; ! 1368: dc->vmsd = &vmstate_uhci; ! 1369: dc->props = uhci_properties; ! 1370: } ! 1371: ! 1372: static TypeInfo ich9_uhci3_info = { ! 1373: .name = "ich9-usb-uhci3", ! 1374: .parent = TYPE_PCI_DEVICE, ! 1375: .instance_size = sizeof(UHCIState), ! 1376: .class_init = ich9_uhci3_class_init, ! 1377: }; ! 1378: ! 1379: static void uhci_register_types(void) ! 1380: { ! 1381: type_register_static(&piix3_uhci_info); ! 1382: type_register_static(&piix4_uhci_info); ! 1383: type_register_static(&vt82c686b_uhci_info); ! 1384: type_register_static(&ich9_uhci1_info); ! 1385: type_register_static(&ich9_uhci2_info); ! 1386: type_register_static(&ich9_uhci3_info); ! 1387: } ! 1388: ! 1389: type_init(uhci_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.