hcd-uhci.c 37.3 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;
G
Gerd Hoffmann 已提交
91
typedef struct UHCIInfo UHCIInfo;
92
typedef struct UHCIPCIDeviceClass UHCIPCIDeviceClass;
G
Gerd Hoffmann 已提交
93 94 95 96 97 98

struct UHCIInfo {
    const char *name;
    uint16_t   vendor_id;
    uint16_t   device_id;
    uint8_t    revision;
99
    uint8_t    irq_pin;
G
Gerd Hoffmann 已提交
100 101 102
    int        (*initfn)(PCIDevice *dev);
    bool       unplug;
};
103

104 105 106 107 108
struct UHCIPCIDeviceClass {
    PCIDeviceClass parent_class;
    UHCIInfo       info;
};

109 110 111 112 113
/* 
 * Pending async transaction.
 * 'packet' must be the first field because completion
 * handler does "(UHCIAsync *) pkt" cast.
 */
G
Gerd Hoffmann 已提交
114 115

struct UHCIAsync {
116
    USBPacket packet;
G
Gerd Hoffmann 已提交
117
    QEMUSGList sgl;
G
Gerd Hoffmann 已提交
118
    UHCIQueue *queue;
G
Gerd Hoffmann 已提交
119
    QTAILQ_ENTRY(UHCIAsync) next;
120
    uint32_t  td_addr;
121
    uint8_t   done;
G
Gerd Hoffmann 已提交
122 123 124
};

struct UHCIQueue {
125
    uint32_t  qh_addr;
G
Gerd Hoffmann 已提交
126 127
    uint32_t  token;
    UHCIState *uhci;
H
Hans de Goede 已提交
128
    USBEndpoint *ep;
G
Gerd Hoffmann 已提交
129
    QTAILQ_ENTRY(UHCIQueue) next;
130
    QTAILQ_HEAD(asyncs_head, UHCIAsync) asyncs;
G
Gerd Hoffmann 已提交
131 132
    int8_t    valid;
};
133

B
bellard 已提交
134 135 136 137 138
typedef struct UHCIPort {
    USBPort port;
    uint16_t ctrl;
} UHCIPort;

139
struct UHCIState {
B
bellard 已提交
140
    PCIDevice dev;
A
Avi Kivity 已提交
141
    MemoryRegion io_bar;
142
    USBBus bus; /* Note unused when we're a companion controller */
B
bellard 已提交
143 144 145 146 147 148 149
    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 */
150
    int64_t expire_time;
B
bellard 已提交
151
    QEMUTimer *frame_timer;
G
Gerd Hoffmann 已提交
152
    QEMUBH *bh;
G
Gerd Hoffmann 已提交
153
    uint32_t frame_bytes;
G
Gerd Hoffmann 已提交
154
    uint32_t frame_bandwidth;
B
bellard 已提交
155
    UHCIPort ports[NB_PORTS];
P
pbrook 已提交
156 157 158

    /* Interrupts that should be raised at the end of the current frame.  */
    uint32_t pending_int_mask;
G
Gerd Hoffmann 已提交
159
    int irq_pin;
160 161

    /* Active packets */
G
Gerd Hoffmann 已提交
162
    QTAILQ_HEAD(, UHCIQueue) queues;
163
    uint8_t num_ports_vmstate;
164 165 166 167

    /* Properties */
    char *masterbus;
    uint32_t firstport;
168
};
B
bellard 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181

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;

182
static void uhci_async_cancel(UHCIAsync *async);
H
Hans de Goede 已提交
183
static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td);
184

G
Gerd Hoffmann 已提交
185 186
static inline int32_t uhci_queue_token(UHCI_TD *td)
{
187 188 189 190 191 192 193
    if ((td->token & (0xf << 15)) == 0) {
        /* ctrl ep, cover ep and dev, not pid! */
        return td->token & 0x7ff00;
    } else {
        /* covers ep, dev, pid -> identifies the endpoint */
        return td->token & 0x7ffff;
    }
G
Gerd Hoffmann 已提交
194 195
}

196 197
static UHCIQueue *uhci_queue_new(UHCIState *s, uint32_t qh_addr, UHCI_TD *td,
                                 USBEndpoint *ep)
G
Gerd Hoffmann 已提交
198 199 200 201 202
{
    UHCIQueue *queue;

    queue = g_new0(UHCIQueue, 1);
    queue->uhci = s;
203 204
    queue->qh_addr = qh_addr;
    queue->token = uhci_queue_token(td);
H
Hans de Goede 已提交
205
    queue->ep = ep;
G
Gerd Hoffmann 已提交
206 207
    QTAILQ_INIT(&queue->asyncs);
    QTAILQ_INSERT_HEAD(&s->queues, queue, next);
208 209 210
    /* valid needs to be large enough to handle 10 frame delay
     * for initial isochronous requests */
    queue->valid = 32;
G
Gerd Hoffmann 已提交
211
    trace_usb_uhci_queue_add(queue->token);
G
Gerd Hoffmann 已提交
212 213 214
    return queue;
}

215
static void uhci_queue_free(UHCIQueue *queue, const char *reason)
G
Gerd Hoffmann 已提交
216 217
{
    UHCIState *s = queue->uhci;
218 219 220 221 222 223
    UHCIAsync *async;

    while (!QTAILQ_EMPTY(&queue->asyncs)) {
        async = QTAILQ_FIRST(&queue->asyncs);
        uhci_async_cancel(async);
    }
G
Gerd Hoffmann 已提交
224

225
    trace_usb_uhci_queue_del(queue->token, reason);
G
Gerd Hoffmann 已提交
226 227 228 229
    QTAILQ_REMOVE(&s->queues, queue, next);
    g_free(queue);
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
static UHCIQueue *uhci_queue_find(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;
        }
    }
    return NULL;
}

static bool uhci_queue_verify(UHCIQueue *queue, uint32_t qh_addr, UHCI_TD *td,
                              uint32_t td_addr, bool queuing)
{
    UHCIAsync *first = QTAILQ_FIRST(&queue->asyncs);

    return queue->qh_addr == qh_addr &&
           queue->token == uhci_queue_token(td) &&
           (queuing || !(td->ctrl & TD_CTRL_ACTIVE) || first == NULL ||
            first->td_addr == td_addr);
}

254
static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t td_addr)
255
{
256
    UHCIAsync *async = g_new0(UHCIAsync, 1);
257

G
Gerd Hoffmann 已提交
258
    async->queue = queue;
259
    async->td_addr = td_addr;
G
Gerd Hoffmann 已提交
260
    usb_packet_init(&async->packet);
G
Gerd Hoffmann 已提交
261
    pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1);
262
    trace_usb_uhci_packet_add(async->queue->token, async->td_addr);
263 264 265 266

    return async;
}

G
Gerd Hoffmann 已提交
267
static void uhci_async_free(UHCIAsync *async)
268
{
269
    trace_usb_uhci_packet_del(async->queue->token, async->td_addr);
G
Gerd Hoffmann 已提交
270
    usb_packet_cleanup(&async->packet);
G
Gerd Hoffmann 已提交
271
    qemu_sglist_destroy(&async->sgl);
272
    g_free(async);
273 274
}

G
Gerd Hoffmann 已提交
275
static void uhci_async_link(UHCIAsync *async)
276
{
G
Gerd Hoffmann 已提交
277 278
    UHCIQueue *queue = async->queue;
    QTAILQ_INSERT_TAIL(&queue->asyncs, async, next);
279
    trace_usb_uhci_packet_link_async(async->queue->token, async->td_addr);
280 281
}

G
Gerd Hoffmann 已提交
282
static void uhci_async_unlink(UHCIAsync *async)
283
{
G
Gerd Hoffmann 已提交
284 285
    UHCIQueue *queue = async->queue;
    QTAILQ_REMOVE(&queue->asyncs, async, next);
286
    trace_usb_uhci_packet_unlink_async(async->queue->token, async->td_addr);
287 288
}

G
Gerd Hoffmann 已提交
289
static void uhci_async_cancel(UHCIAsync *async)
290
{
291
    uhci_async_unlink(async);
292 293
    trace_usb_uhci_packet_cancel(async->queue->token, async->td_addr,
                                 async->done);
294 295
    if (!async->done)
        usb_cancel_packet(&async->packet);
296
    usb_packet_unmap(&async->packet, &async->sgl);
G
Gerd Hoffmann 已提交
297
    uhci_async_free(async);
298 299 300 301 302 303
}

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

G
Gerd Hoffmann 已提交
308 309
    QTAILQ_FOREACH(queue, &s->queues, next) {
        queue->valid--;
310 311 312 313 314 315 316 317
    }
}

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

G
Gerd Hoffmann 已提交
320
    QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) {
321
        if (!queue->valid) {
322
            uhci_queue_free(queue, "validate-end");
G
Gerd Hoffmann 已提交
323
        }
324 325 326
    }
}

327 328
static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
{
329
    UHCIQueue *queue, *n;
330

331 332 333
    QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) {
        if (queue->ep->dev == dev) {
            uhci_queue_free(queue, "cancel-device");
334 335 336 337
        }
    }
}

338 339
static void uhci_async_cancel_all(UHCIState *s)
{
G
Gerd Hoffmann 已提交
340
    UHCIQueue *queue, *nq;
341

G
Gerd Hoffmann 已提交
342
    QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) {
343
        uhci_queue_free(queue, "cancel-all");
344 345 346
    }
}

H
Hans de Goede 已提交
347
static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t td_addr)
348
{
G
Gerd Hoffmann 已提交
349
    UHCIQueue *queue;
G
Gerd Hoffmann 已提交
350
    UHCIAsync *async;
351

G
Gerd Hoffmann 已提交
352
    QTAILQ_FOREACH(queue, &s->queues, next) {
H
Hans de Goede 已提交
353 354 355 356
        QTAILQ_FOREACH(async, &queue->asyncs, next) {
            if (async->td_addr == td_addr) {
                return async;
            }
G
Gerd Hoffmann 已提交
357 358 359
        }
    }
    return NULL;
360 361
}

B
bellard 已提交
362 363 364 365 366 367 368 369 370 371 372 373 374
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;
    }
G
Gerd Hoffmann 已提交
375
    qemu_set_irq(s->dev.irq[s->irq_pin], level);
B
bellard 已提交
376 377
}

G
Gleb Natapov 已提交
378
static void uhci_reset(void *opaque)
B
bellard 已提交
379
{
G
Gleb Natapov 已提交
380
    UHCIState *s = opaque;
B
bellard 已提交
381 382 383 384
    uint8_t *pci_conf;
    int i;
    UHCIPort *port;

G
Gerd Hoffmann 已提交
385
    trace_usb_uhci_reset();
386

B
bellard 已提交
387 388 389 390 391 392 393 394 395 396
    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;
397

B
bellard 已提交
398 399 400
    for(i = 0; i < NB_PORTS; i++) {
        port = &s->ports[i];
        port->ctrl = 0x0080;
401
        if (port->port.dev && port->port.dev->attached) {
G
Gerd Hoffmann 已提交
402
            usb_port_reset(&port->port);
403
        }
B
bellard 已提交
404
    }
405 406

    uhci_async_cancel_all(s);
G
Gerd Hoffmann 已提交
407
    qemu_bh_cancel(s->bh);
408
    uhci_update_irq(s);
B
bellard 已提交
409 410
}

J
Juan Quintela 已提交
411 412 413 414 415 416 417 418 419 420 421
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()
    }
};

422 423 424 425 426 427 428 429 430 431 432
static int uhci_post_load(void *opaque, int version_id)
{
    UHCIState *s = opaque;

    if (version_id < 2) {
        s->expire_time = qemu_get_clock_ns(vm_clock) +
            (get_ticks_per_sec() / FRAME_TIMER_FREQ);
    }
    return 0;
}

J
Juan Quintela 已提交
433 434
static const VMStateDescription vmstate_uhci = {
    .name = "uhci",
435
    .version_id = 2,
J
Juan Quintela 已提交
436 437
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
438
    .post_load = uhci_post_load,
J
Juan Quintela 已提交
439 440 441 442 443 444 445 446 447 448 449 450 451
    .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),
452
        VMSTATE_INT64_V(expire_time, UHCIState, 2),
J
Juan Quintela 已提交
453 454 455
        VMSTATE_END_OF_LIST()
    }
};
456

B
bellard 已提交
457 458 459
static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
{
    UHCIState *s = opaque;
460

B
bellard 已提交
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
    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 已提交
478
        break;
B
bellard 已提交
479 480 481 482 483 484 485 486 487 488
    default:
        val = 0xff;
        break;
    }
    return val;
}

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

B
bellard 已提交
490
    addr &= 0x1f;
G
Gerd Hoffmann 已提交
491
    trace_usb_uhci_mmio_writew(addr, val);
492

B
bellard 已提交
493 494 495 496
    switch(addr) {
    case 0x00:
        if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
            /* start frame processing */
G
Gerd Hoffmann 已提交
497
            trace_usb_uhci_schedule_start();
498 499
            s->expire_time = qemu_get_clock_ns(vm_clock) +
                (get_ticks_per_sec() / FRAME_TIMER_FREQ);
500
            qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
501
            s->status &= ~UHCI_STS_HCHALTED;
B
bellard 已提交
502
        } else if (!(val & UHCI_CMD_RS)) {
503
            s->status |= UHCI_STS_HCHALTED;
B
bellard 已提交
504 505 506 507 508 509 510 511
        }
        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 已提交
512
                usb_device_reset(port->port.dev);
B
bellard 已提交
513 514 515 516
            }
            uhci_reset(s);
            return;
        }
B
bellard 已提交
517
        if (val & UHCI_CMD_HCRESET) {
B
bellard 已提交
518 519 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
            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 已提交
549
            dev = port->port.dev;
550
            if (dev && dev->attached) {
B
bellard 已提交
551
                /* port reset */
552
                if ( (val & UHCI_PORT_RESET) &&
B
bellard 已提交
553
                     !(port->ctrl & UHCI_PORT_RESET) ) {
G
Gerd Hoffmann 已提交
554
                    usb_device_reset(dev);
B
bellard 已提交
555 556
                }
            }
557 558
            port->ctrl &= UHCI_PORT_READ_ONLY;
            port->ctrl |= (val & ~UHCI_PORT_READ_ONLY);
B
bellard 已提交
559
            /* some bits are reset when a '1' is written to them */
560
            port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR);
B
bellard 已提交
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
        }
        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;
590
            if (n >= NB_PORTS)
B
bellard 已提交
591 592 593 594 595 596 597 598 599 600
                goto read_default;
            port = &s->ports[n];
            val = port->ctrl;
        }
        break;
    default:
    read_default:
        val = 0xff7f; /* disabled port */
        break;
    }
601

G
Gerd Hoffmann 已提交
602
    trace_usb_uhci_mmio_readw(addr, val);
603

B
bellard 已提交
604 605 606 607 608 609 610 611
    return val;
}

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

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

B
bellard 已提交
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
    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 已提交
635
    trace_usb_uhci_mmio_readl(addr, val);
B
bellard 已提交
636 637 638
    return val;
}

639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
/* 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);
    }
}

654
static void uhci_attach(USBPort *port1)
B
bellard 已提交
655 656 657 658
{
    UHCIState *s = port1->opaque;
    UHCIPort *port = &s->ports[port1->index];

659 660
    /* set connect status */
    port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
P
pbrook 已提交
661

662 663 664
    /* update speed */
    if (port->port.dev->speed == USB_SPEED_LOW) {
        port->ctrl |= UHCI_PORT_LSDA;
B
bellard 已提交
665
    } else {
666 667
        port->ctrl &= ~UHCI_PORT_LSDA;
    }
668

669 670
    uhci_resume(s);
}
671

672 673 674 675 676
static void uhci_detach(USBPort *port1)
{
    UHCIState *s = port1->opaque;
    UHCIPort *port = &s->ports[port1->index];

677 678
    uhci_async_cancel_device(s, port1->dev);

679 680 681 682
    /* set connect status */
    if (port->ctrl & UHCI_PORT_CCS) {
        port->ctrl &= ~UHCI_PORT_CCS;
        port->ctrl |= UHCI_PORT_CSC;
B
bellard 已提交
683
    }
684 685 686 687 688 689 690
    /* disable port */
    if (port->ctrl & UHCI_PORT_EN) {
        port->ctrl &= ~UHCI_PORT_EN;
        port->ctrl |= UHCI_PORT_ENC;
    }

    uhci_resume(s);
B
bellard 已提交
691 692
}

693 694 695 696 697 698 699
static void uhci_child_detach(USBPort *port1, USBDevice *child)
{
    UHCIState *s = port1->opaque;

    uhci_async_cancel_device(s, child);
}

700
static void uhci_wakeup(USBPort *port1)
701
{
702 703
    UHCIState *s = port1->opaque;
    UHCIPort *port = &s->ports[port1->index];
704 705 706 707 708 709 710

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

711
static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr)
B
bellard 已提交
712
{
713 714
    USBDevice *dev;
    int i;
715

716
    for (i = 0; i < NB_PORTS; i++) {
717
        UHCIPort *port = &s->ports[i];
718 719 720 721 722 723
        if (!(port->ctrl & UHCI_PORT_EN)) {
            continue;
        }
        dev = usb_find_device(&port->port, addr);
        if (dev != NULL) {
            return dev;
724
        }
B
bellard 已提交
725
    }
726
    return NULL;
B
bellard 已提交
727 728
}

729 730 731 732 733 734 735 736 737
static void uhci_read_td(UHCIState *s, UHCI_TD *td, uint32_t link)
{
    pci_dma_read(&s->dev, link & ~0xf, td, sizeof(*td));
    le32_to_cpus(&td->link);
    le32_to_cpus(&td->ctrl);
    le32_to_cpus(&td->token);
    le32_to_cpus(&td->buffer);
}

738
static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask)
B
bellard 已提交
739
{
740
    int len = 0, max_len, err, ret;
B
bellard 已提交
741 742
    uint8_t pid;

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

G
Gerd Hoffmann 已提交
746
    ret = async->packet.result;
747 748 749

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

751 752
    if (ret < 0)
        goto out;
753

G
Gerd Hoffmann 已提交
754
    len = async->packet.result;
755 756 757 758 759 760
    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 已提交
761 762
    if (td->ctrl & TD_CTRL_IOC)
        *int_mask |= 0x01;
763 764 765

    if (pid == USB_TOKEN_IN) {
        if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
B
bellard 已提交
766 767
            *int_mask |= 0x02;
            /* short packet: do not update QH */
G
Gerd Hoffmann 已提交
768
            trace_usb_uhci_packet_complete_shortxfer(async->queue->token,
769
                                                     async->td_addr);
770
            return TD_RESULT_NEXT_QH;
B
bellard 已提交
771
        }
772 773 774
    }

    /* success */
775 776
    trace_usb_uhci_packet_complete_success(async->queue->token,
                                           async->td_addr);
777
    return TD_RESULT_COMPLETE;
778 779 780

out:
    switch(ret) {
H
Hans de Goede 已提交
781 782 783 784
    case USB_RET_NAK:
        td->ctrl |= TD_CTRL_NAK;
        return TD_RESULT_NEXT_QH;

785 786
    case USB_RET_STALL:
        td->ctrl |= TD_CTRL_STALL;
787 788
        trace_usb_uhci_packet_complete_stall(async->queue->token,
                                             async->td_addr);
H
Hans de Goede 已提交
789 790
        err = TD_RESULT_NEXT_QH;
        break;
791 792 793 794

    case USB_RET_BABBLE:
        td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
        /* frame interrupted */
795 796
        trace_usb_uhci_packet_complete_babble(async->queue->token,
                                              async->td_addr);
H
Hans de Goede 已提交
797 798
        err = TD_RESULT_STOP_FRAME;
        break;
799

H
Hans de Goede 已提交
800
    case USB_RET_IOERROR:
801 802
    case USB_RET_NODEV:
    default:
H
Hans de Goede 已提交
803 804
        td->ctrl |= TD_CTRL_TIMEOUT;
        td->ctrl &= ~(3 << TD_CTRL_ERROR_SHIFT);
805 806
        trace_usb_uhci_packet_complete_error(async->queue->token,
                                             async->td_addr);
H
Hans de Goede 已提交
807 808
        err = TD_RESULT_NEXT_QH;
        break;
809 810
    }

H
Hans de Goede 已提交
811 812 813 814
    td->ctrl &= ~TD_CTRL_ACTIVE;
    s->status |= UHCI_STS_USBERR;
    if (td->ctrl & TD_CTRL_IOC) {
        *int_mask |= 0x01;
B
bellard 已提交
815
    }
H
Hans de Goede 已提交
816 817
    uhci_update_irq(s);
    return err;
B
bellard 已提交
818 819
}

820
static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
821
                          UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask)
822
{
823
    int len = 0, max_len;
824
    bool spd;
825
    bool queuing = (q != NULL);
H
Hans de Goede 已提交
826
    uint8_t pid = td->token & 0xff;
H
Hans de Goede 已提交
827 828 829 830 831 832 833 834 835 836 837
    UHCIAsync *async = uhci_async_find_td(s, td_addr);

    if (async) {
        if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) {
            assert(q == NULL || q == async->queue);
            q = async->queue;
        } else {
            uhci_queue_free(async->queue, "guest re-used pending td");
            async = NULL;
        }
    }
838

839 840 841 842 843 844 845 846
    if (q == NULL) {
        q = uhci_queue_find(s, td);
        if (q && !uhci_queue_verify(q, qh_addr, td, td_addr, queuing)) {
            uhci_queue_free(q, "guest re-used qh");
            q = NULL;
        }
    }

847 848 849 850
    if (q) {
        q->valid = 32;
    }

851
    /* Is active ? */
852
    if (!(td->ctrl & TD_CTRL_ACTIVE)) {
853 854 855 856
        if (async) {
            /* Guest marked a pending td non-active, cancel the queue */
            uhci_queue_free(async->queue, "pending td non-active");
        }
857 858 859 860 861 862 863
        /*
         * ehci11d spec page 22: "Even if the Active bit in the TD is already
         * cleared when the TD is fetched ... an IOC interrupt is generated"
         */
        if (td->ctrl & TD_CTRL_IOC) {
                *int_mask |= 0x01;
        }
864
        return TD_RESULT_NEXT_QH;
865
    }
866 867

    if (async) {
G
Gerd Hoffmann 已提交
868 869 870 871 872 873
        if (queuing) {
            /* we are busy filling the queue, we are not prepared
               to consume completed packages then, just leave them
               in async state */
            return TD_RESULT_ASYNC_CONT;
        }
874 875 876 877 878 879 880 881 882 883
        if (!async->done) {
            UHCI_TD last_td;
            UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs, asyncs_head);
            /*
             * While we are waiting for the current td to complete, the guest
             * may have added more tds to the queue. Note we re-read the td
             * rather then caching it, as we want to see guest made changes!
             */
            uhci_read_td(s, &last_td, last->td_addr);
            uhci_queue_fill(async->queue, &last_td);
884

885 886
            return TD_RESULT_ASYNC_CONT;
        }
G
Gerd Hoffmann 已提交
887
        uhci_async_unlink(async);
888 889 890 891
        goto done;
    }

    /* Allocate new packet */
892
    if (q == NULL) {
H
Hans de Goede 已提交
893 894
        USBDevice *dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
        USBEndpoint *ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
895
        q = uhci_queue_new(s, qh_addr, td, ep);
896 897
    }
    async = uhci_async_alloc(q, td_addr);
898 899

    max_len = ((td->token >> 21) + 1) & 0x7ff;
900
    spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
H
Hans de Goede 已提交
901
    usb_packet_setup(&async->packet, pid, q->ep, td_addr, spd,
902
                     (td->ctrl & TD_CTRL_IOC) != 0);
G
Gerd Hoffmann 已提交
903 904
    qemu_sglist_add(&async->sgl, td->buffer, max_len);
    usb_packet_map(&async->packet, &async->sgl);
905 906 907 908

    switch(pid) {
    case USB_TOKEN_OUT:
    case USB_TOKEN_SETUP:
H
Hans de Goede 已提交
909
        len = usb_handle_packet(q->ep->dev, &async->packet);
910 911
        if (len >= 0)
            len = max_len;
912 913 914
        break;

    case USB_TOKEN_IN:
H
Hans de Goede 已提交
915
        len = usb_handle_packet(q->ep->dev, &async->packet);
916 917 918 919
        break;

    default:
        /* invalid pid : frame interrupted */
920
        usb_packet_unmap(&async->packet, &async->sgl);
G
Gerd Hoffmann 已提交
921
        uhci_async_free(async);
922 923
        s->status |= UHCI_STS_HCPERR;
        uhci_update_irq(s);
924
        return TD_RESULT_STOP_FRAME;
925 926
    }
 
927
    if (len == USB_RET_ASYNC) {
G
Gerd Hoffmann 已提交
928
        uhci_async_link(async);
929
        if (!queuing) {
H
Hans de Goede 已提交
930
            uhci_queue_fill(q, td);
931
        }
932
        return TD_RESULT_ASYNC_START;
933 934
    }

G
Gerd Hoffmann 已提交
935
    async->packet.result = len;
936 937

done:
938
    len = uhci_complete_td(s, td, async, int_mask);
939
    usb_packet_unmap(&async->packet, &async->sgl);
G
Gerd Hoffmann 已提交
940
    uhci_async_free(async);
941
    return len;
942 943
}

944
static void uhci_async_complete(USBPort *port, USBPacket *packet)
P
pbrook 已提交
945
{
946
    UHCIAsync *async = container_of(packet, UHCIAsync, packet);
G
Gerd Hoffmann 已提交
947
    UHCIState *s = async->queue->uhci;
948

949 950 951 952 953 954
    if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
        uhci_async_unlink(async);
        uhci_async_cancel(async);
        return;
    }

955 956 957
    async->done = 1;
    if (s->frame_bytes < s->frame_bandwidth) {
        qemu_bh_schedule(s->bh);
958
    }
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
}

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

H
Hans de Goede 已提交
1003
static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td)
1004 1005 1006 1007 1008 1009
{
    uint32_t int_mask = 0;
    uint32_t plink = td->link;
    UHCI_TD ptd;
    int ret;

1010
    while (is_valid(plink)) {
1011
        uhci_read_td(q->uhci, &ptd, plink);
1012 1013 1014
        if (!(ptd.ctrl & TD_CTRL_ACTIVE)) {
            break;
        }
1015
        if (uhci_queue_token(&ptd) != q->token) {
1016 1017
            break;
        }
G
Gerd Hoffmann 已提交
1018
        trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
1019
        ret = uhci_handle_td(q->uhci, q, q->qh_addr, &ptd, plink, &int_mask);
1020 1021 1022
        if (ret == TD_RESULT_ASYNC_CONT) {
            break;
        }
1023
        assert(ret == TD_RESULT_ASYNC_START);
1024 1025 1026
        assert(int_mask == 0);
        plink = ptd.link;
    }
H
Hans de Goede 已提交
1027
    usb_device_flush_ep_queue(q->ep->dev, q->ep);
1028 1029
}

1030 1031 1032
static void uhci_process_frame(UHCIState *s)
{
    uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
G
Gerd Hoffmann 已提交
1033
    uint32_t curr_qh, td_count = 0;
1034
    int cnt, ret;
P
pbrook 已提交
1035
    UHCI_TD td;
1036 1037
    UHCI_QH qh;
    QhDb qhdb;
P
pbrook 已提交
1038

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

1041
    pci_dma_read(&s->dev, frame_addr, &link, 4);
1042
    le32_to_cpus(&link);
1043

1044 1045 1046 1047 1048 1049
    int_mask = 0;
    curr_qh  = 0;

    qhdb_reset(&qhdb);

    for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
G
Gerd Hoffmann 已提交
1050
        if (s->frame_bytes >= s->frame_bandwidth) {
G
Gerd Hoffmann 已提交
1051 1052 1053 1054 1055
            /* We've reached the usb 1.1 bandwidth, which is
               1280 bytes/frame, stop processing */
            trace_usb_uhci_frame_stop_bandwidth();
            break;
        }
1056 1057
        if (is_qh(link)) {
            /* QH */
G
Gerd Hoffmann 已提交
1058
            trace_usb_uhci_qh_load(link & ~0xf);
1059 1060 1061 1062

            if (qhdb_insert(&qhdb, link)) {
                /*
                 * We're going in circles. Which is not a bug because
1063 1064
                 * HCD is allowed to do that as part of the BW management.
                 *
G
Gerd Hoffmann 已提交
1065 1066
                 * Stop processing here if no transaction has been done
                 * since we've been here last time.
1067
                 */
1068
                if (td_count == 0) {
G
Gerd Hoffmann 已提交
1069
                    trace_usb_uhci_frame_loop_stop_idle();
1070 1071
                    break;
                } else {
G
Gerd Hoffmann 已提交
1072
                    trace_usb_uhci_frame_loop_continue();
1073 1074 1075 1076
                    td_count = 0;
                    qhdb_reset(&qhdb);
                    qhdb_insert(&qhdb, link);
                }
1077 1078
            }

1079
            pci_dma_read(&s->dev, link & ~0xf, &qh, sizeof(qh));
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
            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 */
1096
        uhci_read_td(s, &td, link);
G
Gerd Hoffmann 已提交
1097
        trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
1098 1099

        old_td_ctrl = td.ctrl;
1100
        ret = uhci_handle_td(s, NULL, curr_qh, &td, link, &int_mask);
1101
        if (old_td_ctrl != td.ctrl) {
1102
            /* update the status bits of the TD */
1103
            val = cpu_to_le32(td.ctrl);
1104
            pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val));
1105
        }
1106

1107
        switch (ret) {
1108
        case TD_RESULT_STOP_FRAME: /* interrupted frame */
1109
            goto out;
1110

1111
        case TD_RESULT_NEXT_QH:
1112
        case TD_RESULT_ASYNC_CONT:
G
Gerd Hoffmann 已提交
1113
            trace_usb_uhci_td_nextqh(curr_qh & ~0xf, link & ~0xf);
1114 1115 1116
            link = curr_qh ? qh.link : td.link;
            continue;

1117
        case TD_RESULT_ASYNC_START:
G
Gerd Hoffmann 已提交
1118
            trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
1119 1120
            link = curr_qh ? qh.link : td.link;
            continue;
1121

1122
        case TD_RESULT_COMPLETE:
G
Gerd Hoffmann 已提交
1123
            trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf);
1124 1125
            link = td.link;
            td_count++;
G
Gerd Hoffmann 已提交
1126
            s->frame_bytes += (td.ctrl & 0x7ff) + 1;
1127

1128 1129 1130 1131 1132
            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));
1133

1134 1135 1136 1137 1138
                if (!depth_first(link)) {
                    /* done with this QH */
                    curr_qh = 0;
                    link    = qh.link;
                }
1139
            }
1140 1141 1142 1143
            break;

        default:
            assert(!"unknown return code");
P
pbrook 已提交
1144
        }
1145 1146

        /* go to the next entry */
P
pbrook 已提交
1147
    }
1148

1149
out:
1150
    s->pending_int_mask |= int_mask;
P
pbrook 已提交
1151 1152
}

G
Gerd Hoffmann 已提交
1153 1154 1155 1156 1157 1158
static void uhci_bh(void *opaque)
{
    UHCIState *s = opaque;
    uhci_process_frame(s);
}

B
bellard 已提交
1159 1160 1161
static void uhci_frame_timer(void *opaque)
{
    UHCIState *s = opaque;
1162 1163 1164

    /* prepare the timer for the next frame */
    s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ);
G
Gerd Hoffmann 已提交
1165
    s->frame_bytes = 0;
G
Gerd Hoffmann 已提交
1166
    qemu_bh_cancel(s->bh);
B
bellard 已提交
1167 1168

    if (!(s->cmd & UHCI_CMD_RS)) {
1169
        /* Full stop */
G
Gerd Hoffmann 已提交
1170
        trace_usb_uhci_schedule_stop();
B
bellard 已提交
1171
        qemu_del_timer(s->frame_timer);
G
Gerd Hoffmann 已提交
1172
        uhci_async_cancel_all(s);
1173 1174
        /* set hchalted bit in status - UHCI11D 2.1.2 */
        s->status |= UHCI_STS_HCHALTED;
B
bellard 已提交
1175 1176
        return;
    }
1177 1178

    /* Complete the previous frame */
P
pbrook 已提交
1179 1180
    if (s->pending_int_mask) {
        s->status2 |= s->pending_int_mask;
1181
        s->status  |= UHCI_STS_USBINT;
P
pbrook 已提交
1182 1183
        uhci_update_irq(s);
    }
1184
    s->pending_int_mask = 0;
1185

1186 1187 1188
    /* Start new frame */
    s->frnum = (s->frnum + 1) & 0x7ff;

G
Gerd Hoffmann 已提交
1189
    trace_usb_uhci_frame_start(s->frnum);
1190 1191 1192 1193 1194 1195

    uhci_async_validate_begin(s);

    uhci_process_frame(s);

    uhci_async_validate_end(s);
1196

1197
    qemu_mod_timer(s->frame_timer, s->expire_time);
B
bellard 已提交
1198 1199
}

A
Avi Kivity 已提交
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
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 已提交
1213

1214 1215
static USBPortOps uhci_port_ops = {
    .attach = uhci_attach,
1216
    .detach = uhci_detach,
1217
    .child_detach = uhci_child_detach,
1218
    .wakeup = uhci_wakeup,
1219
    .complete = uhci_async_complete,
1220 1221
};

1222 1223 1224
static USBBusOps uhci_bus_ops = {
};

1225
static int usb_uhci_common_initfn(PCIDevice *dev)
B
bellard 已提交
1226
{
G
Gerd Hoffmann 已提交
1227
    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
1228
    UHCIPCIDeviceClass *u = container_of(pc, UHCIPCIDeviceClass, parent_class);
1229
    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
G
Gerd Hoffmann 已提交
1230
    uint8_t *pci_conf = s->dev.config;
B
bellard 已提交
1231 1232
    int i;

1233 1234
    pci_conf[PCI_CLASS_PROG] = 0x00;
    /* TODO: reset value should be 0. */
1235
    pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
1236

1237
    s->irq_pin = u->info.irq_pin;
G
Gerd Hoffmann 已提交
1238 1239
    pci_config_set_interrupt_pin(pci_conf, s->irq_pin + 1);

1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
    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 已提交
1256
    }
G
Gerd Hoffmann 已提交
1257
    s->bh = qemu_bh_new(uhci_bh, s);
1258
    s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
1259
    s->num_ports_vmstate = NB_PORTS;
G
Gerd Hoffmann 已提交
1260
    QTAILQ_INIT(&s->queues);
B
bellard 已提交
1261

1262
    qemu_register_reset(uhci_reset, s);
B
bellard 已提交
1263

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

G
Gerd Hoffmann 已提交
1269
    return 0;
B
bellard 已提交
1270
}
T
ths 已提交
1271

1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
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);

1284
    return usb_uhci_common_initfn(dev);
1285 1286
}

1287
static void usb_uhci_exit(PCIDevice *dev)
A
Avi Kivity 已提交
1288 1289 1290 1291 1292 1293
{
    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);

    memory_region_destroy(&s->io_bar);
}

G
Gerd Hoffmann 已提交
1294 1295 1296
static Property uhci_properties[] = {
    DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
    DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
G
Gerd Hoffmann 已提交
1297
    DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
G
Gerd Hoffmann 已提交
1298 1299 1300
    DEFINE_PROP_END_OF_LIST(),
};

G
Gerd Hoffmann 已提交
1301
static void uhci_class_init(ObjectClass *klass, void *data)
1302
{
1303
    DeviceClass *dc = DEVICE_CLASS(klass);
1304
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1305
    UHCIPCIDeviceClass *u = container_of(k, UHCIPCIDeviceClass, parent_class);
G
Gerd Hoffmann 已提交
1306 1307 1308 1309 1310 1311 1312 1313
    UHCIInfo *info = data;

    k->init = info->initfn ? info->initfn : usb_uhci_common_initfn;
    k->exit = info->unplug ? usb_uhci_exit : NULL;
    k->vendor_id = info->vendor_id;
    k->device_id = info->device_id;
    k->revision  = info->revision;
    k->class_id  = PCI_CLASS_SERIAL_USB;
1314 1315
    dc->vmsd = &vmstate_uhci;
    dc->props = uhci_properties;
1316
    u->info = *info;
1317 1318
}

G
Gerd Hoffmann 已提交
1319 1320 1321 1322 1323 1324
static UHCIInfo uhci_info[] = {
    {
        .name       = "piix3-usb-uhci",
        .vendor_id = PCI_VENDOR_ID_INTEL,
        .device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
        .revision  = 0x01,
1325
        .irq_pin   = 3,
G
Gerd Hoffmann 已提交
1326 1327 1328 1329 1330 1331
        .unplug    = true,
    },{
        .name      = "piix4-usb-uhci",
        .vendor_id = PCI_VENDOR_ID_INTEL,
        .device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
        .revision  = 0x01,
1332
        .irq_pin   = 3,
G
Gerd Hoffmann 已提交
1333 1334 1335 1336 1337 1338
        .unplug    = true,
    },{
        .name      = "vt82c686b-usb-uhci",
        .vendor_id = PCI_VENDOR_ID_VIA,
        .device_id = PCI_DEVICE_ID_VIA_UHCI,
        .revision  = 0x01,
1339
        .irq_pin   = 3,
G
Gerd Hoffmann 已提交
1340 1341 1342
        .initfn    = usb_uhci_vt82c686b_initfn,
        .unplug    = true,
    },{
G
Gerd Hoffmann 已提交
1343
        .name      = "ich9-usb-uhci1", /* 00:1d.0 */
G
Gerd Hoffmann 已提交
1344 1345 1346
        .vendor_id = PCI_VENDOR_ID_INTEL,
        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
        .revision  = 0x03,
1347
        .irq_pin   = 0,
G
Gerd Hoffmann 已提交
1348 1349
        .unplug    = false,
    },{
G
Gerd Hoffmann 已提交
1350
        .name      = "ich9-usb-uhci2", /* 00:1d.1 */
G
Gerd Hoffmann 已提交
1351 1352 1353
        .vendor_id = PCI_VENDOR_ID_INTEL,
        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
        .revision  = 0x03,
1354
        .irq_pin   = 1,
G
Gerd Hoffmann 已提交
1355 1356
        .unplug    = false,
    },{
G
Gerd Hoffmann 已提交
1357
        .name      = "ich9-usb-uhci3", /* 00:1d.2 */
G
Gerd Hoffmann 已提交
1358 1359 1360
        .vendor_id = PCI_VENDOR_ID_INTEL,
        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
        .revision  = 0x03,
1361
        .irq_pin   = 2,
G
Gerd Hoffmann 已提交
1362
        .unplug    = false,
G
Gerd Hoffmann 已提交
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
    },{
        .name      = "ich9-usb-uhci4", /* 00:1a.0 */
        .vendor_id = PCI_VENDOR_ID_INTEL,
        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI4,
        .revision  = 0x03,
        .irq_pin   = 0,
        .unplug    = false,
    },{
        .name      = "ich9-usb-uhci5", /* 00:1a.1 */
        .vendor_id = PCI_VENDOR_ID_INTEL,
        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI5,
        .revision  = 0x03,
        .irq_pin   = 1,
        .unplug    = false,
    },{
        .name      = "ich9-usb-uhci6", /* 00:1a.2 */
        .vendor_id = PCI_VENDOR_ID_INTEL,
        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI6,
        .revision  = 0x03,
        .irq_pin   = 2,
        .unplug    = false,
G
Gerd Hoffmann 已提交
1384
    }
G
Gerd Hoffmann 已提交
1385
};
T
ths 已提交
1386

A
Andreas Färber 已提交
1387
static void uhci_register_types(void)
G
Gerd Hoffmann 已提交
1388
{
G
Gerd Hoffmann 已提交
1389 1390 1391
    TypeInfo uhci_type_info = {
        .parent        = TYPE_PCI_DEVICE,
        .instance_size = sizeof(UHCIState),
1392
        .class_size    = sizeof(UHCIPCIDeviceClass),
G
Gerd Hoffmann 已提交
1393 1394 1395 1396 1397 1398 1399 1400 1401
        .class_init    = uhci_class_init,
    };
    int i;

    for (i = 0; i < ARRAY_SIZE(uhci_info); i++) {
        uhci_type_info.name = uhci_info[i].name;
        uhci_type_info.class_data = uhci_info + i;
        type_register(&uhci_type_info);
    }
G
Gerd Hoffmann 已提交
1402
}
A
Andreas Färber 已提交
1403 1404

type_init(uhci_register_types)