/** * \brief Submit a bulk transfer to the device. * * This method allocates and fills the bulk transfer, and submits it to * the libusb_submit_transfer function. It then starts to handle events, * and only returns when the complete flag is set. * \param dev_handle the libusb device handle */ void BulkTransfer::submit(libusb_device_handle *dev_handle) throw(USBError) { // allocate the transfer structure transfer = libusb_alloc_transfer(0); // fill the transfer libusb_fill_bulk_transfer(transfer, dev_handle, endpoint->bEndpointAddress(), data, length, bulktransfer_callback, this, timeout); // submit the transfer debug(LOG_DEBUG, DEBUG_LOG, 0, "submitting bulk transfer, timeout = %d", timeout); int rc = libusb_submit_transfer(transfer); if (rc != LIBUSB_SUCCESS) { throw USBError(libusb_error_name(rc)); } // handle events until the complete flag is set libusb_context *ctx = getContext(); while (!complete) { libusb_handle_events(ctx); } // at this point, the transfer has somehow completed, but we // don't know yet what happened. const char *cause = usb_status_name(transfer->status); if (NULL != cause) { debug(LOG_ERR, DEBUG_LOG, 0, "transfer failed: %s", cause); throw USBError(cause); } else { debug(LOG_DEBUG, DEBUG_LOG, 0, "transfer complete, %d bytes", transfer->actual_length); } }
/** * \brief Submit a bulk transfer to the device. * * This method allocates and fills the bulk transfer, and submits it to * the libusb_submit_transfer function. It then starts to handle events, * and only returns when the complete flag is set. * \param dev_handle the libusb device handle */ void BulkTransfer::submit(libusb_device_handle *dev_handle) throw(USBError) { // allocate the transfer structure transfer = libusb_alloc_transfer(0); // fill the transfer libusb_fill_bulk_transfer(transfer, dev_handle, endpoint->bEndpointAddress(), data, length, bulktransfer_callback, this, timeout); // submit the transfer int rc = libusb_submit_transfer(transfer); if (rc != LIBUSB_SUCCESS) { throw USBError(libusb_error_name(rc)); } // handle events until the complete flag is set libusb_context *ctx = getContext(); while (!complete) { libusb_handle_events(ctx); } // at this point, the transfer has somehow completed, but we // don't know yet what happened. const char *cause = NULL; switch (transfer->status) { case LIBUSB_TRANSFER_ERROR: cause = "transfer error"; break; case LIBUSB_TRANSFER_TIMED_OUT: cause = "transfer timed out"; break; case LIBUSB_TRANSFER_CANCELLED: cause = "transfer cancelled"; break; case LIBUSB_TRANSFER_STALL: cause = "transfer stall"; break; case LIBUSB_TRANSFER_NO_DEVICE: cause = "transfer no device"; break; case LIBUSB_TRANSFER_OVERFLOW: cause = "transfer overflow"; break; case LIBUSB_TRANSFER_COMPLETED: break; } if (NULL != cause) { debug(LOG_ERR, DEBUG_LOG, 0, "transfer failed: %s", cause); throw USBError(cause); } else { debug(LOG_DEBUG, DEBUG_LOG, 0, "transfer complete, %d bytes", transfer->actual_length); } }
/** * \brief Get active configuaration descriptor. * * This method returns the active device descriptor. The device has to * be open for this to work. This is a restriction imposed by a bug in * libusb-1.0: on Mac OS X, the library causes a segmentation fault when * trying to retrieve the active configuration descriptor of a device that * was not opened. Although it works on other platforms (e.g. Linux), * by enforcing this restriction on all platforms we ensure that code * in Linux cannot inadvertently trigger this bug and cause segementation * faults on Mac OS X. */ ConfigurationPtr Device::activeConfig() throw(USBError) { if (!isOpen()) { throw USBError("device not open"); } struct libusb_config_descriptor *config = NULL; int rc = libusb_get_active_config_descriptor(dev, &config); if (rc != LIBUSB_SUCCESS) { throw USBError(libusb_error_name(rc)); } Configuration *result = new Configuration(*this, config); libusb_free_config_descriptor(config); return ConfigurationPtr(result); }
bool Device::kernelDriverActive(uint8_t interface) const throw(USBError) { int rc = libusb_kernel_driver_active(dev_handle, interface); if (rc < 0) { throw USBError(libusb_error_name(rc)); } return (rc) ? true : false; }
/** * \brief Select a configuration by number * * \param configuration number of the configuration to select. */ void Device::setConfiguration(uint8_t configuration) throw (USBError) { int rc = libusb_set_configuration(dev_handle, configuration); if (rc != LIBUSB_SUCCESS) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot set configuration %d: %s", configuration, libusb_error_name(rc)); throw USBError(libusb_error_name(rc)); } }
void Device::attachKernelDriver(uint8_t interface) const throw(USBError) { int rc = libusb_attach_kernel_driver(dev_handle, interface); if (rc < 0) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot attach kernel driver: %s", libusb_error_name(rc)); throw USBError(libusb_error_name(rc)); } }
void Device::claimInterface(uint8_t interface) throw(USBError) { debug(LOG_DEBUG, DEBUG_LOG, 0, "claiming interface %d", interface); int rc = libusb_claim_interface(dev_handle, interface); if (rc != LIBUSB_SUCCESS) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot claim interface %d: %s", interface, libusb_error_name(rc)); throw USBError(libusb_error_name(rc)); } }
/** * \brief Get configuration by value. * * \param value configuration value to search for. */ ConfigurationPtr Device::configValue(uint8_t value) throw(USBError) { struct libusb_config_descriptor *config; int rc = libusb_get_config_descriptor_by_value(dev, value, &config); if (rc != LIBUSB_SUCCESS) { throw USBError(libusb_error_name(rc)); } Configuration *result = new Configuration(*this, config); libusb_free_config_descriptor(config); return ConfigurationPtr(result); }
/** * \brief Execute a control request. * * All information necessary to execute a control request to the device * is contained in the request argument. This method just sends the * contents of the request to the device. If the request includes * a data phase, then the direction of the data phase was encoded in * the request when the request was constructed. * * \param request pointer to the control request */ void Device::controlRequest(RequestBase *request) throw(USBError) { debug(LOG_DEBUG, DEBUG_LOG, 0, "bmRequest = %02x, bRequest = %02x, " "wValue = %04x, wIndex = %04x, wLength = %d", request->bmRequestType(), request->bRequest(), request->wValue(), request->wIndex(), request->wLength()); // for debugging, display the request content if it is going to // the host if ((request->bmRequestType() & 0x80) == RequestBase::host_to_device) { debug(LOG_DEBUG, DEBUG_LOG, 0, "payload to send:\n%s", request->payloadHex().c_str()); } int rc = libusb_control_transfer(dev_handle, request->bmRequestType(), request->bRequest(), request->wValue(), request->wIndex(), request->payload(), request->wLength(), request->getTimeout()); debug(LOG_DEBUG, DEBUG_LOG, 0, "control request result: %d", rc); if (rc < 0) { throw USBError(libusb_error_name(rc)); } // for debuggung: if the data phase goes from device to host, display // the response if ((request->bmRequestType() & 0x80) == RequestBase::device_to_host) { debug(LOG_DEBUG, DEBUG_LOG, 0, "payload received:\n%s", request->payloadHex().c_str()); } // only accept the response if it has the right length, otherwise // throw an exception if ((rc != request->wLength()) && (!request->accept_short_response)) { std::string message = stringprintf("expecting %d bytes, %d received", request->wLength(), rc); std::cerr << request->payloadHex(); throw USBError(message.c_str()); } }
/** * \brief Select an alternate setting on an interface. * * * \param interface interface number * \param altsetting number of alternate setting */ void Device::setInterfaceAltSetting(uint8_t interface, uint8_t altsetting) throw(USBError) { int rc = libusb_set_interface_alt_setting(dev_handle, interface, altsetting); if (rc != LIBUSB_SUCCESS) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot set altsetting %d: %s", altsetting, libusb_error_name(rc)); throw USBError(libusb_error_name(rc)); } }
/** * \brief Get the number of the current configuration. * * \return configuration number */ int Device::getConfiguration() throw(USBError) { int result; int rc = libusb_get_configuration(dev_handle, &result); if (rc != LIBUSB_SUCCESS) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot get configuration: %s", libusb_error_name(rc)); throw USBError(libusb_error_name(rc)); } return result; }
/** * \brief Compute which is the preferred alternate setting for this interface * * \param interface interface number of the streaming interface */ int UVCCamera::preferredAltSetting(uint8_t interface) { // get the currently negotiated settings getCur(interface); // if the frame interval is 0, we have to ask the format for // the default frame interval if (0 == frameinterval) { debug(LOG_WARNING, DEBUG_LOG, 0, "warning: no negotiated frame interval"); frameinterval = 333333; } // compute the data rate double datarate = maxvideoframesize * (10000000. / frameinterval); debug(LOG_DEBUG, DEBUG_LOG, 0, "required data rate: %.1fMBps", datarate / 1000000.); // for this software, bulk transfers are preferable, if the // device supports them, so we check whether alt setting 0 has a // bulk endpoint, and return 0 in that case InterfacePtr interfaceptr = (*device.activeConfig())[interface]; InterfaceDescriptorPtr ifdescptr = (*interfaceptr)[0]; if (ifdescptr->numEndpoints() > 0) { EndpointDescriptorPtr endpointptr = (*ifdescptr)[0]; if (endpointptr->isBulk()) { return 0; } } // if there was no bulk endpoint, then we have to find an alternate // setting that provides enough bandwidth. So we go through all // the alternate settings and their endpoints and compute the // bandwidth they provide. As soon as we find a suitable setting // we return that. Apparently cameras usually order alt settings // with increasing bandwidth, so this algorithm should be good // enough. for (size_t alt = 1; alt <= interfaceptr->numAltsettings(); alt++) { ifdescptr = (*interfaceptr)[alt]; EndpointDescriptorPtr endpointptr = (*ifdescptr)[0]; size_t maxbandwidth = endpointptr->maxBandwidth(); if (maxbandwidth > datarate) { debug(LOG_DEBUG, DEBUG_LOG, 0, "first alt setting " "matching data rate %.1fMBps: %d (%.1fMBps)", datarate / 1000000., alt, maxbandwidth / 1000000.); return alt; } } // if we get to this point, then we did not find a suitable alternate // setting, then there is no way we can satisfy the bandwidth // requirements of this camera. so we have to throw an exception throw USBError("no alternate setting with enough bandwidth found"); }
void Device::releaseInterface(uint8_t interface) throw(USBError) { debug(LOG_DEBUG, DEBUG_LOG, 0, "releasing interface %d", interface); int rc = libusb_release_interface(dev_handle, interface); rc = libusb_release_interface(dev_handle, interface); if (rc != LIBUSB_SUCCESS) { debug(LOG_ERR, DEBUG_LOG, 0, "cannot release interface %d: %s", interface, libusb_error_name(rc)); throw USBError(libusb_error_name(rc)); } debug(LOG_DEBUG, DEBUG_LOG, 0, "interface released"); }
DeviceDescriptorPtr Device::descriptor() throw(USBError) { // get the device descriptor libusb_device_descriptor d; int rc = libusb_get_device_descriptor(dev, &d); if (rc != LIBUSB_SUCCESS) { throw USBError(libusb_error_name(rc)); } // create a DeviceDescriptor object DeviceDescriptor *devdesc = new DeviceDescriptor(*this, &d); return DeviceDescriptorPtr(devdesc); }
/** * \brief Open the device. * * Most operations need that a USB device that is open. During a bus * scan, we may want to look at a device that is not open, so the default * is to just get a device, but not to open it. This method also opens * the device. */ void Device::open() throw(USBError) { debug(LOG_DEBUG, DEBUG_LOG, 0, "open the device"); // handle the case where the device has already been opened if (isOpen()) { return; } // the device is not open yet, so open it int rc = libusb_open(dev, &dev_handle); if (rc != LIBUSB_SUCCESS) { throw USBError(libusb_error_name(rc)); } }
//================================================================================================ // // RestartControllerFromReset // //================================================================================================ // IOReturn AppleUSBOHCI::RestartControllerFromReset(void) { UInt32 newValue; USBTrace( kUSBTOHCI, KTPOHCIRestartControllerFromReset, (uintptr_t)this, _uimInitialized, 0, 0); USBLog(3, "AppleUSBOHCI[%p]::RestartControllerFromReset - Re-loading UIM if necessary (%d)", this, _uimInitialized ); // first, reinit the op regs InitializeOperationalRegisters(); // Set OHCI to operational state and enable processing of control list. _pOHCIRegisters->hcControl = HostToUSBLong(kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase); IOSync(); IOSleep(3); // wait the required 3 ms before turning on the lists // <rdar://problem/5981624> We need to make sure that the DRWE bit is properly set any time we go to the operational state newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); if (!(newValue & kOHCIHcRhStatus_DRWE)) { _pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE); IOSync(); if (_errataBits & kErrataNECIncompleteWrite) { UInt32 count = 0; newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); // this bit SHOULD now be set while ((count++ < 10) && !(newValue & kOHCIHcRhStatus_DRWE)) { USBError(1, "OHCI driver::RestartControllerFromReset - DRWE bit not sticking. Retrying."); _pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE); IOSync(); newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); } } } _pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase) | kOHCIHcControl_CLE | (_OptiOn ? kOHCIHcControl_Zero : kOHCIHcControl_BLE) | kOHCIHcControl_PLE | kOHCIHcControl_IE); IOSync(); OHCIRootHubPower(1 /* kOn */); _myBusState = kUSBBusStateRunning; return kIOReturnSuccess; }
//================================================================================================ // // ResetControllerState // //================================================================================================ // IOReturn AppleUSBUHCI::ResetControllerState(void) { UInt32 value; int i; USBTrace( kUSBTUHCI, KTPUHCIResetControllerState, (uintptr_t)this, 0, 0, 0); USBLog(5, "AppleUSBUHCI[%p]::+ResetControllerState", this); // reset the controller Command(kUHCI_CMD_HCRESET); for(i=0; (i < kUHCI_RESET_DELAY) && (ioRead16(kUHCI_CMD) & kUHCI_CMD_HCRESET); i++) { IOSleep(1); } if (i >= kUHCI_RESET_DELAY) { USBError(1, "AppleUSBUHCI::ResetControllerStatecontroller - reset failed"); return kIOReturnTimeout; } USBLog(5, "AppleUSBUHCI[%p]::ResetControllerStatecontroller - reset done after %d spins", this, i); // restore the frame list register if (_framesPaddr != NULL) { ioWrite32(kUHCI_FRBASEADDR, _framesPaddr); } for (i = 0; i < kUHCI_NUM_PORTS; i++) { _lastPortStatus[i] = 0; } // Use 64-byte packets, and mark controller as configured Command(kUHCI_CMD_MAXP | kUHCI_CMD_CF); USBLog(5, "AppleUSBUHCI[%p]::-ResetControllerState", this); return kIOReturnSuccess; }
IOReturn IOUSBCommandPool::gatedReturnCommand(IOCommand * command) { IOUSBCommand *usbCommand = OSDynamicCast(IOUSBCommand, command); // only one of these should be non-null IOUSBIsocCommand *isocCommand = OSDynamicCast(IOUSBIsocCommand, command); USBLog(7,"IOUSBCommandPool[%p]::gatedReturnCommand %p", this, command); if (!command) { #if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION panic("IOUSBCommandPool::gatedReturnCommand( NULL )"); #endif return kIOReturnBadArgument; } if (command->fCommandChain.next && (&command->fCommandChain != command->fCommandChain.next || &command->fCommandChain != command->fCommandChain.prev)) { #if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION kprintf("WARNING: gatedReturnCommand(%p) already on queue [next=%p prev=%p]\n", command, command->fCommandChain.next, command->fCommandChain.prev); panic("IOUSBCommandPool::gatedReturnCommand already on queue"); #endif char* bt[8]; OSBacktrace((void**)bt, 8); USBError(1,"IOUSBCommandPool::gatedReturnCommand command already in queue, not putting it back into the queue, bt: [%p][%p][%p][%p][%p][%p][%p][%p]", bt[0], bt[1], bt[2], bt[3], bt[4], bt[5], bt[6], bt[7]); return kIOReturnBadArgument; } if (usbCommand) { IODMACommand *dmaCommand = usbCommand->GetDMACommand(); if (dmaCommand) { if (dmaCommand->getMemoryDescriptor()) { USBError(1, "IOUSBCommandPool::gatedReturnCommand - command (%p) still has dmaCommand(%p) with an active memory descriptor(%p)", usbCommand, dmaCommand, dmaCommand->getMemoryDescriptor()); #if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION panic("IOUSBCommandPool::gatedReturnCommand -dmaCommand still has active IOMD"); #endif } } else { USBError(1,"IOUSBCommandPool::gatedReturnCommand - missing dmaCommand in IOUSBCommand"); } // Test to poison the IOUSBCommand when returning it #if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION { char* bt[kUSBCommandScratchBuffers]; OSBacktrace((void**)bt, kUSBCommandScratchBuffers); for ( int i=0; i < kUSBCommandScratchBuffers; i++) usbCommand->SetBT(i, bt[i]); } #endif // Clean up the command before returning it IOUSBCompletion nullCompletion; nullCompletion.target = (void *) POISONVALUE; nullCompletion.action = (IOUSBCompletionAction) NULL; nullCompletion.parameter = (void *) POISONVALUE; usbCommand->SetSelector(INVALID_SELECTOR); usbCommand->SetRequest((IOUSBDeviceRequestPtr) POISONVALUE); usbCommand->SetAddress(0xFF); usbCommand->SetEndpoint(0xFF); usbCommand->SetDirection(0xFF); usbCommand->SetType(0xFF); usbCommand->SetBufferRounding(false); usbCommand->SetBuffer((IOMemoryDescriptor *) POISONVALUE); usbCommand->SetUSLCompletion(nullCompletion); usbCommand->SetClientCompletion(nullCompletion); usbCommand->SetDataRemaining(POISONVALUE); usbCommand->SetStage(0xFF); usbCommand->SetStatus(POISONVALUE); usbCommand->SetOrigBuffer((IOMemoryDescriptor *) POISONVALUE); usbCommand->SetDisjointCompletion(nullCompletion); usbCommand->SetDblBufLength(POISONVALUE); usbCommand->SetNoDataTimeout(POISONVALUE); usbCommand->SetCompletionTimeout(POISONVALUE); usbCommand->SetReqCount(POISONVALUE); usbCommand->SetMultiTransferTransaction(true); usbCommand->SetFinalTransferInTransaction(true); usbCommand->SetUseTimeStamp(true); usbCommand->SetIsSyncTransfer(FALSE); for ( int i=0; i < kUSBCommandScratchBuffers; i++) usbCommand->SetUIMScratch(i, POISONVALUE); usbCommand->SetStreamID(POISONVALUE); if ( usbCommand->GetBufferUSBCommand() != NULL ) { USBError(1,"IOUSBCommandPool::gatedReturnCommand - GetBufferUSBCommand() is not NULL"); } if ( usbCommand->GetRequestMemoryDescriptor() != NULL ) { USBError(1,"IOUSBCommandPool::gatedReturnCommand - GetRequestMemoryDescriptor() is not NULL"); } if ( usbCommand->GetBufferMemoryDescriptor() != NULL ) { USBError(1,"IOUSBCommandPool::gatedReturnCommand - GetBufferMemoryDescriptor() is not NULL"); } // Do not see these to anything but NULL as a lot of the code depends on checking for NULLness usbCommand->SetBufferUSBCommand(NULL); usbCommand->SetRequestMemoryDescriptor(NULL); usbCommand->SetBufferMemoryDescriptor(NULL); } if (isocCommand) { IODMACommand *dmaCommand = isocCommand->GetDMACommand(); if (dmaCommand) { if (dmaCommand->getMemoryDescriptor()) { USBError(1, "IOUSBCommandPool::gatedReturnCommand - isocCommand (%p) still has dmaCommand(%p) with an active memory descriptor(%p)", isocCommand, dmaCommand, dmaCommand->getMemoryDescriptor()); #if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION panic("IOUSBCommandPool::gatedReturnCommand - dmaCommand still has active IOMD (isoc)"); #endif } } else { USBError(1,"IOUSBCommandPool::gatedReturnCommand - missing dmaCommand in IOUSBIsocCommand"); } } return IOCommandPool::gatedReturnCommand(command); }
static void DisjointCompletion(IOUSBController *me, IOUSBCommand *command, IOReturn status, UInt32 bufferSizeRemaining) { IOBufferMemoryDescriptor *buf = NULL; IODMACommand *dmaCommand = NULL; USBTrace_Start( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)command, status, bufferSizeRemaining ); if (!me || !command) { USBError(1, "DisjointCompletion sanity check failed - me(%p) command (%p)", me, command); return; } buf = OSDynamicCast(IOBufferMemoryDescriptor, command->GetBuffer()); dmaCommand = command->GetDMACommand(); if (!dmaCommand || !buf) { USBLog(1, "%s[%p]::DisjointCompletion - no dmaCommand, or buf(%p) is not an IOBMD", me->getName(), me, command->GetBuffer()); USBTrace( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)command->GetBuffer(), 0, 1 ); return; } if (dmaCommand->getMemoryDescriptor()) { if (dmaCommand->getMemoryDescriptor() != buf) { USBLog(1, "%s[%p]::DisjointCompletion - buf(%p) doesn't match getMemoryDescriptor(%p)", me->getName(), me, buf, dmaCommand->getMemoryDescriptor()); USBTrace( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)buf, (uintptr_t)dmaCommand->getMemoryDescriptor(), 2 ); } // need to complete the dma command USBLog(6, "%s[%p]::DisjointCompletion - clearing memory descriptor (%p) from dmaCommand (%p)", me->getName(), me, dmaCommand->getMemoryDescriptor(), dmaCommand); dmaCommand->clearMemoryDescriptor(); } if (command->GetDirection() == kUSBIn) { USBLog(5, "%s[%p]::DisjointCompletion, copying %d out of %d bytes to desc %p from buffer %p", me->getName(), me, (int)(command->GetDblBufLength()-bufferSizeRemaining), (int)command->GetDblBufLength(), command->GetOrigBuffer(), buf); command->GetOrigBuffer()->writeBytes(0, buf->getBytesNoCopy(), (command->GetDblBufLength()-bufferSizeRemaining)); } buf->complete(); buf->release(); // done with this buffer command->SetBuffer(NULL); // now call through to the original completion routine IOUSBCompletion completion = command->GetDisjointCompletion(); if ( !command->GetIsSyncTransfer() ) { // Free our command now that we have the completion and we are not going to use it anymore me->ReturnUSBCommand(command); } if (completion.action) { USBLog(status == kIOReturnSuccess ? 7 : 3, "%s[%p]::DisjointCompletion calling through to %p - status 0x%x!", me->getName(), me, completion.action, (uint32_t)status); (*completion.action)(completion.target, completion.parameter, status, bufferSizeRemaining); } USBTrace_End( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)completion.target, (uintptr_t)completion.parameter, status, bufferSizeRemaining); }
//================================================================================================ // // SuspendUSBBus // //================================================================================================ // void AppleUSBOHCI::SuspendUSBBus(bool goingToSleep) { UInt32 something; UInt32 hcControl; USBTrace( kUSBTOHCI, KTPOHCISuspendUSBBus, (uintptr_t)this, goingToSleep, 0, 0); USBLog(5,"AppleUSBOHCI[%p]::SuspendUSBBus goingToSleep = %s", this, goingToSleep ? "TRUE" : "FALSE"); // 1st turn off all list processing // hcControl = USBToHostLong(_pOHCIRegisters->hcControl); hcControl &= ~(kOHCIHcControl_CLE | kOHCIHcControl_BLE | kOHCIHcControl_PLE | kOHCIHcControl_IE); _pOHCIRegisters->hcControl = HostToUSBLong(hcControl); // We used to wait for a SOF interrupt here. Now just sleep for 1 ms. // IOSleep(1); // check for the WDH register to see if we need to process is [2405732] // if ( _writeDoneHeadInterrupt ) { USBError(1,"AppleUSBOHCI[%p]::SuspendUSBBus Processing WDH before suspending", this); PollInterrupts(); } if ( goingToSleep ) { // now tell the controller to put the bus into suspend mode if (_errataBits & kErrataOHCINoGlobalSuspendOnSleep) { UInt32 port; hcControl = kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase; for (port=0; port < _rootHubNumPorts; port++) { _savedHcRhPortStatus[port] = USBToHostLong(_pOHCIRegisters->hcRhPortStatus[port]); USBLog(5, "AppleUSBOHCI[%p]::SuspendUSBBus - port %d _savedHcRhPortStatus(%p)", this, (int)port+1, (void*)_savedHcRhPortStatus[port]); } } else { hcControl = kOHCIFunctionalState_Suspend << kOHCIHcControl_HCFSPhase; } if (_hasPCIPwrMgmt) hcControl |= kOHCIHcControl_RWC | kOHCIHcControl_RWE; _pOHCIRegisters->hcControl = HostToUSBLong(hcControl); IOSleep(3); // wait 3 milliseconds for things to settle } else { UInt32 port; for (port=0; port < _rootHubNumPorts; port++) { USBLog(7, "AppleUSBOHCI[%p]::SuspendUSBBus - hcRhPortStatus[%d] = %p", this, (int)port+1, (void*) USBToHostLong(_pOHCIRegisters->hcRhPortStatus[port])); } } }
/** * \brief Construct a camera from a USB Device * * The constructor undertakes an extensive analysis of the descriptors * to find the video control and video streaming interfaces of the video * function of the device. It also makes sure no kernel driver is attached * to the device. It does not, however, claim any of the interfaces, this * is done when the device is really used. * \param _device an USB device to open as a UVC camera * \param force force opening as camera even if the * interface associaten descriptor does not * declare itself as a video interface association * descriptor (handles the TIS camera) * XXX apparently the force parameter is never used, so the question should be * asked whether we can remove it. */ UVCCamera::UVCCamera(Device& _device, bool /* force */) throw(USBError) : device(_device) { debug(LOG_DEBUG, DEBUG_LOG, 0, "create a UVC camera object"); // make sure the camera is open, this most probably will not have // any effect device.open(); // scan the active configuration for one that has an Interface // association descriptor ConfigurationPtr config = device.activeConfig(); if (config->extra().size() == 0) { debug(LOG_ERR, DEBUG_LOG, 0, "no extra descriptors"); throw USBError("no InterfaceAssociationDescriptor"); } // get the list of interface association descriptors std::list<USBDescriptorPtr> iadlist = device.interfaceAssociationDescriptors(true); if (0 == iadlist.size()) { throw USBError("no Video Interface Association found"); } iadptr = *iadlist.begin(); debug(LOG_DEBUG, DEBUG_LOG, 0, "Video Interface Association found"); // get the control interface, and the list of interface descriptors // for the control interface, and claim it uint8_t ci = controlInterfaceNumber(); videocontrol = (*config)[ci]; debug(LOG_DEBUG, DEBUG_LOG, 0, "Control interface number: %d", ci); videocontrol->detachKernelDriver(); // we also need to know all the video control descriptors appended // to this InterfaceDescriptor. The VideoControlDescriptorFactory // does that. debug(LOG_DEBUG, DEBUG_LOG, 0, "parse the video control descriptors"); InterfaceDescriptorPtr controlinterface = (*videocontrol)[0]; VideoControlDescriptorFactory vcdf(device); videocontroldescriptors = vcdf.descriptors(controlinterface->extra()); std::cout << videocontroldescriptors[0]; // now claim get the various interface descriptors, i.e. the // alternate settings for an interface int interfacecount = iad().bInterfaceCount(); debug(LOG_DEBUG, DEBUG_LOG, 0, "interfaces in association: %d", interfacecount); // now parse the video streaming interfaces debug(LOG_DEBUG, DEBUG_LOG, 0, "parse streaming interface descriptors"); VideoStreamingDescriptorFactory vsf(device); for (int vsif = controlInterfaceNumber() + 1; vsif < controlInterfaceNumber() + iad().bInterfaceCount(); vsif++) { debug(LOG_DEBUG, DEBUG_LOG, 0, "analyzing video streaming interface %d", vsif); InterfacePtr interface = (*config)[vsif]; // only alternate setting 0 contains the formats InterfaceDescriptorPtr id = (*interface)[0]; std::string extra = id->extra(); debug(LOG_DEBUG, DEBUG_LOG, 0, "extra descriptors: %d bytes", extra.size()); USBDescriptorPtr vsd = vsf.descriptor(extra); debug(LOG_DEBUG, DEBUG_LOG, 0, "parse complete"); videostreaming.push_back(vsd); } debug(LOG_DEBUG, DEBUG_LOG, 0, "UVCCamera constructed"); }
IOReturn AppleUSBUHCI::RHSuspendPort(int port, bool suspended) { UInt16 cmd, value; USBLog(3, "AppleUSBUHCI[%p]::RHSuspendPort %d (%s) _rhPortBeingResumed[%d](%s)", this, port, suspended ? "SUSPEND" : "RESUME", (int)port-1, _rhPortBeingResumed[port-1] ? "true" : "false"); showRegisters(7, "RHSuspendPort"); port--; // convert 1-based to 0-based. if (_rhPortBeingResumed[port]) { if (!suspended) { USBLog(3, "AppleUSBUHCI[%p]::RHSuspendPort - resume on port (%d) already being resumed - gracefully ignoring", this, (int)port+1); return kIOReturnSuccess; } USBLog(1, "AppleUSBUHCI[%p]::RHSuspendPort - trying to suspend port (%d) which is being resumed - UNEXPECTED", this, (int)port+1); USBTrace( kUSBTUHCI, kTPUHCIRHSuspendPort, (uintptr_t)this, (int)port+1, 0, 0); } cmd = ioRead16(kUHCI_CMD); value = ReadPortStatus(port) & kUHCI_PORTSC_MASK; if (suspended) { value |= kUHCI_PORTSC_SUSPEND; value &= ~kUHCI_PORTSC_RD; } else { if (cmd & kUHCI_CMD_EGSM) { /* Can't un-suspend a port during global suspend. */ USBError(1, "AppleUSBUHCI[%p]: attempt to resume during global suspend", this); return kIOReturnError; } value |= (kUHCI_PORTSC_SUSPEND | kUHCI_PORTSC_RD); } // Always enable the port also. value |= kUHCI_PORTSC_PED; USBLog(5, "AppleUSBUHCI[%p]: writing (%p) to port control", this, (void*)value); WritePortStatus(port, value); if (suspended) { /* Suspending. * Sleep for 3ms to ensure nothing goes out on the bus * until devices are suspended. */ IOSleep(3); } else { // Resuming USBLog(5,"AppleUSBUHCI[%p]::RHSuspendPort - resuming port %d, calling out to timer", this, (int)port+1); _rhPortBeingResumed[port] = true; thread_call_enter1(_rhResumePortTimerThread[port], (void*)(port+1)); } USBLog(5, "AppleUSBUHCI[%p]::RHSuspendPort %d (%s) calling UIMRootHubStatusChange", this, port+1, suspended ? "SUSPEND" : "RESUME"); UIMRootHubStatusChange(); USBLog(5, "AppleUSBUHCI[%p]::RHSuspendPort %d (%s) DONE", this, port+1, suspended ? "SUSPEND" : "RESUME"); return kIOReturnSuccess; }
//================================================================================================ // // ResumeUSBBus // //================================================================================================ // void AppleUSBOHCI::ResumeUSBBus(bool wakingFromSleep) { UInt32 newValue; USBTrace( kUSBTOHCI, KTPOHCIResumeUSBBus, (uintptr_t)this, wakingFromSleep, 0, 0); USBLog(5,"AppleUSBOHCI[%p]::ResumeUSBBus wakingFromSleep = %s", this, wakingFromSleep ? "TRUE" : "FALSE" ); switch ((USBToHostLong(_pOHCIRegisters->hcControl) & kOHCIHcControl_HCFS) >> kOHCIHcControl_HCFSPhase ) { case kOHCIFunctionalState_Suspend: // Place the USB bus into the resume State USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus - Resuming bus from Suspend state", this); _pOHCIRegisters->hcControl = HostToUSBLong(kOHCIFunctionalState_Resume << kOHCIHcControl_HCFSPhase); // intentional fall through case kOHCIFunctionalState_Resume: // Complete the resume by waiting for the required delay if (_errataBits & kErrataLucentSuspendResume) // JRH 08-27-99 // this is a very simple yet clever hack for working around a bug in the Lucent controller // By using 35 instead of 20, we overflow an internal 5 bit counter by exactly 3ms, which // stops an errant 3ms suspend from appearing on the bus { USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus- Delaying 35 milliseconds in resume state", this); IOSleep(35); } else { USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus - Delaying 20 milliseconds in resume state", this); IOSleep(20); } // intentional fall through case kOHCIFunctionalState_Reset: // Place the USB bus into the operational State USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus - Changing bus to operational", this); _pOHCIRegisters->hcControl = HostToUSBLong(kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase); IOSync(); IOSleep(3); // wait the required 3 ms before turning on the lists // <rdar://problem/5981624> We need to make sure that the DRWE bit is properly set any time we go to the operational state newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); if (!(newValue & kOHCIHcRhStatus_DRWE)) { _pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE); IOSync(); if (_errataBits & kErrataNECIncompleteWrite) { UInt32 count = 0; newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); // this bit SHOULD now be set while ((count++ < 10) && !(newValue & kOHCIHcRhStatus_DRWE)) { USBError(1, "OHCI driver::ResumeUSBBus - DRWE bit not sticking. Retrying."); _pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE); IOSync(); newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); } } } _pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase) | kOHCIHcControl_CLE | (_OptiOn ? kOHCIHcControl_Zero : kOHCIHcControl_BLE) | kOHCIHcControl_PLE | kOHCIHcControl_IE); IOSync(); break; default: USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus Bus already operational - turning on the lists", this); _pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase) | kOHCIHcControl_CLE | (_OptiOn ? kOHCIHcControl_Zero : kOHCIHcControl_BLE) | kOHCIHcControl_PLE | kOHCIHcControl_IE); IOSync(); break; } // Do this after waking the controller so you see wakeups. if (wakingFromSleep) { UInt32 port, portSC; IOSleep(1); for (port=0; port < _rootHubNumPorts; port++) { UInt32 portSC = USBToHostLong(_pOHCIRegisters->hcRhPortStatus[port]); //USBLog(6, "AppleUSBOHCI[%p]::ResumeUSBBus Port %d, portSC(%p)", this, (int)port+1, (void*)portSC); if (portSC & kOHCIHcRhPortStatus_CSC) { if (portSC & kOHCIHcRhPortStatus_PES) { USBError(1, "USB (OHCI):Port %d on bus 0x%x has connect status change but is still enabled. setting clear port enable. hcRhPortStatus(%p)", (int)port+1, (uint32_t)_busNumber, (void*)portSC); _pOHCIRegisters->hcRhPortStatus[port] = HostToUSBLong(kOHCIHcRhPortStatus_CCS); // CCS when writing is CPE IOSleep(1); portSC = USBToHostLong(_pOHCIRegisters->hcRhPortStatus[port]); } else { USBLog(5, "AppleUSBOHCI[%p]::ResumeUSBBus Port %d on bus 0x%x connected or disconnected. portSC(%p)", this, (int)port+1, (uint32_t)_busNumber, (void*)portSC); // IOLog("USB (OHCI):Port %d on bus 0x%x connected or disconnected. portSC(%p)\n", (int)port+1, (uint32_t)_busNumber, (void*)portSC); } } else if (portSC & kOHCIHcRhPortStatus_PSSC) { if (_rootHubDevice && _rootHubDevice->GetPolicyMaker()) { // Make sure to send port index, not port number _rootHubDevice->GetPolicyMaker()->message(kIOUSBMessageRootHubWakeEvent, this, (void *)(uintptr_t) (port)); } else { IOLog("USB (OHCI):Port %d on bus 0x%x has remote wakeup from some device\n", (int)port+1, (uint32_t)_busNumber); } USBLog(5, "AppleUSBOHCI[%p]::ResumeUSBBus Port %d on bus 0x%x has remote wakeup from some device", this, (int)port+1, (uint32_t)_busNumber); } else if ((_errataBits & kErrataOHCINoGlobalSuspendOnSleep) // if we are on these controllers && (portSC & kOHCIHcRhPortStatus_CCS) // and we are currently connected && !(portSC & kOHCIHcRhPortStatus_PES) // and we are not currently enabled && (_savedHcRhPortStatus[port] & kOHCIHcRhPortStatus_PES)) // and we were enabled before we went to sleep { USBError(1, "USB (OHCI):Port %d on bus 0x%x is connected but not enabled. trying to set port enable. hcRhPortStatus(%p) _savedHcRhPortStatus(%p)", (int)port+1, (uint32_t)_busNumber, (void*)portSC, (void*)_savedHcRhPortStatus[port]); _pOHCIRegisters->hcRhPortStatus[port] = HostToUSBLong(kOHCIHcRhPortStatus_PES); // CCS when writing is CPE IOSleep(1); portSC = USBToHostLong(_pOHCIRegisters->hcRhPortStatus[port]); USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus - new hcRhPortStatus(%p)", this, (void*)portSC); } _savedHcRhPortStatus[port] = 0; // clear this out to be safe once we have no more need for it } } }
/** * \brief Select format and frame. * * This method negotiates format and frame with the device. This also * implies a frame interval setting, and the bandwith depends on this * setting as well. However, selecting the format and frame a priori * does not yet fix the bandwidth, this is a consideration only for * isochronous transfers. Therefore this method does not do any bandwidth * negotiation, but leaves this to the getFrame method. * * \param interface video streaming interface number, not the index in * the videostreaming array. * \param format format number, one larger than the format index * \param frame frame number, equal to the bFrameIndex field of the * frame descriptor */ void UVCCamera::selectFormatAndFrame(uint8_t interface, uint8_t format, uint8_t frame) throw(USBError) { debug(LOG_DEBUG, DEBUG_LOG, 0, "select interface %d, format %d, frame %d", interface, format, frame); // We want to negotiate use of the a given format and frame. // To do this, we send a SET probe vs_control_request_t control_request; memset(&control_request, 0, sizeof(control_request)); control_request.bFormatIndex = format; control_request.bFrameIndex = frame; control_request.dwFrameInterval = minFrameInterval(interface, format, frame); // do we have to claim the interface? InterfacePtr interfaceptr = (*device.activeConfig())[interface]; debug(LOG_DEBUG, DEBUG_LOG, 0, "interface %d with %d alt settings", interfaceptr->interfaceNumber(), interfaceptr->numAltsettings()); #if 1 interfaceptr->claim(); #endif VideoStreamingProbeControlRequest rset(interfaceptr, SET_CUR, &control_request); device.controlRequest(&rset); // now probe the same thing, this should return a recommended // setting VideoStreamingProbeControlRequest rget(interfaceptr, GET_CUR); device.controlRequest(&rget); if (rget.data()->bFormatIndex != format) { throw USBError("cannot negotiate format index"); } if (rget.data()->bFrameIndex != frame) { throw USBError("cannot negotiate frame index"); } // if we get to this point, then negotiating the format and frame // was successful, and we can commit the negotiated paramters VideoStreamingCommitControlRequest rcommit(interfaceptr, SET_CUR, rget.data()); device.controlRequest(&rcommit); // we now also have to find out how many bits per pixel we can // expect USBDescriptorPtr formatptr = getFormatDescriptor(interface, format); FormatFrameBasedDescriptor *fd = dynamic_cast<FormatFrameBasedDescriptor *>(&*formatptr); if (NULL == fd) { debug(LOG_DEBUG, DEBUG_LOG, 0, "unknown pixel size"); bitsPerPixel = 1; } else { bitsPerPixel = fd->bBitsPerPixel(); debug(LOG_DEBUG, DEBUG_LOG, 0, "bits per pixel: %d", bitsPerPixel); } // just to be on the safe side, we should ask again what the // current settings are getCur(interface); }
IOReturn IOUSBController::IsocIO(IOMemoryDescriptor * buffer, UInt64 frameStart, UInt32 numFrames, IOUSBLowLatencyIsocFrame * frameList, USBDeviceAddress address, Endpoint * endpoint, IOUSBLowLatencyIsocCompletion * completion, UInt32 updateFrequency) { IOReturn err = kIOReturnSuccess; IOUSBIsocCommand * command = NULL; bool crossEndianRequest = false; IODMACommand * dmaCommand = NULL; bool syncTransfer = false; // Validate the completion // USBLog(7, "%s[%p]::IsocIO(LL)", getName(), this); if (completion == 0) { USBLog(1, "%s[%p]::IsocIO(LL) - No completion. Returning kIOReturnNoCompletion(0x%x)", getName(), this, kIOReturnNoCompletion); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnNoCompletion, 0, 3 ); return kIOReturnNoCompletion; } // Validate the commandGate // if (_commandGate == 0) { USBLog(1, "%s[%p]::IsocIO(LL) - Could not get _commandGate. Returning kIOReturnInternalError(0x%x)", getName(), this, kIOReturnInternalError); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnInternalError, 0, 4 ); return kIOReturnInternalError; } // If the high order bit of the endpoint transfer type is set, then this means it's a request from an Rosetta client if ( endpoint->direction & 0x80 ) { endpoint->direction &= ~0x80; crossEndianRequest = true; } // Validate the direction of the endpoint -- it has to be kUSBIn or kUSBOut if ( (endpoint->direction != kUSBOut) && ( endpoint->direction != kUSBIn) ) { USBLog(1, "%s[%p]::IsocIO(LL) - Direction is not kUSBOut or kUSBIn (%d). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->direction, kIOReturnBadArgument); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, endpoint->direction, kIOReturnBadArgument, 6 ); return kIOReturnBadArgument; } if ( (uintptr_t)completion->action == (uintptr_t)&IOUSBSyncIsoCompletion ) { syncTransfer = true; if ( _workLoop->onThread() ) { USBError(1,"IOUSBController(%s)[%p]::DoIsocTransfer sync request on workloop thread. Use async!", getName(), this); return kIOUSBSyncRequestOnWLThread; } } command = (IOUSBIsocCommand *)_freeUSBIsocCommandPool->getCommand(false); // If we couldn't get a command, increase the allocation and try again // if ( command == NULL ) { IncreaseIsocCommandPool(); command = (IOUSBIsocCommand *)_freeUSBIsocCommandPool->getCommand(false); if ( command == NULL ) { USBLog(1, "%s[%p]::IsocIO(LL) Could not get a IOUSBIsocCommand", getName(), this); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnNoResources, 0, 5 ); return kIOReturnNoResources; } } dmaCommand = command->GetDMACommand(); if (!dmaCommand) { USBLog(1, "%s[%p]::IsocIO(LL) no IODMACommand in the IOUSBCommand", getName(), this); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnNoResources, 0, 1 ); return kIOReturnNoResources; } USBLog(7, "%s[%p]::IsocIO(LL) - putting buffer %p into dmaCommand %p which has getMemoryDescriptor %p", getName(), this, buffer, command->GetDMACommand(), command->GetDMACommand()->getMemoryDescriptor()); err = dmaCommand->setMemoryDescriptor(buffer); // this automatically calls prepare() if (err) { USBLog(1, "%s[%p]::IsocIO(LL) - dmaCommand[%p]->setMemoryDescriptor(%p) failed with status (%p)", getName(), this, command->GetDMACommand(), buffer, (void*)err); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, err, 0, 2 ); _freeUSBIsocCommandPool->returnCommand(command); return err; } // If the high order bit of the endpoint transfer type is set, then this means it's a request from an Rosetta client command->SetRosettaClient(crossEndianRequest); command->SetIsSyncTransfer(syncTransfer); // Setup the direction if (endpoint->direction == kUSBOut) { command->SetSelector(WRITE); command->SetDirection(kUSBOut); } else if (endpoint->direction == kUSBIn) { command->SetSelector(READ); command->SetDirection(kUSBIn); } command->SetUseTimeStamp(false); command->SetAddress(address); command->SetEndpoint(endpoint->number); command->SetBuffer(buffer); command->SetCompletion( * ((IOUSBIsocCompletion *) completion) ); command->SetStartFrame(frameStart); command->SetNumFrames(numFrames); command->SetFrameList( (IOUSBIsocFrame *) frameList); command->SetStatus(kIOReturnBadArgument); command->SetUpdateFrequency(updateFrequency); command->SetLowLatency(true); err = _commandGate->runAction(DoIsocTransfer, command); // If we have a sync request, then we always return the command after the DoIsocTransfer. If it's an async request, we only return it if // we get an immediate error // if ( syncTransfer || (kIOReturnSuccess != err) ) { IODMACommand *dmaCommand = command->GetDMACommand(); IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL; if (memDesc) { USBLog(7, "%s[%p]::IsocIO(LL) - sync xfer or err return - clearing memory descriptor (%p) from dmaCommand (%p)", getName(), this, memDesc, dmaCommand); dmaCommand->clearMemoryDescriptor(); } _freeUSBIsocCommandPool->returnCommand(command); } return err; }
IOReturn IOUSBController::Write(IOMemoryDescriptor *buffer, USBDeviceAddress address, Endpoint *endpoint, IOUSBCompletion *completion, UInt32 noDataTimeout, UInt32 completionTimeout, IOByteCount reqCount) { IOReturn err = kIOReturnSuccess; IOUSBCommand * command = NULL; IODMACommand * dmaCommand = NULL; IOUSBCompletion nullCompletion; int i; bool isSyncTransfer = false; USBLog(7, "%s[%p]::Write - reqCount = %qd", getName(), this, (uint64_t)reqCount); // Validate its a outty pipe and that we have a buffer if ((endpoint->direction != kUSBOut) || !buffer || (buffer->getLength() < reqCount)) { USBLog(5, "%s[%p]::Write - direction is not kUSBOut (%d), No Buffer, or buffer length < reqCount (%qd < %qd). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->direction, (uint64_t)buffer->getLength(), (uint64_t)reqCount, kIOReturnBadArgument); return kIOReturnBadArgument; } if ((endpoint->transferType != kUSBBulk) && (noDataTimeout || completionTimeout)) { USBLog(5, "%s[%p]::Write - Pipe is NOT kUSBBulk (%d) AND specified a timeout (%d, %d). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->transferType, (uint32_t)noDataTimeout, (uint32_t)completionTimeout, kIOReturnBadArgument); return kIOReturnBadArgument; // timeouts only on bulk pipes } // Validate the command gate if (!_commandGate) { USBLog(5, "%s[%p]::Write - Could not get _commandGate. Returning kIOReturnInternalError(0x%x)", getName(), this, kIOReturnInternalError); return kIOReturnInternalError; } if ( (uintptr_t) completion->action == (uintptr_t) &IOUSBSyncCompletion ) { isSyncTransfer = true; // 7889995 - check to see if we are on the workloop thread before setting up the IOUSBCommand if ( _workLoop->onThread() ) { USBError(1,"IOUSBController(%s)[%p]::Write sync request on workloop thread. Use async!", getName(), this); return kIOUSBSyncRequestOnWLThread; } } // allocate the command command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false); // If we couldn't get a command, increase the allocation and try again // if ( command == NULL ) { IncreaseCommandPool(); command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false); if ( command == NULL ) { USBLog(3,"%s[%p]::Write Could not get a IOUSBCommand",getName(),this); return kIOReturnNoResources; } } // 7455477: from this point forward, we have the command object, and we need to be careful to put it back if there is an error.. if (reqCount) { IOMemoryDescriptor *memDesc; dmaCommand = command->GetDMACommand(); if (!dmaCommand) { USBLog(1, "%s[%p]::Write - no DMA COMMAND", getName(), this); USBTrace( kUSBTController, kTPControllerWrite, (uintptr_t)this, kIOReturnNoResources, 0, 1 ); err = kIOReturnNoResources; } else { memDesc = (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor(); if (memDesc) { USBLog(1, "%s[%p]::Write - dmaCommand (%p) already contains memory descriptor (%p) - clearing", getName(), this, dmaCommand, memDesc); USBTrace( kUSBTController, kTPControllerWrite, (uintptr_t)this, (uintptr_t)dmaCommand, (uintptr_t)memDesc, 2 ); dmaCommand->clearMemoryDescriptor(); } USBLog(7, "%s[%p]::Write - setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, buffer, dmaCommand); err = dmaCommand->setMemoryDescriptor(buffer); if (err) { USBTrace( kUSBTController, kTPControllerWrite, (uintptr_t)this, err, 0, 4 ); USBLog(1, "%s[%p]::Write - err(%p) attempting to set the memory descriptor to the dmaCommand", getName(), this, (void*)err); } } } if (!err) { command->SetIsSyncTransfer(isSyncTransfer); command->SetUseTimeStamp(false); command->SetSelector(WRITE); command->SetRequest(0); // Not a device request command->SetAddress(address); command->SetEndpoint(endpoint->number); #ifdef SUPPORTS_SS_USB command->SetStreamID(0); #endif command->SetDirection(kUSBOut); command->SetType(endpoint->transferType); command->SetBuffer(buffer); command->SetReqCount(reqCount); command->SetClientCompletion(*completion); command->SetNoDataTimeout(noDataTimeout); command->SetCompletionTimeout(completionTimeout); command->SetMultiTransferTransaction(false); command->SetFinalTransferInTransaction(false); for (i=0; i < 10; i++) command->SetUIMScratch(i, 0); nullCompletion.target = (void *) NULL; nullCompletion.action = (IOUSBCompletionAction) NULL; nullCompletion.parameter = (void *) NULL; command->SetDisjointCompletion(nullCompletion); err = CheckForDisjointDescriptor(command, endpoint->maxPacketSize); if (!err) { err = _commandGate->runAction(DoIOTransfer, command); } } // 7455477: handle and and all errors which may have occured above // If we have a sync request, then we always return the command after the DoIOTransfer. If it's an async request, we only return it if // we get an immediate error // if ( isSyncTransfer || (kIOReturnSuccess != err) ) { IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL; if (!isSyncTransfer) { USBLog(2, "%s[%p]::Write - General error (%p) - cleaning up - command(%p) dmaCommand(%p)", getName(), this, (void*)err, command, dmaCommand); } if (memDesc) { USBLog(7, "%s[%p]::Write - General error (%p) - clearing memory descriptor (%p) from dmaCommand (%p)", getName(), this, (void*)err, memDesc, dmaCommand); dmaCommand->clearMemoryDescriptor(); } nullCompletion = command->GetDisjointCompletion(); if (nullCompletion.action) { USBLog(2, "%s[%p]::Write - SYNC xfer or immediate error with Disjoint Completion", getName(), this); } _freeUSBCommandPool->returnCommand(command); } return err; }
//================================================================================================ // // MergeDictionaryIntoProvider // // We will iterate through the dictionary that we want to merge into our provider. If // the dictionary entry is not an OSDictionary, we will set that property into our provider. If it is a // OSDictionary, we will get our provider's entry and merge our entry into it, recursively. // //================================================================================================ // bool IOUSBUserClientInit::MergeDictionaryIntoProvider(IOService * provider, OSDictionary * dictionaryToMerge) { const OSSymbol * dictionaryEntry = NULL; OSCollectionIterator * iter = NULL; bool result = false; USBLog(6,"+%s[%p]::MergeDictionary(%p)IntoProvider(%p)", getName(), this, dictionaryToMerge, provider); if (!provider || !dictionaryToMerge) return false; // Get the dictionary whose entries we need to merge into our provider and get // an iterator to it. // iter = OSCollectionIterator::withCollection((OSDictionary *)dictionaryToMerge); if ( iter != NULL ) { // Iterate through the dictionary until we run out of entries // while ( NULL != (dictionaryEntry = (const OSSymbol *)iter->getNextObject()) ) { const char * str = NULL; OSDictionary * sourceDictionary = NULL; OSDictionary * providerDictionary = NULL; OSObject * providerProperty = NULL; // Get the symbol name for debugging // str = dictionaryEntry->getCStringNoCopy(); USBLog(6,"%s[%p]::MergeDictionaryIntoProvider merging \"%s\"", getName(), this, str); // Check to see if our destination already has the same entry. // providerProperty = provider->getProperty(dictionaryEntry); if ( providerProperty ) { USBLog(6,"%s[%p]::MergeDictionaryIntoProvider provider already had property %s", getName(), this, str); providerDictionary = OSDynamicCast(OSDictionary, providerProperty); if ( providerDictionary ) { USBLog(6,"%s[%p]::MergeDictionaryIntoProvider provider's %s is also a dictionary (%p)", getName(), this, str, providerDictionary); } } // See if our source entry is also a dictionary // sourceDictionary = OSDynamicCast(OSDictionary, dictionaryToMerge->getObject(dictionaryEntry)); if ( sourceDictionary ) { USBLog(6,"%s[%p]::MergeDictionaryIntoProvider source dictionary had %s as a dictionary (%p)", getName(), this, str, sourceDictionary); } if ( providerDictionary && sourceDictionary ) { // Need to merge our entry into the provider's dictionary. However, we don't have a copy of our dictionary, just // a reference to it. So, we need to make a copy of our provider's dictionary so that we don't modify our provider's // dictionary using non-synchronize calls. // OSDictionary * localCopyOfProvidersDictionary; UInt32 providerSize; UInt32 providerSizeAfterMerge; // A capacity of 0 indicates that the dictionary should have the same size as the source // localCopyOfProvidersDictionary = OSDictionary::withDictionary( providerDictionary, 0); if ( localCopyOfProvidersDictionary == NULL ) { USBError(1,"%s::MergeDictionaryIntoProvider could not copy our provider's dictionary",getName()); break; } // Get the size of our provider's dictionary so that we can check later whether it changed // providerSize = providerDictionary->getCapacity(); USBLog(6,"%s[%p]::MergeDictionaryIntoProvider Created a local copy(%p) of dictionary (%p), size %d", getName(), this, localCopyOfProvidersDictionary, providerDictionary, (uint32_t)providerSize); USBLog(6,"%s[%p]::MergeDictionaryIntoProvider need to merge a dictionary (%s)", getName(), this, str); // Recursively merge the two dictionaries // result = MergeDictionaryIntoDictionary( sourceDictionary, localCopyOfProvidersDictionary); if ( result ) { // Get the size of our provider's dictionary so to see if it's changed (Yes, the size could remain the same but the contents // could have changed, but this gives us a first approximation. We're not doing anything with this result, although we could // remerge if the size changed) // providerSizeAfterMerge = providerDictionary->getCapacity(); if ( providerSizeAfterMerge != providerSize ) { USBError(1,"%s::MergeDictionaryIntoProvider our provider's dictionary size changed (%d,%d)",getName(), (uint32_t)providerSize, (uint32_t)providerSizeAfterMerge); } USBLog(6,"%s[%p]::MergeDictionaryIntoProvider setting property %s from merged dictionary (%p)", getName(), this, str, providerDictionary); // OK, now we can just set the property in our provider // result = provider->setProperty( dictionaryEntry, localCopyOfProvidersDictionary ); if ( !result ) { USBLog(6,"%s[%p]::MergeDictionaryIntoProvider setProperty %s , returned false", getName(), this, str); break; } } else { // If we got an error merging dictionaries, then just bail out without doing anything // USBLog(6,"%s[%p]::MergeDictionaryIntoProvider MergeDictionaryIntoDictionary(%p,%p) returned false", getName(), this, sourceDictionary, providerDictionary); break; } } else { // Not a dictionary, so just set the property // USBLog(6,"%s[%p]::MergeDictionaryIntoProvider setting property %s", getName(), this, str); result = provider->setProperty(dictionaryEntry, dictionaryToMerge->getObject(dictionaryEntry)); if ( !result ) { USBLog(6,"%s[%p]::MergeDictionaryIntoProvider setProperty %s, returned false", getName(), this, str); break; } } } iter->release(); } USBLog(6,"-%s[%p]::MergeDictionaryIntoProvider(%p, %p) result %d", getName(), this, provider, dictionaryToMerge, result); return result; }
//================================================================================================ // // CheckSleepCapability // //================================================================================================ // void AppleUSBOHCI::CheckSleepCapability(void) { // assume that sleep is OK _controllerCanSleep = true; _hasPCIPwrMgmt = false; // We need to determine which OHCI controllers don't survive sleep. These fall into 2 categories: // // 1. CardBus cards // 2. PCI Cards that lose power (right now because of a bug in the PCI Family, USB PCI cards do not prevent // sleep, so even cards that don't support the PCI Power Mgmt stuff get their power removed. // // Additionally, the PowerBook 101 controller cannot survive across sleep (I doesn't support remote wakeup). // // So here, we look at all those cases and set the _unloadUIMAcrossSleep boolean to true. As it turns out, // if a controller does not have the "AAPL,clock-id" property, then it means that it cannot survive sleep. We // might need to refine this later once we figure how to deal with PCI cards that can go into PCI sleep mode. // An exception is the B&W G3, that does not have this property but can sleep. Sigh... // Now, look at PCI cards. Note that the onboard controller's provider is an IOPCIDevice so we cannot use that // to distinguish between USB PCI cards and the on board controller. Instead, we use the existence of the // "AAPL,clock-id" property in the provider. If it does not exist, then we are a OHCI controller on a USB PCI card. // if ( !_device->getProperty("AAPL,clock-id") && !((getPlatform()->getChipSetType() == kChipSetTypeGossamer) && getPlatform()->getMachineType() == kGossamerTypeYosemite) ) { if (_device->getProperty("built-in")) { if (_errataBits & kErrataNECIncompleteWrite) { FixupNECControllerConfigRegisters(); } // rdar://5769508 - if we are on a built in PCI device, then assume the system supports D3cold if (_device->hasPCIPowerManagement(kPCIPMCPMESupportFromD3Cold) && (_device->enablePCIPowerManagement(kPCIPMCSPowerStateD3) == kIOReturnSuccess)) { _hasPCIPwrMgmt = true; setProperty("Card Type","Built-in"); } } else { // rdar://5856545 - on older machines without the built-in property, we need to use the "default" case in the IOPCIDevice code if (_device->hasPCIPowerManagement() && (_device->enablePCIPowerManagement() == kIOReturnSuccess)) { _hasPCIPwrMgmt = true; setProperty("Card Type","Built-in"); } } if (!_hasPCIPwrMgmt) { USBError(1, "AppleUSBOHCI[%p]::CheckSleepCapability - controller will be unloaded across sleep",this); _controllerCanSleep = false; setProperty("Card Type","PCI"); } } else { setProperty("Card Type","Built-in"); } // if we have an ExpressCard attached (non-zero port), then we will need to disable port resume // for that port (some cards disconnect when the ExpressCard power goes away and we would like to ignore these extra detach events. _ExpressCardPort = ExpressCardPort(_device); _badExpressCardAttached = false; // Call registerService() so that the IOUSBController object is published and clients (like Prober) can find it registerService(); }
AppleEHCIitdMemoryBlock* AppleEHCIitdMemoryBlock::NewMemoryBlock(void) { AppleEHCIitdMemoryBlock *me = new AppleEHCIitdMemoryBlock; IOByteCount len; IODMACommand *dmaCommand = NULL; UInt64 offset = 0; IODMACommand::Segment32 segments; UInt32 numSegments = 1; IOReturn status = kIOReturnSuccess; if (me) { // Use IODMACommand to get the physical address dmaCommand = IODMACommand::withSpecification(kIODMACommandOutputHost32, 32, PAGE_SIZE, (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly)); if (!dmaCommand) { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not create IODMACommand"); return NULL; } USBLog(6, "AppleEHCIitdMemoryBlock::NewMemoryBlock - got IODMACommand %p", dmaCommand); // allocate one page on a page boundary below the 4GB line me->_buffer = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, kIOMemoryUnshared | kIODirectionInOut, kEHCIPageSize, kEHCIStructureAllocationPhysicalMask); // allocate exactly one physical page if (me->_buffer) { status = me->_buffer->prepare(); if (status) { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not prepare buffer"); me->_buffer->release(); me->_buffer = NULL; me->release(); dmaCommand->release(); return NULL; } me->_sharedLogical = (EHCIIsochTransferDescriptorSharedPtr)me->_buffer->getBytesNoCopy(); bzero(me->_sharedLogical, kEHCIPageSize); status = dmaCommand->setMemoryDescriptor(me->_buffer); if (status) { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not set memory descriptor"); me->_buffer->complete(); me->_buffer->release(); me->_buffer = NULL; me->release(); dmaCommand->release(); return NULL; } status = dmaCommand->gen32IOVMSegments(&offset, &segments, &numSegments); dmaCommand->clearMemoryDescriptor(); dmaCommand->release(); if (status || (numSegments != 1) || (segments.fLength != kEHCIPageSize)) { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not get physical segment"); me->_buffer->complete(); me->_buffer->release(); me->_buffer = NULL; me->release(); return NULL; } me->_sharedPhysical = segments.fIOVMAddr; } else { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock, could not allocate buffer!"); me->release(); me = NULL; } } else { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock, constructor failed!"); } return me; }
/** * \brief Isochronous transfer implementation * * Doing an isochrounous transfer for a certain number of bytes is * quite complicated. In an isochronous transfer, a packet is transmitted * in every micro frame, even if there is no new data available. So the * transfer has to be resubmitted each time a few packets have been received. * \param dev_handle libusb_device_handle to use for the transfer */ void IsoTransfer::submit(libusb_device_handle *dev_handle) throw(USBError) { debug(LOG_DEBUG, DEBUG_LOG, 0, "preparing isochronous transfer"); // find the packet size that the endpoint can handle int packetsize = endpoint->maxPacketSize() * endpoint->transactionOpportunities(); debug(LOG_DEBUG, DEBUG_LOG, 0, "found packet size: %d", packetsize); // each segment should be the same number of segments int packets_per_segment = 400; // create a bunch of IsoSegments and add them to the queue debug(LOG_DEBUG, DEBUG_LOG, 0, "total packets: %d", totalpackets); int packetcount = 0; while (packetcount < totalpackets) { IsoSegment *segptr = new IsoSegment(endpoint, packets_per_segment, this, dev_handle, timeout); incoming.push(IsoSegmentPtr(segptr)); packetcount += packets_per_segment; } debug(LOG_DEBUG, DEBUG_LOG, 0, "incoming now contains %d segments", incoming.size()); if (incoming.size() == 0) { return; } // mark the transfer as incomplete complete = false; // lock the mutex, this will cause the thread to block when it starts lock.lock(); // now create a new thread which will handle the events. But because // the mutex is locked, it will not start working just yet, only // when the mutex is unlocked, that thread will be released try { eventthread = std::thread(isotransfer_event_thread, this); } catch (...) { throw USBError("cannot create event handling thread"); } // wait for completion of the request, using the condition variable // this will release the lock, so the thread will be released too try { condition.wait(lock); } catch (...) { throw USBError("cannot release event handling thread"); } debug(LOG_DEBUG, DEBUG_LOG, 0, "all callbacks completed"); // wait for the thread to terminate eventthread.join(); // copy all the packets while (outgoing.size() > 0) { debug(LOG_DEBUG, DEBUG_LOG, 0, "extracting packets from segment"); outgoing.front()->extract(packets); outgoing.pop(); } debug(LOG_DEBUG, DEBUG_LOG, 0, "have now %d packets", packets.size()); }