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

📄 usb-uhci.c

📁 qemu虚拟机代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * USB UHCI controller emulation *  * Copyright (c) 2005 Fabrice Bellard *  * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include "vl.h"//#define DEBUG//#define DEBUG_PACKET#define UHCI_CMD_GRESET   (1 << 2)#define UHCI_CMD_HCRESET  (1 << 1)#define UHCI_CMD_RS       (1 << 0)#define UHCI_STS_HCHALTED (1 << 5)#define UHCI_STS_HCPERR   (1 << 4)#define UHCI_STS_HSERR    (1 << 3)#define UHCI_STS_RD       (1 << 2)#define UHCI_STS_USBERR   (1 << 1)#define UHCI_STS_USBINT   (1 << 0)#define TD_CTRL_SPD     (1 << 29)#define TD_CTRL_ERROR_SHIFT  27#define TD_CTRL_IOS     (1 << 25)#define TD_CTRL_IOC     (1 << 24)#define TD_CTRL_ACTIVE  (1 << 23)#define TD_CTRL_STALL   (1 << 22)#define TD_CTRL_BABBLE  (1 << 20)#define TD_CTRL_NAK     (1 << 19)#define TD_CTRL_TIMEOUT (1 << 18)#define UHCI_PORT_RESET (1 << 9)#define UHCI_PORT_LSDA  (1 << 8)#define UHCI_PORT_ENC   (1 << 3)#define UHCI_PORT_EN    (1 << 2)#define UHCI_PORT_CSC   (1 << 1)#define UHCI_PORT_CCS   (1 << 0)#define FRAME_TIMER_FREQ 1000#define FRAME_MAX_LOOPS  100#define NB_PORTS 2typedef struct UHCIPort {    USBPort port;    uint16_t ctrl;} UHCIPort;typedef struct UHCIState {    PCIDevice dev;    uint16_t cmd; /* cmd register */    uint16_t status;    uint16_t intr; /* interrupt enable register */    uint16_t frnum; /* frame number */    uint32_t fl_base_addr; /* frame list base address */    uint8_t sof_timing;    uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */    QEMUTimer *frame_timer;    UHCIPort ports[NB_PORTS];} UHCIState;typedef struct UHCI_TD {    uint32_t link;    uint32_t ctrl; /* see TD_CTRL_xxx */    uint32_t token;    uint32_t buffer;} UHCI_TD;typedef struct UHCI_QH {    uint32_t link;    uint32_t el_link;} UHCI_QH;static void uhci_attach(USBPort *port1, USBDevice *dev);static void uhci_update_irq(UHCIState *s){    int level;    if (((s->status2 & 1) && (s->intr & (1 << 2))) ||        ((s->status2 & 2) && (s->intr & (1 << 3))) ||        ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||        ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||        (s->status & UHCI_STS_HSERR) ||        (s->status & UHCI_STS_HCPERR)) {        level = 1;    } else {        level = 0;    }    pci_set_irq(&s->dev, 3, level);}static void uhci_reset(UHCIState *s){    uint8_t *pci_conf;    int i;    UHCIPort *port;    pci_conf = s->dev.config;    pci_conf[0x6a] = 0x01; /* usb clock */    pci_conf[0x6b] = 0x00;    s->cmd = 0;    s->status = 0;    s->status2 = 0;    s->intr = 0;    s->fl_base_addr = 0;    s->sof_timing = 64;    for(i = 0; i < NB_PORTS; i++) {        port = &s->ports[i];        port->ctrl = 0x0080;        if (port->port.dev)            uhci_attach(&port->port, port->port.dev);    }}static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val){    UHCIState *s = opaque;        addr &= 0x1f;    switch(addr) {    case 0x0c:        s->sof_timing = val;        break;    }}static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr){    UHCIState *s = opaque;    uint32_t val;    addr &= 0x1f;    switch(addr) {    case 0x0c:        val = s->sof_timing;        break;    default:        val = 0xff;        break;    }    return val;}static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val){    UHCIState *s = opaque;        addr &= 0x1f;#ifdef DEBUG    printf("uhci writew port=0x%04x val=0x%04x\n", addr, val);#endif    switch(addr) {    case 0x00:        if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {            /* start frame processing */            qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock));            s->status &= ~UHCI_STS_HCHALTED;        } else if (!(val & UHCI_CMD_RS)) {            s->status |= UHCI_STS_HCHALTED;        }        if (val & UHCI_CMD_GRESET) {            UHCIPort *port;            USBDevice *dev;            int i;            /* send reset on the USB bus */            for(i = 0; i < NB_PORTS; i++) {                port = &s->ports[i];                dev = port->port.dev;                if (dev) {                    dev->handle_packet(dev,                                        USB_MSG_RESET, 0, 0, NULL, 0);                }            }            uhci_reset(s);            return;        }        if (val & UHCI_CMD_HCRESET) {            uhci_reset(s);            return;        }        s->cmd = val;        break;    case 0x02:        s->status &= ~val;        /* XXX: the chip spec is not coherent, so we add a hidden           register to distinguish between IOC and SPD */        if (val & UHCI_STS_USBINT)            s->status2 = 0;        uhci_update_irq(s);        break;    case 0x04:        s->intr = val;        uhci_update_irq(s);        break;    case 0x06:        if (s->status & UHCI_STS_HCHALTED)            s->frnum = val & 0x7ff;        break;    case 0x10 ... 0x1f:        {            UHCIPort *port;            USBDevice *dev;            int n;            n = (addr >> 1) & 7;            if (n >= NB_PORTS)                return;            port = &s->ports[n];            dev = port->port.dev;            if (dev) {                /* port reset */                if ( (val & UHCI_PORT_RESET) &&                      !(port->ctrl & UHCI_PORT_RESET) ) {                    dev->handle_packet(dev,                                        USB_MSG_RESET, 0, 0, NULL, 0);                }            }            port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb);            /* some bits are reset when a '1' is written to them */            port->ctrl &= ~(val & 0x000a);        }        break;    }}static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr){    UHCIState *s = opaque;    uint32_t val;    addr &= 0x1f;    switch(addr) {    case 0x00:        val = s->cmd;        break;    case 0x02:        val = s->status;        break;    case 0x04:        val = s->intr;        break;    case 0x06:        val = s->frnum;        break;    case 0x10 ... 0x1f:        {            UHCIPort *port;            int n;            n = (addr >> 1) & 7;            if (n >= NB_PORTS)                 goto read_default;            port = &s->ports[n];            val = port->ctrl;        }        break;    default:    read_default:        val = 0xff7f; /* disabled port */        break;    }#ifdef DEBUG    printf("uhci readw port=0x%04x val=0x%04x\n", addr, val);#endif    return val;}static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val){    UHCIState *s = opaque;    addr &= 0x1f;#ifdef DEBUG    printf("uhci writel port=0x%04x val=0x%08x\n", addr, val);#endif    switch(addr) {    case 0x08:        s->fl_base_addr = val & ~0xfff;        break;    }}static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr){    UHCIState *s = opaque;    uint32_t val;    addr &= 0x1f;    switch(addr) {    case 0x08:        val = s->fl_base_addr;        break;    default:        val = 0xffffffff;        break;    }    return val;}static void uhci_attach(USBPort *port1, USBDevice *dev){    UHCIState *s = port1->opaque;    UHCIPort *port = &s->ports[port1->index];    if (dev) {        if (port->port.dev) {            usb_attach(port1, NULL);        }        /* set connect status */        if (!(port->ctrl & UHCI_PORT_CCS)) {            port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;        }        /* update speed */        if (dev->speed == USB_SPEED_LOW)            port->ctrl |= UHCI_PORT_LSDA;        else            port->ctrl &= ~UHCI_PORT_LSDA;        port->port.dev = dev;        /* send the attach message */        dev->handle_packet(dev,                            USB_MSG_ATTACH, 0, 0, NULL, 0);

⌨️ 快捷键说明

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