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

1.1     ! root        1: /*
        !             2:  * USB UHCI controller emulation
        !             3:  * 
        !             4:  * Copyright (c) 2005 Fabrice Bellard
        !             5:  * 
        !             6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
        !             7:  * of this software and associated documentation files (the "Software"), to deal
        !             8:  * in the Software without restriction, including without limitation the rights
        !             9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        !            10:  * copies of the Software, and to permit persons to whom the Software is
        !            11:  * furnished to do so, subject to the following conditions:
        !            12:  *
        !            13:  * The above copyright notice and this permission notice shall be included in
        !            14:  * all copies or substantial portions of the Software.
        !            15:  *
        !            16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        !            17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
        !            19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        !            21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
        !            22:  * THE SOFTWARE.
        !            23:  */
        !            24: #include "vl.h"
        !            25: 
        !            26: //#define DEBUG
        !            27: //#define DEBUG_PACKET
        !            28: 
        !            29: #define UHCI_CMD_GRESET   (1 << 2)
        !            30: #define UHCI_CMD_HCRESET  (1 << 1)
        !            31: #define UHCI_CMD_RS       (1 << 0)
        !            32: 
        !            33: #define UHCI_STS_HCHALTED (1 << 5)
        !            34: #define UHCI_STS_HCPERR   (1 << 4)
        !            35: #define UHCI_STS_HSERR    (1 << 3)
        !            36: #define UHCI_STS_RD       (1 << 2)
        !            37: #define UHCI_STS_USBERR   (1 << 1)
        !            38: #define UHCI_STS_USBINT   (1 << 0)
        !            39: 
        !            40: #define TD_CTRL_SPD     (1 << 29)
        !            41: #define TD_CTRL_ERROR_SHIFT  27
        !            42: #define TD_CTRL_IOS     (1 << 25)
        !            43: #define TD_CTRL_IOC     (1 << 24)
        !            44: #define TD_CTRL_ACTIVE  (1 << 23)
        !            45: #define TD_CTRL_STALL   (1 << 22)
        !            46: #define TD_CTRL_BABBLE  (1 << 20)
        !            47: #define TD_CTRL_NAK     (1 << 19)
        !            48: #define TD_CTRL_TIMEOUT (1 << 18)
        !            49: 
        !            50: #define UHCI_PORT_RESET (1 << 9)
        !            51: #define UHCI_PORT_LSDA  (1 << 8)
        !            52: #define UHCI_PORT_ENC   (1 << 3)
        !            53: #define UHCI_PORT_EN    (1 << 2)
        !            54: #define UHCI_PORT_CSC   (1 << 1)
        !            55: #define UHCI_PORT_CCS   (1 << 0)
        !            56: 
        !            57: #define FRAME_TIMER_FREQ 1000
        !            58: 
        !            59: #define FRAME_MAX_LOOPS  100
        !            60: 
        !            61: #define NB_PORTS 2
        !            62: 
        !            63: typedef struct UHCIPort {
        !            64:     USBPort port;
        !            65:     uint16_t ctrl;
        !            66: } UHCIPort;
        !            67: 
        !            68: typedef struct UHCIState {
        !            69:     PCIDevice dev;
        !            70:     uint16_t cmd; /* cmd register */
        !            71:     uint16_t status;
        !            72:     uint16_t intr; /* interrupt enable register */
        !            73:     uint16_t frnum; /* frame number */
        !            74:     uint32_t fl_base_addr; /* frame list base address */
        !            75:     uint8_t sof_timing;
        !            76:     uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
        !            77:     QEMUTimer *frame_timer;
        !            78:     UHCIPort ports[NB_PORTS];
        !            79: } UHCIState;
        !            80: 
        !            81: typedef struct UHCI_TD {
        !            82:     uint32_t link;
        !            83:     uint32_t ctrl; /* see TD_CTRL_xxx */
        !            84:     uint32_t token;
        !            85:     uint32_t buffer;
        !            86: } UHCI_TD;
        !            87: 
        !            88: typedef struct UHCI_QH {
        !            89:     uint32_t link;
        !            90:     uint32_t el_link;
        !            91: } UHCI_QH;
        !            92: 
        !            93: static void uhci_attach(USBPort *port1, USBDevice *dev);
        !            94: 
        !            95: static void uhci_update_irq(UHCIState *s)
        !            96: {
        !            97:     int level;
        !            98:     if (((s->status2 & 1) && (s->intr & (1 << 2))) ||
        !            99:         ((s->status2 & 2) && (s->intr & (1 << 3))) ||
        !           100:         ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||
        !           101:         ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||
        !           102:         (s->status & UHCI_STS_HSERR) ||
        !           103:         (s->status & UHCI_STS_HCPERR)) {
        !           104:         level = 1;
        !           105:     } else {
        !           106:         level = 0;
        !           107:     }
        !           108:     pci_set_irq(&s->dev, 3, level);
        !           109: }
        !           110: 
        !           111: static void uhci_reset(UHCIState *s)
        !           112: {
        !           113:     uint8_t *pci_conf;
        !           114:     int i;
        !           115:     UHCIPort *port;
        !           116: 
        !           117:     pci_conf = s->dev.config;
        !           118: 
        !           119:     pci_conf[0x6a] = 0x01; /* usb clock */
        !           120:     pci_conf[0x6b] = 0x00;
        !           121:     s->cmd = 0;
        !           122:     s->status = 0;
        !           123:     s->status2 = 0;
        !           124:     s->intr = 0;
        !           125:     s->fl_base_addr = 0;
        !           126:     s->sof_timing = 64;
        !           127:     for(i = 0; i < NB_PORTS; i++) {
        !           128:         port = &s->ports[i];
        !           129:         port->ctrl = 0x0080;
        !           130:         if (port->port.dev)
        !           131:             uhci_attach(&port->port, port->port.dev);
        !           132:     }
        !           133: }
        !           134: 
        !           135: static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
        !           136: {
        !           137:     UHCIState *s = opaque;
        !           138:     
        !           139:     addr &= 0x1f;
        !           140:     switch(addr) {
        !           141:     case 0x0c:
        !           142:         s->sof_timing = val;
        !           143:         break;
        !           144:     }
        !           145: }
        !           146: 
        !           147: static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr)
        !           148: {
        !           149:     UHCIState *s = opaque;
        !           150:     uint32_t val;
        !           151: 
        !           152:     addr &= 0x1f;
        !           153:     switch(addr) {
        !           154:     case 0x0c:
        !           155:         val = s->sof_timing;
        !           156:     default:
        !           157:         val = 0xff;
        !           158:         break;
        !           159:     }
        !           160:     return val;
        !           161: }
        !           162: 
        !           163: static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
        !           164: {
        !           165:     UHCIState *s = opaque;
        !           166:     
        !           167:     addr &= 0x1f;
        !           168: #ifdef DEBUG
        !           169:     printf("uhci writew port=0x%04x val=0x%04x\n", addr, val);
        !           170: #endif
        !           171:     switch(addr) {
        !           172:     case 0x00:
        !           173:         if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
        !           174:             /* start frame processing */
        !           175:             qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock));
        !           176:         }
        !           177:         if (val & UHCI_CMD_GRESET) {
        !           178:             UHCIPort *port;
        !           179:             USBDevice *dev;
        !           180:             int i;
        !           181: 
        !           182:             /* send reset on the USB bus */
        !           183:             for(i = 0; i < NB_PORTS; i++) {
        !           184:                 port = &s->ports[i];
        !           185:                 dev = port->port.dev;
        !           186:                 if (dev) {
        !           187:                     dev->handle_packet(dev, 
        !           188:                                        USB_MSG_RESET, 0, 0, NULL, 0);
        !           189:                 }
        !           190:             }
        !           191:             uhci_reset(s);
        !           192:             return;
        !           193:         }
        !           194:         if (val & UHCI_CMD_HCRESET) {
        !           195:             uhci_reset(s);
        !           196:             return;
        !           197:         }
        !           198:         s->cmd = val;
        !           199:         break;
        !           200:     case 0x02:
        !           201:         s->status &= ~val;
        !           202:         /* XXX: the chip spec is not coherent, so we add a hidden
        !           203:            register to distinguish between IOC and SPD */
        !           204:         if (val & UHCI_STS_USBINT)
        !           205:             s->status2 = 0;
        !           206:         uhci_update_irq(s);
        !           207:         break;
        !           208:     case 0x04:
        !           209:         s->intr = val;
        !           210:         uhci_update_irq(s);
        !           211:         break;
        !           212:     case 0x06:
        !           213:         if (s->status & UHCI_STS_HCHALTED)
        !           214:             s->frnum = val & 0x7ff;
        !           215:         break;
        !           216:     case 0x10 ... 0x1f:
        !           217:         {
        !           218:             UHCIPort *port;
        !           219:             USBDevice *dev;
        !           220:             int n;
        !           221: 
        !           222:             n = (addr >> 1) & 7;
        !           223:             if (n >= NB_PORTS)
        !           224:                 return;
        !           225:             port = &s->ports[n];
        !           226:             dev = port->port.dev;
        !           227:             if (dev) {
        !           228:                 /* port reset */
        !           229:                 if ( (val & UHCI_PORT_RESET) && 
        !           230:                      !(port->ctrl & UHCI_PORT_RESET) ) {
        !           231:                     dev->handle_packet(dev, 
        !           232:                                        USB_MSG_RESET, 0, 0, NULL, 0);
        !           233:                 }
        !           234:             }
        !           235:             port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb);
        !           236:             /* some bits are reset when a '1' is written to them */
        !           237:             port->ctrl &= ~(val & 0x000a);
        !           238:         }
        !           239:         break;
        !           240:     }
        !           241: }
        !           242: 
        !           243: static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
        !           244: {
        !           245:     UHCIState *s = opaque;
        !           246:     uint32_t val;
        !           247: 
        !           248:     addr &= 0x1f;
        !           249:     switch(addr) {
        !           250:     case 0x00:
        !           251:         val = s->cmd;
        !           252:         break;
        !           253:     case 0x02:
        !           254:         val = s->status;
        !           255:         break;
        !           256:     case 0x04:
        !           257:         val = s->intr;
        !           258:         break;
        !           259:     case 0x06:
        !           260:         val = s->frnum;
        !           261:         break;
        !           262:     case 0x10 ... 0x1f:
        !           263:         {
        !           264:             UHCIPort *port;
        !           265:             int n;
        !           266:             n = (addr >> 1) & 7;
        !           267:             if (n >= NB_PORTS) 
        !           268:                 goto read_default;
        !           269:             port = &s->ports[n];
        !           270:             val = port->ctrl;
        !           271:         }
        !           272:         break;
        !           273:     default:
        !           274:     read_default:
        !           275:         val = 0xff7f; /* disabled port */
        !           276:         break;
        !           277:     }
        !           278: #ifdef DEBUG
        !           279:     printf("uhci readw port=0x%04x val=0x%04x\n", addr, val);
        !           280: #endif
        !           281:     return val;
        !           282: }
        !           283: 
        !           284: static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
        !           285: {
        !           286:     UHCIState *s = opaque;
        !           287: 
        !           288:     addr &= 0x1f;
        !           289: #ifdef DEBUG
        !           290:     printf("uhci writel port=0x%04x val=0x%08x\n", addr, val);
        !           291: #endif
        !           292:     switch(addr) {
        !           293:     case 0x08:
        !           294:         s->fl_base_addr = val & ~0xfff;
        !           295:         break;
        !           296:     }
        !           297: }
        !           298: 
        !           299: static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr)
        !           300: {
        !           301:     UHCIState *s = opaque;
        !           302:     uint32_t val;
        !           303: 
        !           304:     addr &= 0x1f;
        !           305:     switch(addr) {
        !           306:     case 0x08:
        !           307:         val = s->fl_base_addr;
        !           308:         break;
        !           309:     default:
        !           310:         val = 0xffffffff;
        !           311:         break;
        !           312:     }
        !           313:     return val;
        !           314: }
        !           315: 
        !           316: static void uhci_attach(USBPort *port1, USBDevice *dev)
        !           317: {
        !           318:     UHCIState *s = port1->opaque;
        !           319:     UHCIPort *port = &s->ports[port1->index];
        !           320: 
        !           321:     if (dev) {
        !           322:         if (port->port.dev) {
        !           323:             usb_attach(port1, NULL);
        !           324:         }
        !           325:         /* set connect status */
        !           326:         if (!(port->ctrl & UHCI_PORT_CCS)) {
        !           327:             port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
        !           328:         }
        !           329:         /* update speed */
        !           330:         if (dev->speed == USB_SPEED_LOW)
        !           331:             port->ctrl |= UHCI_PORT_LSDA;
        !           332:         else
        !           333:             port->ctrl &= ~UHCI_PORT_LSDA;
        !           334:         port->port.dev = dev;
        !           335:         /* send the attach message */
        !           336:         dev->handle_packet(dev, 
        !           337:                            USB_MSG_ATTACH, 0, 0, NULL, 0);
        !           338:     } else {
        !           339:         /* set connect status */
        !           340:         if (!(port->ctrl & UHCI_PORT_CCS)) {
        !           341:             port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
        !           342:         }
        !           343:         /* disable port */
        !           344:         if (port->ctrl & UHCI_PORT_EN) {
        !           345:             port->ctrl &= ~UHCI_PORT_EN;
        !           346:             port->ctrl |= UHCI_PORT_ENC;
        !           347:         }
        !           348:         dev = port->port.dev;
        !           349:         if (dev) {
        !           350:             /* send the detach message */
        !           351:             dev->handle_packet(dev, 
        !           352:                                USB_MSG_DETACH, 0, 0, NULL, 0);
        !           353:         }
        !           354:         port->port.dev = NULL;
        !           355:     }
        !           356: }
        !           357: 
        !           358: static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, 
        !           359:                                  uint8_t devaddr, uint8_t devep,
        !           360:                                  uint8_t *data, int len)
        !           361: {
        !           362:     UHCIPort *port;
        !           363:     USBDevice *dev;
        !           364:     int i, ret;
        !           365: 
        !           366: #ifdef DEBUG_PACKET
        !           367:     {
        !           368:         const char *pidstr;
        !           369:         switch(pid) {
        !           370:         case USB_TOKEN_SETUP: pidstr = "SETUP"; break;
        !           371:         case USB_TOKEN_IN: pidstr = "IN"; break;
        !           372:         case USB_TOKEN_OUT: pidstr = "OUT"; break;
        !           373:         default: pidstr = "?"; break;
        !           374:         }
        !           375:         printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n",
        !           376:                s->frnum, pidstr, devaddr, devep, len);
        !           377:         if (pid != USB_TOKEN_IN) {
        !           378:             printf("     data_out=");
        !           379:             for(i = 0; i < len; i++) {
        !           380:                 printf(" %02x", data[i]);
        !           381:             }
        !           382:             printf("\n");
        !           383:         }
        !           384:     }
        !           385: #endif
        !           386:     for(i = 0; i < NB_PORTS; i++) {
        !           387:         port = &s->ports[i];
        !           388:         dev = port->port.dev;
        !           389:         if (dev && (port->ctrl & UHCI_PORT_EN)) {
        !           390:             ret = dev->handle_packet(dev, pid, 
        !           391:                                      devaddr, devep,
        !           392:                                      data, len);
        !           393:             if (ret != USB_RET_NODEV) {
        !           394: #ifdef DEBUG_PACKET
        !           395:                 {
        !           396:                     printf("     ret=%d ", ret);
        !           397:                     if (pid == USB_TOKEN_IN && ret > 0) {
        !           398:                         printf("data_in=");
        !           399:                         for(i = 0; i < ret; i++) {
        !           400:                             printf(" %02x", data[i]);
        !           401:                         }
        !           402:                     }
        !           403:                     printf("\n");
        !           404:                 }
        !           405: #endif
        !           406:                 return ret;
        !           407:             }
        !           408:         }
        !           409:     }
        !           410:     return USB_RET_NODEV;
        !           411: }
        !           412: 
        !           413: /* return -1 if fatal error (frame must be stopped)
        !           414:           0 if TD successful
        !           415:           1 if TD unsuccessful or inactive
        !           416: */
        !           417: static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask)
        !           418: {
        !           419:     uint8_t pid;
        !           420:     uint8_t buf[1280];
        !           421:     int len, max_len, err, ret;
        !           422: 
        !           423:     if (td->ctrl & TD_CTRL_IOC) {
        !           424:         *int_mask |= 0x01;
        !           425:     }
        !           426:     
        !           427:     if (!(td->ctrl & TD_CTRL_ACTIVE))
        !           428:         return 1;
        !           429: 
        !           430:     /* TD is active */
        !           431:     max_len = ((td->token >> 21) + 1) & 0x7ff;
        !           432:     pid = td->token & 0xff;
        !           433:     switch(pid) {
        !           434:     case USB_TOKEN_OUT:
        !           435:     case USB_TOKEN_SETUP:
        !           436:         cpu_physical_memory_read(td->buffer, buf, max_len);
        !           437:         ret = uhci_broadcast_packet(s, pid, 
        !           438:                                     (td->token >> 8) & 0x7f,
        !           439:                                     (td->token >> 15) & 0xf,
        !           440:                                     buf, max_len);
        !           441:         len = max_len;
        !           442:         break;
        !           443:     case USB_TOKEN_IN:
        !           444:         ret = uhci_broadcast_packet(s, pid, 
        !           445:                                     (td->token >> 8) & 0x7f,
        !           446:                                     (td->token >> 15) & 0xf,
        !           447:                                     buf, max_len);
        !           448:         if (ret >= 0) {
        !           449:             len = ret;
        !           450:             if (len > max_len) {
        !           451:                 len = max_len;
        !           452:                 ret = USB_RET_BABBLE;
        !           453:             }
        !           454:             if (len > 0) {
        !           455:                 /* write the data back */
        !           456:                 cpu_physical_memory_write(td->buffer, buf, len);
        !           457:             }
        !           458:         } else {
        !           459:             len = 0;
        !           460:         }
        !           461:         break;
        !           462:     default:
        !           463:         /* invalid pid : frame interrupted */
        !           464:         s->status |= UHCI_STS_HCPERR;
        !           465:         uhci_update_irq(s);
        !           466:         return -1;
        !           467:     }
        !           468:     if (td->ctrl & TD_CTRL_IOS)
        !           469:         td->ctrl &= ~TD_CTRL_ACTIVE;
        !           470:     if (ret >= 0) {
        !           471:         td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
        !           472:         td->ctrl &= ~TD_CTRL_ACTIVE;
        !           473:         if (pid == USB_TOKEN_IN && 
        !           474:             (td->ctrl & TD_CTRL_SPD) &&
        !           475:             len < max_len) {
        !           476:             *int_mask |= 0x02;
        !           477:             /* short packet: do not update QH */
        !           478:             return 1;
        !           479:         } else {
        !           480:             /* success */
        !           481:             return 0;
        !           482:         }
        !           483:     } else {
        !           484:         switch(ret) {
        !           485:         default:
        !           486:         case USB_RET_NODEV:
        !           487:         do_timeout:
        !           488:             td->ctrl |= TD_CTRL_TIMEOUT;
        !           489:             err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;
        !           490:             if (err != 0) {
        !           491:                 err--;
        !           492:                 if (err == 0) {
        !           493:                     td->ctrl &= ~TD_CTRL_ACTIVE;
        !           494:                     s->status |= UHCI_STS_USBERR;
        !           495:                     uhci_update_irq(s);
        !           496:                 }
        !           497:             }
        !           498:             td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | 
        !           499:                 (err << TD_CTRL_ERROR_SHIFT);
        !           500:             return 1;
        !           501:         case USB_RET_NAK:
        !           502:             td->ctrl |= TD_CTRL_NAK;
        !           503:             if (pid == USB_TOKEN_SETUP)
        !           504:                 goto do_timeout;
        !           505:             return 1;
        !           506:         case USB_RET_STALL:
        !           507:             td->ctrl |= TD_CTRL_STALL;
        !           508:             td->ctrl &= ~TD_CTRL_ACTIVE;
        !           509:             return 1;
        !           510:         case USB_RET_BABBLE:
        !           511:             td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
        !           512:             td->ctrl &= ~TD_CTRL_ACTIVE;
        !           513:             /* frame interrupted */
        !           514:             return -1;
        !           515:         }
        !           516:     }
        !           517: }
        !           518: 
        !           519: static void uhci_frame_timer(void *opaque)
        !           520: {
        !           521:     UHCIState *s = opaque;
        !           522:     int64_t expire_time;
        !           523:     uint32_t frame_addr, link, old_td_ctrl, val;
        !           524:     int int_mask, cnt, ret;
        !           525:     UHCI_TD td;
        !           526:     UHCI_QH qh;
        !           527: 
        !           528:     if (!(s->cmd & UHCI_CMD_RS)) {
        !           529:         qemu_del_timer(s->frame_timer);
        !           530:         return;
        !           531:     }
        !           532:     frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
        !           533:     cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
        !           534:     le32_to_cpus(&link);
        !           535:     int_mask = 0;
        !           536:     cnt = FRAME_MAX_LOOPS;
        !           537:     while ((link & 1) == 0) {
        !           538:         if (--cnt == 0)
        !           539:             break;
        !           540:         /* valid frame */
        !           541:         if (link & 2) {
        !           542:             /* QH */
        !           543:             cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh));
        !           544:             le32_to_cpus(&qh.link);
        !           545:             le32_to_cpus(&qh.el_link);
        !           546:         depth_first:
        !           547:             if (qh.el_link & 1) {
        !           548:                 /* no element : go to next entry */
        !           549:                 link = qh.link;
        !           550:             } else if (qh.el_link & 2) {
        !           551:                 /* QH */
        !           552:                 link = qh.el_link;
        !           553:             } else {
        !           554:                 /* TD */
        !           555:                 if (--cnt == 0)
        !           556:                     break;
        !           557:                 cpu_physical_memory_read(qh.el_link & ~0xf, 
        !           558:                                          (uint8_t *)&td, sizeof(td));
        !           559:                 le32_to_cpus(&td.link);
        !           560:                 le32_to_cpus(&td.ctrl);
        !           561:                 le32_to_cpus(&td.token);
        !           562:                 le32_to_cpus(&td.buffer);
        !           563:                 old_td_ctrl = td.ctrl;
        !           564:                 ret = uhci_handle_td(s, &td, &int_mask);
        !           565:                 /* update the status bits of the TD */
        !           566:                 if (old_td_ctrl != td.ctrl) {
        !           567:                     val = cpu_to_le32(td.ctrl);
        !           568:                     cpu_physical_memory_write((qh.el_link & ~0xf) + 4, 
        !           569:                                               (const uint8_t *)&val, 
        !           570:                                               sizeof(val));
        !           571:                 }
        !           572:                 if (ret < 0)
        !           573:                     break; /* interrupted frame */
        !           574:                 if (ret == 0) {
        !           575:                     /* update qh element link */
        !           576:                     qh.el_link = td.link;
        !           577:                     val = cpu_to_le32(qh.el_link);
        !           578:                     cpu_physical_memory_write((link & ~0xf) + 4, 
        !           579:                                               (const uint8_t *)&val, 
        !           580:                                               sizeof(val));
        !           581:                     if (qh.el_link & 4) {
        !           582:                         /* depth first */
        !           583:                         goto depth_first;
        !           584:                     }
        !           585:                 }
        !           586:                 /* go to next entry */
        !           587:                 link = qh.link;
        !           588:             }
        !           589:         } else {
        !           590:             /* TD */
        !           591:             cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td));
        !           592:             le32_to_cpus(&td.link);
        !           593:             le32_to_cpus(&td.ctrl);
        !           594:             le32_to_cpus(&td.token);
        !           595:             le32_to_cpus(&td.buffer);
        !           596:             old_td_ctrl = td.ctrl;
        !           597:             ret = uhci_handle_td(s, &td, &int_mask);
        !           598:             /* update the status bits of the TD */
        !           599:             if (old_td_ctrl != td.ctrl) {
        !           600:                 val = cpu_to_le32(td.ctrl);
        !           601:                 cpu_physical_memory_write((link & ~0xf) + 4, 
        !           602:                                           (const uint8_t *)&val, 
        !           603:                                           sizeof(val));
        !           604:             }
        !           605:             if (ret < 0)
        !           606:                 break; /* interrupted frame */
        !           607:             link = td.link;
        !           608:         }
        !           609:     }
        !           610:     s->frnum = (s->frnum + 1) & 0x7ff;
        !           611:     if (int_mask) {
        !           612:         s->status2 |= int_mask;
        !           613:         s->status |= UHCI_STS_USBINT;
        !           614:         uhci_update_irq(s);
        !           615:     }
        !           616:     /* prepare the timer for the next frame */
        !           617:     expire_time = qemu_get_clock(vm_clock) + 
        !           618:         (ticks_per_sec / FRAME_TIMER_FREQ);
        !           619:     qemu_mod_timer(s->frame_timer, expire_time);
        !           620: }
        !           621: 
        !           622: static void uhci_map(PCIDevice *pci_dev, int region_num, 
        !           623:                     uint32_t addr, uint32_t size, int type)
        !           624: {
        !           625:     UHCIState *s = (UHCIState *)pci_dev;
        !           626: 
        !           627:     register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
        !           628:     register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
        !           629:     register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
        !           630:     register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
        !           631:     register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
        !           632:     register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
        !           633: }
        !           634: 
        !           635: void usb_uhci_init(PCIBus *bus, USBPort **usb_ports)
        !           636: {
        !           637:     UHCIState *s;
        !           638:     uint8_t *pci_conf;
        !           639:     UHCIPort *port;
        !           640:     int i;
        !           641: 
        !           642:     s = (UHCIState *)pci_register_device(bus,
        !           643:                                         "USB-UHCI", sizeof(UHCIState),
        !           644:                                         ((PCIDevice *)piix3_state)->devfn + 2, 
        !           645:                                         NULL, NULL);
        !           646:     pci_conf = s->dev.config;
        !           647:     pci_conf[0x00] = 0x86;
        !           648:     pci_conf[0x01] = 0x80;
        !           649:     pci_conf[0x02] = 0x20;
        !           650:     pci_conf[0x03] = 0x70;
        !           651:     pci_conf[0x08] = 0x01; // revision number
        !           652:     pci_conf[0x09] = 0x00;
        !           653:     pci_conf[0x0a] = 0x03;
        !           654:     pci_conf[0x0b] = 0x0c;
        !           655:     pci_conf[0x0e] = 0x00; // header_type
        !           656:     pci_conf[0x3d] = 4; // interrupt pin 3
        !           657:     
        !           658:     for(i = 0; i < NB_PORTS; i++) {
        !           659:         port = &s->ports[i];
        !           660:         port->port.opaque = s;
        !           661:         port->port.index = i;
        !           662:         port->port.attach = uhci_attach;
        !           663:         usb_ports[i] = &port->port;
        !           664:     }
        !           665:     s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
        !           666: 
        !           667:     uhci_reset(s);
        !           668: 
        !           669:     pci_register_io_region(&s->dev, 0, 0x20, 
        !           670:                            PCI_ADDRESS_SPACE_IO, uhci_map);
        !           671: }

unix.superglobalmegacorp.com

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