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);
        }
303 304 305
    }
}

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

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

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

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

B
bellard 已提交
330 331 332 333 334 335 336 337 338 339 340 341 342
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 已提交
343
    qemu_set_irq(s->dev.irq[3], level);
B
bellard 已提交
344 345
}

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

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

B
bellard 已提交
355 356 357 358 359 360 361 362 363 364
    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;
365

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

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

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

381
    uhci_async_cancel_all(s);
382 383
}

J
Juan Quintela 已提交
384 385 386 387 388 389 390 391 392 393 394 395 396
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",
397
    .version_id = 2,
J
Juan Quintela 已提交
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
    .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),
414
        VMSTATE_INT64_V(expire_time, UHCIState, 2),
J
Juan Quintela 已提交
415 416 417
        VMSTATE_END_OF_LIST()
    }
};
418

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

B
bellard 已提交
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
    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 已提交
440
        break;
B
bellard 已提交
441 442 443 444 445 446 447 448 449 450
    default:
        val = 0xff;
        break;
    }
    return val;
}

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

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

B
bellard 已提交
455 456 457 458
    switch(addr) {
    case 0x00:
        if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
            /* start frame processing */
459 460
            s->expire_time = qemu_get_clock_ns(vm_clock) +
                (get_ticks_per_sec() / FRAME_TIMER_FREQ);
461
            qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
462
            s->status &= ~UHCI_STS_HCHALTED;
B
bellard 已提交
463
        } else if (!(val & UHCI_CMD_RS)) {
464
            s->status |= UHCI_STS_HCHALTED;
B
bellard 已提交
465 466 467 468 469 470 471 472
        }
        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 已提交
473
                usb_device_reset(port->port.dev);
B
bellard 已提交
474 475 476 477
            }
            uhci_reset(s);
            return;
        }
B
bellard 已提交
478
        if (val & UHCI_CMD_HCRESET) {
B
bellard 已提交
479 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
            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 已提交
510
            dev = port->port.dev;
511
            if (dev && dev->attached) {
B
bellard 已提交
512
                /* port reset */
513
                if ( (val & UHCI_PORT_RESET) &&
B
bellard 已提交
514
                     !(port->ctrl & UHCI_PORT_RESET) ) {
G
Gerd Hoffmann 已提交
515
                    usb_device_reset(dev);
B
bellard 已提交
516 517
                }
            }
518 519
            port->ctrl &= UHCI_PORT_READ_ONLY;
            port->ctrl |= (val & ~UHCI_PORT_READ_ONLY);
B
bellard 已提交
520
            /* some bits are reset when a '1' is written to them */
521
            port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR);
B
bellard 已提交
522 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
        }
        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;
551
            if (n >= NB_PORTS)
B
bellard 已提交
552 553 554 555 556 557 558 559 560 561
                goto read_default;
            port = &s->ports[n];
            val = port->ctrl;
        }
        break;
    default:
    read_default:
        val = 0xff7f; /* disabled port */
        break;
    }
562

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

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

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

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

B
bellard 已提交
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
    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;
}

599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
/* 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);
    }
}

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

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

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

629 630
    uhci_resume(s);
}
631

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

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

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

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

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

    uhci_async_cancel_device(s, child);
}

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

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

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

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

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

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

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

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

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

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

G
Gerd Hoffmann 已提交
712
    len = async->packet.result;
713 714 715 716 717 718
    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 已提交
719 720
    if (td->ctrl & TD_CTRL_IOC)
        *int_mask |= 0x01;
721 722 723 724 725

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

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

    /* success */
    return 0;

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

    case USB_RET_BABBLE:
        td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
        td->ctrl &= ~TD_CTRL_ACTIVE;
754
        s->status |= UHCI_STS_USBERR;
755 756 757
        if (td->ctrl & TD_CTRL_IOC) {
            *int_mask |= 0x01;
        }
758
        uhci_update_irq(s);
759 760 761 762 763 764 765 766 767
        /* 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 已提交
768
    case USB_RET_IOERROR:
769 770 771 772 773 774 775 776 777 778 779 780
    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 已提交
781
            td->ctrl &= ~TD_CTRL_ACTIVE;
782
            s->status |= UHCI_STS_USBERR;
P
Paul Brook 已提交
783 784
            if (td->ctrl & TD_CTRL_IOC)
                *int_mask |= 0x01;
785
            uhci_update_irq(s);
B
bellard 已提交
786 787
        }
    }
788 789 790
    td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
        (err << TD_CTRL_ERROR_SHIFT);
    return 1;
B
bellard 已提交
791 792
}

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

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

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

        if (!async->done)
            return 1;

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

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

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

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

831 832 833
    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 已提交
834 835
    qemu_sglist_add(&async->sgl, td->buffer, max_len);
    usb_packet_map(&async->packet, &async->sgl);
836 837 838 839

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

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

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

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

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

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

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

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

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

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

893 894
        /* update the status bits of the TD */
        val = cpu_to_le32(td.ctrl);
895
        pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val));
G
Gerd Hoffmann 已提交
896
        uhci_async_free(async);
897 898 899 900
    } else {
        async->done = 1;
        uhci_process_frame(s);
    }
901 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
}

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;
}

945 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
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;
    }
}

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

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

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

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

988 989 990 991 992 993 994 995 996 997 998 999
    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
1000 1001 1002 1003 1004 1005 1006
                 * 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.
1007
                 */
M
malc 已提交
1008
                DPRINTF("uhci: detected loop. qh 0x%x\n", link);
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
                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);
                }
1020 1021
            }

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

M
malc 已提交
1026
            DPRINTF("uhci: QH 0x%x load. link 0x%x elink 0x%x\n",
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
                    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 */
1042
        pci_dma_read(&s->dev, link & ~0xf, &td, sizeof(td));
1043 1044 1045 1046 1047
        le32_to_cpus(&td.link);
        le32_to_cpus(&td.ctrl);
        le32_to_cpus(&td.token);
        le32_to_cpus(&td.buffer);

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

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

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

1063 1064 1065 1066
        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);
1067 1068 1069
            link = curr_qh ? qh.link : td.link;
            continue;

1070 1071 1072 1073
        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);
1074 1075 1076
            if (is_valid(td.link)) {
                uhci_fill_queue(s, &td);
            }
1077 1078
            link = curr_qh ? qh.link : td.link;
            continue;
1079

1080 1081 1082 1083
        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);
1084

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

1089 1090 1091 1092 1093
            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));
1094

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

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

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

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

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

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

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

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

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

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

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

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

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

    uhci_async_validate_begin(s);

    uhci_process_frame(s);

    uhci_async_validate_end(s);
1153

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

A
Avi Kivity 已提交
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
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 已提交
1170

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

1179 1180 1181
static USBBusOps uhci_bus_ops = {
};

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

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

1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
    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 已提交
1209
    }
1210
    s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
1211
    s->num_ports_vmstate = NB_PORTS;
G
Gerd Hoffmann 已提交
1212
    QTAILQ_INIT(&s->queues);
B
bellard 已提交
1213

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

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

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

1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
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);

1236
    return usb_uhci_common_initfn(dev);
1237 1238
}

A
Avi Kivity 已提交
1239 1240 1241 1242 1243 1244 1245 1246
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 已提交
1247 1248 1249 1250 1251 1252
static Property uhci_properties[] = {
    DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
    DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
    DEFINE_PROP_END_OF_LIST(),
};

1253 1254
static void piix3_uhci_class_init(ObjectClass *klass, void *data)
{
1255
    DeviceClass *dc = DEVICE_CLASS(klass);
1256 1257 1258 1259 1260 1261 1262 1263
    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;
1264 1265
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1266 1267
}

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

1275 1276
static void piix4_uhci_class_init(ObjectClass *klass, void *data)
{
1277
    DeviceClass *dc = DEVICE_CLASS(klass);
1278 1279 1280 1281 1282 1283 1284 1285
    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;
1286 1287
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1288 1289
}

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

1297 1298
static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data)
{
1299
    DeviceClass *dc = DEVICE_CLASS(klass);
1300 1301 1302 1303 1304 1305 1306 1307
    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;
1308 1309
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1310 1311
}

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

1319 1320
static void ich9_uhci1_class_init(ObjectClass *klass, void *data)
{
1321
    DeviceClass *dc = DEVICE_CLASS(klass);
1322 1323 1324 1325 1326 1327 1328
    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;
1329 1330
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1331 1332
}

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

1340 1341
static void ich9_uhci2_class_init(ObjectClass *klass, void *data)
{
1342
    DeviceClass *dc = DEVICE_CLASS(klass);
1343 1344 1345 1346 1347 1348 1349
    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;
1350 1351
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1352 1353
}

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

1361 1362
static void ich9_uhci3_class_init(ObjectClass *klass, void *data)
{
1363
    DeviceClass *dc = DEVICE_CLASS(klass);
1364 1365 1366 1367 1368 1369 1370
    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;
1371 1372
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1373 1374
}

1375 1376 1377 1378 1379
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 已提交
1380
};
T
ths 已提交
1381

A
Andreas Färber 已提交
1382
static void uhci_register_types(void)
G
Gerd Hoffmann 已提交
1383
{
1384 1385 1386 1387 1388 1389
    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 已提交
1390
}
A
Andreas Färber 已提交
1391 1392

type_init(uhci_register_types)