void pci_free_consistent(void *pdev, size_t size, void *vaddr, dma_addr_t dma_handle) { // free a hw dma scatter/gather list located in host memory int index; OSArray *dma_info_array; IOBufferMemoryDescriptor *memDesc; IOVirtualAddress virt_address; // search for the correct dma_info by checking against passed virtual address dma_info_array = g_bcm_dma_info; for(index = 0; index < (int)dma_info_array->getCount(); index++) { memDesc = (IOBufferMemoryDescriptor*)dma_info_array->getObject(index); virt_address = (IOVirtualAddress)memDesc->getBytesNoCopy(); if ((IOVirtualAddress)vaddr == virt_address) { //IOLog("pci_free_consistent padd(%p), size(0x%X)\n", dma_handle, size); // found it, now complete. removeObject will release it memDesc->complete(); dma_info_array->removeObject(index); // should be able to just call memDesc->release() after memDesc->complete() // but on atv, there's something holding a ref to memDesc and so we leak memory // everytime the crystalhs driver closes. Doing the release this way fixes the mem // leak on atv and is fine under real 10.4/10.5 boxes. SAFE_RELEASE(memDesc); break; } } }
int HoRNDIS::rndisCommand(struct rndis_msg_hdr *buf, int buflen) { int count; int rc = kIOReturnSuccess; IOUSBDevRequestDesc rq; IOBufferMemoryDescriptor *txdsc = IOBufferMemoryDescriptor::withCapacity(le32_to_cpu(buf->msg_len), kIODirectionOut); IOBufferMemoryDescriptor *rxdsc = IOBufferMemoryDescriptor::withCapacity(RNDIS_CMD_BUF_SZ, kIODirectionIn); if (buf->msg_type != RNDIS_MSG_HALT && buf->msg_type != RNDIS_MSG_RESET) { /* lock? */ buf->request_id = cpu_to_le32(xid++); if (!buf->request_id) buf->request_id = cpu_to_le32(xid++); } memcpy(txdsc->getBytesNoCopy(), buf, le32_to_cpu(buf->msg_len)); rq.bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; rq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface); rq.wValue = 0; rq.wIndex = fCommInterface->GetInterfaceNumber(); rq.pData = txdsc; rq.wLength = cpu_to_le32(buf->msg_len); if ((rc = fCommInterface->DeviceRequest(&rq)) != kIOReturnSuccess) goto bailout; /* Linux polls on the status channel, too; hopefully this shouldn't be needed if we're just talking to Android. */ /* Now we wait around a while for the device to get back to us. */ for (count = 0; count < 10; count++) { struct rndis_msg_hdr *inbuf = (struct rndis_msg_hdr *) rxdsc->getBytesNoCopy(); IOUSBDevRequestDesc rxrq; memset(inbuf, 0, RNDIS_CMD_BUF_SZ); rxrq.bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; rxrq.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface); rxrq.wValue = 0; rxrq.wIndex = fCommInterface->GetInterfaceNumber(); rxrq.pData = rxdsc; rxrq.wLength = RNDIS_CMD_BUF_SZ; if ((rc = fCommInterface->DeviceRequest(&rxrq)) != kIOReturnSuccess) goto bailout; if (rxrq.wLenDone < 8) { LOG(V_ERROR, "short read on control request?"); IOSleep(20); continue; } if (inbuf->msg_type == (buf->msg_type | RNDIS_MSG_COMPLETION)) { if (inbuf->request_id == buf->request_id) { if (inbuf->msg_type == RNDIS_MSG_RESET_C) break; if (inbuf->status == RNDIS_STATUS_SUCCESS) { /* ...and copy it out! */ LOG(V_DEBUG, "RNDIS command completed"); memcpy(buf, inbuf, le32_to_cpu(rxrq.wLenDone)); break; } LOG(V_ERROR, "RNDIS command returned status %08x", inbuf->status); rc = -1; break; } else { LOG(V_ERROR, "RNDIS return had incorrect xid?"); } } else { switch (inbuf->msg_type) { case RNDIS_MSG_INDICATE: LOG(V_ERROR, "unsupported: RNDIS_MSG_INDICATE"); break; case RNDIS_MSG_KEEPALIVE: LOG(V_ERROR, "unsupported: RNDIS_MSG_KEEPALIVE"); break; default: LOG(V_ERROR, "unexpected msg type %08x, msg_len %08x", inbuf->msg_type, inbuf->msg_len); break; } } IOSleep(20); } if (count == 10) { LOG(V_ERROR, "command timed out?"); rc = kIOReturnTimeout; } bailout: txdsc->complete(); txdsc->release(); rxdsc->complete(); rxdsc->release(); return rc; }
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); }
IOReturn IOUSBController::CheckForDisjointDescriptor(IOUSBCommand *command, UInt16 maxPacketSize) { IOMemoryDescriptor *buf = command->GetBuffer(); IOBufferMemoryDescriptor *newBuf = NULL; IOByteCount length = command->GetReqCount(); IODMACommand *dmaCommand = command->GetDMACommand(); IOByteCount segLength = 0; IOByteCount offset = 0; IOReturn err; UInt64 offset64; IODMACommand::Segment64 segment64; UInt32 numSegments; // USBTrace_Start( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this ); // Zero length buffers are valid, but they are surely not disjoint, so just return success. // if ( length == 0 ) return kIOReturnSuccess; if (!dmaCommand) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - no dmaCommand", getName(), this); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnBadArgument, 0, 1 ); return kIOReturnBadArgument; } if (dmaCommand->getMemoryDescriptor() != buf) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - mismatched memory descriptor (%p) and dmaCommand memory descriptor (%p)", getName(), this, buf, dmaCommand->getMemoryDescriptor()); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, kIOReturnBadArgument, (uintptr_t)buf, (uintptr_t)dmaCommand->getMemoryDescriptor(), 2 ); return kIOReturnBadArgument; } while (length) { offset64 = offset; numSegments = 1; err = dmaCommand->gen64IOVMSegments(&offset64, &segment64, &numSegments); if (err || (numSegments != 1)) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err (%p) trying to generate segments at offset (%qd), length (%d), segLength (%d), total length (%d), buf (%p), numSegments (%d)", getName(), this, (void*)err, offset64, (int)length, (int)segLength, (int)command->GetReqCount(), buf, (int)numSegments); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, offset64, length, segLength, 3 ); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, segLength, command->GetReqCount(), numSegments, 4 ); return kIOReturnBadArgument; } // 3036056 since length might be less than the length of the descriptor, we are OK if the physical // segment is longer than we need if (segment64.fLength >= length) return kIOReturnSuccess; // this is the last segment, so we are OK // since length is a 32 bit quantity, then we know from the above statement that if we are here we are 32 bit only segLength = (IOByteCount)segment64.fLength; // so the segment is less than the rest of the length - we need to check against maxPacketSize if (segLength % maxPacketSize) { // this is the error case. I need to copy the descriptor to a new descriptor and remember that I did it USBLog(6, "%s[%p]::CheckForDisjointDescriptor - found a disjoint segment of length (%d) MPS (%d)", getName(), this, (int)segLength, maxPacketSize); length = command->GetReqCount(); // we will not return to the while loop, so don't worry about changing the value of length // allocate a new descriptor which is the same total length as the old one newBuf = IOBufferMemoryDescriptor::withOptions((command->GetDirection() == kUSBIn) ? kIODirectionIn : kIODirectionOut, length); if (!newBuf) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - could not allocate new buffer", getName(), this); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnNoMemory, 0, 5 ); return kIOReturnNoMemory; } USBLog(7, "%s[%p]::CheckForDisjointDescriptor, obtained buffer %p of length %d", getName(), this, newBuf, (int)length); // first close out (and complete) the original dma command descriptor USBLog(7, "%s[%p]::CheckForDisjointDescriptor, clearing memDec (%p) from dmaCommand (%p)", getName(), this, dmaCommand->getMemoryDescriptor(), dmaCommand); dmaCommand->clearMemoryDescriptor(); // copy the bytes to the buffer if necessary if (command->GetDirection() == kUSBOut) { USBLog(7, "%s[%p]::CheckForDisjointDescriptor, copying %d bytes from desc %p to buffer %p", getName(), this, (int)length, buf, newBuf->getBytesNoCopy()); if (buf->readBytes(0, newBuf->getBytesNoCopy(), length) != length) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - bad copy on a write", getName(), this); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, 0, 0, 6 ); newBuf->release(); return kIOReturnNoMemory; } } err = newBuf->prepare(); if (err) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err 0x%x in prepare", getName(), this, err); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, err, 0, 7 ); newBuf->release(); return err; } err = dmaCommand->setMemoryDescriptor(newBuf); if (err) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err 0x%x in setMemoryDescriptor", getName(), this, err); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, err, 0, 8 ); newBuf->complete(); newBuf->release(); return err; } command->SetOrigBuffer(command->GetBuffer()); command->SetDisjointCompletion(command->GetClientCompletion()); USBLog(7, "%s[%p]::CheckForDisjointDescriptor - changing buffer from (%p) to (%p) and putting new buffer in dmaCommand (%p)", getName(), this, command->GetBuffer(), newBuf, dmaCommand); command->SetBuffer(newBuf); IOUSBCompletion completion; completion.target = this; completion.action = (IOUSBCompletionAction)DisjointCompletion; completion.parameter = command; command->SetClientCompletion(completion); command->SetDblBufLength(length); // for the IOFree - the other buffer may change size return kIOReturnSuccess; } length -= segLength; // adjust our master length pointer offset += segLength; } USBLog(5, "%s[%p]::CheckForDisjointDescriptor - returning kIOReturnBadArgument(0x%x)", getName(), this, kIOReturnBadArgument); // USBTrace_End( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnBadArgument); return kIOReturnBadArgument; }