/* Attach or detach a device on a root hub port. */ static void ohci_attach(USBPort *port1, USBDevice *dev) { OHCIState *s = port1->opaque; OHCIPort *port = &s->rhport[port1->index]; uint32_t old_state = port->ctrl; if (dev) { if (port->port.dev) { usb_attach(port1, NULL); } /* set connect status */ port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; /* update speed */ if (dev->speed == USB_SPEED_LOW) port->ctrl |= OHCI_PORT_LSDA; else port->ctrl &= ~OHCI_PORT_LSDA; port->port.dev = dev; /* notify of remote-wakeup */ if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) ohci_set_interrupt(s, OHCI_INTR_RD); /* send the attach message */ usb_send_msg(dev, USB_MSG_ATTACH); dprintf("usb-ohci: Attached port %d\n", port1->index); } else { /* set connect status */ if (port->ctrl & OHCI_PORT_CCS) { port->ctrl &= ~OHCI_PORT_CCS; port->ctrl |= OHCI_PORT_CSC; } /* disable port */ if (port->ctrl & OHCI_PORT_PES) { port->ctrl &= ~OHCI_PORT_PES; port->ctrl |= OHCI_PORT_PESC; } dev = port->port.dev; if (dev) { /* send the detach message */ usb_send_msg(dev, USB_MSG_DETACH); } port->port.dev = NULL; dprintf("usb-ohci: Detached port %d\n", port1->index); } if (old_state != port->ctrl) ohci_set_interrupt(s, OHCI_INTR_RHSC); }
/* 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); }
/* Do frame processing on frame boundary */ static void ohci_frame_boundary(void *opaque) { OHCIState *ohci = opaque; struct ohci_hcca hcca; ohci_read_hcca(ohci, ohci->hcca, &hcca); /* Process all the lists at the end of the frame */ if (ohci->ctl & OHCI_CTL_PLE) { int n; n = ohci->frame_number & 0x1f; ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0); } /* Cancel all pending packets if either of the lists has been disabled. */ if (ohci->async_td && ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; } ohci->old_ctl = ohci->ctl; ohci_process_lists(ohci, 0); /* Frame boundary, so do EOF stuf here */ ohci->frt = ohci->fit; /* Increment frame number and take care of endianness. */ ohci->frame_number = (ohci->frame_number + 1) & 0xffff; hcca.frame = cpu_to_le16(ohci->frame_number); if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) { if (!ohci->done) abort(); if (ohci->intr & ohci->intr_status) ohci->done |= 1; hcca.done = cpu_to_le32(ohci->done); ohci->done = 0; ohci->done_count = 7; ohci_set_interrupt(ohci, OHCI_INTR_WD); } if (ohci->done_count != 7 && ohci->done_count != 0) ohci->done_count--; /* Do SOF stuff here */ ohci_sof(ohci); /* Writeback HCCA */ ohci_put_hcca(ohci, ohci->hcca, &hcca); }
/* 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 void ohci_detach(USBPort *port1) { OHCIState *s = port1->opaque; OHCIPort *port = &s->rhport[port1->index]; uint32_t old_state = port->ctrl; /* set connect status */ if (port->ctrl & OHCI_PORT_CCS) { port->ctrl &= ~OHCI_PORT_CCS; port->ctrl |= OHCI_PORT_CSC; } /* disable port */ if (port->ctrl & OHCI_PORT_PES) { port->ctrl &= ~OHCI_PORT_PES; port->ctrl |= OHCI_PORT_PESC; } DPRINTF("usb-ohci: Detached port %d\n", port1->index); if (old_state != port->ctrl) ohci_set_interrupt(s, OHCI_INTR_RHSC); }
/* Attach or detach a device on a root hub port. */ static void ohci_attach(USBPort *port1) { OHCIState *s = port1->opaque; OHCIPort *port = &s->rhport[port1->index]; /* set connect status */ port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; /* update speed */ if (port->port.dev->speed == USB_SPEED_LOW) { port->ctrl |= OHCI_PORT_LSDA; } else { port->ctrl &= ~OHCI_PORT_LSDA; } /* notify of remote-wakeup */ if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { ohci_set_interrupt(s, OHCI_INTR_RD); } DPRINTF("usb-ohci: Attached port %d\n", port1->index); }
/* Generate a SOF event, and set a timer for EOF */ static void ohci_sof(OHCIState *ohci) { ohci->sof_time = qemu_get_clock_ns(vm_clock); qemu_mod_timer(ohci->eof_timer, ohci->sof_time + usb_frame_time); ohci_set_interrupt(ohci, OHCI_INTR_SF); }