static int32 ohci_std_ops(int32 op, ...) { switch (op) { case B_MODULE_INIT: TRACE_MODULE("init module\n"); return B_OK; case B_MODULE_UNINIT: TRACE_MODULE("uninit module\n"); return B_OK; } return EINVAL; }
const usb_configuration_info * get_configuration(usb_device device) { TRACE_MODULE("get_configuration(%" B_PRId32 ")\n", device); Object *object = gUSBStack->GetObject(device); if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) return NULL; return ((Device *)object)->Configuration(); }
const usb_device_descriptor * get_device_descriptor(usb_device device) { TRACE_MODULE("get_device_descriptor(%" B_PRId32 ")\n", device); Object *object = gUSBStack->GetObject(device); if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) return NULL; return ((Device *)object)->DeviceDescriptor(); }
status_t clear_feature(usb_id handle, uint16 selector) { TRACE_MODULE("clear_feature(%" B_PRId32 ", %d)\n", handle, selector); Object *object = gUSBStack->GetObject(handle); if (!object) return B_DEV_INVALID_PIPE; return object->ClearFeature(selector); }
status_t set_alt_interface(usb_device device, const usb_interface_info *interface) { TRACE_MODULE("set_alt_interface(%" B_PRId32 ", %p)\n", device, interface); Object *object = gUSBStack->GetObject(device); if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) return B_DEV_INVALID_PIPE; return ((Device *)object)->SetAltInterface(interface); }
status_t cancel_queued_transfers(usb_pipe pipe) { TRACE_MODULE("cancel_queued_transfers(%" B_PRId32 ")\n", pipe); Object *object = gUSBStack->GetObject(pipe); if (!object || (object->Type() & USB_OBJECT_PIPE) == 0) return B_DEV_INVALID_PIPE; return ((Pipe *)object)->CancelQueuedTransfers(false); }
status_t set_configuration(usb_device device, const usb_configuration_info *configuration) { TRACE_MODULE("set_configuration(%" B_PRId32 ", %p)\n", device, configuration); Object *object = gUSBStack->GetObject(device); if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) return B_DEV_INVALID_PIPE; return ((Device *)object)->SetConfiguration(configuration); }
status_t get_status(usb_id handle, uint16 *status) { TRACE_MODULE("get_status(%" B_PRId32 ", %p)\n", handle, status); if (!status) return B_BAD_VALUE; Object *object = gUSBStack->GetObject(handle); if (!object) return B_DEV_INVALID_PIPE; return object->GetStatus(status); }
status_t set_pipe_policy(usb_pipe pipe, uint8 maxQueuedPackets, uint16 maxBufferDurationMS, uint16 sampleSize) { TRACE_MODULE("set_pipe_policy(%" B_PRId32 ", %d, %d, %d)\n", pipe, maxQueuedPackets, maxBufferDurationMS, sampleSize); Object *object = gUSBStack->GetObject(pipe); if (!object || (object->Type() & USB_OBJECT_ISO_PIPE) == 0) return B_DEV_INVALID_PIPE; return ((IsochronousPipe *)object)->SetPipePolicy(maxQueuedPackets, maxBufferDurationMS, sampleSize); }
status_t queue_bulk_v_physical(usb_pipe pipe, iovec *vector, size_t vectorCount, usb_callback_func callback, void *callbackCookie) { TRACE_MODULE("queue_bulk_v_physical(%" B_PRId32 ", %p, %" B_PRIuSIZE ", %p, %p)\n", pipe, vector, vectorCount, callback, callbackCookie); Object *object = gUSBStack->GetObject(pipe); if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0) return B_DEV_INVALID_PIPE; return ((BulkPipe *)object)->QueueBulkV(vector, vectorCount, callback, callbackCookie, true); }
status_t queue_interrupt(usb_pipe pipe, void *data, size_t dataLength, usb_callback_func callback, void *callbackCookie) { TRACE_MODULE("queue_interrupt(%" B_PRId32 ", %p, %ld, %p, %p)\n", pipe, data, dataLength, callback, callbackCookie); Object *object = gUSBStack->GetObject(pipe); if (!object || (object->Type() & USB_OBJECT_INTERRUPT_PIPE) == 0) return B_DEV_INVALID_PIPE; return ((InterruptPipe *)object)->QueueInterrupt(data, dataLength, callback, callbackCookie); }
status_t queue_bulk(usb_pipe pipe, void *data, size_t dataLength, usb_callback_func callback, void *callbackCookie) { TRACE_MODULE("queue_bulk(%" B_PRId32 ", %p, %" B_PRIuSIZE ", %p, %p)\n", pipe, data, dataLength, callback, callbackCookie); Object *object = gUSBStack->GetObject(pipe); if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0) return B_DEV_INVALID_PIPE; return ((BulkPipe *)object)->QueueBulk(data, dataLength, callback, callbackCookie); }
status_t get_descriptor(usb_device device, uint8 type, uint8 index, uint16 languageID, void *data, size_t dataLength, size_t *actualLength) { TRACE_MODULE("get_descriptor(%" B_PRId32 ", 0x%02x, 0x%02x, 0x%04x, %p, " "%" B_PRIuSIZE ", %p)\n", device, type, index, languageID, data, dataLength, actualLength); Object *object = gUSBStack->GetObject(device); if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) return B_DEV_INVALID_PIPE; return ((Device *)object)->GetDescriptor(type, index, languageID, data, dataLength, actualLength); }
status_t send_request(usb_device device, uint8 requestType, uint8 request, uint16 value, uint16 index, uint16 length, void *data, size_t *actualLength) { TRACE_MODULE("send_request(%" B_PRId32 ", 0x%02x, 0x%02x, 0x%04x, 0x%04x, " "%d, %p, %p)\n", device, requestType, request, value, index, length, data, actualLength); Object *object = gUSBStack->GetObject(device); if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) return B_DEV_INVALID_PIPE; return ((Device *)object)->DefaultPipe()->SendRequest(requestType, request, value, index, length, data, length, actualLength); }
status_t queue_request(usb_device device, uint8 requestType, uint8 request, uint16 value, uint16 index, uint16 length, void *data, usb_callback_func callback, void *callbackCookie) { TRACE_MODULE("queue_request(%" B_PRId32 ", 0x%02x, 0x%02x, 0x%04x, 0x%04x," " %u, %p, %p, %p)\n", device, requestType, request, value, index, length, data, callback, callbackCookie); Object *object = gUSBStack->GetObject(device); if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) return B_DEV_INVALID_PIPE; return ((Device *)object)->DefaultPipe()->QueueRequest(requestType, request, value, index, length, data, length, callback, callbackCookie); }
status_t queue_isochronous(usb_pipe pipe, void *data, size_t dataLength, usb_iso_packet_descriptor *packetDesc, uint32 packetCount, uint32 *startingFrameNumber, uint32 flags, usb_callback_func callback, void *callbackCookie) { TRACE_MODULE("queue_isochronous(%" B_PRId32 ", %p, %" B_PRIuSIZE ", %p, " "%" B_PRId32 ", %p, 0x%08" B_PRIx32 ", %p, %p)\n", pipe, data, dataLength, packetDesc, packetCount, startingFrameNumber, flags, callback, callbackCookie); Object *object = gUSBStack->GetObject(pipe); if (!object || (object->Type() & USB_OBJECT_ISO_PIPE) == 0) return B_DEV_INVALID_PIPE; return ((IsochronousPipe *)object)->QueueIsochronous(data, dataLength, packetDesc, packetCount, startingFrameNumber, flags, callback, callbackCookie); }
status_t usb_ioctl(uint32 opcode, void *buffer, size_t bufferSize) { TRACE_MODULE("usb_ioctl(%" B_PRIu32 ", %p, %" B_PRIuSIZE ")\n", opcode, buffer, bufferSize); switch (opcode) { case 'DNAM': { Object *object = gUSBStack->GetObject(*(usb_id *)buffer); if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) return B_BAD_VALUE; uint32 index = 0; return ((Device *)object)->BuildDeviceName((char *)buffer, &index, bufferSize, NULL); } } return B_DEV_INVALID_IOCTL; }
status_t OHCI::AddTo(Stack *stack) { #ifdef TRACE_USB set_dprintf_enabled(true); #ifndef ANTARES_TARGET_PLATFORM_ANTARES load_driver_symbols("ohci"); #endif #endif if (!sPCIModule) { status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); if (status < B_OK) { TRACE_MODULE_ERROR("getting pci module failed! 0x%08lx\n", status); return status; } } TRACE_MODULE("searching devices\n"); bool found = false; pci_info *item = new(std::nothrow) pci_info; if (!item) { sPCIModule = NULL; put_module(B_PCI_MODULE_NAME); return B_NO_MEMORY; } for (uint32 i = 0 ; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb && item->class_api == PCI_usb_ohci) { if (item->u.h0.interrupt_line == 0 || item->u.h0.interrupt_line == 0xFF) { TRACE_MODULE_ERROR("found device with invalid IRQ -" " check IRQ assignement\n"); continue; } TRACE_MODULE("found device at IRQ %u\n", item->u.h0.interrupt_line); OHCI *bus = new(std::nothrow) OHCI(item, stack); if (!bus) { delete item; sPCIModule = NULL; put_module(B_PCI_MODULE_NAME); return B_NO_MEMORY; } if (bus->InitCheck() < B_OK) { TRACE_MODULE_ERROR("bus failed init check\n"); delete bus; continue; } // the bus took it away item = new(std::nothrow) pci_info; bus->Start(); stack->AddBusManager(bus); found = true; } } if (!found) { TRACE_MODULE_ERROR("no devices found\n"); delete item; sPCIModule = NULL; put_module(B_PCI_MODULE_NAME); return ENODEV; } delete item; return B_OK; }
int32 OHCI::_Interrupt() { static spinlock lock = B_SPINLOCK_INITIALIZER; acquire_spinlock(&lock); uint32 status = 0; uint32 acknowledge = 0; bool finishTransfers = false; int32 result = B_HANDLED_INTERRUPT; // The LSb of done_head is used to inform the HCD that an interrupt // condition exists for both the done list and for another event recorded in // the HcInterruptStatus register. If done_head is 0, then the interrupt // was caused by other than the HccaDoneHead update and the // HcInterruptStatus register needs to be accessed to determine that exact // interrupt cause. If HccDoneHead is nonzero, then a done list update // interrupt is indicated and if the LSb of the Dword is nonzero, then an // additional interrupt event is indicated and HcInterruptStatus should be // checked to determine its cause. uint32 doneHead = fHcca->done_head; if (doneHead != 0) { status = OHCI_WRITEBACK_DONE_HEAD; if (doneHead & OHCI_DONE_INTERRUPTS) status |= _ReadReg(OHCI_INTERRUPT_STATUS) & _ReadReg(OHCI_INTERRUPT_ENABLE); } else { status = _ReadReg(OHCI_INTERRUPT_STATUS) & _ReadReg(OHCI_INTERRUPT_ENABLE) & ~OHCI_WRITEBACK_DONE_HEAD; if (status == 0) { // Nothing to be done (PCI shared interrupt) release_spinlock(&lock); return B_UNHANDLED_INTERRUPT; } } if (status & OHCI_SCHEDULING_OVERRUN) { TRACE_MODULE("scheduling overrun occured\n"); acknowledge |= OHCI_SCHEDULING_OVERRUN; } if (status & OHCI_WRITEBACK_DONE_HEAD) { TRACE_MODULE("transfer descriptors processed\n"); fHcca->done_head = 0; acknowledge |= OHCI_WRITEBACK_DONE_HEAD; result = B_INVOKE_SCHEDULER; finishTransfers = true; } if (status & OHCI_RESUME_DETECTED) { TRACE_MODULE("resume detected\n"); acknowledge |= OHCI_RESUME_DETECTED; } if (status & OHCI_UNRECOVERABLE_ERROR) { TRACE_MODULE_ERROR("unrecoverable error - controller halted\n"); _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); // TODO: clear all pending transfers, reset and resetup the controller } if (status & OHCI_ROOT_HUB_STATUS_CHANGE) { TRACE_MODULE("root hub status change\n"); // Disable the interrupt as it will otherwise be retriggered until the // port has been reset and the change is cleared explicitly. // TODO: renable it once we use status changes instead of polling _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ROOT_HUB_STATUS_CHANGE); acknowledge |= OHCI_ROOT_HUB_STATUS_CHANGE; } if (acknowledge != 0) _WriteReg(OHCI_INTERRUPT_STATUS, acknowledge); release_spinlock(&lock); if (finishTransfers) release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); return result; }
static int32 bus_std_ops(int32 op, ...) { switch (op) { case B_MODULE_INIT: { TRACE_MODULE("init\n"); if (gUSBStack) return B_OK; #ifdef HAIKU_TARGET_PLATFORM_BEOS // This code is to handle plain R5 (non-BONE) where the same module // gets loaded multiple times (once for each exported module // interface, the USB v2 and v3 API in our case). We don't want to // ever create multiple stacks however, so we "share" the same stack // for both modules by storing it's address in a shared area. void *address = NULL; area_id shared = find_area("shared usb stack"); if (shared >= B_OK && clone_area("usb stack clone", &address, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, shared) >= B_OK) { gUSBStack = *((Stack **)address); TRACE_MODULE("found shared stack at %p\n", gUSBStack); return B_OK; } #endif #ifdef TRACE_USB set_dprintf_enabled(true); #ifndef HAIKU_TARGET_PLATFORM_HAIKU load_driver_symbols("usb"); #endif #endif Stack *stack = new(std::nothrow) Stack(); TRACE_MODULE("usb_module: stack created %p\n", stack); if (!stack) return B_NO_MEMORY; if (stack->InitCheck() != B_OK) { delete stack; return ENODEV; } gUSBStack = stack; #ifdef HAIKU_TARGET_PLATFORM_HAIKU add_debugger_command("get_usb_pipe_for_id", &debug_get_pipe_for_id, "Gets the config for a USB pipe"); #elif HAIKU_TARGET_PLATFORM_BEOS // Plain R5 workaround, see comment above. shared = create_area("shared usb stack", &address, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_NO_LOCK, B_KERNEL_WRITE_AREA); if (shared >= B_OK) *((Stack **)address) = gUSBStack; #endif break; } case B_MODULE_UNINIT: TRACE_MODULE("uninit\n"); delete gUSBStack; gUSBStack = NULL; #ifdef HAIKU_TARGET_PLATFORM_HAIKU remove_debugger_command("get_usb_pipe_for_id", &debug_get_pipe_for_id); #endif break; default: return EINVAL; } return B_OK; }
status_t OHCIRootHub::ProcessTransfer(OHCI *ohci, Transfer *transfer) { if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0) return B_ERROR; usb_request_data *request = transfer->RequestData(); TRACE_MODULE("request: %d\n", request->Request); status_t status = B_TIMED_OUT; size_t actualLength = 0; switch (request->Request) { case USB_REQUEST_GET_STATUS: { if (request->Index == 0) { // get hub status actualLength = MIN(sizeof(usb_port_status), transfer->DataLength()); // the hub reports whether the local power failed (bit 0) // and if there is a over-current condition (bit 1). // everything as 0 means all is ok. memset(transfer->Data(), 0, actualLength); status = B_OK; break; } usb_port_status portStatus; if (ohci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) { actualLength = MIN(sizeof(usb_port_status), transfer->DataLength()); memcpy(transfer->Data(), (void *)&portStatus, actualLength); status = B_OK; } break; } case USB_REQUEST_SET_ADDRESS: if (request->Value >= 128) { status = B_TIMED_OUT; break; } TRACE_MODULE("set address: %d\n", request->Value); status = B_OK; break; case USB_REQUEST_GET_DESCRIPTOR: TRACE_MODULE("get descriptor: %d\n", request->Value >> 8); switch (request->Value >> 8) { case USB_DESCRIPTOR_DEVICE: { actualLength = MIN(sizeof(usb_device_descriptor), transfer->DataLength()); memcpy(transfer->Data(), (void *)&sOHCIRootHubDevice, actualLength); status = B_OK; break; } case USB_DESCRIPTOR_CONFIGURATION: { actualLength = MIN(sizeof(ohci_root_hub_configuration_s), transfer->DataLength()); sOHCIRootHubConfig.hub.num_ports = ohci->PortCount(); memcpy(transfer->Data(), (void *)&sOHCIRootHubConfig, actualLength); status = B_OK; break; } case USB_DESCRIPTOR_STRING: { uint8 index = request->Value & 0x00ff; if (index > 2) break; actualLength = MIN(sOHCIRootHubStrings[index].length, transfer->DataLength()); memcpy(transfer->Data(), (void *)&sOHCIRootHubStrings[index], actualLength); status = B_OK; break; } case USB_DESCRIPTOR_HUB: { actualLength = MIN(sizeof(usb_hub_descriptor), transfer->DataLength()); sOHCIRootHubConfig.hub.num_ports = ohci->PortCount(); memcpy(transfer->Data(), (void *)&sOHCIRootHubConfig.hub, actualLength); status = B_OK; break; } } break; case USB_REQUEST_SET_CONFIGURATION: status = B_OK; break; case USB_REQUEST_CLEAR_FEATURE: { if (request->Index == 0) { // we don't support any hub changes TRACE_MODULE_ERROR("clear feature: no hub changes\n"); break; } TRACE_MODULE("clear feature: %d\n", request->Value); if (ohci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK) status = B_OK; break; } case USB_REQUEST_SET_FEATURE: { if (request->Index == 0) { // we don't support any hub changes TRACE_MODULE_ERROR("set feature: no hub changes\n"); break; } TRACE_MODULE("set feature: %d\n", request->Value); if (ohci->SetPortFeature(request->Index - 1, request->Value) >= B_OK) status = B_OK; break; } } transfer->Finished(status, actualLength); delete transfer; return B_OK; }