📄 usb-ohci.c
字号:
/* Set the frame interval - frame interval toggle is manipulated by the hcd only */static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val){ val &= OHCI_FMI_FI; if (val != ohci->fi) { dprintf("usb-ohci: %s: FrameInterval = 0x%x (%u)\n", ohci->pci_dev.name, ohci->fi, ohci->fi); } ohci->fi = val;}static void ohci_port_power(OHCIState *ohci, int i, int p){ if (p) { ohci->rhport[i].ctrl |= OHCI_PORT_PPS; } else { ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS| OHCI_PORT_CCS| OHCI_PORT_PSS| OHCI_PORT_PRS); }}/* Set HcControlRegister */static void ohci_set_ctl(OHCIState *ohci, uint32_t val){ uint32_t old_state; uint32_t new_state; old_state = ohci->ctl & OHCI_CTL_HCFS; ohci->ctl = val; new_state = ohci->ctl & OHCI_CTL_HCFS; /* no state change */ if (old_state == new_state) return; switch (new_state) { case OHCI_USB_OPERATIONAL: ohci_bus_start(ohci); break; case OHCI_USB_SUSPEND: ohci_bus_stop(ohci); dprintf("usb-ohci: %s: USB Suspended\n", ohci->pci_dev.name); break; case OHCI_USB_RESUME: dprintf("usb-ohci: %s: USB Resume\n", ohci->pci_dev.name); break; case OHCI_USB_RESET: dprintf("usb-ohci: %s: USB Reset\n", ohci->pci_dev.name); break; }}static uint32_t ohci_get_frame_remaining(OHCIState *ohci){ uint16_t fr; int64_t tks; if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL) return (ohci->frt << 31); /* Being in USB operational state guarnatees sof_time was * set already. */ tks = qemu_get_clock(vm_clock) - ohci->sof_time; /* avoid muldiv if possible */ if (tks >= usb_frame_time) return (ohci->frt << 31); tks = muldiv64(1, tks, usb_bit_time); fr = (uint16_t)(ohci->fi - tks); return (ohci->frt << 31) | fr;}/* Set root hub status */static void ohci_set_hub_status(OHCIState *ohci, uint32_t val){ uint32_t old_state; old_state = ohci->rhstatus; /* write 1 to clear OCIC */ if (val & OHCI_RHS_OCIC) ohci->rhstatus &= ~OHCI_RHS_OCIC; if (val & OHCI_RHS_LPS) { int i; for (i = 0; i < ohci->num_ports; i++) ohci_port_power(ohci, i, 0); dprintf("usb-ohci: powered down all ports\n"); } if (val & OHCI_RHS_LPSC) { int i; for (i = 0; i < ohci->num_ports; i++) ohci_port_power(ohci, i, 1); dprintf("usb-ohci: powered up all ports\n"); } if (val & OHCI_RHS_DRWE) ohci->rhstatus |= OHCI_RHS_DRWE; if (val & OHCI_RHS_CRWE) ohci->rhstatus &= ~OHCI_RHS_DRWE; if (old_state != ohci->rhstatus) ohci_set_interrupt(ohci, OHCI_INTR_RHSC);}/* Set root hub port status */static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val){ uint32_t old_state; OHCIPort *port; port = &ohci->rhport[portnum]; old_state = port->ctrl; /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */ if (val & OHCI_PORT_WTC) port->ctrl &= ~(val & OHCI_PORT_WTC); if (val & OHCI_PORT_CCS) port->ctrl &= ~OHCI_PORT_PES; ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES); if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) dprintf("usb-ohci: port %d: SUSPEND\n", portnum); if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { dprintf("usb-ohci: port %d: RESET\n", portnum); usb_send_msg(port->port.dev, USB_MSG_RESET); port->ctrl &= ~OHCI_PORT_PRS; /* ??? Should this also set OHCI_PORT_PESC. */ port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; } /* Invert order here to ensure in ambiguous case, device is * powered up... */ if (val & OHCI_PORT_LSDA) ohci_port_power(ohci, portnum, 0); if (val & OHCI_PORT_PPS) ohci_port_power(ohci, portnum, 1); if (old_state != port->ctrl) ohci_set_interrupt(ohci, OHCI_INTR_RHSC); return;}static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr){ OHCIState *ohci = ptr; addr -= ohci->mem_base; /* Only aligned reads are allowed on OHCI */ if (addr & 3) { fprintf(stderr, "usb-ohci: Mis-aligned read\n"); return 0xffffffff; } if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { /* HcRhPortStatus */ return ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS; } switch (addr >> 2) { case 0: /* HcRevision */ return 0x10; case 1: /* HcControl */ return ohci->ctl; case 2: /* HcCommandStatus */ return ohci->status; case 3: /* HcInterruptStatus */ return ohci->intr_status; case 4: /* HcInterruptEnable */ case 5: /* HcInterruptDisable */ return ohci->intr; case 6: /* HcHCCA */ return ohci->hcca; case 7: /* HcPeriodCurrentED */ return ohci->per_cur; case 8: /* HcControlHeadED */ return ohci->ctrl_head; case 9: /* HcControlCurrentED */ return ohci->ctrl_cur; case 10: /* HcBulkHeadED */ return ohci->bulk_head; case 11: /* HcBulkCurrentED */ return ohci->bulk_cur; case 12: /* HcDoneHead */ return ohci->done; case 13: /* HcFmInterval */ return (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi); case 14: /* HcFmRemaining */ return ohci_get_frame_remaining(ohci); case 15: /* HcFmNumber */ return ohci->frame_number; case 16: /* HcPeriodicStart */ return ohci->pstart; case 17: /* HcLSThreshold */ return ohci->lst; case 18: /* HcRhDescriptorA */ return ohci->rhdesc_a; case 19: /* HcRhDescriptorB */ return ohci->rhdesc_b; case 20: /* HcRhStatus */ return ohci->rhstatus; default: fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr); return 0xffffffff; }}static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val){ OHCIState *ohci = ptr; addr -= ohci->mem_base; /* Only aligned reads are allowed on OHCI */ if (addr & 3) { fprintf(stderr, "usb-ohci: Mis-aligned write\n"); return; } if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { /* HcRhPortStatus */ ohci_port_set_status(ohci, (addr - 0x54) >> 2, val); return; } switch (addr >> 2) { case 1: /* HcControl */ ohci_set_ctl(ohci, val); break; case 2: /* HcCommandStatus */ /* SOC is read-only */ val = (val & ~OHCI_STATUS_SOC); /* Bits written as '0' remain unchanged in the register */ ohci->status |= val; if (ohci->status & OHCI_STATUS_HCR) ohci_reset(ohci); break; case 3: /* HcInterruptStatus */ ohci->intr_status &= ~val; ohci_intr_update(ohci); break; case 4: /* HcInterruptEnable */ ohci->intr |= val; ohci_intr_update(ohci); break; case 5: /* HcInterruptDisable */ ohci->intr &= ~val; ohci_intr_update(ohci); break; case 6: /* HcHCCA */ ohci->hcca = val & OHCI_HCCA_MASK; break; case 8: /* HcControlHeadED */ ohci->ctrl_head = val & OHCI_EDPTR_MASK; break; case 9: /* HcControlCurrentED */ ohci->ctrl_cur = val & OHCI_EDPTR_MASK; break; case 10: /* HcBulkHeadED */ ohci->bulk_head = val & OHCI_EDPTR_MASK; break; case 11: /* HcBulkCurrentED */ ohci->bulk_cur = val & OHCI_EDPTR_MASK; break; case 13: /* HcFmInterval */ ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16; ohci->fit = (val & OHCI_FMI_FIT) >> 31; ohci_set_frame_interval(ohci, val); break; case 16: /* HcPeriodicStart */ ohci->pstart = val & 0xffff; break; case 17: /* HcLSThreshold */ ohci->lst = val & 0xffff; break; case 18: /* HcRhDescriptorA */ ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK; ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK; break; case 19: /* HcRhDescriptorB */ break; case 20: /* HcRhStatus */ ohci_set_hub_status(ohci, val); break; default: fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr); break; }}/* Only dword reads are defined on OHCI register space */static CPUReadMemoryFunc *ohci_readfn[3]={ ohci_mem_read, ohci_mem_read, ohci_mem_read};/* Only dword writes are defined on OHCI register space */static CPUWriteMemoryFunc *ohci_writefn[3]={ ohci_mem_write, ohci_mem_write, ohci_mem_write};static void ohci_mapfunc(PCIDevice *pci_dev, int i, uint32_t addr, uint32_t size, int type){ OHCIState *ohci = (OHCIState *)pci_dev; ohci->mem_base = addr; cpu_register_physical_memory(addr, size, ohci->mem);}void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn){ OHCIState *ohci; int vid = 0x106b; int did = 0x003f; int i; if (usb_frame_time == 0) {#if OHCI_TIME_WARP usb_frame_time = ticks_per_sec; usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ/1000);#else usb_frame_time = muldiv64(1, ticks_per_sec, 1000); if (ticks_per_sec >= USB_HZ) { usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ); } else { usb_bit_time = 1; }#endif dprintf("usb-ohci: usb_bit_time=%lli usb_frame_time=%lli\n", usb_frame_time, usb_bit_time); } ohci = (OHCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci), devfn, NULL, NULL); if (ohci == NULL) { fprintf(stderr, "usb-ohci: Failed to register PCI device\n"); return; } ohci->pci_dev.config[0x00] = vid & 0xff; ohci->pci_dev.config[0x01] = (vid >> 8) & 0xff; ohci->pci_dev.config[0x02] = did & 0xff; ohci->pci_dev.config[0x03] = (did >> 8) & 0xff; ohci->pci_dev.config[0x09] = 0x10; /* OHCI */ ohci->pci_dev.config[0x0a] = 0x3; ohci->pci_dev.config[0x0b] = 0xc; ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */ ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci); pci_register_io_region((struct PCIDevice *)ohci, 0, 256, PCI_ADDRESS_SPACE_MEM, ohci_mapfunc); ohci->num_ports = num_ports; for (i = 0; i < num_ports; i++) { qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); } ohci->async_td = 0; ohci_reset(ohci);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -