hrev45972 adds 12 changesets to branch 'master' old head: 883b8dd0b9be3798b6cf822c9a64470a63fc1afa new head: a69892cadca9288b901ac66273d342bfb4329373 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=a69892c+%5E883b8dd ---------------------------------------------------------------------------- cf58476: USB OHCI: Support for isochronous transfers Finishing and refactoring the draft, initially implemented during April-May 2012 NOTE: startingFrameNumber returned to device contains the number of the next free frame right after the last packed of submitted data. For more details please Look into corresponding [haiku-development] discussion started at 03 Jul 2013. Partially fixes #1045. 291e40c: USB OHCI: Fix finalizing of STALL-ed control request transfers In case control transfer is finished with STALL answer from device only the setup TD is retired into the Done Queue but other TDs (data and status) are left in the ED queue. HC set the endpoint halted - so we process such endpoint regardless of it's non-empty queue. PS: cleanup some trailing spaces. 2cc4703: Fix and force USB audio driver to work with new OHCI module * some functionality like recording temporarily disabled; * set the endpoint speed call added; * packet size hard-coded for 48kHz case; * draft support for formats and sampling rate handling; * implement sampling rate change on the fly; * optimized using of starting frame; * fix user_memory in buffer exchaqnge call; * fix exchanged buffer recoriding processing; * debug tweaks, fix current buffer switching; * cleanup, cleanup, cleanup... 673ef2c: USB audio: cleanup and codestyle fixes. * cleanup and codestyle fixes; * AudioFunction module contents purged out as unused. b42544e: USB audio: fInsideNotify guard added to Remote/Close callbacks 1a6d941: USB audio: Use system-wide USB_audio.h instead local one * switching driver code to use system usb/USB_audio.h header; * refactor USB_audio.h specification header for both USB audio specifications. 7ff9cd3: USB audio: Refactor TRACE-es for more configurability a8066fe: USB audio: dev.entry number should be 1-based, etc * USB audio device entry number made 1-based instead of 0. According to Haiku MultiAudio specs audio device entries should be 1-based but 0-based; * cleanup and refactoring. No functional changes; * recording stream activated; * fix input channels description report and codestyle issues. 353a4e0: USB audio: Fix function of Selector Unit control * restore function of Selector Unit that was previously disabled; * fix Selector Unit input pin names "Unknwon" case. 743d759: USB audio: Mixer Unit control implementation * support of Mixer Unit control in UI implemented; * improve SetMix/GetMix to support Mixer Unit control type; * cleanup and improvements. 14f9200: USB audio: use new(std::nothrow) for allocations * Use new(std::nothrow) for allocations; * Input buffer index counter restored; * Improve unsupported UI controls debug info tracing; * Some cleanup. a69892c: Rename driver folder 'usb_audio' to 'usb' ... just because the source path ./kernel/drivers/audio/usb obviously references audio hardware so "_audio" suffix is excessive. No functional changes. [ Siarzhuk Zharski <zharik@xxxxxx> ] ---------------------------------------------------------------------------- 36 files changed, 5898 insertions(+), 6658 deletions(-) headers/os/drivers/USB_spec.h | 13 + headers/os/drivers/usb/USB_audio.h | 500 ++++- src/add-ons/kernel/busses/usb/ohci.cpp | 794 ++++++- src/add-ons/kernel/busses/usb/ohci.h | 61 +- src/add-ons/kernel/busses/usb/ohci.rdef | 2 +- src/add-ons/kernel/busses/usb/ohci_hardware.h | 33 +- src/add-ons/kernel/drivers/audio/Jamfile | 2 +- .../drivers/audio/usb/AudioControlInterface.cpp | 2059 ++++++++++++++++++ .../drivers/audio/usb/AudioControlInterface.h | 352 +++ .../audio/usb/AudioStreamingInterface.cpp | 516 +++++ .../drivers/audio/usb/AudioStreamingInterface.h | 162 ++ src/add-ons/kernel/drivers/audio/usb/Device.cpp | 667 ++++++ src/add-ons/kernel/drivers/audio/usb/Device.h | 88 + .../drivers/audio/{usb_audio => usb}/Driver.cpp | 118 +- .../drivers/audio/{usb_audio => usb}/Driver.h | 29 +- .../drivers/audio/{usb_audio => usb}/Jamfile | 7 +- .../audio/{usb_audio => usb}/Settings.cpp | 41 +- src/add-ons/kernel/drivers/audio/usb/Settings.h | 40 + src/add-ons/kernel/drivers/audio/usb/Stream.cpp | 537 +++++ src/add-ons/kernel/drivers/audio/usb/Stream.h | 74 + .../kernel/drivers/audio/usb/usb_audio.settings | 36 + .../audio/usb_audio/AudioControlInterface.cpp | 1711 --------------- .../audio/usb_audio/AudioControlInterface.h | 319 --- .../drivers/audio/usb_audio/AudioFunction.cpp | 1092 ---------- .../drivers/audio/usb_audio/AudioFunction.h | 349 --- .../audio/usb_audio/AudioStreamingInterface.cpp | 406 ---- .../audio/usb_audio/AudioStreamingInterface.h | 156 -- .../kernel/drivers/audio/usb_audio/Device.cpp | 778 ------- .../kernel/drivers/audio/usb_audio/Device.h | 139 -- .../kernel/drivers/audio/usb_audio/Settings.h | 34 - .../kernel/drivers/audio/usb_audio/Stream.cpp | 528 ----- .../kernel/drivers/audio/usb_audio/Stream.h | 96 - .../drivers/audio/usb_audio/USB_audio_spec.h | 497 ----- .../kernel/drivers/audio/usb_audio/audio.h | 165 -- .../kernel/drivers/audio/usb_audio/makefile | 127 -- .../drivers/audio/usb_audio/usb_audio.settings | 28 - ############################################################################ Commit: cf58476cccdd470c401dd06dec94dc1939e4f3fc URL: http://cgit.haiku-os.org/haiku/commit/?id=cf58476 Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Sat May 25 18:46:44 2013 UTC Ticket: https://dev.haiku-os.org/ticket/1045 USB OHCI: Support for isochronous transfers Finishing and refactoring the draft, initially implemented during April-May 2012 NOTE: startingFrameNumber returned to device contains the number of the next free frame right after the last packed of submitted data. For more details please Look into corresponding [haiku-development] discussion started at 03 Jul 2013. Partially fixes #1045. ---------------------------------------------------------------------------- diff --git a/headers/os/drivers/USB_spec.h b/headers/os/drivers/USB_spec.h index 08fe588..9b94857 100644 --- a/headers/os/drivers/USB_spec.h +++ b/headers/os/drivers/USB_spec.h @@ -62,6 +62,19 @@ #define USB_ENDPOINT_ATTR_INTERRUPT 0x03 #define USB_ENDPOINT_ATTR_MASK 0x03 +/* Synchronization - isochrnous endpoints only */ +#define USB_ENDPOINT_ATTR_NO_SYNCHRONIZE 0x00 +#define USB_ENDPOINT_ATTR_ASYNCRONOUS 0x04 +#define USB_ENDPOINT_ATTR_ADAPTIVE_SYNCHRO 0x08 +#define USB_ENDPOINT_ATTR_SYNCHRONOUS 0x0C +#define USB_ENDPOINT_ATTR_SYNCHRONIZE_MASK 0x0C + +/* Usage Type - isochrnous endpoints only */ +#define USB_ENDPOINT_ATTR_DATA_USAGE 0x00 +#define USB_ENDPOINT_ATTR_FEEDBACK_USAGE 0x10 +#define USB_ENDPOINT_ATTR_IMPLICIT_USAGE 0x20 +#define USB_ENDPOINT_ATTR_USAGE_MASK 0x30 + #define USB_ENDPOINT_ADDR_DIR_IN 0x80 #define USB_ENDPOINT_ADDR_DIR_OUT 0x00 diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp index 3a28a49..489a762 100644 --- a/src/add-ons/kernel/busses/usb/ohci.cpp +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -1,11 +1,12 @@ /* - * Copyright 2005-2008, Haiku Inc. All rights reserved. + * Copyright 2005-2013, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Jan-Rixt Van Hoye * Salvatore Benedetto <salvatore.benedetto@xxxxxxxxx> * Michael Lotz <mmlr@xxxxxxxx> + * Siarzhuk Zharski <imker@xxxxxx> */ #include <module.h> @@ -74,6 +75,7 @@ OHCI::OHCI(pci_info *info, Stack *stack) fFinishThread(-1), fStopFinishThread(false), fProcessingPipe(NULL), + fFrameBandwidth(NULL), fRootHub(NULL), fRootHubAddress(0), fPortCount(0), @@ -312,6 +314,12 @@ OHCI::OHCI(pci_info *info, Stack *stack) fPortCount = numberOfPorts; TRACE("port count is %d\n", fPortCount); + // Create the array that will keep bandwidth information + fFrameBandwidth = new(std::nothrow) uint16[NUMBER_OF_FRAMES]; + + for (int32 i = 0; i < NUMBER_OF_FRAMES; i++) + fFrameBandwidth[i] = MAX_AVAILABLE_BANDWIDTH; + // Create semaphore the finisher thread will wait for fFinishTransfersSem = create_sem(0, "OHCI Finish Transfers"); if (fFinishTransfersSem < B_OK) { @@ -378,6 +386,7 @@ OHCI::~OHCI() _FreeEndpoint(fInterruptEndpoints[i]); } + delete [] fFrameBandwidth; delete [] fInterruptEndpoints; delete fRootHub; @@ -459,9 +468,6 @@ OHCI::SubmitTransfer(Transfer *transfer) status_t OHCI::CancelQueuedTransfers(Pipe *pipe, bool force) { - if (pipe->Type() & USB_OBJECT_ISO_PIPE) - return _CancelQueuedIsochronousTransfers(pipe, force); - if (!Lock()) return B_ERROR; @@ -487,6 +493,25 @@ OHCI::CancelQueuedTransfers(Pipe *pipe, bool force) = current->endpoint->tail_physical_descriptor; if (!force) { + if (pipe->Type() & USB_OBJECT_ISO_PIPE) { + ohci_isochronous_td *descriptor + = (ohci_isochronous_td *)current->first_descriptor; + while (descriptor) { + uint16 frame = OHCI_ITD_GET_STARTING_FRAME( + descriptor->flags); + _ReleaseIsochronousBandwidth(frame, + OHCI_ITD_GET_FRAME_COUNT(descriptor->flags)); + if (descriptor + == (ohci_isochronous_td*)current->last_descriptor) + // this is the last ITD of the transfer + break; + + descriptor + = (ohci_isochronous_td *) + descriptor->next_done_descriptor; + } + } + // If the transfer is canceled by force, the one causing the // cancel is probably not the one who initiated the transfer // and the callback is likely not safe anymore @@ -914,10 +939,55 @@ OHCI::_AddPendingTransfer(Transfer *transfer, status_t -OHCI::_CancelQueuedIsochronousTransfers(Pipe *pipe, bool force) +OHCI::_AddPendingIsochronousTransfer(Transfer *transfer, + ohci_endpoint_descriptor *endpoint, ohci_isochronous_td *firstDescriptor, + ohci_isochronous_td *lastDescriptor, bool directionIn) { - // TODO - return B_ERROR; + if (!transfer || !endpoint || !lastDescriptor) + return B_BAD_VALUE; + + transfer_data *data = new(std::nothrow) transfer_data; + if (!data) + return B_NO_MEMORY; + + status_t result = transfer->InitKernelAccess(); + if (result < B_OK) { + delete data; + return result; + } + + data->transfer = transfer; + data->endpoint = endpoint; + data->incoming = directionIn; + data->canceled = false; + data->link = NULL; + + // the current tail will become the first descriptor + data->first_descriptor = (ohci_general_td*)endpoint->tail_logical_descriptor; + + // the data and first descriptors are the same + data->data_descriptor = data->first_descriptor; + + // the last and the first descriptor might be the same + if (lastDescriptor == firstDescriptor) + data->last_descriptor = data->first_descriptor; + else + data->last_descriptor = (ohci_general_td*)lastDescriptor; + + if (!Lock()) { + delete data; + return B_ERROR; + } + + if (fLastTransfer) + fLastTransfer->link = data; + else + fFirstTransfer = data; + + fLastTransfer = data; + Unlock(); + + return B_OK; } @@ -957,10 +1027,20 @@ OHCI::_FinishTransfers() ohci_endpoint_descriptor *endpoint = transfer->endpoint; status_t callbackStatus = B_OK; + if (endpoint->flags & OHCI_ENDPOINT_ISOCHRONOUS_FORMAT) { + transfer_data *next = transfer->link; + if (_FinishIsochronousTransfer(transfer, &lastTransfer)) { + delete transfer->transfer; + delete transfer; + } + transfer = next; + continue; + } + MutexLocker endpointLocker(endpoint->lock); if ((endpoint->head_physical_descriptor & OHCI_ENDPOINT_HEAD_MASK) - != endpoint->tail_physical_descriptor) { + != endpoint->tail_physical_descriptor) { // there are still active transfers on this endpoint, we need // to wait for all of them to complete, otherwise we'd read // a potentially bogus data toggle value below @@ -991,49 +1071,7 @@ OHCI::_FinishTransfers() // still ensures that this td was handled before). TRACE_ERROR("td error: 0x%08" B_PRIx32 "\n", status); - switch (status) { - case OHCI_TD_CONDITION_CRC_ERROR: - case OHCI_TD_CONDITION_BIT_STUFFING: - case OHCI_TD_CONDITION_TOGGLE_MISMATCH: - callbackStatus = B_DEV_CRC_ERROR; - break; - - case OHCI_TD_CONDITION_STALL: - callbackStatus = B_DEV_STALLED; - break; - - case OHCI_TD_CONDITION_NO_RESPONSE: - callbackStatus = B_TIMED_OUT; - break; - - case OHCI_TD_CONDITION_PID_CHECK_FAILURE: - callbackStatus = B_DEV_BAD_PID; - break; - - case OHCI_TD_CONDITION_UNEXPECTED_PID: - callbackStatus = B_DEV_UNEXPECTED_PID; - break; - - case OHCI_TD_CONDITION_DATA_OVERRUN: - callbackStatus = B_DEV_DATA_OVERRUN; - break; - - case OHCI_TD_CONDITION_DATA_UNDERRUN: - callbackStatus = B_DEV_DATA_UNDERRUN; - break; - - case OHCI_TD_CONDITION_BUFFER_OVERRUN: - callbackStatus = B_DEV_FIFO_OVERRUN; - break; - - case OHCI_TD_CONDITION_BUFFER_UNDERRUN: - callbackStatus = B_DEV_FIFO_UNDERRUN; - break; - - default: - callbackStatus = B_ERROR; - break; - } + callbackStatus = _GetStatusOfConditionCode(status); transferDone = true; break; @@ -1163,6 +1201,141 @@ OHCI::_FinishTransfers() } +bool +OHCI::_FinishIsochronousTransfer(transfer_data *transfer, + transfer_data **_lastTransfer) +{ + status_t callbackStatus = B_OK; + size_t actualLength = 0; + uint32 packet = 0; + + if (transfer->canceled) + callbackStatus = B_CANCELED; + else { + // at first check if ALL ITDs are retired by HC + ohci_isochronous_td *descriptor + = (ohci_isochronous_td *)transfer->first_descriptor; + while (descriptor) { + if (OHCI_TD_GET_CONDITION_CODE(descriptor->flags) + == OHCI_TD_CONDITION_NOT_ACCESSED) { + TRACE("ITD %p still active\n", descriptor); + *_lastTransfer = transfer; + return false; + } + + if (descriptor == (ohci_isochronous_td*)transfer->last_descriptor) { + // this is the last ITD of the transfer + descriptor = (ohci_isochronous_td *)transfer->first_descriptor; + break; + } + + descriptor + = (ohci_isochronous_td *)descriptor->next_done_descriptor; + } + + while (descriptor) { + uint32 status = OHCI_TD_GET_CONDITION_CODE(descriptor->flags); + if (status != OHCI_TD_CONDITION_NO_ERROR) { + TRACE_ERROR("ITD error: 0x%08" B_PRIx32 "\n", status); + // spec says that in most cases condition code + // of retired ITDs is set to NoError, but for the + // time overrun it can be DataOverrun. We assume + // the _first_ occurience of such error as status + // reported to the callback + if (callbackStatus == B_OK) + callbackStatus = _GetStatusOfConditionCode(status); + } + + usb_isochronous_data *isochronousData + = transfer->transfer->IsochronousData(); + + uint32 frameCount = OHCI_ITD_GET_FRAME_COUNT(descriptor->flags); + for (size_t i = 0; i < frameCount; i++, packet++) { + usb_iso_packet_descriptor* packet_descriptor + = &isochronousData->packet_descriptors[packet]; + + uint16 offset = descriptor->offset[OHCI_ITD_OFFSET_IDX(i)]; + uint8 code = OHCI_ITD_GET_BUFFER_CONDITION_CODE(offset); + packet_descriptor->status = _GetStatusOfConditionCode(code); + + // not touched by HC - sheduled too late to be processed + // in the requested frame - so we ignore it too + if (packet_descriptor->status == B_DEV_TOO_LATE) + continue; + + size_t len = OHCI_ITD_GET_BUFFER_LENGTH(offset); + if (!transfer->incoming) + len = packet_descriptor->request_length - len; + + packet_descriptor->actual_length = len; + actualLength += len; + } + + uint16 frame = OHCI_ITD_GET_STARTING_FRAME(descriptor->flags); + _ReleaseIsochronousBandwidth(frame, + OHCI_ITD_GET_FRAME_COUNT(descriptor->flags)); + + TRACE("ITD %p done\n", descriptor); + + if (descriptor == (ohci_isochronous_td*)transfer->last_descriptor) + break; + + descriptor + = (ohci_isochronous_td *)descriptor->next_done_descriptor; + } + } + + // remove the transfer from the list first so we are sure + // it doesn't get canceled while we still process it + if (Lock()) { + if (*_lastTransfer) + (*_lastTransfer)->link = transfer->link; + + if (transfer == fFirstTransfer) + fFirstTransfer = transfer->link; + if (transfer == fLastTransfer) + fLastTransfer = *_lastTransfer; + + // store the currently processing pipe here so we can wait + // in cancel if we are processing something on the target pipe + if (!transfer->canceled) + fProcessingPipe = transfer->transfer->TransferPipe(); + + transfer->link = NULL; + Unlock(); + } + + // break the descriptor chain on the last descriptor + transfer->last_descriptor->next_logical_descriptor = NULL; + TRACE("iso.transfer %p done with status 0x%08" B_PRIx32 " len:%ld\n", + transfer, callbackStatus, actualLength); + + // if canceled the callback has already been called + if (!transfer->canceled) { + if (callbackStatus == B_OK && actualLength > 0) { + if (transfer->data_descriptor && transfer->incoming) { + // data to read out + iovec *vector = transfer->transfer->Vector(); + size_t vectorCount = transfer->transfer->VectorCount(); + + transfer->transfer->PrepareKernelAccess(); + _ReadIsochronousDescriptorChain( + (ohci_isochronous_td*)transfer->data_descriptor, + vector, vectorCount); + } + } + + transfer->transfer->Finished(callbackStatus, actualLength); + fProcessingPipe = NULL; + } + + _FreeIsochronousDescriptorChain( + (ohci_isochronous_td*)transfer->first_descriptor); + + return true; +} + + status_t OHCI::_SubmitRequest(Transfer *transfer) { @@ -1307,8 +1480,58 @@ OHCI::_SubmitTransfer(Transfer *transfer) status_t OHCI::_SubmitIsochronousTransfer(Transfer *transfer) { - TRACE_ERROR("isochronous transfers not implemented\n"); - return B_ERROR; + Pipe *pipe = transfer->TransferPipe(); + bool directionIn = (pipe->Direction() == Pipe::In); + usb_isochronous_data *isochronousData = transfer->IsochronousData(); + + ohci_isochronous_td *firstDescriptor = NULL; + ohci_isochronous_td *lastDescriptor = NULL; + status_t result = _CreateIsochronousDescriptorChain(&firstDescriptor, + &lastDescriptor, transfer); + + if (firstDescriptor == 0 || lastDescriptor == 0) + return B_ERROR; + + if (result < B_OK) + return result; + + // Set the last descriptor to generate an interrupt + lastDescriptor->flags &= ~OHCI_ITD_INTERRUPT_MASK; + // let the controller retire last ITD + lastDescriptor->flags |= OHCI_ITD_SET_DELAY_INTERRUPT(1); + + // If direction is out set every descriptor data + if (pipe->Direction() == Pipe::Out) + _WriteIsochronousDescriptorChain(firstDescriptor, + transfer->Vector(), transfer->VectorCount()); + else + // Initialize the packet descriptors + for (uint32 i = 0; i < isochronousData->packet_count; i++) { + isochronousData->packet_descriptors[i].actual_length = 0; + isochronousData->packet_descriptors[i].status = B_NO_INIT; + } + + // Add to the transfer list + ohci_endpoint_descriptor *endpoint + = (ohci_endpoint_descriptor *)pipe->ControllerCookie(); + + MutexLocker endpointLocker(endpoint->lock); + result = _AddPendingIsochronousTransfer(transfer, endpoint, + firstDescriptor, lastDescriptor, directionIn); + if (result < B_OK) { + TRACE_ERROR("failed to add pending iso.transfer:" + "0x%08" B_PRIx32 "\n", result); + _FreeIsochronousDescriptorChain(firstDescriptor); + return result; + } + + // Add the descriptor chain to the endpoint + _SwitchIsochronousEndpointTail(endpoint, firstDescriptor, lastDescriptor); + endpointLocker.Unlock(); + + endpoint->flags &= ~OHCI_ENDPOINT_SKIP; + + return B_OK; } @@ -1353,6 +1576,54 @@ OHCI::_SwitchEndpointTail(ohci_endpoint_descriptor *endpoint, void +OHCI::_SwitchIsochronousEndpointTail(ohci_endpoint_descriptor *endpoint, + ohci_isochronous_td *first, ohci_isochronous_td *last) +{ + // fill in the information of the first descriptor into the current tail + ohci_isochronous_td *tail + = (ohci_isochronous_td*)endpoint->tail_logical_descriptor; + tail->flags = first->flags; + tail->buffer_page_byte_0 = first->buffer_page_byte_0; + tail->next_physical_descriptor = first->next_physical_descriptor; + tail->last_byte_address = first->last_byte_address; + tail->buffer_size = first->buffer_size; + tail->buffer_logical = first->buffer_logical; + tail->next_logical_descriptor = first->next_logical_descriptor; + tail->next_done_descriptor = first->next_done_descriptor; + + // the first descriptor becomes the new tail + first->flags = 0; + first->buffer_page_byte_0 = 0; + first->next_physical_descriptor = 0; + first->last_byte_address = 0; + first->buffer_size = 0; + first->buffer_logical = NULL; + first->next_logical_descriptor = NULL; + first->next_done_descriptor = NULL; + + for (int i = 0; i < OHCI_ITD_NOFFSET; i++) { + tail->offset[i] = first->offset[i]; + first->offset[i] = 0; + } + + if (first == last) + _LinkIsochronousDescriptors(tail, first, NULL); + else + _LinkIsochronousDescriptors(last, first, NULL); + + // update the endpoint tail pointer to reflect the change + endpoint->tail_logical_descriptor = first; + endpoint->tail_physical_descriptor = (uint32)first->physical_address; + TRACE("switched tail from %p to %p\n", tail, first); + +#if 0 + _PrintEndpoint(endpoint); + _PrintDescriptorChain(tail); +#endif +} + + +void OHCI::_RemoveTransferFromEndpoint(transfer_data *transfer) { // The transfer failed and the endpoint was halted. This means that the @@ -1515,9 +1786,11 @@ OHCI::_InsertEndpointForPipe(Pipe *pipe) if (pipe->Type() & USB_OBJECT_ISO_PIPE) { // Set the isochronous bit format endpoint->flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT; - // TODO - _FreeEndpoint(endpoint); - return B_ERROR; + ohci_isochronous_td *tail = _CreateIsochronousDescriptor(0); + tail->flags = 0; + endpoint->tail_logical_descriptor = tail; + endpoint->head_physical_descriptor = tail->physical_address; + endpoint->tail_physical_descriptor = tail->physical_address; } else { ohci_general_td *tail = _CreateGeneralDescriptor(0); tail->flags = 0; @@ -1691,6 +1964,191 @@ OHCI::_FreeDescriptorChain(ohci_general_td *topDescriptor) } +ohci_isochronous_td * +OHCI::_CreateIsochronousDescriptor(size_t bufferSize) +{ + ohci_isochronous_td *descriptor = NULL; + phys_addr_t physicalAddress; + + if (fStack->AllocateChunk((void **)&descriptor, &physicalAddress, + sizeof(ohci_isochronous_td)) != B_OK) { + TRACE_ERROR("failed to allocate isochronous descriptor\n"); + return NULL; + } + + descriptor->physical_address = (uint32)physicalAddress; + descriptor->next_physical_descriptor = 0; + descriptor->next_logical_descriptor = NULL; + descriptor->next_done_descriptor = NULL; + descriptor->buffer_size = bufferSize; + if (bufferSize == 0) { + descriptor->buffer_page_byte_0 = 0; + descriptor->buffer_logical = NULL; + descriptor->last_byte_address = 0; + return descriptor; + } + + if (fStack->AllocateChunk(&descriptor->buffer_logical, + &physicalAddress, bufferSize) != B_OK) { + TRACE_ERROR("failed to allocate space for iso.buffer\n"); + fStack->FreeChunk(descriptor, descriptor->physical_address, + sizeof(ohci_isochronous_td)); + return NULL; + } + descriptor->buffer_page_byte_0 = (uint32)physicalAddress; + descriptor->last_byte_address + = descriptor->buffer_page_byte_0 + bufferSize - 1; + + return descriptor; +} + + +void +OHCI::_FreeIsochronousDescriptor(ohci_isochronous_td *descriptor) +{ + if (!descriptor) + return; + + if (descriptor->buffer_logical) { + fStack->FreeChunk(descriptor->buffer_logical, + descriptor->buffer_page_byte_0, descriptor->buffer_size); + } + + fStack->FreeChunk((void *)descriptor, descriptor->physical_address, + sizeof(ohci_general_td)); +} + + +status_t +OHCI::_CreateIsochronousDescriptorChain(ohci_isochronous_td **_firstDescriptor, + ohci_isochronous_td **_lastDescriptor, Transfer *transfer) +{ + Pipe *pipe = transfer->TransferPipe(); + usb_isochronous_data *isochronousData = transfer->IsochronousData(); + + size_t dataLength = transfer->VectorLength(); + size_t packet_count = isochronousData->packet_count; + + if (packet_count == 0) { + TRACE_ERROR("isochronous packet_count should not be equal to zero."); + return B_BAD_VALUE; + } + + size_t packetSize = dataLength / packet_count; + if (dataLength % packet_count != 0) + packetSize++; + + if (packetSize > pipe->MaxPacketSize()) { + TRACE_ERROR("isochronous packetSize %ld is bigger" + " than pipe MaxPacketSize %ld.", packetSize, pipe->MaxPacketSize()); + return B_BAD_VALUE; + } + + uint16 bandwidth = transfer->Bandwidth() / packet_count; + if (transfer->Bandwidth() % packet_count != 0) + bandwidth++; + + ohci_isochronous_td *firstDescriptor = NULL; + ohci_isochronous_td *lastDescriptor = *_firstDescriptor; + + // the frame number currently processed by the host controller + uint16 currentFrame = fHcca->current_frame_number & 0xFFFF; + uint16 safeFrames = 5; + + // The entry where to start inserting the first Isochronous descriptor + // real frame number may differ in case provided one has not bandwidth + if (isochronousData->flags & USB_ISO_ASAP || + isochronousData->starting_frame_number == NULL) + // We should stay about 5-10 ms ahead of the controller + // USB1 frame is equal to 1 ms + currentFrame += safeFrames; + else + currentFrame = *isochronousData->starting_frame_number; + + uint16 packets = packet_count; + uint16 frameOffset = 0; + while (packets > 0) { + // look for up to 8 continous frames with available bandwidth + uint16 frameCount = 0; + while (frameCount < min_c(OHCI_ITD_NOFFSET, packets) + && _AllocateIsochronousBandwidth(frameOffset + currentFrame + + frameCount, bandwidth)) + frameCount++; + + if (frameCount == 0) { + // starting frame has no bandwidth for our transaction - try next + if (++frameOffset >= 0xFFFF) { + TRACE_ERROR("failed to allocate bandwidth\n"); + _FreeIsochronousDescriptorChain(firstDescriptor); + return B_NO_MEMORY; + } + continue; + } + + ohci_isochronous_td *descriptor = _CreateIsochronousDescriptor( + packetSize * frameCount); + + if (!descriptor) { + TRACE_ERROR("failed to allocate ITD\n"); + _ReleaseIsochronousBandwidth(currentFrame + frameOffset, frameCount); + _FreeIsochronousDescriptorChain(firstDescriptor); + return B_NO_MEMORY; + } + + uint16 pageOffset = descriptor->buffer_page_byte_0 & 0xfff; + descriptor->buffer_page_byte_0 &= ~0xfff; + for (uint16 i = 0; i < frameCount; i++) { + descriptor->offset[OHCI_ITD_OFFSET_IDX(i)] + = OHCI_ITD_MK_OFFS(pageOffset + packetSize * i); + } + + descriptor->flags = OHCI_ITD_SET_FRAME_COUNT(frameCount) + | OHCI_ITD_SET_CONDITION_CODE(OHCI_ITD_CONDITION_NOT_ACCESSED) + | OHCI_ITD_SET_DELAY_INTERRUPT(OHCI_ITD_INTERRUPT_NONE) + | OHCI_ITD_SET_STARTING_FRAME(currentFrame + frameOffset); + + // the last packet may be shorter than other ones in this transfer + if (packets <= OHCI_ITD_NOFFSET) + descriptor->last_byte_address + += dataLength - packetSize * (packet_count); + + // link to previous + if (lastDescriptor) + _LinkIsochronousDescriptors(lastDescriptor, descriptor, descriptor); + + lastDescriptor = descriptor; + if (!firstDescriptor) + firstDescriptor = descriptor; + + packets -= frameCount; + + frameOffset += frameCount; + + if (packets == 0 && isochronousData->starting_frame_number) + *isochronousData->starting_frame_number = currentFrame + frameOffset; + } + + *_firstDescriptor = firstDescriptor; + *_lastDescriptor = lastDescriptor; + + return B_OK; +} + + +void +OHCI::_FreeIsochronousDescriptorChain(ohci_isochronous_td *topDescriptor) +{ + ohci_isochronous_td *current = topDescriptor; + ohci_isochronous_td *next = NULL; + + while (current) { + next = (ohci_isochronous_td *)current->next_done_descriptor; + _FreeIsochronousDescriptor(current); + current = next; + } +} + + size_t OHCI::_WriteDescriptorChain(ohci_general_td *topDescriptor, iovec *vector, size_t vectorCount) @@ -1747,6 +2205,61 @@ OHCI::_WriteDescriptorChain(ohci_general_td *topDescriptor, iovec *vector, size_t +OHCI::_WriteIsochronousDescriptorChain(ohci_isochronous_td *topDescriptor, + iovec *vector, size_t vectorCount) +{ + ohci_isochronous_td *current = topDescriptor; + size_t actualLength = 0; + size_t vectorIndex = 0; + size_t vectorOffset = 0; + size_t bufferOffset = 0; + + while (current) { + if (!current->buffer_logical) + break; + + while (true) { + size_t length = min_c(current->buffer_size - bufferOffset, + vector[vectorIndex].iov_len - vectorOffset); + + TRACE("copying %ld bytes to bufferOffset %ld from" + " vectorOffset %ld at index %ld of %ld\n", length, bufferOffset, + vectorOffset, vectorIndex, vectorCount); + memcpy((uint8 *)current->buffer_logical + bufferOffset, + (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); + + actualLength += length; + vectorOffset += length; + bufferOffset += length; + + if (vectorOffset >= vector[vectorIndex].iov_len) { + if (++vectorIndex >= vectorCount) { + TRACE("wrote descriptor chain (%ld bytes, no" + " more vectors)\n", actualLength); + return actualLength; + } + + vectorOffset = 0; + } + + if (bufferOffset >= current->buffer_size) { + bufferOffset = 0; + break; + } + } + + if (!current->next_logical_descriptor) + break; + + current = (ohci_isochronous_td *)current->next_logical_descriptor; + } + + TRACE("wrote descriptor chain (%ld bytes)\n", actualLength); + return actualLength; +} + + +size_t OHCI::_ReadDescriptorChain(ohci_general_td *topDescriptor, iovec *vector, size_t vectorCount) { @@ -1805,6 +2318,59 @@ OHCI::_ReadDescriptorChain(ohci_general_td *topDescriptor, iovec *vector, } +void +OHCI::_ReadIsochronousDescriptorChain(ohci_isochronous_td *topDescriptor, + iovec *vector, size_t vectorCount) +{ + ohci_isochronous_td *current = topDescriptor; + size_t actualLength = 0; + size_t vectorIndex = 0; + size_t vectorOffset = 0; + size_t bufferOffset = 0; + + while (current && OHCI_ITD_GET_CONDITION_CODE(current->flags) + != OHCI_ITD_CONDITION_NOT_ACCESSED) { + size_t bufferSize = current->buffer_size; + if (current->buffer_logical != NULL && bufferSize > 0) { + while (true) { + size_t length = min_c(bufferSize - bufferOffset, + vector[vectorIndex].iov_len - vectorOffset); + + TRACE("copying %ld bytes to vectorOffset %ld from bufferOffset" + " %ld at index %ld of %ld\n", length, vectorOffset, + bufferOffset, vectorIndex, vectorCount); + memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, + (uint8 *)current->buffer_logical + bufferOffset, length); + + actualLength += length; + vectorOffset += length; + bufferOffset += length; + + if (vectorOffset >= vector[vectorIndex].iov_len) { + if (++vectorIndex >= vectorCount) { + TRACE("read descriptor chain (%ld bytes, " + "no more vectors)\n", actualLength); + return; + } + + vectorOffset = 0; + } + + if (bufferOffset >= bufferSize) { + bufferOffset = 0; + break; + } + } + } + + current = (ohci_isochronous_td *)current->next_done_descriptor; + } + + TRACE("read descriptor chain (%ld bytes)\n", actualLength); + return; +} + + size_t OHCI::_ReadActualLength(ohci_general_td *topDescriptor) { @@ -1836,18 +2402,85 @@ OHCI::_LinkDescriptors(ohci_general_td *first, ohci_general_td *second) } -ohci_isochronous_td * -OHCI::_CreateIsochronousDescriptor() +void +OHCI::_LinkIsochronousDescriptors(ohci_isochronous_td *first, + ohci_isochronous_td *second, ohci_isochronous_td *nextDone) { - // TODO - return NULL; + first->next_physical_descriptor = second->physical_address; + first->next_logical_descriptor = second; + first->next_done_descriptor = nextDone; +} + + +bool +OHCI::_AllocateIsochronousBandwidth(uint16 frame, uint16 size) +{ + frame %= NUMBER_OF_FRAMES; + if (size > fFrameBandwidth[frame]) + return false; + + fFrameBandwidth[frame]-= size; + return true; } void -OHCI::_FreeIsochronousDescriptor(ohci_isochronous_td *descriptor) +OHCI::_ReleaseIsochronousBandwidth(uint16 startFrame, uint16 frameCount) { - // TODO + for (size_t index = 0; index < frameCount; index++) { + uint16 frame = (startFrame + index) % NUMBER_OF_FRAMES; + fFrameBandwidth[frame] = MAX_AVAILABLE_BANDWIDTH; + } +} + + +status_t +OHCI::_GetStatusOfConditionCode(uint8 conditionCode) +{ + switch (conditionCode) { + case OHCI_TD_CONDITION_NO_ERROR: + return B_OK; + + case OHCI_TD_CONDITION_CRC_ERROR: + case OHCI_TD_CONDITION_BIT_STUFFING: + case OHCI_TD_CONDITION_TOGGLE_MISMATCH: + return B_DEV_CRC_ERROR; + + case OHCI_TD_CONDITION_STALL: + return B_DEV_STALLED; + + case OHCI_TD_CONDITION_NO_RESPONSE: + return B_TIMED_OUT; + + case OHCI_TD_CONDITION_PID_CHECK_FAILURE: + return B_DEV_BAD_PID; + + case OHCI_TD_CONDITION_UNEXPECTED_PID: + return B_DEV_UNEXPECTED_PID; + + case OHCI_TD_CONDITION_DATA_OVERRUN: + return B_DEV_DATA_OVERRUN; + + case OHCI_TD_CONDITION_DATA_UNDERRUN: + return B_DEV_DATA_UNDERRUN; + + case OHCI_TD_CONDITION_BUFFER_OVERRUN: + return B_DEV_FIFO_OVERRUN; + + case OHCI_TD_CONDITION_BUFFER_UNDERRUN: + return B_DEV_FIFO_UNDERRUN; + + case OHCI_TD_CONDITION_NOT_ACCESSED: + return B_DEV_PENDING; + + case 0x0E: + return B_DEV_TOO_LATE; // PSW: _NOT_ACCESSED + + default: + break; + } + + return B_ERROR; } @@ -1882,7 +2515,7 @@ OHCI::_ReadReg(uint32 reg) void OHCI::_PrintEndpoint(ohci_endpoint_descriptor *endpoint) { - TRACE_ALWAYS("endpoint %p\n", endpoint); + dprintf("endpoint %p\n", endpoint); dprintf("\tflags........... 0x%08" B_PRIx32 "\n", endpoint->flags); dprintf("\ttail_physical... 0x%08" B_PRIx32 "\n", endpoint->tail_physical_descriptor); dprintf("\thead_physical... 0x%08" B_PRIx32 "\n", endpoint->head_physical_descriptor); @@ -1897,7 +2530,7 @@ void OHCI::_PrintDescriptorChain(ohci_general_td *topDescriptor) { while (topDescriptor) { - TRACE_ALWAYS("descriptor %p\n", topDescriptor); + dprintf("descriptor %p\n", topDescriptor); dprintf("\tflags........... 0x%08" B_PRIx32 "\n", topDescriptor->flags); dprintf("\tbuffer_physical. 0x%08" B_PRIx32 "\n", topDescriptor->buffer_physical); dprintf("\tnext_physical... 0x%08" B_PRIx32 "\n", topDescriptor->next_physical_descriptor); @@ -1910,3 +2543,30 @@ OHCI::_PrintDescriptorChain(ohci_general_td *topDescriptor) topDescriptor = (ohci_general_td *)topDescriptor->next_logical_descriptor; } } + + +void +OHCI::_PrintDescriptorChain(ohci_isochronous_td *topDescriptor) +{ + while (topDescriptor) { + dprintf("iso.descriptor %p\n", topDescriptor); + dprintf("\tflags........... 0x%08" B_PRIx32 "\n", topDescriptor->flags); + dprintf("\tbuffer_pagebyte0 0x%08" B_PRIx32 "\n", topDescriptor->buffer_page_byte_0); + dprintf("\tnext_physical... 0x%08" B_PRIx32 "\n", topDescriptor->next_physical_descriptor); + dprintf("\tlast_byte....... 0x%08" B_PRIx32 "\n", topDescriptor->last_byte_address); + dprintf("\toffset:\n\t0x%04x 0x%04x 0x%04x 0x%04x\n" + "\t0x%04x 0x%04x 0x%04x 0x%04x\n", + topDescriptor->offset[0], topDescriptor->offset[1], + topDescriptor->offset[2], topDescriptor->offset[3], + topDescriptor->offset[4], topDescriptor->offset[5], + topDescriptor->offset[6], topDescriptor->offset[7]); + dprintf("\tphysical........ 0x%08" B_PRIx32 "\n", topDescriptor->physical_address); + dprintf("\tbuffer_size..... %lu\n", topDescriptor->buffer_size); + dprintf("\tbuffer_logical.. %p\n", topDescriptor->buffer_logical); + dprintf("\tnext_logical.... %p\n", topDescriptor->next_logical_descriptor); + dprintf("\tnext_done....... %p\n", topDescriptor->next_done_descriptor); + + topDescriptor = (ohci_isochronous_td *)topDescriptor->next_done_descriptor; + } +} + diff --git a/src/add-ons/kernel/busses/usb/ohci.h b/src/add-ons/kernel/busses/usb/ohci.h index 341e8a4..7327653 100644 --- a/src/add-ons/kernel/busses/usb/ohci.h +++ b/src/add-ons/kernel/busses/usb/ohci.h @@ -1,11 +1,12 @@ /* - * Copyright 2005-2008, Haiku Inc. All rights reserved. + * Copyright 2005-2013, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Jan-Rixt Van Hoye * Salvatore Benedetto <salvatore.benedetto@xxxxxxxxx> * Michael Lotz <mmlr@xxxxxxxx> + * Siarzhuk Zharski <imker@xxxxxx> */ #ifndef OHCI_H #define OHCI_H @@ -69,12 +70,20 @@ static int32 _InterruptHandler(void *data); ohci_general_td *dataDescriptor, ohci_general_td *lastDescriptor, bool directionIn); - status_t _CancelQueuedIsochronousTransfers( - Pipe *pipe, bool force); + status_t _AddPendingIsochronousTransfer( + Transfer *transfer, + ohci_endpoint_descriptor *endpoint, + ohci_isochronous_td *firstDescriptor, + ohci_isochronous_td *lastDescriptor, + bool directionIn); + status_t _UnlinkTransfer(transfer_data *transfer); static int32 _FinishThread(void *data); void _FinishTransfers(); + bool _FinishIsochronousTransfer( + transfer_data *transfer, + transfer_data **_lastTransfer); status_t _SubmitRequest(Transfer *transfer); status_t _SubmitTransfer(Transfer *transfer); @@ -85,6 +94,11 @@ static int32 _FinishThread(void *data); ohci_endpoint_descriptor *endpoint, ohci_general_td *first, ohci_general_td *last); + void _SwitchIsochronousEndpointTail( + ohci_endpoint_descriptor *endpoint, + ohci_isochronous_td *first, + ohci_isochronous_td *last); + void _RemoveTransferFromEndpoint( transfer_data *transfer); @@ -101,7 +115,6 @@ static int32 _FinishThread(void *data); size_t bufferSize); void _FreeGeneralDescriptor( ohci_general_td *descriptor); - status_t _CreateDescriptorChain( ohci_general_td **firstDescriptor, ohci_general_td **lastDescriptor, @@ -110,22 +123,48 @@ static int32 _FinishThread(void *data); void _FreeDescriptorChain( ohci_general_td *topDescriptor); + ohci_isochronous_td * _CreateIsochronousDescriptor( + size_t bufferSize); + void _FreeIsochronousDescriptor( + ohci_isochronous_td *descriptor); + status_t _CreateIsochronousDescriptorChain( + ohci_isochronous_td **firstDescriptor, + ohci_isochronous_td **lastDescriptor, + Transfer *transfer); + void _FreeIsochronousDescriptorChain( + ohci_isochronous_td *topDescriptor); + size_t _WriteDescriptorChain( ohci_general_td *topDescriptor, iovec *vector, size_t vectorCount); size_t _ReadDescriptorChain( ohci_general_td *topDescriptor, iovec *vector, size_t vectorCount); + + size_t _WriteIsochronousDescriptorChain( + ohci_isochronous_td *topDescriptor, + iovec *vector, size_t vectorCount); + void _ReadIsochronousDescriptorChain( + ohci_isochronous_td *topDescriptor, + iovec *vector, size_t vectorCount); + size_t _ReadActualLength( ohci_general_td *topDescriptor); void _LinkDescriptors(ohci_general_td *first, ohci_general_td *second); - - ohci_isochronous_td * _CreateIsochronousDescriptor(); - void _FreeIsochronousDescriptor( - ohci_isochronous_td *descriptor); - + void _LinkIsochronousDescriptors( + ohci_isochronous_td *first, + ohci_isochronous_td *second, + ohci_isochronous_td *nextDone); + + bool _AllocateIsochronousBandwidth(uint16 frame, + uint16 size); + void _ReleaseIsochronousBandwidth( + uint16 startFrame, uint16 count); + + status_t _GetStatusOfConditionCode( + uint8 conditionCode); // Private locking bool _LockEndpoints(); void _UnlockEndpoints(); @@ -139,6 +178,8 @@ inline uint32 _ReadReg(uint32 reg); ohci_endpoint_descriptor *endpoint); void _PrintDescriptorChain( ohci_general_td *topDescriptor); + void _PrintDescriptorChain( + ohci_isochronous_td *topDescriptor); static pci_module_info * sPCIModule; static pci_x86_module_info * sPCIx86Module; @@ -167,6 +208,8 @@ static pci_x86_module_info * sPCIx86Module; thread_id fFinishThread; bool fStopFinishThread; Pipe * fProcessingPipe; + // frame bandwidth watchdogs array + uint16 * fFrameBandwidth; // Root Hub OHCIRootHub * fRootHub; diff --git a/src/add-ons/kernel/busses/usb/ohci.rdef b/src/add-ons/kernel/busses/usb/ohci.rdef index a70dc36..be184dd 100644 --- a/src/add-ons/kernel/busses/usb/ohci.rdef +++ b/src/add-ons/kernel/busses/usb/ohci.rdef @@ -12,6 +12,6 @@ resource app_version { variety = 0, internal = 0, short_info = "OHCI host controller driver", - long_info = "Haiku OHCI HCD - Copyright 2005-2009, Haiku Inc." + long_info = "Haiku OHCI HCD - Copyright 2005-2013, Haiku Inc." }; diff --git a/src/add-ons/kernel/busses/usb/ohci_hardware.h b/src/add-ons/kernel/busses/usb/ohci_hardware.h index 308a27b..4244796 100644 --- a/src/add-ons/kernel/busses/usb/ohci_hardware.h +++ b/src/add-ons/kernel/busses/usb/ohci_hardware.h @@ -1,11 +1,12 @@ /* - * Copyright 2005-2008, Haiku Inc. All rights reserved. + * Copyright 2005-2013, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Jan-Rixt Van Hoye * Salvatore Benedetto <salvatore.benedetto@xxxxxxxxx> * Michael Lotz <mmlr@xxxxxxxx> + * Siarzhuk Zharski <imker@xxxxxx> */ #ifndef OHCI_HARDWARE_H @@ -396,6 +397,8 @@ typedef struct { uint16 offset[OHCI_ITD_NOFFSET]; // Buffer offsets // Software part uint32 physical_address; // Physical address of this descriptor + size_t buffer_size; // Size of the buffer + void *buffer_logical; // Logical pointer to the buffer void *next_logical_descriptor; // Logical pointer next descriptor void *next_done_descriptor; // Used for collision in the hash table } ohci_isochronous_td; @@ -404,11 +407,31 @@ typedef struct { #define OHCI_ITD_SET_STARTING_FRAME(x) ((x) & 0xffff) #define OHCI_ITD_GET_DELAY_INTERRUPT(x) (((x) >> 21) & 7) #define OHCI_ITD_SET_DELAY_INTERRUPT(x) ((x) << 21) -#define OHCI_ITD_NO_INTERRUPT 0x00e00000 +#define OHCI_ITD_INTERRUPT_MASK 0x00e00000 #define OHCI_ITD_GET_FRAME_COUNT(x) ((((x) >> 24) & 7) + 1) #define OHCI_ITD_SET_FRAME_COUNT(x) (((x) - 1) << 24) #define OHCI_ITD_GET_CONDITION_CODE(x) ((x) >> 28) -#define OHCI_ITD_NO_CONDITION_CODE 0xf0000000 +#define OHCI_ITD_SET_CONDITION_CODE(x) ((x) << 28) +#define OHCI_ITD_CONDITION_CODE_MASK 0xf0000000 + +#define OHCI_ITD_OFFSET_IDX(x) (x) + +#define OHCI_ITD_INTERRUPT_IMMEDIATE 0x00 +#define OHCI_ITD_INTERRUPT_NONE 0x07 + +#define OHCI_ITD_CONDITION_NO_ERROR 0x00 +#define OHCI_ITD_CONDITION_CRC_ERROR 0x01 +#define OHCI_ITD_CONDITION_BIT_STUFFING 0x02 +#define OHCI_ITD_CONDITION_TOGGLE_MISMATCH 0x03 +#define OHCI_ITD_CONDITION_STALL 0x04 +#define OHCI_ITD_CONDITION_NO_RESPONSE 0x05 +#define OHCI_ITD_CONDITION_PID_CHECK_FAILURE 0x06 +#define OHCI_ITD_CONDITION_UNEXPECTED_PID 0x07 +#define OHCI_ITD_CONDITION_DATA_OVERRUN 0x08 +#define OHCI_ITD_CONDITION_DATA_UNDERRUN 0x09 +#define OHCI_ITD_CONDITION_BUFFER_OVERRUN 0x0c +#define OHCI_ITD_CONDITION_BUFFER_UNDERRUN 0x0d +#define OHCI_ITD_CONDITION_NOT_ACCESSED 0x0f // TO FIX #define itd_pswn itd_offset // Packet Status Word @@ -419,6 +442,10 @@ typedef struct { #define OHCI_ISOCHRONOUS_TD_ALIGN 32 +// Number of frames +#define NUMBER_OF_FRAMES 1024 +#define MAX_AVAILABLE_BANDWIDTH 900 // Microseconds + // -------------------------------- // Completion Codes (section 4.3.3) // -------------------------------- ############################################################################ Commit: 291e40c3092eec114393f5463d481375736af6d3 URL: http://cgit.haiku-os.org/haiku/commit/?id=291e40c Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Sun Aug 4 17:49:41 2013 UTC USB OHCI: Fix finalizing of STALL-ed control request transfers In case control transfer is finished with STALL answer from device only the setup TD is retired into the Done Queue but other TDs (data and status) are left in the ED queue. HC set the endpoint halted - so we process such endpoint regardless of it's non-empty queue. PS: cleanup some trailing spaces. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp index 489a762..899280b 100644 --- a/src/add-ons/kernel/busses/usb/ohci.cpp +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -217,7 +217,7 @@ OHCI::OHCI(pci_info *info, Stack *stack) // interrupts during handover. Therefore we disable interrupts before // requesting ownership. We have to keep the ownership change interrupt // enabled though, as otherwise the SMM will not be notified of the - // ownership change request we trigger below. + // ownership change request we trigger below. _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS & ~OHCI_OWNERSHIP_CHANGE) ; @@ -234,7 +234,7 @@ OHCI::OHCI(pci_info *info, Stack *stack) if ((control & OHCI_INTERRUPT_ROUTING) != 0) { TRACE_ERROR("smm does not respond.\n"); - + // TODO: Enable this reset as soon as the non-specified // reset a few lines later is replaced by a better solution. //_WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); @@ -1040,7 +1040,9 @@ OHCI::_FinishTransfers() MutexLocker endpointLocker(endpoint->lock); if ((endpoint->head_physical_descriptor & OHCI_ENDPOINT_HEAD_MASK) - != endpoint->tail_physical_descriptor) { + != endpoint->tail_physical_descriptor + && (endpoint->head_physical_descriptor + & OHCI_ENDPOINT_HALTED) == 0) { // there are still active transfers on this endpoint, we need // to wait for all of them to complete, otherwise we'd read // a potentially bogus data toggle value below ############################################################################ Commit: 2cc4703b91929ece9a3d95942a37363ff32344c7 URL: http://cgit.haiku-os.org/haiku/commit/?id=2cc4703 Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Mon May 28 16:14:05 2012 UTC Fix and force USB audio driver to work with new OHCI module * some functionality like recording temporarily disabled; * set the endpoint speed call added; * packet size hard-coded for 48kHz case; * draft support for formats and sampling rate handling; * implement sampling rate change on the fly; * optimized using of starting frame; * fix user_memory in buffer exchaqnge call; * fix exchanged buffer recoriding processing; * debug tweaks, fix current buffer switching; * cleanup, cleanup, cleanup... ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.cpp b/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.cpp index 0c91140..653dfae 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.cpp +++ b/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.cpp @@ -11,6 +11,29 @@ #include "audio.h" +static struct RatePair { + uint32 rate; + uint32 rateId; +} ratesMap[] = { + { 8000, B_SR_8000 }, + { 11025, B_SR_11025 }, + { 12000, B_SR_12000 }, + { 16000, B_SR_16000 }, + { 22050, B_SR_22050 }, + { 24000, B_SR_24000 }, + { 32000, B_SR_32000 }, + { 44100, B_SR_44100 }, + { 48000, B_SR_48000 }, + { 64000, B_SR_64000 }, + { 88200, B_SR_88200 }, + { 96000, B_SR_96000 }, + { 176400, B_SR_176400 }, + { 192000, B_SR_192000 }, + { 384000, B_SR_384000 }, + { 1536000, B_SR_1536000 } +}; + + // // Audio Stream information entities // @@ -44,28 +67,31 @@ ASInterfaceDescriptor::~ASInterfaceDescriptor() ASEndpointDescriptor::ASEndpointDescriptor(usb_endpoint_descriptor* Endpoint, usb_as_cs_endpoint_descriptor* Descriptor) : - fAttributes(0), + fCSAttributes(0), fLockDelayUnits(0), fLockDelay(0), fMaxPacketSize(0), - fEndpointAddress(0) + fEndpointAddress(0), + fEndpointAttributes(0) { // usb_audiocontrol_header_descriptor *Header // = (usb_audiocontrol_header_descriptor *)Interface->generic[i]; - fAttributes = Descriptor->attributes; + fCSAttributes = Descriptor->attributes; fLockDelayUnits = Descriptor->lock_delay_units; fLockDelay = Descriptor->lock_delay; // usb_endpoint_descriptor* endpoint = Interface->endpoint[0]->descr; + fEndpointAttributes = Endpoint->attributes; fEndpointAddress = Endpoint->endpoint_address; fMaxPacketSize = Endpoint->max_packet_size; - TRACE("fAttributes:%d\n", fAttributes); + TRACE("fCSAttributes:%d\n", fCSAttributes); TRACE("fLockDelayUnits:%d\n", fLockDelayUnits); TRACE("fLockDelay:%d\n", fLockDelay); TRACE("fMaxPacketSize:%d\n", fMaxPacketSize); TRACE("fEndpointAddress:%#02x\n", fEndpointAddress); + TRACE("fEndpointAttributes:%d\n", fEndpointAttributes); } @@ -186,8 +212,10 @@ AudioStreamAlternate::AudioStreamAlternate(size_t alternate, fAlternate(alternate), fInterface(interface), fEndpoint(endpoint), - fFormat(format) + fFormat(format), + fSamplingRate(0) { + // SetSamplingRate(0); // init to default (max) sampling rate } @@ -199,6 +227,166 @@ AudioStreamAlternate::~AudioStreamAlternate() } +status_t +AudioStreamAlternate::SetSamplingRate(uint32 newRate) +{ + TypeIFormatDescriptor* format + = static_cast<TypeIFormatDescriptor*>(Format()); + + if (format == NULL) { + TRACE_ALWAYS("Format not set for active alternate\n"); + return B_NO_INIT; + } + + Vector<uint32>& frequencies = format->fSampleFrequencies; + bool continuous = format->fSampleFrequencyType == 0; + + if (newRate == 0) { // by default select max available + fSamplingRate = 0; + if (continuous) + fSamplingRate = max_c(frequencies[0], frequencies[1]); + else + for (int i = 0; i < frequencies.Count(); i++) + fSamplingRate = max_c(fSamplingRate, frequencies[i]); + } else { + if (continuous) { + uint32 min = min_c(frequencies[0], frequencies[1]); + uint32 max = max_c(frequencies[0], frequencies[1]); + if (newRate < min || newRate > max) { + TRACE_ALWAYS("Rate %d outside of %d - %d ignored.\n", + newRate, min, max); + return B_BAD_INDEX; + } + fSamplingRate = newRate; + } else { + for (int i = 0; i < frequencies.Count(); i++) + if (newRate == frequencies[i]) { + fSamplingRate = newRate; + return B_OK; + } + TRACE_ALWAYS("Rate %d not found - ignore it.\n", newRate); + return B_BAD_INDEX; + } + } + +// newRate = fSamplingRate; + return B_OK; +} + + +uint32 +AudioStreamAlternate::GetSamplingRateId(uint32 rate) +{ + if (rate == 0) + rate = fSamplingRate; + + for (size_t i = 0; i < _countof(ratesMap); i++) + if (ratesMap[i].rate == rate) + return ratesMap[i].rateId; + + TRACE_ALWAYS("Ignore unsupported sample rate %d.\n", rate); + return 0; +} + + +uint32 +AudioStreamAlternate::GetSamplingRateIds() +{ + TypeIFormatDescriptor* format + = static_cast<TypeIFormatDescriptor*>(Format()); + + if (format == NULL) { + TRACE_ALWAYS("Format not set for active alternate\n"); + return 0; + } + + uint32 rates = 0; + Vector<uint32>& frequencies = format->fSampleFrequencies; + if (format->fSampleFrequencyType == 0) { // continuous frequencies + uint32 min = min_c(frequencies[0], frequencies[1]); + uint32 max = max_c(frequencies[0], frequencies[1]); + + for (int i = 0; i < frequencies.Count(); i++) { + if (frequencies[i] < min || frequencies[i] > max) + continue; + rates |= GetSamplingRateId(frequencies[i]); + } + } else + for (int i = 0; i < frequencies.Count(); i++) + rates |= GetSamplingRateId(frequencies[i]); + + return rates; +} + + +uint32 +AudioStreamAlternate::GetFormatId() +{ + TypeIFormatDescriptor* format + = static_cast<TypeIFormatDescriptor*>(Format()); + + if (format == NULL || Interface() == NULL) { + TRACE_ALWAYS("Ignore alternate due format " + "%#08x or interface %#08x null.\n", format, Interface()); + return 0; + } + + uint32 formats = 0; + switch (Interface()->fFormatTag) { + case UAF_PCM8: formats = B_FMT_8BIT_U; break; + case UAF_IEEE_FLOAT: formats = B_FMT_FLOAT; break; + case UAF_PCM: + switch(format->fBitResolution) { + case 8: formats = B_FMT_8BIT_S; break; + case 16: formats = B_FMT_16BIT; break; + case 18: formats = B_FMT_18BIT; break; + case 20: formats = B_FMT_20BIT; break; + case 24: formats = B_FMT_24BIT; break; + case 32: formats = B_FMT_32BIT; break; + default: + TRACE_ALWAYS("Ignore unsupported " + "bit resolution %d for alternate.\n", + format->fBitResolution); + break; + } + break; + default: + TRACE_ALWAYS("Ignore unsupported " + "format bit resolution %d for alternate.\n", + Interface()->fFormatTag); + break; + } + + return formats; +} + + +uint32 +AudioStreamAlternate::SamplingRateFromId(uint32 id) +{ + for (size_t i = 0; i < _countof(ratesMap); i++) + if (ratesMap[i].rateId == id) + return ratesMap[i].rate; + + TRACE_ALWAYS("Unknown sample rate id: %d.\n", id); + return 0; +} + + +status_t +AudioStreamAlternate::SetSamplingRateById(uint32 newId) +{ + return SetSamplingRate(SamplingRateFromId(newId)); +} + + +status_t +AudioStreamAlternate::SetFormatId(uint32 /*newFormatId*/) +{ + return B_OK; // TODO +} + + AudioStreamingInterface::AudioStreamingInterface( AudioControlInterface* controlInterface, size_t interface, usb_interface_list *List) @@ -329,9 +517,8 @@ AudioStreamingInterface::GetFormatsAndRates(multi_description *Description) Description->interface_flags |= fIsInput ? B_MULTI_INTERFACE_RECORD : B_MULTI_INTERFACE_PLAYBACK; - uint32 rates = 0; - uint32 formats = 0; - +// uint32 rates = 0; +/* TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>( fAlternates[fActiveAlternate]->Format()); @@ -373,27 +560,9 @@ AudioStreamingInterface::GetFormatsAndRates(multi_description *Description) } } } - - switch (fAlternates[fActiveAlternate]->Interface()->fFormatTag) { - case UAF_PCM8: formats = B_FMT_8BIT_U; break; - case UAF_IEEE_FLOAT: formats = B_FMT_FLOAT; break; - case UAF_PCM: - switch(format->fBitResolution) { - case 8: formats = B_FMT_8BIT_S; break; - case 16: formats = B_FMT_16BIT; break; - case 18: formats = B_FMT_18BIT; break; - case 20: formats = B_FMT_20BIT; break; - case 24: formats = B_FMT_24BIT; break; - case 32: formats = B_FMT_32BIT; break; - break; - default: - TRACE_ALWAYS("Ignore unsupported " - "bit resolution %d for alternate %d.\n", - format->fBitResolution, fActiveAlternate); - break; - } - break; - } +*/ + uint32 rates = fAlternates[fActiveAlternate]->GetSamplingRateIds(); + uint32 formats = fAlternates[fActiveAlternate]->GetFormatId(); if (fIsInput) { Description->input_rates = rates; diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.h b/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.h index 5e89f5b..0815c9e 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.h +++ b/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.h @@ -40,11 +40,12 @@ public: ~ASEndpointDescriptor(); // protected: - uint8 fAttributes; + uint8 fCSAttributes; uint8 fLockDelayUnits; uint16 fLockDelay; uint16 fMaxPacketSize; uint8 fEndpointAddress; + uint8 fEndpointAttributes; }; @@ -113,11 +114,22 @@ public: ASEndpointDescriptor* Endpoint() { return fEndpoint; } _ASFormatDescriptor* Format() { return fFormat; } + status_t SetSamplingRate(uint32 newRate); + status_t SetSamplingRateById(uint32 newId); + uint32 GetSamplingRate() { return fSamplingRate; } + uint32 GetSamplingRateId(uint32 rate); + uint32 GetSamplingRateIds(); + uint32 GetFormatId(); + status_t SetFormatId(uint32 newFormatId); + uint32 SamplingRateFromId(uint32 id); + protected: + size_t fAlternate; ASInterfaceDescriptor* fInterface; ASEndpointDescriptor* fEndpoint; _ASFormatDescriptor* fFormat; + uint32 fSamplingRate; }; diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/Device.cpp b/src/add-ons/kernel/drivers/audio/usb_audio/Device.cpp index 16000ab..8bc2055 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Device.cpp +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Device.cpp @@ -23,9 +23,9 @@ Device::Device(usb_device device) fDevice(device), fNonBlocking(false), fAudioControl(this), - fControlEndpoint(0), - fInStreamEndpoint(0), - fOutStreamEndpoint(0), + // fControlEndpoint(0), + // fInStreamEndpoint(0), + // fOutStreamEndpoint(0), fNotifyReadSem(-1), fNotifyWriteSem(-1), fNotifyBuffer(NULL), @@ -42,6 +42,7 @@ Device::Device(usb_device device) fVendorID = deviceDescriptor->vendor_id; fProductID = deviceDescriptor->product_id; + fUSBVersion = deviceDescriptor->usb_version; fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read"); if (fNotifyReadSem < B_OK) { @@ -155,9 +156,9 @@ Device::Close() // wait until possible notification handling finished... while (atomic_add(&fInsideNotify, 0) != 0) snooze(100); - gUSBModule->cancel_queued_transfers(fControlEndpoint); - gUSBModule->cancel_queued_transfers(fInStreamEndpoint); - gUSBModule->cancel_queued_transfers(fOutStreamEndpoint); +// gUSBModule->cancel_queued_transfers(fControlEndpoint); +// gUSBModule->cancel_queued_transfers(fInStreamEndpoint); +// gUSBModule->cancel_queued_transfers(fOutStreamEndpoint); fOpen = false; @@ -289,9 +290,9 @@ Device::Removed() while (atomic_add(&fInsideNotify, 0) != 0) snooze(100); - gUSBModule->cancel_queued_transfers(fControlEndpoint); - gUSBModule->cancel_queued_transfers(fInStreamEndpoint); - gUSBModule->cancel_queued_transfers(fOutStreamEndpoint); +// gUSBModule->cancel_queued_transfers(fControlEndpoint); +// gUSBModule->cancel_queued_transfers(fInStreamEndpoint); +// gUSBModule->cancel_queued_transfers(fOutStreamEndpoint); /* if (fLinkStateChangeSem >= B_OK) release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE); @@ -415,7 +416,7 @@ Device::_MultiGetDescription(multi_description *multiDescription) TraceMultiDescription(&Description, Channels); if (user_memcpy(multiDescription, &Description, - sizeof(multi_description)) != B_OK) { + sizeof(multi_description)) != B_OK) { return B_BAD_ADDRESS; } @@ -555,6 +556,10 @@ Device::_MultiGetBuffers(multi_buffer_list* List) List->request_record_channels, List->request_record_buffer_size); + List->flags = 0; + List->return_playback_channels = 0; + List->return_record_channels = 0; + for (int i = 0; i < fStreams.Count() && status == B_OK; i++) { status = fStreams[i]->GetBuffers(List); } @@ -564,18 +569,23 @@ Device::_MultiGetBuffers(multi_buffer_list* List) status_t -Device::_MultiBufferExchange(multi_buffer_info* Info) +Device::_MultiBufferExchange(multi_buffer_info* multiInfo) { + multi_buffer_info Info; + if (user_memcpy(&Info, multiInfo, sizeof(multi_buffer_info)) != B_OK) + return B_BAD_ADDRESS; + for (int i = 0; i < fStreams.Count(); i++) { if (!fStreams[i]->IsRunning()) { fStreams[i]->Start(); } } - TRACE_ALWAYS("Exchange!\n"); +// TRACE_ALWAYS("Exchange!\n"); +/* snooze(1000000); return B_OK; - +*/ status_t status = B_ERROR; bool anyBufferProcessed = false; for (int i = 0; i < fStreams.Count() && !anyBufferProcessed; i++) { @@ -586,10 +596,13 @@ Device::_MultiBufferExchange(multi_buffer_info* Info) break; } - anyBufferProcessed = fStreams[i]->ExchangeBuffer(Info); + anyBufferProcessed = fStreams[i]->ExchangeBuffer(&Info); status = anyBufferProcessed ? B_OK : B_ERROR; } + if (user_memcpy(multiInfo, &Info, sizeof(multi_buffer_info)) != B_OK) + return B_BAD_ADDRESS; + return status; } @@ -713,7 +726,7 @@ Device::_SetupEndpoints() status_t Device::StopDevice() { - status_t result = B_OK; // WriteRXControlRegister(0); + status_t result = B_OK; if (result != B_OK) { TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result); diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/Device.h b/src/add-ons/kernel/drivers/audio/usb_audio/Device.h index e40991d..facf389 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Device.h +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Device.h @@ -81,6 +81,7 @@ virtual status_t StopDevice(); bool fRemoved; vint32 fInsideNotify; usb_device fDevice; + uint16 fUSBVersion; uint16 fVendorID; uint16 fProductID; const char * fDescription; @@ -116,9 +117,9 @@ protected: // uint16 fFrameSize; // pipes for notifications and data io - usb_pipe fControlEndpoint; - usb_pipe fInStreamEndpoint; - usb_pipe fOutStreamEndpoint; +// usb_pipe fControlEndpoint; +// usb_pipe fInStreamEndpoint; +// usb_pipe fOutStreamEndpoint; // data stores for async usb transfers uint32 fActualLengthRead; diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/Stream.cpp b/src/add-ons/kernel/drivers/audio/usb_audio/Stream.cpp index 9ea21dc..6bf20f0 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Stream.cpp +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Stream.cpp @@ -21,18 +21,16 @@ Stream::Stream(Device *device, size_t interface, usb_interface_list *List fStreamEndpoint(0), fIsRunning(false), fArea(-1), - fDescriptors(0), + fAreaSize(0), + fDescriptors(NULL), fDescriptorsCount(0), fCurrentBuffer(0), fStartingFrame(0), fSamplesCount(0), - fProcessedBuffers(0)/*, - fBuffersPhysAddress(0)/ *, - fRealTime(0), - fFramesCount(0), - fBufferCycle(0)*/ + fPacketSize(0), + fProcessedBuffers(0) { - + memset(&fFormat, 0, sizeof(_multi_format)); } @@ -43,7 +41,7 @@ Stream::~Stream() status_t -Stream::Init() +Stream::_ChooseAlternate() { // lookup alternate with maximal (ch * 100 + resolution) uint16 maxChxRes = 0; @@ -80,6 +78,12 @@ Stream::Init() TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(fAlternates[i]->Format()); + if (format->fNumChannels > 2) { + TRACE("Ignore alternate %d - channel count %d " + "is not supported.\n", i, format->fNumChannels); + continue; + } + if (fAlternates[i]->Interface()->fFormatTag == UAF_PCM) { switch(format->fBitResolution) { default: @@ -100,80 +104,94 @@ Stream::Init() if (maxChxRes <= 0) { TRACE("No compatible alternate found. Stream initialization failed.\n"); - return fStatus; + return B_NO_INIT; } + const ASEndpointDescriptor* endpoint = fAlternates[ fActiveAlternate]->Endpoint(); fIsInput = (endpoint->fEndpointAddress & USB_ENDPOINT_ADDR_DIR_IN) == USB_ENDPOINT_ADDR_DIR_IN; - TRACE("Alternate %d selected!\n", fActiveAlternate); + TRACE("Alternate %d EP:%x selected for %s!\n", + fActiveAlternate, endpoint->fEndpointAddress, + fIsInput ? "recording" : "playback"); - TypeIFormatDescriptor* format - = static_cast<TypeIFormatDescriptor*>(fAlternates[ - fActiveAlternate]->Format()); + return B_OK; +} - size_t bufferSize = format->fNumChannels * format->fSubframeSize; - TRACE("bufferSize:%d\n", bufferSize); - - bufferSize *= kSamplesBufferSize; - TRACE("bufferSize:%d\n", bufferSize); - - bufferSize *= (sizeof(usb_iso_packet_descriptor) + endpoint->fMaxPacketSize); - TRACE("bufferSize:%d\n", bufferSize); - - bufferSize /= endpoint->fMaxPacketSize; - TRACE("bufferSize:%d\n", bufferSize); - - bufferSize = (bufferSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1); - TRACE("bufferSize:%d\n", bufferSize); - - fArea = create_area( (fIsInput) ? DRIVER_NAME "_record_area" : - DRIVER_NAME "_playback_area", - (void**)&fDescriptors, B_ANY_KERNEL_ADDRESS, - bufferSize, B_CONTIGUOUS, - B_READ_AREA | B_WRITE_AREA); - if (fArea < 0) { - TRACE_ALWAYS("Error of creating %#x - bytes size buffer area:%#010x\n", - bufferSize, fArea); - fStatus = fArea; - return fStatus; - } - physical_entry PhysEntry; - get_memory_map(fDescriptors, bufferSize, &PhysEntry, 1); +status_t +Stream::Init() +{ + fStatus = _ChooseAlternate(); + //if (fStatus != B_OK) + return fStatus; +} - TRACE_ALWAYS("Created area id: " - "%d\naddress:%#010x[phys:%#010x]\nsize:%#010x\n", - fArea, fDescriptors, PhysEntry.address, bufferSize); - fDescriptorsCount = bufferSize; - fDescriptorsCount /= (sizeof(usb_iso_packet_descriptor) - + endpoint->fMaxPacketSize); +status_t +Stream::_SetupBuffers() +{ + // allocate buffer for worst (maximal size) case + TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>( + fAlternates[fActiveAlternate]->Format()); + + uint32 samplingRate = fAlternates[fActiveAlternate]->GetSamplingRate(); + uint32 sampleSize = format->fNumChannels * format->fSubframeSize; + + // data size pro 1 ms USB 1 frame or 1/8 ms USB 2 microframe + fPacketSize = samplingRate * sampleSize + / (fDevice->fUSBVersion < 0x0200 ? 1000 : 8000); + TRACE("packetSize:%ld\n", fPacketSize); + + if (fArea == -1) { + fAreaSize = (sizeof(usb_iso_packet_descriptor) + fPacketSize) + * sampleSize * 1024 / fPacketSize; + TRACE("estimate fAreaSize:%d\n", fAreaSize); + + // round up to B_PAGE_SIZE and create area + fAreaSize = (fAreaSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1); + TRACE("rounded up fAreaSize:%d\n", fAreaSize); + + fArea = create_area( (fIsInput) ? DRIVER_NAME "_record_area" + : DRIVER_NAME "_playback_area", (void**)&fDescriptors, + B_ANY_KERNEL_ADDRESS, fAreaSize, B_CONTIGUOUS, + B_READ_AREA | B_WRITE_AREA); + + if (fArea < 0) { + TRACE_ALWAYS("Error of creating %#x - bytes size buffer area:%#010x\n", + fAreaSize, fArea); + fStatus = fArea; + return fStatus; + } + + // physical_entry PhysEntry; + // get_memory_map(fDescriptors, fAreaSize, &PhysEntry, 1); + + TRACE_ALWAYS("Created area id:%d at addr:%#010x size:%#010lx\n", + fArea, fDescriptors, fAreaSize); + } + + // descriptors count + fDescriptorsCount = fAreaSize + / (sizeof(usb_iso_packet_descriptor) + fPacketSize); + + // we need same size sub-buffers. round it fDescriptorsCount /= kSamplesBufferCount; - // we need same size buffers. round it! fDescriptorsCount *= kSamplesBufferCount; + TRACE("descriptorsCount:%d\n", fDescriptorsCount); - fSamplesCount = fDescriptorsCount * endpoint->fMaxPacketSize; - TRACE("samplesCount:%d\n", fSamplesCount); - - fSamplesCount /= format->fNumChannels * format->fSubframeSize; + // samples count + fSamplesCount = fDescriptorsCount * fPacketSize / sampleSize; TRACE("samplesCount:%d\n", fSamplesCount); + // initialize descriptors array for (size_t i = 0; i < fDescriptorsCount; i++) { - fDescriptors[i].request_length = endpoint->fMaxPacketSize; + fDescriptors[i].request_length = fPacketSize; fDescriptors[i].actual_length = 0; fDescriptors[i].status = B_OK; } -/* uint32* b = (uint32*)(fDescriptors + fDescriptorsCount); - for (size_t i = 0; i < fSamplesCount; i++) { - b[i] = i * 10; - }*/ - - TRACE_ALWAYS("Descriptors count:%d\nsample size:%d\nchannels:%d:%d\n", - fDescriptorsCount, format->fSubframeSize, format->fNumChannels, - sizeof(usb_iso_packet_descriptor)); - return fStatus = B_OK; + return fStatus; } @@ -193,14 +211,32 @@ Stream::OnSetConfiguration(usb_device device, return B_ERROR; } - /*status_t status =*/ gUSBModule->set_alt_interface(device, interface); + status_t status = gUSBModule->set_alt_interface(device, interface); uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress; + TRACE_ALWAYS("set_alt_interface %x\n", status); + for (size_t i = 0; i < interface->endpoint_count; i++) { if (address == interface->endpoint[i].descr->endpoint_address) { fStreamEndpoint = interface->endpoint[i].handle; TRACE("%s Stream Endpoint [address %#04x] handle is: %#010x.\n", fIsInput ? "Input" : "Output", address, fStreamEndpoint); +/* + size_t actualLength = 0; + uint32 speed = 48000; + uint8 data[3]; + data[0] = 0xFF & speed; + data[1] = (uint8) 0xFF & speed >> 8; + data[2] = (uint8) 0xFF & speed >> 16; + + status_t status = gUSBModule->send_request(device, + USB_REQTYPE_CLASS | USB_REQTYPE_ENDPOINT_OUT, + UAS_SET_CUR, UAS_SAMPLING_FREQ_CONTROL << 8, + address, 3, data, &actualLength); + + TRACE_ALWAYS("set_speed for ep %#x %d: %x\n", + address, actualLength, status); +*/ return B_OK; } } @@ -216,12 +252,9 @@ Stream::Start() { status_t result = B_BUSY; if (!fIsRunning) { - if (!fIsInput) { - // for (size_t i = 0; i < kSamplesBufferCount; i++) - // result = _QueueNextTransfer(i); - // TODO - // result = _QueueNextTransfer(0); - result = B_OK; + if (!fIsInput) { // TODO: recording + for (size_t i = 0; i < kSamplesBufferCount; i++) + result = _QueueNextTransfer(i, true); } else result = B_OK; fIsRunning = result == B_OK; @@ -243,7 +276,7 @@ Stream::Stop() status_t -Stream::_QueueNextTransfer(size_t queuedBuffer) +Stream::_QueueNextTransfer(size_t queuedBuffer, bool start) { TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(fAlternates[ @@ -259,14 +292,35 @@ Stream::_QueueNextTransfer(size_t queuedBuffer) TRACE("buffers:%#010x[%#x]\ndescrs:%#010x[%#x]\n", buffers + bufferSize * queuedBuffer, bufferSize, fDescriptors + queuedBuffer * packetsCount, packetsCount); +#if 0 +{ + static int16 sin[24] = { 0, 4277, 8481, 12540, 16384, 19948, 23170, 25996, + 28378, 30273, 31651, 32487, 32767, 32487, 31651, 30273, 28378, 25996, + 23170, 19948, 16384, 12540, 8481, 4277 }; + static uint16 sample = 0; + static bool sign = true; + + uint16* b = (uint16*)(buffers + bufferSize * queuedBuffer); + size_t length = bufferSize; + for (size_t u = 0; u < length / 2; u += 2) { + b[u] = b[u + 1] = sign ? sin[sample] : -sin[sample]; + sample ++; + if (sample == 24) { + sample = 0; + sign = !sign; + } + } +} +#endif - return gUSBModule->queue_isochronous(fStreamEndpoint, + status_t status = gUSBModule->queue_isochronous(fStreamEndpoint, buffers + bufferSize * queuedBuffer, bufferSize, fDescriptors + queuedBuffer * packetsCount, packetsCount, - NULL/*&fStartingFrame*/, USB_ISO_ASAP, + &fStartingFrame, start ? USB_ISO_ASAP : 0, Stream::_TransferCallback, this); - return B_OK; + TRACE("frame:%#010x\n", fStartingFrame); + return status; // B_OK; } @@ -274,48 +328,39 @@ void Stream::_TransferCallback(void *cookie, int32 status, void *data, uint32 actualLength) { - Stream *stream = (Stream *)cookie; - - stream->fCurrentBuffer++; - if (stream->fCurrentBuffer >= kSamplesBufferCount) { - stream->fCurrentBuffer = 0; + if (status == B_CANCELED) { + TRACE_ALWAYS("Cancelled: c:%p st:%#010x, data:%#010x, len:%d\n", + cookie, status, data, actualLength); + return; } - stream->_DumpDescriptors(); + Stream *stream = (Stream *)cookie; + + stream->fCurrentBuffer = (stream->fCurrentBuffer + 1) % kSamplesBufferCount; stream->_DumpDescriptors(); - /* - status_t result = stream->_QueueNextTransfer(stream->fCurrentBuffer); + /*status_t result =*/ stream->_QueueNextTransfer(stream->fCurrentBuffer, false); if (atomic_add(&stream->fProcessedBuffers, 1) > (int32)kSamplesBufferCount) { TRACE_ALWAYS("Processed buffers overflow:%d\n", stream->fProcessedBuffers); } -*/ + release_sem_etc(stream->fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE); // TRACE_ALWAYS("st:%#010x, len:%d -> %#010x\n", status, actualLength, result); - TRACE_ALWAYS("st:%#010x, data:%#010x, len:%d\n", status, data, actualLength); - -/* if (status != B_OK) { - TRACE_ALWAYS("Device status error:%#010x\n", status); - status_t result = gUSBModule->clear_feature(device->fControLeNDPOint, - USB_FEATURE_ENDPOINT_HALT); - if (result != B_OK) - TRACE_ALWAYS("Error during clearing of HALT state:%#010x.\n", result); - } -*/ + TRACE("st:%#010x, data:%#010x, len:%d\n", status, data, actualLength); } void Stream::_DumpDescriptors() { - size_t packetsCount = fDescriptorsCount / kSamplesBufferCount; + //size_t packetsCount = fDescriptorsCount / kSamplesBufferCount; size_t from = /*fCurrentBuffer > 0 ? packetsCount :*/ 0 ; size_t to = /*fCurrentBuffer > 0 ?*/ fDescriptorsCount /*: packetsCount*/ ; for (size_t i = from; i < to; i++) { - TRACE_ALWAYS("%d:req_len:%d; act_len:%d; stat:%#010x\n", i, + TRACE("%d:req_len:%d; act_len:%d; stat:%#010x\n", i, fDescriptors[i].request_length, fDescriptors[i].actual_length, fDescriptors[i].status); } @@ -359,18 +404,13 @@ Stream::SetEnabledChannels(uint32& offset, multi_channel_enable *Enable) status_t Stream::GetGlobalFormat(multi_format_info *Format) { - if (IsInput()) { - // TODO - Format->input.rate = B_SR_48000; - Format->input.cvsr = 48000; - Format->input.format = B_FMT_16BIT; - } else { - // TODO - Format->output.rate = B_SR_48000; - Format->output.cvsr = 48000; - Format->output.format = B_FMT_16BIT; - } - + _multi_format* format = fIsInput ? &Format->input : &Format->output; + format->cvsr = fAlternates[fActiveAlternate]->GetSamplingRate(); + format->rate = fAlternates[fActiveAlternate]->GetSamplingRateId(0); + format->format = fAlternates[fActiveAlternate]->GetFormatId(); + TRACE("%s.rate:%d cvsr:%f format:%#08x\n", + fIsInput ? "input" : "ouput", + format->rate, format->cvsr, format->format); return B_OK; } @@ -378,19 +418,49 @@ Stream::GetGlobalFormat(multi_format_info *Format) status_t Stream::SetGlobalFormat(multi_format_info *Format) { - if (IsInput()) { - // TODO - TRACE("input.rate:%d\n", Format->input.rate); - TRACE("input.cvsr:%f\n", Format->input.cvsr); - TRACE("input.format:%#08x\n", Format->input.format); - } else { - // TODO - TRACE("output.rate:%d\n", Format->output.rate); - TRACE("output.cvsr:%f\n", Format->output.cvsr); - TRACE("output.format:%#08x\n", Format->output.format); + _multi_format* format = fIsInput ? &Format->input : &Format->output; + AudioStreamAlternate* alternate = fAlternates[fActiveAlternate]; + if (format->rate == alternate->GetSamplingRateId(0) + && format->format == alternate->GetFormatId()) { + TRACE("No changes required\n"); + return B_OK; } - return B_OK; + alternate->SetSamplingRateById(format->rate); + alternate->SetFormatId(format->format); + TRACE("%s.rate:%d cvsr:%f format:%#08x\n", + fIsInput ? "input" : "ouput", + format->rate, format->cvsr, format->format); + + // cancel data flow - it will be rewaked at next buffer exchange call + Stop(); + + // TODO: wait for cancelling? + + // layout of buffers should be adjusted after changing sampling rate/format + status_t status = _SetupBuffers(); + + if (status != B_OK) + return status; + + // set endpoint speed + uint32 samplingRate = fAlternates[fActiveAlternate]->GetSamplingRate(); + size_t actualLength = 0; + uint8 data[3]; + data[0] = 0xFF & samplingRate; + data[1] = 0xFF & samplingRate >> 8; + data[2] = 0xFF & samplingRate >> 16; + uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress; + + status = gUSBModule->send_request(fDevice->fDevice, + USB_REQTYPE_CLASS | USB_REQTYPE_ENDPOINT_OUT, + UAS_SET_CUR, UAS_SAMPLING_FREQ_CONTROL << 8, + address, 3, data, &actualLength); + + TRACE_ALWAYS("set_speed %02x%02x%02x for ep %#x %d: %x\n", + data[0], data[1], data[2], + address, actualLength, status); + return status; } @@ -398,6 +468,8 @@ status_t Stream::GetBuffers(multi_buffer_list* List) { // TODO: check the available buffers count! + if (fAreaSize == 0) + return B_NO_INIT; int32 startChannel = List->return_playback_channels; buffer_desc** Buffers = List->playback_buffers; @@ -425,8 +497,8 @@ Stream::GetBuffers(multi_buffer_list* List) TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>( fAlternates[fActiveAlternate]->Format()); - const ASEndpointDescriptor* endpoint - = fAlternates[fActiveAlternate]->Endpoint(); +// const ASEndpointDescriptor* endpoint +// = fAlternates[fActiveAlternate]->Endpoint(); // [buffer][channel] init buffers for (size_t buffer = 0; buffer < kSamplesBufferCount; buffer++) { @@ -443,7 +515,7 @@ Stream::GetBuffers(multi_buffer_list* List) Buffers[buffer][channel].base = (char*)(fDescriptors + fDescriptorsCount); // shift for whole buffer if required - size_t bufferSize = endpoint->fMaxPacketSize + size_t bufferSize = fPacketSize/*endpoint->fMaxPacketSize*/ * (fDescriptorsCount / kSamplesBufferCount); Buffers[buffer][channel].base += buffer * bufferSize; // shift for channel if required @@ -467,29 +539,6 @@ Stream::GetBuffers(multi_buffer_list* List) } -/* -int32 -Stream::InterruptHandler(uint32 SignaledChannelsMask) -{ - uint32 ChannelMask = 1 << fHWChannel; - if ((SignaledChannelsMask & ChannelMask) == 0) { - return B_UNHANDLED_INTERRUPT; - } - - uint32 CurrentSamplePositionFlag = fDevice->ReadPCI32(TrCurSPFBReg); - - fRealTime = system_time(); - fFramesCount += fBufferSize; - fBufferCycle = ((CurrentSamplePositionFlag & ChannelMask) == ChannelMask) ? 1 : 0; - -fCSP = CurrentSamplePositionFlag; - - release_sem_etc(fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE); - - return B_HANDLED_INTERRUPT; -}*/ - - bool Stream::ExchangeBuffer(multi_buffer_info* Info) { @@ -499,12 +548,15 @@ Stream::ExchangeBuffer(multi_buffer_info* Info) return false; } - Info->played_real_time = system_time();// TODO fRealTime; - Info->played_frames_count += fSamplesCount / kSamplesBufferCount; - Info->playback_buffer_cycle = fCurrentBuffer; - - fCurrentBuffer++; - fCurrentBuffer %= kSamplesBufferCount; + if (fIsInput) { + Info->recorded_real_time = system_time();// TODO fRealTime; + Info->recorded_frames_count += fSamplesCount / kSamplesBufferCount; + Info->record_buffer_cycle = fCurrentBuffer; + } else { + Info->played_real_time = system_time();// TODO fRealTime; + Info->played_frames_count += fSamplesCount / kSamplesBufferCount; + Info->playback_buffer_cycle = fCurrentBuffer; + } atomic_add(&fProcessedBuffers, -1); diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/Stream.h b/src/add-ons/kernel/drivers/audio/usb_audio/Stream.h index 960ef9c..927e08b 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Stream.h +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Stream.h @@ -62,22 +62,21 @@ protected: uint8 fTerminalID; usb_pipe fStreamEndpoint; bool fIsRunning; -/* uint32 fHWChannel;*/ area_id fArea; + size_t fAreaSize; usb_iso_packet_descriptor* fDescriptors; size_t fDescriptorsCount; size_t fCurrentBuffer; uint32 fStartingFrame; size_t fSamplesCount; + size_t fPacketSize; int32 fProcessedBuffers; -// void* fBuffersPhysAddress; -/* bigtime_t fRealTime; - bigtime_t fFramesCount; - int32 fBufferCycle; -public: - uint32 fCSP; */ + _multi_format fFormat; + private: - status_t _QueueNextTransfer(size_t buffer); + status_t _ChooseAlternate(); + status_t _SetupBuffers(); + status_t _QueueNextTransfer(size_t buffer, bool start); static void _TransferCallback(void *cookie, int32 status, void *data, uint32 actualLength); void _DumpDescriptors(); ############################################################################ Commit: 673ef2cbafb7291204d1cfcb79466ea7fe799beb URL: http://cgit.haiku-os.org/haiku/commit/?id=673ef2c Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Sun Jun 23 19:05:20 2013 UTC USB audio: cleanup and codestyle fixes. * cleanup and codestyle fixes; * AudioFunction module contents purged out as unused. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/AudioControlInterface.cpp b/src/add-ons/kernel/drivers/audio/usb_audio/AudioControlInterface.cpp index 417a4b0..3bf0b52 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/AudioControlInterface.cpp +++ b/src/add-ons/kernel/drivers/audio/usb_audio/AudioControlInterface.cpp @@ -1,14 +1,16 @@ /* * Driver for USB Audio Device Class devices. - * Copyright (c) 2009,10,12 S.Zharski <imker@xxxxxx> + * Copyright (c) 2009-13 S.Zharski <imker@xxxxxx> * Distributed under the tems of the MIT license. * */ #include "AudioControlInterface.h" -#include "Settings.h" -#include "Device.h" + #include "audio.h" +#include "Device.h" +#include "Driver.h" +#include "Settings.h" enum TerminalTypes { @@ -185,14 +187,14 @@ GetTerminalDescription(uint16 TerminalType) _AudioControl::_AudioControl(AudioControlInterface* interface, - usb_audiocontrol_header_descriptor* Header) - : - fStatus(B_NO_INIT), - fInterface(interface), - fSubType(Header->descriptor_subtype), - fID(0), - fSourceID(0), - fStringIndex(0) + usb_audiocontrol_header_descriptor* Header) + : + fStatus(B_NO_INIT), + fInterface(interface), + fSubType(Header->descriptor_subtype), + fID(0), + fSourceID(0), + fStringIndex(0) { } @@ -205,51 +207,45 @@ _AudioControl::~_AudioControl() AudioChannelCluster* _AudioControl::OutCluster() { - if (SourceID() == 0 || fInterface == NULL) { + if (SourceID() == 0 || fInterface == NULL) return NULL; - } _AudioControl* control = fInterface->Find(SourceID()); - if (control == NULL) { + if (control == NULL) return NULL; - } return control->OutCluster(); } AudioChannelCluster::AudioChannelCluster() - : - fOutChannelsNumber(0), - fChannelsConfig(0), - fChannelNames(0) + : + fOutChannelsNumber(0), + fChannelsConfig(0), + fChannelNames(0) { - } AudioChannelCluster::~AudioChannelCluster() { - } _Terminal::_Terminal(AudioControlInterface* interface, - usb_audiocontrol_header_descriptor* Header) - : - _AudioControl(interface, Header), - fTerminalType(0), - fAssociatedTerminal(0), - fClockSourceId(0), - fControlsBitmap(0) + usb_audiocontrol_header_descriptor* Header) + : + _AudioControl(interface, Header), + fTerminalType(0), + fAssociatedTerminal(0), + fClockSourceId(0), + fControlsBitmap(0) { - } _Terminal::~_Terminal() { - } @@ -268,9 +264,9 @@ _Terminal::IsUSBIO() InputTerminal::InputTerminal(AudioControlInterface* interface, - usb_audiocontrol_header_descriptor* Header) - : - _AudioChannelCluster<_Terminal>(interface, Header) + usb_audiocontrol_header_descriptor* Header) + : + _AudioChannelCluster<_Terminal>(interface, Header) { usb_input_terminal_descriptor_r1* Terminal = (usb_input_terminal_descriptor_r1*) Header; @@ -280,7 +276,7 @@ InputTerminal::InputTerminal(AudioControlInterface* interface, TRACE("Input Terminal ID:%d >>>\n", fID); TRACE("Terminal type:%s (%#06x)\n", - GetTerminalDescription(fTerminalType), fTerminalType); + GetTerminalDescription(fTerminalType), fTerminalType); TRACE("Assoc.terminal:%d\n", fAssociatedTerminal); if (fInterface->SpecReleaseNumber() < 0x200) { @@ -317,9 +313,9 @@ InputTerminal::~InputTerminal() OutputTerminal::OutputTerminal(AudioControlInterface* interface, - usb_audiocontrol_header_descriptor* Header) - : - _Terminal(interface, Header) + usb_audiocontrol_header_descriptor* Header) + : + _Terminal(interface, Header) { usb_output_terminal_descriptor_r1* Terminal = (usb_output_terminal_descriptor_r1*) Header; @@ -331,7 +327,7 @@ OutputTerminal::OutputTerminal(AudioControlInterface* interface, TRACE("Output Terminal ID:%d >>>\n", fID); TRACE("Terminal type:%s (%#06x)\n", - GetTerminalDescription(fTerminalType), fTerminalType); + GetTerminalDescription(fTerminalType), fTerminalType); TRACE("Assoc.terminal:%d\n", fAssociatedTerminal); TRACE("Source ID:%d\n", fSourceID); @@ -361,10 +357,10 @@ OutputTerminal::~OutputTerminal() MixerUnit::MixerUnit(AudioControlInterface* interface, - usb_audiocontrol_header_descriptor* Header) - : - _AudioChannelCluster<_AudioControl>(interface, Header), - fControlsBitmap(0) + usb_audiocontrol_header_descriptor* Header) + : + _AudioChannelCluster<_AudioControl>(interface, Header), + fControlsBitmap(0) { usb_mixer_unit_descriptor* Mixer = (usb_mixer_unit_descriptor*) Header; @@ -384,7 +380,7 @@ MixerUnit::MixerUnit(AudioControlInterface* interface, if (fInterface->SpecReleaseNumber() < 0x200) { usb_output_channels_descriptor_r1* OutChannels = (usb_output_channels_descriptor_r1*) - &Mixer->input_pins[Mixer->num_input_pins]; + &Mixer->input_pins[Mixer->num_input_pins]; fOutChannelsNumber = OutChannels->num_output_pins; fChannelsConfig = OutChannels->channel_config; @@ -396,7 +392,7 @@ MixerUnit::MixerUnit(AudioControlInterface* interface, } else { usb_output_channels_descriptor* OutChannels = (usb_output_channels_descriptor*) - &Mixer->input_pins[Mixer->num_input_pins]; + &Mixer->input_pins[Mixer->num_input_pins]; fOutChannelsNumber = OutChannels->num_output_pins; fChannelsConfig = OutChannels->channel_config; @@ -432,10 +428,10 @@ MixerUnit::~MixerUnit() SelectorUnit::SelectorUnit(AudioControlInterface* interface, - usb_audiocontrol_header_descriptor* Header) - : - _AudioControl(interface, Header), - fControlsBitmap(0) + usb_audiocontrol_header_descriptor* Header) + : + _AudioControl(interface, Header), + fControlsBitmap(0) { usb_selector_unit_descriptor* Selector = (usb_selector_unit_descriptor*) Header; @@ -450,10 +446,8 @@ SelectorUnit::SelectorUnit(AudioControlInterface* interface, } if (fInterface->SpecReleaseNumber() < 0x200) { - fStringIndex = Selector->input_pins[Selector->num_input_pins]; } else { - fControlsBitmap = Selector->input_pins[Selector->num_input_pins]; fStringIndex = Selector->input_pins[Selector->num_input_pins + 1]; @@ -474,19 +468,16 @@ SelectorUnit::~SelectorUnit() AudioChannelCluster* SelectorUnit::OutCluster() { - if (fInterface == NULL) { + if (fInterface == NULL) return NULL; - } for (int i = 0; i < fInputPins.Count(); i++) { _AudioControl* control = fInterface->Find(fInputPins[i]); - if (control == NULL) { + if (control == NULL) continue; - } - if (control->OutCluster() != NULL) { + if (control->OutCluster() != NULL) return control->OutCluster(); - } } return NULL; @@ -494,9 +485,9 @@ SelectorUnit::OutCluster() FeatureUnit::FeatureUnit(AudioControlInterface* interface, - usb_audiocontrol_header_descriptor* Header) [ *** diff truncated: 5358 lines dropped *** ] ############################################################################ Commit: b42544e71d4ccb28fec64112b8facaddf91a94f5 URL: http://cgit.haiku-os.org/haiku/commit/?id=b42544e Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Thu Jun 27 14:14:02 2013 UTC USB audio: fInsideNotify guard added to Remote/Close callbacks ---------------------------------------------------------------------------- ############################################################################ Commit: 1a6d941d1dea2ab1d924983cb1b09b0360c5e8bf URL: http://cgit.haiku-os.org/haiku/commit/?id=1a6d941 Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Tue Jun 25 21:05:56 2013 UTC USB audio: Use system-wide USB_audio.h instead local one * switching driver code to use system usb/USB_audio.h header; * refactor USB_audio.h specification header for both USB audio specifications. ---------------------------------------------------------------------------- ############################################################################ Commit: 7ff9cd33a9d13b3993a60817482dd83df10bee8b URL: http://cgit.haiku-os.org/haiku/commit/?id=7ff9cd3 Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Thu Jun 27 19:22:54 2013 UTC USB audio: Refactor TRACE-es for more configurability ---------------------------------------------------------------------------- ############################################################################ Commit: a8066fe34aa482e529b7afcedec1456c8fd7bd02 URL: http://cgit.haiku-os.org/haiku/commit/?id=a8066fe Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Fri Jun 28 13:19:11 2013 UTC USB audio: dev.entry number should be 1-based, etc * USB audio device entry number made 1-based instead of 0. According to Haiku MultiAudio specs audio device entries should be 1-based but 0-based; * cleanup and refactoring. No functional changes; * recording stream activated; * fix input channels description report and codestyle issues. ---------------------------------------------------------------------------- ############################################################################ Commit: 353a4e04d132525d1d2ce39e57971eed83267c9d URL: http://cgit.haiku-os.org/haiku/commit/?id=353a4e0 Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Wed Jul 17 05:12:00 2013 UTC USB audio: Fix function of Selector Unit control * restore function of Selector Unit that was previously disabled; * fix Selector Unit input pin names "Unknwon" case. ---------------------------------------------------------------------------- ############################################################################ Commit: 743d75946f1b6ca948107bf8c2a5b115ad9f33de URL: http://cgit.haiku-os.org/haiku/commit/?id=743d759 Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Wed Jul 17 20:09:13 2013 UTC USB audio: Mixer Unit control implementation * support of Mixer Unit control in UI implemented; * improve SetMix/GetMix to support Mixer Unit control type; * cleanup and improvements. ---------------------------------------------------------------------------- ############################################################################ Commit: 14f92002e1f4542a8afc6d43a2fd145eabc7519d URL: http://cgit.haiku-os.org/haiku/commit/?id=14f9200 Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Tue Aug 6 04:14:28 2013 UTC USB audio: use new(std::nothrow) for allocations * Use new(std::nothrow) for allocations; * Input buffer index counter restored; * Improve unsupported UI controls debug info tracing; * Some cleanup. ---------------------------------------------------------------------------- ############################################################################ Revision: hrev45972 Commit: a69892cadca9288b901ac66273d342bfb4329373 URL: http://cgit.haiku-os.org/haiku/commit/?id=a69892c Author: Siarzhuk Zharski <zharik@xxxxxx> Date: Sat Aug 17 19:22:52 2013 UTC Rename driver folder 'usb_audio' to 'usb' ... just because the source path ./kernel/drivers/audio/usb obviously references audio hardware so "_audio" suffix is excessive. No functional changes. ----------------------------------------------------------------------------