hcd-uhci.c 35.9 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"
G
Gerd Hoffmann 已提交
34
#include "trace.h"
B
bellard 已提交
35 36

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

39 40
#define UHCI_CMD_FGR      (1 << 4)
#define UHCI_CMD_EGSM     (1 << 3)
B
bellard 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
#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)

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

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

B
bellard 已提交
74 75
#define FRAME_TIMER_FREQ 1000

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

#define NB_PORTS 2

80
enum {
81 82 83
    TD_RESULT_STOP_FRAME = 10,
    TD_RESULT_COMPLETE,
    TD_RESULT_NEXT_QH,
84 85
    TD_RESULT_ASYNC_START,
    TD_RESULT_ASYNC_CONT,
86 87
};

88
typedef struct UHCIState UHCIState;
G
Gerd Hoffmann 已提交
89 90
typedef struct UHCIAsync UHCIAsync;
typedef struct UHCIQueue UHCIQueue;
91

92 93 94 95 96
/* 
 * Pending async transaction.
 * 'packet' must be the first field because completion
 * handler does "(UHCIAsync *) pkt" cast.
 */
G
Gerd Hoffmann 已提交
97 98

struct UHCIAsync {
99
    USBPacket packet;
G
Gerd Hoffmann 已提交
100
    QEMUSGList sgl;
G
Gerd Hoffmann 已提交
101
    UHCIQueue *queue;
G
Gerd Hoffmann 已提交
102
    QTAILQ_ENTRY(UHCIAsync) next;
103
    uint32_t  td;
104
    uint8_t   isoc;
105
    uint8_t   done;
G
Gerd Hoffmann 已提交
106 107 108 109 110 111 112 113 114
};

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

B
bellard 已提交
116 117 118 119 120
typedef struct UHCIPort {
    USBPort port;
    uint16_t ctrl;
} UHCIPort;

121
struct UHCIState {
B
bellard 已提交
122
    PCIDevice dev;
A
Avi Kivity 已提交
123
    MemoryRegion io_bar;
124
    USBBus bus; /* Note unused when we're a companion controller */
B
bellard 已提交
125 126 127 128 129 130 131
    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 */
132
    int64_t expire_time;
B
bellard 已提交
133 134
    QEMUTimer *frame_timer;
    UHCIPort ports[NB_PORTS];
P
pbrook 已提交
135 136 137

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

    /* Active packets */
G
Gerd Hoffmann 已提交
140
    QTAILQ_HEAD(, UHCIQueue) queues;
141
    uint8_t num_ports_vmstate;
142 143 144 145

    /* Properties */
    char *masterbus;
    uint32_t firstport;
146
};
B
bellard 已提交
147 148 149 150 151 152 153 154 155 156 157 158 159

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 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
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);
G
Gerd Hoffmann 已提交
182
    trace_usb_uhci_queue_add(queue->token);
G
Gerd Hoffmann 已提交
183 184 185 186 187 188 189
    return queue;
}

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

G
Gerd Hoffmann 已提交
190
    trace_usb_uhci_queue_del(queue->token);
G
Gerd Hoffmann 已提交
191 192 193 194
    QTAILQ_REMOVE(&s->queues, queue, next);
    g_free(queue);
}

195
static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t addr)
196
{
197
    UHCIAsync *async = g_new0(UHCIAsync, 1);
198

G
Gerd Hoffmann 已提交
199
    async->queue = queue;
200
    async->td = addr;
G
Gerd Hoffmann 已提交
201
    usb_packet_init(&async->packet);
G
Gerd Hoffmann 已提交
202
    pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1);
G
Gerd Hoffmann 已提交
203
    trace_usb_uhci_packet_add(async->queue->token, async->td);
204 205 206 207

    return async;
}

G
Gerd Hoffmann 已提交
208
static void uhci_async_free(UHCIAsync *async)
209
{
G
Gerd Hoffmann 已提交
210
    trace_usb_uhci_packet_del(async->queue->token, async->td);
G
Gerd Hoffmann 已提交
211
    usb_packet_cleanup(&async->packet);
G
Gerd Hoffmann 已提交
212
    qemu_sglist_destroy(&async->sgl);
213
    g_free(async);
214 215
}

G
Gerd Hoffmann 已提交
216
static void uhci_async_link(UHCIAsync *async)
217
{
G
Gerd Hoffmann 已提交
218 219
    UHCIQueue *queue = async->queue;
    QTAILQ_INSERT_TAIL(&queue->asyncs, async, next);
G
Gerd Hoffmann 已提交
220
    trace_usb_uhci_packet_link_async(async->queue->token, async->td);
221 222
}

G
Gerd Hoffmann 已提交
223
static void uhci_async_unlink(UHCIAsync *async)
224
{
G
Gerd Hoffmann 已提交
225 226
    UHCIQueue *queue = async->queue;
    QTAILQ_REMOVE(&queue->asyncs, async, next);
G
Gerd Hoffmann 已提交
227
    trace_usb_uhci_packet_unlink_async(async->queue->token, async->td);
228 229
}

G
Gerd Hoffmann 已提交
230
static void uhci_async_cancel(UHCIAsync *async)
231
{
G
Gerd Hoffmann 已提交
232
    trace_usb_uhci_packet_cancel(async->queue->token, async->td, async->done);
233 234
    if (!async->done)
        usb_cancel_packet(&async->packet);
G
Gerd Hoffmann 已提交
235
    uhci_async_free(async);
236 237 238 239 240 241
}

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

G
Gerd Hoffmann 已提交
246 247
    QTAILQ_FOREACH(queue, &s->queues, next) {
        queue->valid--;
248 249 250 251 252 253 254 255
    }
}

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

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

272 273
static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
{
G
Gerd Hoffmann 已提交
274
    UHCIQueue *queue;
275 276
    UHCIAsync *curr, *n;

G
Gerd Hoffmann 已提交
277 278 279 280 281 282 283 284
    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);
285 286 287 288
        }
    }
}

289 290
static void uhci_async_cancel_all(UHCIState *s)
{
G
Gerd Hoffmann 已提交
291
    UHCIQueue *queue;
G
Gerd Hoffmann 已提交
292
    UHCIAsync *curr, *n;
293

G
Gerd Hoffmann 已提交
294 295 296 297 298
    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 已提交
299
        uhci_queue_free(queue);
300 301 302
    }
}

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

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

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

G
Gerd Hoffmann 已提交
324
    return NULL;
325 326
}

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

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

G
Gerd Hoffmann 已提交
350
    trace_usb_uhci_reset();
351

B
bellard 已提交
352 353 354 355 356 357 358 359 360 361
    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;
362

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

    uhci_async_cancel_all(s);
B
bellard 已提交
372 373
}

J
Juan Quintela 已提交
374
static void uhci_pre_save(void *opaque)
375 376 377
{
    UHCIState *s = opaque;

378
    uhci_async_cancel_all(s);
379 380
}

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

B
bellard 已提交
416 417 418
static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
{
    UHCIState *s = opaque;
419

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

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

B
bellard 已提交
449
    addr &= 0x1f;
G
Gerd Hoffmann 已提交
450
    trace_usb_uhci_mmio_writew(addr, val);
451

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

G
Gerd Hoffmann 已提交
561
    trace_usb_uhci_mmio_readw(addr, val);
562

B
bellard 已提交
563 564 565 566 567 568 569 570
    return val;
}

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

    addr &= 0x1f;
G
Gerd Hoffmann 已提交
571
    trace_usb_uhci_mmio_writel(addr, val);
572

B
bellard 已提交
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
    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;
    }
G
Gerd Hoffmann 已提交
594
    trace_usb_uhci_mmio_readl(addr, val);
B
bellard 已提交
595 596 597
    return val;
}

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

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

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

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

628 629
    uhci_resume(s);
}
630

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

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

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

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

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

    uhci_async_cancel_device(s, child);
}

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

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

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

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

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

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

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

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

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

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

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

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

727
        if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
B
bellard 已提交
728 729
            *int_mask |= 0x02;
            /* short packet: do not update QH */
G
Gerd Hoffmann 已提交
730 731
            trace_usb_uhci_packet_complete_shortxfer(async->queue->token,
                                                    async->td);
732
            return TD_RESULT_NEXT_QH;
B
bellard 已提交
733
        }
734 735 736
    }

    /* success */
G
Gerd Hoffmann 已提交
737
    trace_usb_uhci_packet_complete_success(async->queue->token, async->td);
738
    return TD_RESULT_COMPLETE;
739 740 741 742 743 744

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);
G
Gerd Hoffmann 已提交
750
        trace_usb_uhci_packet_complete_stall(async->queue->token, async->td);
751
        return TD_RESULT_NEXT_QH;
752 753 754 755

    case USB_RET_BABBLE:
        td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
        td->ctrl &= ~TD_CTRL_ACTIVE;
756
        s->status |= UHCI_STS_USBERR;
757 758 759
        if (td->ctrl & TD_CTRL_IOC) {
            *int_mask |= 0x01;
        }
760
        uhci_update_irq(s);
761
        /* frame interrupted */
G
Gerd Hoffmann 已提交
762
        trace_usb_uhci_packet_complete_babble(async->queue->token, async->td);
763
        return TD_RESULT_STOP_FRAME;
764 765 766 767 768

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

H
Hans de Goede 已提交
771
    case USB_RET_IOERROR:
772 773 774 775 776 777 778 779 780 781 782 783
    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 已提交
784
            td->ctrl &= ~TD_CTRL_ACTIVE;
785
            s->status |= UHCI_STS_USBERR;
P
Paul Brook 已提交
786 787
            if (td->ctrl & TD_CTRL_IOC)
                *int_mask |= 0x01;
788
            uhci_update_irq(s);
G
Gerd Hoffmann 已提交
789 790
            trace_usb_uhci_packet_complete_error(async->queue->token,
                                                 async->td);
B
bellard 已提交
791 792
        }
    }
793 794
    td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
        (err << TD_CTRL_ERROR_SHIFT);
795
    return TD_RESULT_NEXT_QH;
B
bellard 已提交
796 797
}

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

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

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

        if (!async->done)
816
            return TD_RESULT_ASYNC_CONT;
817

G
Gerd Hoffmann 已提交
818
        uhci_async_unlink(async);
819 820 821 822
        goto done;
    }

    /* Allocate new packet */
823
    async = uhci_async_alloc(uhci_queue_get(s, td), addr);
824
    if (!async)
825
        return TD_RESULT_NEXT_QH;
826

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

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

836 837 838
    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 已提交
839 840
    qemu_sglist_add(&async->sgl, td->buffer, max_len);
    usb_packet_map(&async->packet, &async->sgl);
841 842 843 844

    switch(pid) {
    case USB_TOKEN_OUT:
    case USB_TOKEN_SETUP:
845
        len = usb_handle_packet(dev, &async->packet);
846 847
        if (len >= 0)
            len = max_len;
848 849 850
        break;

    case USB_TOKEN_IN:
851
        len = usb_handle_packet(dev, &async->packet);
852 853 854 855
        break;

    default:
        /* invalid pid : frame interrupted */
G
Gerd Hoffmann 已提交
856
        uhci_async_free(async);
857 858
        s->status |= UHCI_STS_HCPERR;
        uhci_update_irq(s);
859
        return TD_RESULT_STOP_FRAME;
860 861
    }
 
862
    if (len == USB_RET_ASYNC) {
G
Gerd Hoffmann 已提交
863
        uhci_async_link(async);
864
        return TD_RESULT_ASYNC_START;
865 866
    }

G
Gerd Hoffmann 已提交
867
    async->packet.result = len;
868 869

done:
870
    len = uhci_complete_td(s, td, async, int_mask);
G
Gerd Hoffmann 已提交
871
    usb_packet_unmap(&async->packet);
G
Gerd Hoffmann 已提交
872
    uhci_async_free(async);
873
    return len;
874 875
}

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

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

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

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

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

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

948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
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;
        }
G
Gerd Hoffmann 已提交
968
        trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
969
        ret = uhci_handle_td(s, plink, &ptd, &int_mask);
970
        assert(ret == TD_RESULT_ASYNC_START);
971 972 973 974 975
        assert(int_mask == 0);
        plink = ptd.link;
    }
}

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

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

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

990 991 992 993 994 995 996 997
    int_mask = 0;
    curr_qh  = 0;

    qhdb_reset(&qhdb);

    for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
        if (is_qh(link)) {
            /* QH */
G
Gerd Hoffmann 已提交
998
            trace_usb_uhci_qh_load(link & ~0xf);
999 1000 1001 1002

            if (qhdb_insert(&qhdb, link)) {
                /*
                 * We're going in circles. Which is not a bug because
1003 1004 1005 1006 1007 1008 1009
                 * 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.
1010
                 */
1011
                if (td_count == 0) {
G
Gerd Hoffmann 已提交
1012
                    trace_usb_uhci_frame_loop_stop_idle();
1013 1014
                    break;
                } else if (bytes_count >= 1280) {
G
Gerd Hoffmann 已提交
1015
                    trace_usb_uhci_frame_loop_stop_bandwidth();
1016 1017
                    break;
                } else {
G
Gerd Hoffmann 已提交
1018
                    trace_usb_uhci_frame_loop_continue();
1019 1020 1021 1022
                    td_count = 0;
                    qhdb_reset(&qhdb);
                    qhdb_insert(&qhdb, link);
                }
1023 1024
            }

1025
            pci_dma_read(&s->dev, link & ~0xf, &qh, sizeof(qh));
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
            le32_to_cpus(&qh.link);
            le32_to_cpus(&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
        le32_to_cpus(&td.link);
        le32_to_cpus(&td.ctrl);
        le32_to_cpus(&td.token);
        le32_to_cpus(&td.buffer);
G
Gerd Hoffmann 已提交
1047
        trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
1048 1049 1050

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

1057
        switch (ret) {
1058
        case TD_RESULT_STOP_FRAME: /* interrupted frame */
1059
            goto out;
1060

1061
        case TD_RESULT_NEXT_QH:
1062
        case TD_RESULT_ASYNC_CONT:
G
Gerd Hoffmann 已提交
1063
            trace_usb_uhci_td_nextqh(curr_qh & ~0xf, link & ~0xf);
1064 1065 1066
            link = curr_qh ? qh.link : td.link;
            continue;

1067
        case TD_RESULT_ASYNC_START:
G
Gerd Hoffmann 已提交
1068
            trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
1069 1070 1071
            if (is_valid(td.link)) {
                uhci_fill_queue(s, &td);
            }
1072 1073
            link = curr_qh ? qh.link : td.link;
            continue;
1074

1075
        case TD_RESULT_COMPLETE:
G
Gerd Hoffmann 已提交
1076
            trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf);
1077 1078 1079
            link = td.link;
            td_count++;
            bytes_count += (td.ctrl & 0x7ff) + 1;
1080

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

1087 1088 1089 1090 1091
                if (!depth_first(link)) {
                    /* done with this QH */
                    curr_qh = 0;
                    link    = qh.link;
                }
1092
            }
1093 1094 1095 1096
            break;

        default:
            assert(!"unknown return code");
P
pbrook 已提交
1097
        }
1098 1099

        /* go to the next entry */
P
pbrook 已提交
1100
    }
1101

1102
out:
1103
    s->pending_int_mask |= int_mask;
P
pbrook 已提交
1104 1105
}

B
bellard 已提交
1106 1107 1108
static void uhci_frame_timer(void *opaque)
{
    UHCIState *s = opaque;
1109 1110 1111

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

    if (!(s->cmd & UHCI_CMD_RS)) {
1114
        /* Full stop */
G
Gerd Hoffmann 已提交
1115
        trace_usb_uhci_schedule_stop();
B
bellard 已提交
1116
        qemu_del_timer(s->frame_timer);
G
Gerd Hoffmann 已提交
1117
        uhci_async_cancel_all(s);
1118 1119
        /* set hchalted bit in status - UHCI11D 2.1.2 */
        s->status |= UHCI_STS_HCHALTED;
B
bellard 已提交
1120 1121
        return;
    }
1122 1123

    /* Complete the previous frame */
P
pbrook 已提交
1124 1125
    if (s->pending_int_mask) {
        s->status2 |= s->pending_int_mask;
1126
        s->status  |= UHCI_STS_USBINT;
P
pbrook 已提交
1127 1128
        uhci_update_irq(s);
    }
1129
    s->pending_int_mask = 0;
1130

1131 1132 1133
    /* Start new frame */
    s->frnum = (s->frnum + 1) & 0x7ff;

G
Gerd Hoffmann 已提交
1134
    trace_usb_uhci_frame_start(s->frnum);
1135 1136 1137 1138 1139 1140

    uhci_async_validate_begin(s);

    uhci_process_frame(s);

    uhci_async_validate_end(s);
1141

1142
    qemu_mod_timer(s->frame_timer, s->expire_time);
B
bellard 已提交
1143 1144
}

A
Avi Kivity 已提交
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
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 已提交
1158

1159 1160
static USBPortOps uhci_port_ops = {
    .attach = uhci_attach,
1161
    .detach = uhci_detach,
1162
    .child_detach = uhci_child_detach,
1163
    .wakeup = uhci_wakeup,
1164
    .complete = uhci_async_complete,
1165 1166
};

1167 1168 1169
static USBBusOps uhci_bus_ops = {
};

1170
static int usb_uhci_common_initfn(PCIDevice *dev)
B
bellard 已提交
1171
{
1172
    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
G
Gerd Hoffmann 已提交
1173
    uint8_t *pci_conf = s->dev.config;
B
bellard 已提交
1174 1175
    int i;

1176 1177
    pci_conf[PCI_CLASS_PROG] = 0x00;
    /* TODO: reset value should be 0. */
1178
    pci_conf[PCI_INTERRUPT_PIN] = 4; /* interrupt pin D */
1179
    pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
1180

1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
    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 已提交
1197
    }
1198
    s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
1199
    s->num_ports_vmstate = NB_PORTS;
G
Gerd Hoffmann 已提交
1200
    QTAILQ_INIT(&s->queues);
B
bellard 已提交
1201

1202
    qemu_register_reset(uhci_reset, s);
B
bellard 已提交
1203

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

G
Gerd Hoffmann 已提交
1209
    return 0;
B
bellard 已提交
1210
}
T
ths 已提交
1211

1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
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);

1224
    return usb_uhci_common_initfn(dev);
1225 1226
}

A
Avi Kivity 已提交
1227 1228 1229 1230 1231 1232 1233 1234
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 已提交
1235 1236 1237 1238 1239 1240
static Property uhci_properties[] = {
    DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
    DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
    DEFINE_PROP_END_OF_LIST(),
};

1241 1242
static void piix3_uhci_class_init(ObjectClass *klass, void *data)
{
1243
    DeviceClass *dc = DEVICE_CLASS(klass);
1244 1245 1246 1247 1248 1249 1250 1251
    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;
1252 1253
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1254 1255
}

1256 1257 1258 1259 1260
static TypeInfo piix3_uhci_info = {
    .name          = "piix3-usb-uhci",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = piix3_uhci_class_init,
1261 1262
};

1263 1264
static void piix4_uhci_class_init(ObjectClass *klass, void *data)
{
1265
    DeviceClass *dc = DEVICE_CLASS(klass);
1266 1267 1268 1269 1270 1271 1272 1273
    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;
1274 1275
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1276 1277
}

1278 1279 1280 1281 1282
static TypeInfo piix4_uhci_info = {
    .name          = "piix4-usb-uhci",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = piix4_uhci_class_init,
1283 1284
};

1285 1286
static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data)
{
1287
    DeviceClass *dc = DEVICE_CLASS(klass);
1288 1289 1290 1291 1292 1293 1294 1295
    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;
1296 1297
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1298 1299
}

1300 1301 1302 1303 1304
static TypeInfo vt82c686b_uhci_info = {
    .name          = "vt82c686b-usb-uhci",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = vt82c686b_uhci_class_init,
1305 1306
};

1307 1308
static void ich9_uhci1_class_init(ObjectClass *klass, void *data)
{
1309
    DeviceClass *dc = DEVICE_CLASS(klass);
1310 1311 1312 1313 1314 1315 1316
    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;
1317 1318
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1319 1320
}

1321 1322 1323 1324 1325
static TypeInfo ich9_uhci1_info = {
    .name          = "ich9-usb-uhci1",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = ich9_uhci1_class_init,
1326 1327
};

1328 1329
static void ich9_uhci2_class_init(ObjectClass *klass, void *data)
{
1330
    DeviceClass *dc = DEVICE_CLASS(klass);
1331 1332 1333 1334 1335 1336 1337
    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;
1338 1339
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1340 1341
}

1342 1343 1344 1345 1346
static TypeInfo ich9_uhci2_info = {
    .name          = "ich9-usb-uhci2",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(UHCIState),
    .class_init    = ich9_uhci2_class_init,
1347 1348
};

1349 1350
static void ich9_uhci3_class_init(ObjectClass *klass, void *data)
{
1351
    DeviceClass *dc = DEVICE_CLASS(klass);
1352 1353 1354 1355 1356 1357 1358
    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;
1359 1360
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1361 1362
}

1363 1364 1365 1366 1367
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 已提交
1368
};
T
ths 已提交
1369

A
Andreas Färber 已提交
1370
static void uhci_register_types(void)
G
Gerd Hoffmann 已提交
1371
{
1372 1373 1374 1375 1376 1377
    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 已提交
1378
}
A
Andreas Färber 已提交
1379 1380

type_init(uhci_register_types)