⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb-uhci.c

📁 qemu虚拟机代码
💻 C
📖 第 1 页 / 共 2 页
字号:
    } else {        /* set connect status */        if (!(port->ctrl & UHCI_PORT_CCS)) {            port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;        }        /* disable port */        if (port->ctrl & UHCI_PORT_EN) {            port->ctrl &= ~UHCI_PORT_EN;            port->ctrl |= UHCI_PORT_ENC;        }        dev = port->port.dev;        if (dev) {            /* send the detach message */            dev->handle_packet(dev,                                USB_MSG_DETACH, 0, 0, NULL, 0);        }        port->port.dev = NULL;    }}static int uhci_broadcast_packet(UHCIState *s, uint8_t pid,                                  uint8_t devaddr, uint8_t devep,                                 uint8_t *data, int len){    UHCIPort *port;    USBDevice *dev;    int i, ret;#ifdef DEBUG_PACKET    {        const char *pidstr;        switch(pid) {        case USB_TOKEN_SETUP: pidstr = "SETUP"; break;        case USB_TOKEN_IN: pidstr = "IN"; break;        case USB_TOKEN_OUT: pidstr = "OUT"; break;        default: pidstr = "?"; break;        }        printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n",               s->frnum, pidstr, devaddr, devep, len);        if (pid != USB_TOKEN_IN) {            printf("     data_out=");            for(i = 0; i < len; i++) {                printf(" %02x", data[i]);            }            printf("\n");        }    }#endif    for(i = 0; i < NB_PORTS; i++) {        port = &s->ports[i];        dev = port->port.dev;        if (dev && (port->ctrl & UHCI_PORT_EN)) {            ret = dev->handle_packet(dev, pid,                                      devaddr, devep,                                     data, len);            if (ret != USB_RET_NODEV) {#ifdef DEBUG_PACKET                {                    printf("     ret=%d ", ret);                    if (pid == USB_TOKEN_IN && ret > 0) {                        printf("data_in=");                        for(i = 0; i < ret; i++) {                            printf(" %02x", data[i]);                        }                    }                    printf("\n");                }#endif                return ret;            }        }    }    return USB_RET_NODEV;}/* return -1 if fatal error (frame must be stopped)          0 if TD successful          1 if TD unsuccessful or inactive*/static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask){    uint8_t pid;    uint8_t buf[1280];    int len, max_len, err, ret;    if (td->ctrl & TD_CTRL_IOC) {        *int_mask |= 0x01;    }        if (!(td->ctrl & TD_CTRL_ACTIVE))        return 1;    /* TD is active */    max_len = ((td->token >> 21) + 1) & 0x7ff;    pid = td->token & 0xff;    switch(pid) {    case USB_TOKEN_OUT:    case USB_TOKEN_SETUP:        cpu_physical_memory_read(td->buffer, buf, max_len);        ret = uhci_broadcast_packet(s, pid,                                     (td->token >> 8) & 0x7f,                                    (td->token >> 15) & 0xf,                                    buf, max_len);        len = max_len;        break;    case USB_TOKEN_IN:        ret = uhci_broadcast_packet(s, pid,                                     (td->token >> 8) & 0x7f,                                    (td->token >> 15) & 0xf,                                    buf, max_len);        if (ret >= 0) {            len = ret;            if (len > max_len) {                len = max_len;                ret = USB_RET_BABBLE;            }            if (len > 0) {                /* write the data back */                cpu_physical_memory_write(td->buffer, buf, len);            }        } else {            len = 0;        }        break;    default:        /* invalid pid : frame interrupted */        s->status |= UHCI_STS_HCPERR;        uhci_update_irq(s);        return -1;    }    if (td->ctrl & TD_CTRL_IOS)        td->ctrl &= ~TD_CTRL_ACTIVE;    if (ret >= 0) {        td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);        td->ctrl &= ~TD_CTRL_ACTIVE;        if (pid == USB_TOKEN_IN &&             (td->ctrl & TD_CTRL_SPD) &&            len < max_len) {            *int_mask |= 0x02;            /* short packet: do not update QH */            return 1;        } else {            /* success */            return 0;        }    } else {        switch(ret) {        default:        case USB_RET_NODEV:        do_timeout:            td->ctrl |= TD_CTRL_TIMEOUT;            err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;            if (err != 0) {                err--;                if (err == 0) {                    td->ctrl &= ~TD_CTRL_ACTIVE;                    s->status |= UHCI_STS_USBERR;                    uhci_update_irq(s);                }            }            td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |                 (err << TD_CTRL_ERROR_SHIFT);            return 1;        case USB_RET_NAK:            td->ctrl |= TD_CTRL_NAK;            if (pid == USB_TOKEN_SETUP)                goto do_timeout;            return 1;        case USB_RET_STALL:            td->ctrl |= TD_CTRL_STALL;            td->ctrl &= ~TD_CTRL_ACTIVE;            return 1;        case USB_RET_BABBLE:            td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;            td->ctrl &= ~TD_CTRL_ACTIVE;            /* frame interrupted */            return -1;        }    }}static void uhci_frame_timer(void *opaque){    UHCIState *s = opaque;    int64_t expire_time;    uint32_t frame_addr, link, old_td_ctrl, val;    int int_mask, cnt, ret;    UHCI_TD td;    UHCI_QH qh;    if (!(s->cmd & UHCI_CMD_RS)) {        qemu_del_timer(s->frame_timer);        /* set hchalted bit in status - UHCI11D 2.1.2 */        s->status |= UHCI_STS_HCHALTED;        return;    }    frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);    cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);    le32_to_cpus(&link);    int_mask = 0;    cnt = FRAME_MAX_LOOPS;    while ((link & 1) == 0) {        if (--cnt == 0)            break;        /* valid frame */        if (link & 2) {            /* QH */            cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh));            le32_to_cpus(&qh.link);            le32_to_cpus(&qh.el_link);        depth_first:            if (qh.el_link & 1) {                /* no element : go to next entry */                link = qh.link;            } else if (qh.el_link & 2) {                /* QH */                link = qh.el_link;            } else {                /* TD */                if (--cnt == 0)                    break;                cpu_physical_memory_read(qh.el_link & ~0xf,                                          (uint8_t *)&td, sizeof(td));                le32_to_cpus(&td.link);                le32_to_cpus(&td.ctrl);                le32_to_cpus(&td.token);                le32_to_cpus(&td.buffer);                old_td_ctrl = td.ctrl;                ret = uhci_handle_td(s, &td, &int_mask);                /* update the status bits of the TD */                if (old_td_ctrl != td.ctrl) {                    val = cpu_to_le32(td.ctrl);                    cpu_physical_memory_write((qh.el_link & ~0xf) + 4,                                               (const uint8_t *)&val,                                               sizeof(val));                }                if (ret < 0)                    break; /* interrupted frame */                if (ret == 0) {                    /* update qh element link */                    qh.el_link = td.link;                    val = cpu_to_le32(qh.el_link);                    cpu_physical_memory_write((link & ~0xf) + 4,                                               (const uint8_t *)&val,                                               sizeof(val));                    if (qh.el_link & 4) {                        /* depth first */                        goto depth_first;                    }                }                /* go to next entry */                link = qh.link;            }        } else {            /* TD */            cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td));            le32_to_cpus(&td.link);            le32_to_cpus(&td.ctrl);            le32_to_cpus(&td.token);            le32_to_cpus(&td.buffer);            old_td_ctrl = td.ctrl;            ret = uhci_handle_td(s, &td, &int_mask);            /* update the status bits of the TD */            if (old_td_ctrl != td.ctrl) {                val = cpu_to_le32(td.ctrl);                cpu_physical_memory_write((link & ~0xf) + 4,                                           (const uint8_t *)&val,                                           sizeof(val));            }            if (ret < 0)                break; /* interrupted frame */            link = td.link;        }    }    s->frnum = (s->frnum + 1) & 0x7ff;    if (int_mask) {        s->status2 |= int_mask;        s->status |= UHCI_STS_USBINT;        uhci_update_irq(s);    }    /* prepare the timer for the next frame */    expire_time = qemu_get_clock(vm_clock) +         (ticks_per_sec / FRAME_TIMER_FREQ);    qemu_mod_timer(s->frame_timer, expire_time);}static void uhci_map(PCIDevice *pci_dev, int region_num,                     uint32_t addr, uint32_t size, int type){    UHCIState *s = (UHCIState *)pci_dev;    register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);    register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);    register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);    register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);    register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);    register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);}void usb_uhci_init(PCIBus *bus, USBPort **usb_ports){    UHCIState *s;    uint8_t *pci_conf;    UHCIPort *port;    int i;    s = (UHCIState *)pci_register_device(bus,                                        "USB-UHCI", sizeof(UHCIState),                                        ((PCIDevice *)piix3_state)->devfn + 2,                                         NULL, NULL);    pci_conf = s->dev.config;    pci_conf[0x00] = 0x86;    pci_conf[0x01] = 0x80;    pci_conf[0x02] = 0x20;    pci_conf[0x03] = 0x70;    pci_conf[0x08] = 0x01; // revision number    pci_conf[0x09] = 0x00;    pci_conf[0x0a] = 0x03;    pci_conf[0x0b] = 0x0c;    pci_conf[0x0e] = 0x00; // header_type    pci_conf[0x3d] = 4; // interrupt pin 3    pci_conf[0x60] = 0x10; // release number        for(i = 0; i < NB_PORTS; i++) {        port = &s->ports[i];        port->port.opaque = s;        port->port.index = i;        port->port.attach = uhci_attach;        usb_ports[i] = &port->port;    }    s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);    uhci_reset(s);    /* Use region 4 for consistency with real hardware.  BSD guests seem       to rely on this.  */    pci_register_io_region(&s->dev, 4, 0x20,                            PCI_ADDRESS_SPACE_IO, uhci_map);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -