Annotation of qemu/hw/usb/hcd-uhci.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.