static void xhci_process_commands(XHCIState *xhci) { XHCITRB trb; TRBType type; XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS}; dma_addr_t addr; unsigned int i, slotid = 0; DPRINTF("xhci_process_commands()\n"); if (!xhci_running(xhci)) { DPRINTF("xhci_process_commands() called while xHC stopped or paused\n"); return; } xhci->crcr_low |= CRCR_CRR; while ((type = xhci_ring_fetch(xhci, &xhci->cmd_ring, &trb, &addr))) { event.ptr = addr; switch (type) { case CR_ENABLE_SLOT: for (i = 0; i < xhci->numslots; i++) { if (!xhci->slots[i].enabled) { break; } } if (i >= xhci->numslots) { DPRINTF("xhci: no device slots available\n"); event.ccode = CC_NO_SLOTS_ERROR; } else { slotid = i+1; event.ccode = xhci_enable_slot(xhci, slotid); } break; case CR_DISABLE_SLOT: slotid = xhci_get_slot(xhci, &event, &trb); if (slotid) { event.ccode = xhci_disable_slot(xhci, slotid); } break; case CR_ADDRESS_DEVICE: slotid = xhci_get_slot(xhci, &event, &trb); if (slotid) { event.ccode = xhci_address_slot(xhci, slotid, trb.parameter, trb.control & TRB_CR_BSR); } break; case CR_CONFIGURE_ENDPOINT: slotid = xhci_get_slot(xhci, &event, &trb); if (slotid) { event.ccode = xhci_configure_slot(xhci, slotid, trb.parameter, trb.control & TRB_CR_DC); } break; case CR_EVALUATE_CONTEXT: slotid = xhci_get_slot(xhci, &event, &trb); if (slotid) { event.ccode = xhci_evaluate_slot(xhci, slotid, trb.parameter); } break; case CR_STOP_ENDPOINT: slotid = xhci_get_slot(xhci, &event, &trb); if (slotid) { unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT) & TRB_CR_EPID_MASK; event.ccode = xhci_stop_ep(xhci, slotid, epid); } break; case CR_RESET_ENDPOINT: slotid = xhci_get_slot(xhci, &event, &trb); if (slotid) { unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT) & TRB_CR_EPID_MASK; event.ccode = xhci_reset_ep(xhci, slotid, epid); } break; case CR_SET_TR_DEQUEUE: slotid = xhci_get_slot(xhci, &event, &trb); if (slotid) { unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT) & TRB_CR_EPID_MASK; unsigned int streamid = (trb.status >> 16) & 0xffff; event.ccode = xhci_set_ep_dequeue(xhci, slotid, epid, streamid, trb.parameter); } break; case CR_RESET_DEVICE: slotid = xhci_get_slot(xhci, &event, &trb); if (slotid) { event.ccode = xhci_reset_slot(xhci, slotid); } break; case CR_GET_PORT_BANDWIDTH: event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter); break; case CR_VENDOR_VIA_CHALLENGE_RESPONSE: xhci_via_challenge(xhci, trb.parameter); break; case CR_VENDOR_NEC_FIRMWARE_REVISION: event.type = 48; /* NEC reply */ event.length = 0x3025; break; case CR_VENDOR_NEC_CHALLENGE_RESPONSE: { uint32_t chi = trb.parameter >> 32; uint32_t clo = trb.parameter; uint32_t val = xhci_nec_challenge(chi, clo); event.length = val & 0xFFFF; event.epid = val >> 16; slotid = val >> 24; event.type = 48; /* NEC reply */ } break; default: trace_usb_xhci_unimplemented("command", type); event.ccode = CC_TRB_ERROR; break; } event.slotid = slotid; xhci_event(xhci, &event, 0); } }