hcd-uhci.c 35.7 KB
Newer Older
B
bellard 已提交
1 2
/*
 * USB UHCI controller emulation
3
 *
B
bellard 已提交
4
 * Copyright (c) 2005 Fabrice Bellard
5
 *
6 7 8 9
 * Copyright (c) 2008 Max Krasnyansky
 *     Magor rewrite of the UHCI data structures parser and frame processor
 *     Support for fully async operation and multiple outstanding transactions
 *
B
bellard 已提交
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
G
Gerd Hoffmann 已提交
28 29 30
#include "hw/hw.h"
#include "hw/usb.h"
#include "hw/pci.h"
P
pbrook 已提交
31
#include "qemu-timer.h"
G
Gerd Hoffmann 已提交
32
#include "iov.h"
G
Gerd Hoffmann 已提交
33
#include "dma.h"
B
bellard 已提交
34 35

//#define DEBUG
36
//#define DEBUG_DUMP_DATA
B
bellard 已提交
37

38 39
#define UHCI_CMD_FGR      (1 << 4)
#define UHCI_CMD_EGSM     (1 << 3)
B
bellard 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#define UHCI_CMD_GRESET   (1 << 2)
#define UHCI_CMD_HCRESET  (1 << 1)
#define UHCI_CMD_RS       (1 << 0)

#define UHCI_STS_HCHALTED (1 << 5)
#define UHCI_STS_HCPERR   (1 << 4)
#define UHCI_STS_HSERR    (1 << 3)
#define UHCI_STS_RD       (1 << 2)
#define UHCI_STS_USBERR   (1 << 1)
#define UHCI_STS_USBINT   (1 << 0)

#define TD_CTRL_SPD     (1 << 29)
#define TD_CTRL_ERROR_SHIFT  27
#define TD_CTRL_IOS     (1 << 25)
#define TD_CTRL_IOC     (1 << 24)
#define TD_CTRL_ACTIVE  (1 << 23)
#define TD_CTRL_STALL   (1 << 22)
#define TD_CTRL_BABBLE  (1 << 20)
#define TD_CTRL_NAK     (1 << 19)
#define TD_CTRL_TIMEOUT (1 << 18)

61
#define UHCI_PORT_SUSPEND (1 << 12)
B
bellard 已提交
62 63
#define UHCI_PORT_RESET (1 << 9)
#define UHCI_PORT_LSDA  (1 << 8)
64
#define UHCI_PORT_RD    (1 << 6)
B
bellard 已提交
65 66 67 68 69
#define UHCI_PORT_ENC   (1 << 3)
#define UHCI_PORT_EN    (1 << 2)
#define UHCI_PORT_CSC   (1 << 1)
#define UHCI_PORT_CCS   (1 << 0)

70 71 72
#define UHCI_PORT_READ_ONLY    (0x1bb)
#define UHCI_PORT_WRITE_CLEAR  (UHCI_PORT_CSC | UHCI_PORT_ENC)

B
bellard 已提交
73 74
#define FRAME_TIMER_FREQ 1000

75
#define FRAME_MAX_LOOPS  256
B
bellard 已提交
76 77 78

#define NB_PORTS 2

79
#ifdef DEBUG
M
malc 已提交
80
#define DPRINTF printf
81

82
static const char *pid2str(int pid)
83 84 85 86 87 88 89 90 91 92
{
    switch (pid) {
    case USB_TOKEN_SETUP: return "SETUP";
    case USB_TOKEN_IN:    return "IN";
    case USB_TOKEN_OUT:   return "OUT";
    }
    return "?";
}

#else
M
malc 已提交
93
#define DPRINTF(...)
94 95
#endif

96
typedef struct UHCIState UHCIState;
G
Gerd Hoffmann 已提交
97 98
typedef struct UHCIAsync UHCIAsync;
typedef struct UHCIQueue UHCIQueue;
99

100 101 102 103 104
/* 
 * Pending async transaction.
 * 'packet' must be the first field because completion
 * handler does "(UHCIAsync *) pkt" cast.
 */
G
Gerd Hoffmann 已提交
105 106

struct UHCIAsync {
107
    USBPacket packet;
G
Gerd Hoffmann 已提交
108
    QEMUSGList sgl;
G
Gerd Hoffmann 已提交
109
    UHCIQueue *queue;
G
Gerd Hoffmann 已提交
110
    QTAILQ_ENTRY(UHCIAsync) next;
111
    uint32_t  td;
112
    uint8_t   isoc;
113
    uint8_t   done;
G
Gerd Hoffmann 已提交
114 115 116 117 118 119 120 121 122
};

struct UHCIQueue {
    uint32_t  token;
    UHCIState *uhci;
    QTAILQ_ENTRY(UHCIQueue) next;
    QTAILQ_HEAD(, UHCIAsync) asyncs;
    int8_t    valid;
};
123

B
bellard 已提交
124 125 126 127 128
typedef struct UHCIPort {
    USBPort port;
    uint16_t ctrl;
} UHCIPort;

129
struct UHCIState {
B
bellard 已提交
130
    PCIDevice dev;
A
Avi Kivity 已提交
131
    MemoryRegion io_bar;
132
    USBBus bus; /* Note unused when we're a companion controller */
B
bellard 已提交
133 134 135 136 137 138 139
    uint16_t cmd; /* cmd register */
    uint16_t status;
    uint16_t intr; /* interrupt enable register */
    uint16_t frnum; /* frame number */
    uint32_t fl_base_addr; /* frame list base address */
    uint8_t sof_timing;
    uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
140
    int64_t expire_time;
B
bellard 已提交
141 142
    QEMUTimer *frame_timer;
    UHCIPort ports[NB_PORTS];
P
pbrook 已提交
143 144 145

    /* Interrupts that should be raised at the end of the current frame.  */
    uint32_t pending_int_mask;
146 147

    /* Active packets */
G
Gerd Hoffmann 已提交
148
    QTAILQ_HEAD(, UHCIQueue) queues;
149
    uint8_t num_ports_vmstate;
150 151 152 153

    /* Properties */
    char *masterbus;
    uint32_t firstport;
154
};
B
bellard 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167

typedef struct UHCI_TD {
    uint32_t link;
    uint32_t ctrl; /* see TD_CTRL_xxx */
    uint32_t token;
    uint32_t buffer;
} UHCI_TD;

typedef struct UHCI_QH {
    uint32_t link;
    uint32_t el_link;
} UHCI_QH;

G
Gerd Hoffmann 已提交
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
static inline int32_t uhci_queue_token(UHCI_TD *td)
{
    /* covers ep, dev, pid -> identifies the endpoint */
    return td->token & 0x7ffff;
}

static UHCIQueue *uhci_queue_get(UHCIState *s, UHCI_TD *td)
{
    uint32_t token = uhci_queue_token(td);
    UHCIQueue *queue;

    QTAILQ_FOREACH(queue, &s->queues, next) {
        if (queue->token == token) {
            return queue;
        }
    }

    queue = g_new0(UHCIQueue, 1);
    queue->uhci = s;
    queue->token = token;
    QTAILQ_INIT(&queue->asyncs);
    QTAILQ_INSERT_HEAD(&s->queues, queue, next);
    return queue;
}

static void uhci_queue_free(UHCIQueue *queue)
{
    UHCIState *s = queue->uhci;

    QTAILQ_REMOVE(&s->queues, queue, next);
    g_free(queue);
}

201
static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t addr)
202
{
203
    UHCIAsync *async = g_new0(UHCIAsync, 1);
204

G
Gerd Hoffmann 已提交
205
    async->queue = queue;
206
    async->td = addr;
G
Gerd Hoffmann 已提交
207
    usb_packet_init(&async->packet);
G
Gerd Hoffmann 已提交
208
    pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1);
209 210 211 212

    return async;
}

G
Gerd Hoffmann 已提交
213
static void uhci_async_free(UHCIAsync *async)
214
{
G
Gerd Hoffmann 已提交
215
    usb_packet_cleanup(&async->packet);
G
Gerd Hoffmann 已提交
216
    qemu_sglist_destroy(&async->sgl);
217
    g_free(async);
218 219
}

G
Gerd Hoffmann 已提交
220
static void uhci_async_link(UHCIAsync *async)
221
{
G
Gerd Hoffmann 已提交
222 223
    UHCIQueue *queue = async->queue;
    QTAILQ_INSERT_TAIL(&queue->asyncs, async, next);
224 225
}

G
Gerd Hoffmann 已提交
226
static void uhci_async_unlink(UHCIAsync *async)
227
{
G
Gerd Hoffmann 已提交
228 229
    UHCIQueue *queue = async->queue;
    QTAILQ_REMOVE(&queue->asyncs, async, next);
230 231
}

G
Gerd Hoffmann 已提交
232
static void uhci_async_cancel(UHCIAsync *async)
233
{
M
malc 已提交
234
    DPRINTF("uhci: cancel td 0x%x token 0x%x done %u\n",
235 236 237 238
           async->td, async->token, async->done);

    if (!async->done)
        usb_cancel_packet(&async->packet);
G
Gerd Hoffmann 已提交
239
    uhci_async_free(async);
240 241 242 243 244 245
}

/*
 * Mark all outstanding async packets as invalid.
 * This is used for canceling them when TDs are removed by the HCD.
 */
G
Gerd Hoffmann 已提交
246
static void uhci_async_validate_begin(UHCIState *s)
247
{
G
Gerd Hoffmann 已提交
248
    UHCIQueue *queue;
249

G
Gerd Hoffmann 已提交
250 251
    QTAILQ_FOREACH(queue, &s->queues, next) {
        queue->valid--;
252 253 254 255 256 257 258 259
    }
}

/*
 * Cancel async packets that are no longer valid
 */
static void uhci_async_validate_end(UHCIState *s)
{
G
Gerd Hoffmann 已提交
260 261
    UHCIQueue *queue, *n;
    UHCIAsync *async;
262

G
Gerd Hoffmann 已提交
263 264
    QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) {
        if (queue->valid > 0) {
265 266
            continue;
        }
G
Gerd Hoffmann 已提交
267 268 269 270 271 272
        while (!QTAILQ_EMPTY(&queue->asyncs)) {
            async = QTAILQ_FIRST(&queue->asyncs);
            uhci_async_unlink(async);
            uhci_async_cancel(async);
        }
        uhci_queue_free(queue);
273 274 275
    }
}

276 277
static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
{
G
Gerd Hoffmann 已提交
278
    UHCIQueue *queue;
279 280
    UHCIAsync *curr, *n;

G
Gerd Hoffmann 已提交
281 282 283 284 285 286 287 288
    QTAILQ_FOREACH(queue, &s->queues, next) {
        QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) {
            if (!usb_packet_is_inflight(&curr->packet) ||
                curr->packet.ep->dev != dev) {
                continue;
            }
            uhci_async_unlink(curr);
            uhci_async_cancel(curr);
289 290 291 292
        }
    }
}

293 294
static void uhci_async_cancel_all(UHCIState *s)
{
G
Gerd Hoffmann 已提交
295
    UHCIQueue *queue;
G
Gerd Hoffmann 已提交
296
    UHCIAsync *curr, *n;
297

G
Gerd Hoffmann 已提交
298 299 300 301 302
    QTAILQ_FOREACH(queue, &s->queues, next) {
        QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) {
            uhci_async_unlink(curr);
            uhci_async_cancel(curr);
        }
G
Gerd Hoffmann 已提交
303
        uhci_queue_free(queue);
304 305 306
    }
}

G
Gerd Hoffmann 已提交
307
static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, UHCI_TD *td)
308
{
G
Gerd Hoffmann 已提交
309 310
    uint32_t token = uhci_queue_token(td);
    UHCIQueue *queue;
G
Gerd Hoffmann 已提交
311
    UHCIAsync *async;
312

G
Gerd Hoffmann 已提交
313 314 315
    QTAILQ_FOREACH(queue, &s->queues, next) {
        if (queue->token == token) {
            break;
316
        }
G
Gerd Hoffmann 已提交
317 318 319
    }
    if (queue == NULL) {
        return NULL;
320
    }
321

G
Gerd Hoffmann 已提交
322 323 324 325 326
    QTAILQ_FOREACH(async, &queue->asyncs, next) {
        if (async->td == addr) {
            return async;
        }
    }
327

G
Gerd Hoffmann 已提交
328
    return NULL;
329 330
}

B
bellard 已提交
331 332 333 334 335 336 337 338 339 340 341 342 343
static void uhci_update_irq(UHCIState *s)
{
    int level;
    if (((s->status2 & 1) && (s->intr & (1 << 2))) ||
        ((s->status2 & 2) && (s->intr & (1 << 3))) ||
        ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||
        ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||
        (s->status & UHCI_STS_HSERR) ||
        (s->status & UHCI_STS_HCPERR)) {
        level = 1;
    } else {
        level = 0;
    }
P
pbrook 已提交
344
    qemu_set_irq(s->dev.irq[3], level);
B
bellard 已提交
345 346
}

G
Gleb Natapov 已提交
347
static void uhci_reset(void *opaque)
B
bellard 已提交
348
{
G
Gleb Natapov 已提交
349
    UHCIState *s = opaque;
B
bellard 已提交
350 351 352 353
    uint8_t *pci_conf;
    int i;
    UHCIPort *port;

M
malc 已提交
354
    DPRINTF("uhci: full reset\n");
355

B
bellard 已提交
356 357 358 359 360 361 362 363 364 365
    pci_conf = s->dev.config;

    pci_conf[0x6a] = 0x01; /* usb clock */
    pci_conf[0x6b] = 0x00;
    s->cmd = 0;
    s->status = 0;
    s->status2 = 0;
    s->intr = 0;
    s->fl_base_addr = 0;
    s->sof_timing = 64;
366

B
bellard 已提交
367 368 369
    for(i = 0; i < NB_PORTS; i++) {
        port = &s->ports[i];
        port->ctrl = 0x0080;
370
        if (port->port.dev && port->port.dev->attached) {
G
Gerd Hoffmann 已提交
371
            usb_port_reset(&port->port);
372
        }
B
bellard 已提交
373
    }
374 375

    uhci_async_cancel_all(s);
B
bellard 已提交
376 377
}

J
Juan Quintela 已提交
378
static void uhci_pre_save(void *opaque)
379 380 381
{
    UHCIState *s = opaque;

382
    uhci_async_cancel_all(s);
383 384
}

J
Juan Quintela 已提交
385 386 387 388 389 390 391 392 393 394 395 396 397
static const VMStateDescription vmstate_uhci_port = {
    .name = "uhci port",
    .version_id = 1,
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
    .fields      = (VMStateField []) {
        VMSTATE_UINT16(ctrl, UHCIPort),
        VMSTATE_END_OF_LIST()
    }
};

static const VMStateDescription vmstate_uhci = {
    .name = "uhci",
398
    .version_id = 2,
J
Juan Quintela 已提交
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
    .pre_save = uhci_pre_save,
    .fields      = (VMStateField []) {
        VMSTATE_PCI_DEVICE(dev, UHCIState),
        VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState),
        VMSTATE_STRUCT_ARRAY(ports, UHCIState, NB_PORTS, 1,
                             vmstate_uhci_port, UHCIPort),
        VMSTATE_UINT16(cmd, UHCIState),
        VMSTATE_UINT16(status, UHCIState),
        VMSTATE_UINT16(intr, UHCIState),
        VMSTATE_UINT16(frnum, UHCIState),
        VMSTATE_UINT32(fl_base_addr, UHCIState),
        VMSTATE_UINT8(sof_timing, UHCIState),
        VMSTATE_UINT8(status2, UHCIState),
        VMSTATE_TIMER(frame_timer, UHCIState),
415
        VMSTATE_INT64_V(expire_time, UHCIState, 2),
J
Juan Quintela 已提交
416 417 418
        VMSTATE_END_OF_LIST()
    }
};
419

B
bellard 已提交
420 421 422
static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
{
    UHCIState *s = opaque;
423

B
bellard 已提交
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
    addr &= 0x1f;
    switch(addr) {
    case 0x0c:
        s->sof_timing = val;
        break;
    }
}

static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr)
{
    UHCIState *s = opaque;
    uint32_t val;

    addr &= 0x1f;
    switch(addr) {
    case 0x0c:
        val = s->sof_timing;
P
pbrook 已提交
441
        break;
B
bellard 已提交
442 443 444 445 446 447 448 449 450 451
    default:
        val = 0xff;
        break;
    }
    return val;
}

static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
{
    UHCIState *s = opaque;
452

B
bellard 已提交
453
    addr &= 0x1f;
M
malc 已提交
454
    DPRINTF("uhci: writew port=0x%04x val=0x%04x\n", addr, val);
455

B
bellard 已提交
456 457 458 459
    switch(addr) {
    case 0x00:
        if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
            /* start frame processing */
460 461
            s->expire_time = qemu_get_clock_ns(vm_clock) +
                (get_ticks_per_sec() / FRAME_TIMER_FREQ);
462
            qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
463
            s->status &= ~UHCI_STS_HCHALTED;
B
bellard 已提交
464
        } else if (!(val & UHCI_CMD_RS)) {
465
            s->status |= UHCI_STS_HCHALTED;
B
bellard 已提交
466 467 468 469 470 471 472 473
        }
        if (val & UHCI_CMD_GRESET) {
            UHCIPort *port;
            int i;

            /* send reset on the USB bus */
            for(i = 0; i < NB_PORTS; i++) {
                port = &s->ports[i];
G
Gerd Hoffmann 已提交
474
                usb_device_reset(port->port.dev);
B
bellard 已提交
475 476 477 478
            }
            uhci_reset(s);
            return;
        }
B
bellard 已提交
479
        if (val & UHCI_CMD_HCRESET) {
B
bellard 已提交
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
            uhci_reset(s);
            return;
        }
        s->cmd = val;
        break;
    case 0x02:
        s->status &= ~val;
        /* XXX: the chip spec is not coherent, so we add a hidden
           register to distinguish between IOC and SPD */
        if (val & UHCI_STS_USBINT)
            s->status2 = 0;
        uhci_update_irq(s);
        break;
    case 0x04:
        s->intr = val;
        uhci_update_irq(s);
        break;
    case 0x06:
        if (s->status & UHCI_STS_HCHALTED)
            s->frnum = val & 0x7ff;
        break;
    case 0x10 ... 0x1f:
        {
            UHCIPort *port;
            USBDevice *dev;
            int n;

            n = (addr >> 1) & 7;
            if (n >= NB_PORTS)
                return;
            port = &s->ports[n];
B
bellard 已提交
511
            dev = port->port.dev;
512
            if (dev && dev->attached) {
B
bellard 已提交
513
                /* port reset */
514
                if ( (val & UHCI_PORT_RESET) &&
B
bellard 已提交
515
                     !(port->ctrl & UHCI_PORT_RESET) ) {
G
Gerd Hoffmann 已提交
516
                    usb_device_reset(dev);
B
bellard 已提交
517 518
                }
            }
519 520
            port->ctrl &= UHCI_PORT_READ_ONLY;
            port->ctrl |= (val & ~UHCI_PORT_READ_ONLY);
B
bellard 已提交
521
            /* some bits are reset when a '1' is written to them */
522
            port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR);
B
bellard 已提交
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
        }
        break;
    }
}

static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
{
    UHCIState *s = opaque;
    uint32_t val;

    addr &= 0x1f;
    switch(addr) {
    case 0x00:
        val = s->cmd;
        break;
    case 0x02:
        val = s->status;
        break;
    case 0x04:
        val = s->intr;
        break;
    case 0x06:
        val = s->frnum;
        break;
    case 0x10 ... 0x1f:
        {
            UHCIPort *port;
            int n;
            n = (addr >> 1) & 7;
552
            if (n >= NB_PORTS)
B
bellard 已提交
553 554 555 556 557 558 559 560 561 562
                goto read_default;
            port = &s->ports[n];
            val = port->ctrl;
        }
        break;
    default:
    read_default:
        val = 0xff7f; /* disabled port */
        break;
    }
563

M
malc 已提交
564
    DPRINTF("uhci: readw port=0x%04x val=0x%04x\n", addr, val);
565

B
bellard 已提交
566 567 568 569 570 571 572 573
    return val;
}

static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
{
    UHCIState *s = opaque;

    addr &= 0x1f;
M
malc 已提交
574
    DPRINTF("uhci: writel port=0x%04x val=0x%08x\n", addr, val);
575

B
bellard 已提交
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
    switch(addr) {
    case 0x08:
        s->fl_base_addr = val & ~0xfff;
        break;
    }
}

static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr)
{
    UHCIState *s = opaque;
    uint32_t val;

    addr &= 0x1f;
    switch(addr) {
    case 0x08:
        val = s->fl_base_addr;
        break;
    default:
        val = 0xffffffff;
        break;
    }
    return val;
}

600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
/* signal resume if controller suspended */
static void uhci_resume (void *opaque)
{
    UHCIState *s = (UHCIState *)opaque;

    if (!s)
        return;

    if (s->cmd & UHCI_CMD_EGSM) {
        s->cmd |= UHCI_CMD_FGR;
        s->status |= UHCI_STS_RD;
        uhci_update_irq(s);
    }
}

615
static void uhci_attach(USBPort *port1)
B
bellard 已提交
616 617 618 619
{
    UHCIState *s = port1->opaque;
    UHCIPort *port = &s->ports[port1->index];

620 621
    /* set connect status */
    port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
P
pbrook 已提交
622

623 624 625
    /* update speed */
    if (port->port.dev->speed == USB_SPEED_LOW) {
        port->ctrl |= UHCI_PORT_LSDA;
B
bellard 已提交
626
    } else {
627 628
        port->ctrl &= ~UHCI_PORT_LSDA;
    }
629

630 631
    uhci_resume(s);
}
632

633 634 635 636 637
static void uhci_detach(USBPort *port1)
{
    UHCIState *s = port1->opaque;
    UHCIPort *port = &s->ports[port1->index];

638 639
    uhci_async_cancel_device(s, port1->dev);

640 641 642 643
    /* set connect status */
    if (port->ctrl & UHCI_PORT_CCS) {
        port->ctrl &= ~UHCI_PORT_CCS;
        port->ctrl |= UHCI_PORT_CSC;
B
bellard 已提交
644
    }
645 646 647 648 649 650 651
    /* disable port */
    if (port->ctrl & UHCI_PORT_EN) {
        port->ctrl &= ~UHCI_PORT_EN;
        port->ctrl |= UHCI_PORT_ENC;
    }

    uhci_resume(s);
B
bellard 已提交
652 653
}

654 655 656 657 658 659 660
static void uhci_child_detach(USBPort *port1, USBDevice *child)
{
    UHCIState *s = port1->opaque;

    uhci_async_cancel_device(s, child);
}

661
static void uhci_wakeup(USBPort *port1)
662
{
663 664
    UHCIState *s = port1->opaque;
    UHCIPort *port = &s->ports[port1->index];
665 666 667 668 669 670 671

    if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) {
        port->ctrl |= UHCI_PORT_RD;
        uhci_resume(s);
    }
}

672
static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr)
B
bellard 已提交
673
{
674 675
    USBDevice *dev;
    int i;
676

677
    for (i = 0; i < NB_PORTS; i++) {
678
        UHCIPort *port = &s->ports[i];
679 680 681 682 683 684
        if (!(port->ctrl & UHCI_PORT_EN)) {
            continue;
        }
        dev = usb_find_device(&port->port, addr);
        if (dev != NULL) {
            return dev;
685
        }
B
bellard 已提交
686
    }
687
    return NULL;
B
bellard 已提交
688 689
}

690
static void uhci_async_complete(USBPort *port, USBPacket *packet);
691
static void uhci_process_frame(UHCIState *s);
P
pbrook 已提交
692

B
bellard 已提交
693 694 695 696
/* return -1 if fatal error (frame must be stopped)
          0 if TD successful
          1 if TD unsuccessful or inactive
*/
697
static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask)
B
bellard 已提交
698
{
699
    int len = 0, max_len, err, ret;
B
bellard 已提交
700 701
    uint8_t pid;

702 703 704
    max_len = ((td->token >> 21) + 1) & 0x7ff;
    pid = td->token & 0xff;

G
Gerd Hoffmann 已提交
705
    ret = async->packet.result;
706 707 708

    if (td->ctrl & TD_CTRL_IOS)
        td->ctrl &= ~TD_CTRL_ACTIVE;
B
bellard 已提交
709

710 711
    if (ret < 0)
        goto out;
712

G
Gerd Hoffmann 已提交
713
    len = async->packet.result;
714 715 716 717 718 719
    td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);

    /* The NAK bit may have been set by a previous frame, so clear it
       here.  The docs are somewhat unclear, but win2k relies on this
       behavior.  */
    td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
P
Paul Brook 已提交
720 721
    if (td->ctrl & TD_CTRL_IOC)
        *int_mask |= 0x01;
722 723 724 725 726

    if (pid == USB_TOKEN_IN) {
        if (len > max_len) {
            ret = USB_RET_BABBLE;
            goto out;
P
pbrook 已提交
727
        }
728

729
        if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
B
bellard 已提交
730 731
            *int_mask |= 0x02;
            /* short packet: do not update QH */
M
malc 已提交
732
            DPRINTF("uhci: short packet. td 0x%x token 0x%x\n", async->td, async->token);
B
bellard 已提交
733 734
            return 1;
        }
735 736 737 738 739 740 741 742 743 744
    }

    /* success */
    return 0;

out:
    switch(ret) {
    case USB_RET_STALL:
        td->ctrl |= TD_CTRL_STALL;
        td->ctrl &= ~TD_CTRL_ACTIVE;
745
        s->status |= UHCI_STS_USBERR;
746 747 748
        if (td->ctrl & TD_CTRL_IOC) {
            *int_mask |= 0x01;
        }
749
        uhci_update_irq(s);
750 751 752 753 754
        return 1;

    case USB_RET_BABBLE:
        td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
        td->ctrl &= ~TD_CTRL_ACTIVE;
755
        s->status |= UHCI_STS_USBERR;
756 757 758
        if (td->ctrl & TD_CTRL_IOC) {
            *int_mask |= 0x01;
        }
759
        uhci_update_irq(s);
760 761 762 763 764 765 766 767 768
        /* frame interrupted */
        return -1;

    case USB_RET_NAK:
        td->ctrl |= TD_CTRL_NAK;
        if (pid == USB_TOKEN_SETUP)
            break;
	return 1;

H
Hans de Goede 已提交
769
    case USB_RET_IOERROR:
770 771 772 773 774 775 776 777 778 779 780 781
    case USB_RET_NODEV:
    default:
	break;
    }

    /* Retry the TD if error count is not zero */

    td->ctrl |= TD_CTRL_TIMEOUT;
    err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;
    if (err != 0) {
        err--;
        if (err == 0) {
B
bellard 已提交
782
            td->ctrl &= ~TD_CTRL_ACTIVE;
783
            s->status |= UHCI_STS_USBERR;
P
Paul Brook 已提交
784 785
            if (td->ctrl & TD_CTRL_IOC)
                *int_mask |= 0x01;
786
            uhci_update_irq(s);
B
bellard 已提交
787 788
        }
    }
789 790 791
    td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
        (err << TD_CTRL_ERROR_SHIFT);
    return 1;
B
bellard 已提交
792 793
}

794 795 796
static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *int_mask)
{
    UHCIAsync *async;
797
    int len = 0, max_len;
G
Gerd Hoffmann 已提交
798
    uint8_t pid;
799 800
    USBDevice *dev;
    USBEndpoint *ep;
801 802 803 804 805

    /* Is active ? */
    if (!(td->ctrl & TD_CTRL_ACTIVE))
        return 1;

G
Gerd Hoffmann 已提交
806
    async = uhci_async_find_td(s, addr, td);
807 808
    if (async) {
        /* Already submitted */
G
Gerd Hoffmann 已提交
809
        async->queue->valid = 32;
810 811 812 813

        if (!async->done)
            return 1;

G
Gerd Hoffmann 已提交
814
        uhci_async_unlink(async);
815 816 817 818
        goto done;
    }

    /* Allocate new packet */
819
    async = uhci_async_alloc(uhci_queue_get(s, td), addr);
820 821 822
    if (!async)
        return 1;

823 824 825
    /* valid needs to be large enough to handle 10 frame delay
     * for initial isochronous requests
     */
G
Gerd Hoffmann 已提交
826 827
    async->queue->valid = 32;
    async->isoc  = td->ctrl & TD_CTRL_IOS;
828 829 830 831

    max_len = ((td->token >> 21) + 1) & 0x7ff;
    pid = td->token & 0xff;

832 833 834
    dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
    ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
    usb_packet_setup(&async->packet, pid, ep);
G
Gerd Hoffmann 已提交
835 836
    qemu_sglist_add(&async->sgl, td->buffer, max_len);
    usb_packet_map(&async->packet, &async->sgl);
837 838 839 840

    switch(pid) {
    case USB_TOKEN_OUT:
    case USB_TOKEN_SETUP:
841
        len = usb_handle_packet(dev, &async->packet);
842 843
        if (len >= 0)
            len = max_len;
844 845 846
        break;

    case USB_TOKEN_IN:
847
        len = usb_handle_packet(dev, &async->packet);
848 849 850 851
        break;

    default:
        /* invalid pid : frame interrupted */
G
Gerd Hoffmann 已提交
852
        uhci_async_free(async);
853 854 855 856 857
        s->status |= UHCI_STS_HCPERR;
        uhci_update_irq(s);
        return -1;
    }
 
858
    if (len == USB_RET_ASYNC) {
G
Gerd Hoffmann 已提交
859
        uhci_async_link(async);
860 861 862
        return 2;
    }

G
Gerd Hoffmann 已提交
863
    async->packet.result = len;
864 865

done:
866
    len = uhci_complete_td(s, td, async, int_mask);
G
Gerd Hoffmann 已提交
867
    usb_packet_unmap(&async->packet);
G
Gerd Hoffmann 已提交
868
    uhci_async_free(async);
869
    return len;
870 871
}

872
static void uhci_async_complete(USBPort *port, USBPacket *packet)
P
pbrook 已提交
873
{
874
    UHCIAsync *async = container_of(packet, UHCIAsync, packet);
G
Gerd Hoffmann 已提交
875
    UHCIState *s = async->queue->uhci;
876

M
malc 已提交
877
    DPRINTF("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token);
878

879 880 881 882
    if (async->isoc) {
        UHCI_TD td;
        uint32_t link = async->td;
        uint32_t int_mask = 0, val;
883

884
        pci_dma_read(&s->dev, link & ~0xf, &td, sizeof(td));
885 886 887 888 889
        le32_to_cpus(&td.link);
        le32_to_cpus(&td.ctrl);
        le32_to_cpus(&td.token);
        le32_to_cpus(&td.buffer);

G
Gerd Hoffmann 已提交
890
        uhci_async_unlink(async);
891
        uhci_complete_td(s, &td, async, &int_mask);
892
        s->pending_int_mask |= int_mask;
893

894 895
        /* update the status bits of the TD */
        val = cpu_to_le32(td.ctrl);
896
        pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val));
G
Gerd Hoffmann 已提交
897
        uhci_async_free(async);
898 899 900 901
    } else {
        async->done = 1;
        uhci_process_frame(s);
    }
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
}

static int is_valid(uint32_t link)
{
    return (link & 1) == 0;
}

static int is_qh(uint32_t link)
{
    return (link & 2) != 0;
}

static int depth_first(uint32_t link)
{
    return (link & 4) != 0;
}

/* QH DB used for detecting QH loops */
#define UHCI_MAX_QUEUES 128
typedef struct {
    uint32_t addr[UHCI_MAX_QUEUES];
    int      count;
} QhDb;

static void qhdb_reset(QhDb *db)
{
    db->count = 0;
}

/* Add QH to DB. Returns 1 if already present or DB is full. */
static int qhdb_insert(QhDb *db, uint32_t addr)
{
    int i;
    for (i = 0; i < db->count; i++)
        if (db->addr[i] == addr)
            return 1;

    if (db->count >= UHCI_MAX_QUEUES)
        return 1;

    db->addr[db->count++] = addr;
    return 0;
}

946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
{
    uint32_t int_mask = 0;
    uint32_t plink = td->link;
    uint32_t token = uhci_queue_token(td);
    UHCI_TD ptd;
    int ret;

    while (is_valid(plink)) {
        pci_dma_read(&s->dev, plink & ~0xf, &ptd, sizeof(ptd));
        le32_to_cpus(&ptd.link);
        le32_to_cpus(&ptd.ctrl);
        le32_to_cpus(&ptd.token);
        le32_to_cpus(&ptd.buffer);
        if (!(ptd.ctrl & TD_CTRL_ACTIVE)) {
            break;
        }
        if (uhci_queue_token(&ptd) != token) {
            break;
        }
        ret = uhci_handle_td(s, plink, &ptd, &int_mask);
        assert(ret == 2); /* got USB_RET_ASYNC */
        assert(int_mask == 0);
        plink = ptd.link;
    }
}

973 974 975
static void uhci_process_frame(UHCIState *s)
{
    uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
976
    uint32_t curr_qh, td_count = 0, bytes_count = 0;
977
    int cnt, ret;
P
pbrook 已提交
978
    UHCI_TD td;
979 980
    UHCI_QH qh;
    QhDb qhdb;
P
pbrook 已提交
981

982 983
    frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);

M
malc 已提交
984
    DPRINTF("uhci: processing frame %d addr 0x%x\n" , s->frnum, frame_addr);
985

986
    pci_dma_read(&s->dev, frame_addr, &link, 4);
987
    le32_to_cpus(&link);
988

989 990 991 992 993 994 995 996 997 998 999 1000
    int_mask = 0;
    curr_qh  = 0;

    qhdb_reset(&qhdb);

    for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
        if (is_qh(link)) {
            /* QH */

            if (qhdb_insert(&qhdb, link)) {
                /*
                 * We're going in circles. Which is not a bug because
1001 1002 1003 1004 1005 1006 1007
                 * HCD is allowed to do that as part of the BW management.
                 *
                 * Stop processing here if
                 *  (a) no transaction has been done since we've been
                 *      here last time, or
                 *  (b) we've reached the usb 1.1 bandwidth, which is
                 *      1280 bytes/frame.
1008
                 */
M
malc 已提交
1009
                DPRINTF("uhci: detected loop. qh 0x%x\n", link);
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
                if (td_count == 0) {
                    DPRINTF("uhci: no transaction last round, stop\n");
                    break;
                } else if (bytes_count >= 1280) {
                    DPRINTF("uhci: bandwidth limit reached, stop\n");
                    break;
                } else {
                    td_count = 0;
                    qhdb_reset(&qhdb);
                    qhdb_insert(&qhdb, link);
                }
1021 1022
            }

1023
            pci_dma_read(&s->dev, link & ~0xf, &qh, sizeof(qh));
1024 1025 1026
            le32_to_cpus(&qh.link);
            le32_to_cpus(&qh.el_link);

M
malc 已提交
1027
            DPRINTF("uhci: QH 0x%x load. link 0x%x elink 0x%x\n",
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
                    link, qh.link, qh.el_link);

            if (!is_valid(qh.el_link)) {
                /* QH w/o elements */
                curr_qh = 0;
                link = qh.link;
            } else {
                /* QH with elements */
            	curr_qh = link;
            	link = qh.el_link;
            }
            continue;
        }

        /* TD */
1043
        pci_dma_read(&s->dev, link & ~0xf, &td, sizeof(td));
1044 1045 1046 1047 1048
        le32_to_cpus(&td.link);
        le32_to_cpus(&td.ctrl);
        le32_to_cpus(&td.token);
        le32_to_cpus(&td.buffer);

M
malc 已提交
1049
        DPRINTF("uhci: TD 0x%x load. link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", 
1050 1051 1052 1053
                link, td.link, td.ctrl, td.token, curr_qh);

        old_td_ctrl = td.ctrl;
        ret = uhci_handle_td(s, link, &td, &int_mask);
1054
        if (old_td_ctrl != td.ctrl) {
1055
            /* update the status bits of the TD */
1056
            val = cpu_to_le32(td.ctrl);
1057
            pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val));
1058
        }
1059

1060 1061 1062
        switch (ret) {
        case -1: /* interrupted frame */
            goto out;
1063

1064 1065 1066 1067
        case 1: /* goto next queue */
            DPRINTF("uhci: TD 0x%x skip. "
                    "link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n",
                    link, td.link, td.ctrl, td.token, curr_qh);
1068 1069 1070
            link = curr_qh ? qh.link : td.link;
            continue;

1071 1072 1073 1074
        case 2: /* got USB_RET_ASYNC */
            DPRINTF("uhci: TD 0x%x async. "
                    "link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n",
                    link, td.link, td.ctrl, td.token, curr_qh);
1075 1076 1077
            if (is_valid(td.link)) {
                uhci_fill_queue(s, &td);
            }
1078 1079
            link = curr_qh ? qh.link : td.link;
            continue;
1080

1081 1082 1083 1084
        case 0: /* completed TD */
            DPRINTF("uhci: TD 0x%x done. "
                    "link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n",
                    link, td.link, td.ctrl, td.token, curr_qh);
1085

1086 1087 1088
            link = td.link;
            td_count++;
            bytes_count += (td.ctrl & 0x7ff) + 1;
1089

1090 1091 1092 1093 1094
            if (curr_qh) {
                /* update QH element link */
                qh.el_link = link;
                val = cpu_to_le32(qh.el_link);
                pci_dma_write(&s->dev, (curr_qh & ~0xf) + 4, &val, sizeof(val));
1095

1096 1097
                if (!depth_first(link)) {
                    /* done with this QH */
1098

1099 1100
                    DPRINTF("uhci: QH 0x%x done. link 0x%x elink 0x%x\n",
                            curr_qh, qh.link, qh.el_link);
1101

1102 1103 1104
                    curr_qh = 0;
                    link    = qh.link;
                }
1105
            }
1106 1107 1108 1109
            break;

        default:
            assert(!"unknown return code");
P
pbrook 已提交
1110
        }
1111 1112

        /* go to the next entry */
P
pbrook 已提交
1113
    }
1114

1115
out:
1116
    s->pending_int_mask |= int_mask;
P
pbrook 已提交
1117 1118
}

B
bellard 已提交
1119 1120 1121
static void uhci_frame_timer(void *opaque)
{
    UHCIState *s = opaque;
1122 1123 1124

    /* prepare the timer for the next frame */
    s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ);
B
bellard 已提交
1125 1126

    if (!(s->cmd & UHCI_CMD_RS)) {
1127
        /* Full stop */
B
bellard 已提交
1128
        qemu_del_timer(s->frame_timer);
1129 1130
        /* set hchalted bit in status - UHCI11D 2.1.2 */
        s->status |= UHCI_STS_HCHALTED;
1131

M
malc 已提交
1132
        DPRINTF("uhci: halted\n");
B
bellard 已提交
1133 1134
        return;
    }
1135 1136

    /* Complete the previous frame */
P
pbrook 已提交
1137 1138
    if (s->pending_int_mask) {
        s->status2 |= s->pending_int_mask;
1139
        s->status  |= UHCI_STS_USBINT;
P
pbrook 已提交
1140 1141
        uhci_update_irq(s);
    }
1142
    s->pending_int_mask = 0;
1143

1144 1145 1146
    /* Start new frame */
    s->frnum = (s->frnum + 1) & 0x7ff;

M
malc 已提交
1147
    DPRINTF("uhci: new frame #%u\n" , s->frnum);
1148 1149 1150 1151 1152 1153

    uhci_async_validate_begin(s);

    uhci_process_frame(s);

    uhci_async_validate_end(s);
1154

1155
    qemu_mod_timer(s->frame_timer, s->expire_time);
B
bellard 已提交
1156 1157
}

A
Avi Kivity 已提交
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
static const MemoryRegionPortio uhci_portio[] = {
    { 0, 32, 2, .write = uhci_ioport_writew, },
    { 0, 32, 2, .read = uhci_ioport_readw, },
    { 0, 32, 4, .write = uhci_ioport_writel, },
    { 0, 32, 4, .read = uhci_ioport_readl, },
    { 0, 32, 1, .write = uhci_ioport_writeb, },
    { 0, 32, 1, .read = uhci_ioport_readb, },
    PORTIO_END_OF_LIST()
};

static const MemoryRegionOps uhci_ioport_ops = {
    .old_portio = uhci_portio,
};
B
bellard 已提交
1171

1172 1173
static USBPortOps uhci_port_ops = {
    .attach = uhci_attach,
1174
    .detach = uhci_detach,
1175
    .child_detach = uhci_child_detach,
1176
    .wakeup = uhci_wakeup,
1177
    .complete = uhci_async_complete,
1178 1179
};

1180 1181 1182
static USBBusOps uhci_bus_ops = {
};

1183
static int usb_uhci_common_initfn(PCIDevice *dev)
B
bellard 已提交
1184
{
1185
    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
G
Gerd Hoffmann 已提交
1186
    uint8_t *pci_conf = s->dev.config;
B
bellard 已提交
1187 1188
    int i;

1189 1190
    pci_conf[PCI_CLASS_PROG] = 0x00;
    /* TODO: reset value should be 0. */
1191
    pci_conf[PCI_INTERRUPT_PIN] = 4; /* interrupt pin D */
1192
    pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
1193

1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
    if (s->masterbus) {
        USBPort *ports[NB_PORTS];
        for(i = 0; i < NB_PORTS; i++) {
            ports[i] = &s->ports[i].port;
        }
        if (usb_register_companion(s->masterbus, ports, NB_PORTS,
                s->firstport, s, &uhci_port_ops,
                USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) {
            return -1;
        }
    } else {
        usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev);
        for (i = 0; i < NB_PORTS; i++) {
            usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
                              USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
        }
B
bellard 已提交
1210
    }
1211
    s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
1212
    s->num_ports_vmstate = NB_PORTS;
G
Gerd Hoffmann 已提交
1213
    QTAILQ_INIT(&s->queues);
B
bellard 已提交
1214

1215
    qemu_register_reset(uhci_reset, s);
B
bellard 已提交
1216

A
Avi Kivity 已提交
1217
    memory_region_init_io(&s->io_bar, &uhci_ioport_ops, s, "uhci", 0x20);
1218 1219
    /* Use region 4 for consistency with real hardware.  BSD guests seem
       to rely on this.  */
1220
    pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
1221

G
Gerd Hoffmann 已提交
1222
    return 0;
B
bellard 已提交
1223
}
T
ths 已提交
1224

1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
{
    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
    uint8_t *pci_conf = s->dev.config;

    /* USB misc control 1/2 */
    pci_set_long(pci_conf + 0x40,0x00001000);
    /* PM capability */
    pci_set_long(pci_conf + 0x80,0x00020001);
    /* USB legacy support  */
    pci_set_long(pci_conf + 0xc0,0x00002000);

1237
    return usb_uhci_common_initfn(dev);
1238 1239
}

A
Avi Kivity 已提交
1240 1241 1242 1243 1244 1245 1246 1247
static int usb_uhci_exit(PCIDevice *dev)
{
    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);

    memory_region_destroy(&s->io_bar);
    return 0;
}

G
Gerd Hoffmann 已提交
1248 1249 1250 1251 1252 1253
static Property uhci_properties[] = {
    DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
    DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
    DEFINE_PROP_END_OF_LIST(),
};

1254 1255
static void piix3_uhci_class_init(ObjectClass *klass, void *data)
{
1256
    DeviceClass *dc = DEVICE_CLASS(klass);
1257 1258 1259 1260 1261 1262 1263 1264
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

    k->init = usb_uhci_common_initfn;
    k->exit = usb_uhci_exit;
    k->vendor_id = PCI_VENDOR_ID_INTEL;
    k->device_id = PCI_DEVICE_ID_INTEL_82371SB_2;
    k->revision = 0x01;
    k->class_id = PCI_CLASS_SERIAL_USB;
1265 1266
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1267 1268
}

1269 1270 1271 1272 1273
static TypeInfo piix3_uhci_info = {
    .name          = "piix3-usb-uhci",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = piix3_uhci_class_init,
1274 1275
};

1276 1277
static void piix4_uhci_class_init(ObjectClass *klass, void *data)
{
1278
    DeviceClass *dc = DEVICE_CLASS(klass);
1279 1280 1281 1282 1283 1284 1285 1286
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

    k->init = usb_uhci_common_initfn;
    k->exit = usb_uhci_exit;
    k->vendor_id = PCI_VENDOR_ID_INTEL;
    k->device_id = PCI_DEVICE_ID_INTEL_82371AB_2;
    k->revision = 0x01;
    k->class_id = PCI_CLASS_SERIAL_USB;
1287 1288
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1289 1290
}

1291 1292 1293 1294 1295
static TypeInfo piix4_uhci_info = {
    .name          = "piix4-usb-uhci",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = piix4_uhci_class_init,
1296 1297
};

1298 1299
static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data)
{
1300
    DeviceClass *dc = DEVICE_CLASS(klass);
1301 1302 1303 1304 1305 1306 1307 1308
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

    k->init = usb_uhci_vt82c686b_initfn;
    k->exit = usb_uhci_exit;
    k->vendor_id = PCI_VENDOR_ID_VIA;
    k->device_id = PCI_DEVICE_ID_VIA_UHCI;
    k->revision = 0x01;
    k->class_id = PCI_CLASS_SERIAL_USB;
1309 1310
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1311 1312
}

1313 1314 1315 1316 1317
static TypeInfo vt82c686b_uhci_info = {
    .name          = "vt82c686b-usb-uhci",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = vt82c686b_uhci_class_init,
1318 1319
};

1320 1321
static void ich9_uhci1_class_init(ObjectClass *klass, void *data)
{
1322
    DeviceClass *dc = DEVICE_CLASS(klass);
1323 1324 1325 1326 1327 1328 1329
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

    k->init = usb_uhci_common_initfn;
    k->vendor_id = PCI_VENDOR_ID_INTEL;
    k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1;
    k->revision = 0x03;
    k->class_id = PCI_CLASS_SERIAL_USB;
1330 1331
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1332 1333
}

1334 1335 1336 1337 1338
static TypeInfo ich9_uhci1_info = {
    .name          = "ich9-usb-uhci1",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = ich9_uhci1_class_init,
1339 1340
};

1341 1342
static void ich9_uhci2_class_init(ObjectClass *klass, void *data)
{
1343
    DeviceClass *dc = DEVICE_CLASS(klass);
1344 1345 1346 1347 1348 1349 1350
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

    k->init = usb_uhci_common_initfn;
    k->vendor_id = PCI_VENDOR_ID_INTEL;
    k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2;
    k->revision = 0x03;
    k->class_id = PCI_CLASS_SERIAL_USB;
1351 1352
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1353 1354
}

1355 1356 1357 1358 1359
static TypeInfo ich9_uhci2_info = {
    .name          = "ich9-usb-uhci2",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = ich9_uhci2_class_init,
1360 1361
};

1362 1363
static void ich9_uhci3_class_init(ObjectClass *klass, void *data)
{
1364
    DeviceClass *dc = DEVICE_CLASS(klass);
1365 1366 1367 1368 1369 1370 1371
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

    k->init = usb_uhci_common_initfn;
    k->vendor_id = PCI_VENDOR_ID_INTEL;
    k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3;
    k->revision = 0x03;
    k->class_id = PCI_CLASS_SERIAL_USB;
1372 1373
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1374 1375
}

1376 1377 1378 1379 1380
static TypeInfo ich9_uhci3_info = {
    .name          = "ich9-usb-uhci3",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = ich9_uhci3_class_init,
G
Gerd Hoffmann 已提交
1381
};
T
ths 已提交
1382

A
Andreas Färber 已提交
1383
static void uhci_register_types(void)
G
Gerd Hoffmann 已提交
1384
{
1385 1386 1387 1388 1389 1390
    type_register_static(&piix3_uhci_info);
    type_register_static(&piix4_uhci_info);
    type_register_static(&vt82c686b_uhci_info);
    type_register_static(&ich9_uhci1_info);
    type_register_static(&ich9_uhci2_info);
    type_register_static(&ich9_uhci3_info);
G
Gerd Hoffmann 已提交
1391
}
A
Andreas Färber 已提交
1392 1393

type_init(uhci_register_types)