Author: siarzhuk Date: 2010-01-19 22:08:52 +0100 (Tue, 19 Jan 2010) New Revision: 35183 Changeset: http://dev.haiku-os.org/changeset/35183/haiku Modified: haiku/branches/developer/siarzhuk/usb_audio/Device.cpp haiku/branches/developer/siarzhuk/usb_audio/Device.h haiku/branches/developer/siarzhuk/usb_audio/Stream.cpp haiku/branches/developer/siarzhuk/usb_audio/Stream.h Log: - draft implementation of the buffer exchnage; - multi buffer force stop handler added; - cleanup. Modified: haiku/branches/developer/siarzhuk/usb_audio/Device.cpp =================================================================== --- haiku/branches/developer/siarzhuk/usb_audio/Device.cpp 2010-01-19 20:45:20 UTC (rev 35182) +++ haiku/branches/developer/siarzhuk/usb_audio/Device.cpp 2010-01-19 21:08:52 UTC (rev 35183) @@ -28,7 +28,8 @@ fNotifyReadSem(-1), fNotifyWriteSem(-1), fNotifyBuffer(NULL), - fNotifyBufferLength(0) + fNotifyBufferLength(0), + fBuffersReadySem(-1) { const usb_device_descriptor *deviceDescriptor = gUSBModule->get_device_descriptor(device); @@ -55,6 +56,12 @@ return; } + fBuffersReadySem = create_sem(0, DRIVER_NAME "_buffers_ready"); + if (fBuffersReadySem < B_OK) { + TRACE_ALWAYS("Error of creating ready buffers semaphore:%#010x\n", + fBuffersReadySem); + return; + } if (_SetupEndpoints() != B_OK) { return; @@ -94,6 +101,9 @@ if (fNotifyWriteSem >= B_OK) delete_sem(fNotifyWriteSem); + if(fBuffersReadySem > B_OK) + delete_sem(fBuffersReadySem); + // if (!fRemoved) //??? // gUSBModule->cancel_queued_transfers(fNotifyEndpoint); @@ -249,8 +259,7 @@ return _MultiBufferExchange((multi_buffer_info*)buffer); case B_MULTI_BUFFER_FORCE_STOP: /* force stop of playback, nothing in data */ - TRACE(("B_MULTI_BUFFER_FORCE_STOP\n")); - return B_ERROR; + return _MultiBufferForceStop(); default: TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op); @@ -556,7 +565,30 @@ } } - snooze(1000000); + status_t status = B_ERROR; + bool anyBufferProcessed = false; + for(int i = 0; i < fStreams.Count() && !anyBufferProcessed; i++) { + status = acquire_sem_etc(fBuffersReadySem, 1, + B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, 50000); + if(status == B_TIMED_OUT) { + TRACE_ALWAYS("Timeout during buffers exchange.\n"); + break; + } + + anyBufferProcessed = fStreams[i]->ExchangeBuffer(Info); + status = anyBufferProcessed ? B_OK : B_ERROR; + } + + return status; +} + + +status_t +Device::_MultiBufferForceStop() +{ + for(int i = 0; i < fStreams.Count(); i++) { + fStreams[i]->Stop(); + } return B_OK; } Modified: haiku/branches/developer/siarzhuk/usb_audio/Device.h =================================================================== --- haiku/branches/developer/siarzhuk/usb_audio/Device.h 2010-01-19 20:45:20 UTC (rev 35182) +++ haiku/branches/developer/siarzhuk/usb_audio/Device.h 2010-01-19 21:08:52 UTC (rev 35183) @@ -26,6 +26,7 @@ class FeatureUnit; class Device { friend class FeatureUnit; + friend class Stream; public: Device(usb_device device); @@ -118,6 +119,7 @@ status_t _MultiSetMix(multi_mix_value_info *Info); status_t _MultiListMixControls(multi_mix_control_info* Info); status_t _MultiBufferExchange(multi_buffer_info* Info); + status_t _MultiBufferForceStop(); // interface and device infos // uint16 fFrameSize; @@ -138,6 +140,7 @@ uint8 * fNotifyBuffer; uint32 fNotifyBufferLength; + sem_id fBuffersReadySem; // MII bus handler // MIIBus fMII; Modified: haiku/branches/developer/siarzhuk/usb_audio/Stream.cpp =================================================================== --- haiku/branches/developer/siarzhuk/usb_audio/Stream.cpp 2010-01-19 20:45:20 UTC (rev 35182) +++ haiku/branches/developer/siarzhuk/usb_audio/Stream.cpp 2010-01-19 21:08:52 UTC (rev 35183) @@ -22,7 +22,8 @@ fDescriptorsCount(0), fCurrentBuffer(0), fStartingFrame(0), - fSamplesCount(0)/*, + fSamplesCount(0), + fProcessedBuffers(0)/*, fBuffersPhysAddress(0)/ *, fRealTime(0), fFramesCount(0), @@ -205,8 +206,10 @@ { status_t result = B_BUSY; if(!fIsRunning) { - if(!fIsInput) - result = _QueueNextTransfer(); + if(!fIsInput) { + for(size_t i = 0; i < kSamplesBufferCount; i++) + result = _QueueNextTransfer(i); + } else result = B_OK; fIsRunning = result == B_OK; @@ -228,7 +231,7 @@ status_t -Stream::_QueueNextTransfer() +Stream::_QueueNextTransfer(size_t queuedBuffer) { TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(fAlternates[fActiveAlternate]->Format()); @@ -241,12 +244,12 @@ size_t packetsCount = fDescriptorsCount / kSamplesBufferCount; TRACE("buffers:%#010x[%#x]\ndescrs:%#010x[%#x]\n", - buffers + bufferSize * fCurrentBuffer, bufferSize, - fDescriptors + fCurrentBuffer * packetsCount, packetsCount); + buffers + bufferSize * queuedBuffer, bufferSize, + fDescriptors + queuedBuffer * packetsCount, packetsCount); return gUSBModule->queue_isochronous(fStreamEndpoint, - buffers + bufferSize * fCurrentBuffer, bufferSize, - fDescriptors + fCurrentBuffer * packetsCount, packetsCount, + buffers + bufferSize * queuedBuffer, bufferSize, + fDescriptors + queuedBuffer * packetsCount, packetsCount, NULL/*&fStartingFrame*/, 0, Stream::_TransferCallback, this); return B_OK; @@ -258,22 +261,23 @@ uint32 actualLength) { Stream *stream = (Stream *)cookie; - +/* stream->fCurrentBuffer++; if(stream->fCurrentBuffer >= kSamplesBufferCount) { stream->fCurrentBuffer = 0; } +*/ + + status_t result = stream->_QueueNextTransfer(stream->fCurrentBuffer); + + if(atomic_add(&stream->fProcessedBuffers, 1) > (int32)kSamplesBufferCount) { + TRACE_ALWAYS("Processed buffers overflow:%d\n", stream->fProcessedBuffers); + } - status_t result = stream->_QueueNextTransfer(); + release_sem_etc(stream->fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE); TRACE_ALWAYS("st:%#010x, len:%d -> %#010x\n", status, actualLength, result); -/* - atomic_add(&device->fInsideNotify, 1); - if (status == B_CANCELED || device->fRemoved) { - atomic_add(&device->fInsideNotify, -1); - return; - } -*/ + /* if (status != B_OK) { TRACE_ALWAYS("Device status error:%#010x\n", status); status_t result = gUSBModule->clear_feature(device->fControLeNDPOint, @@ -282,14 +286,6 @@ TRACE_ALWAYS("Error during clearing of HALT state:%#010x.\n", result); } */ - // parse data in overriden class -// device->OnNotify(actualLength); - - // schedule next notification buffer -// gUSBModule->queue_interrupt(device->fNotifyEndpoint, device->fNotifyBuffer, -// device->fNotifyBufferLength, _NotifyCallback, device); - -// atomic_add(&device->fInsideNotify, -1); } @@ -457,92 +453,27 @@ return B_HANDLED_INTERRUPT; } - -void -Stream::ExchangeBuffers(bigtime_t& RealTime, - bigtime_t& FramesCount, int32& BufferCycle) +*/ +bool +Stream::ExchangeBuffer(multi_buffer_info* Info) { - RealTime = fRealTime; - FramesCount = fFramesCount; - BufferCycle = fBufferCycle; -} - - -RecordStream::RecordStream(Device* device, uint32 HWChannel) : Stream(device, true, HWChannel) -{ -} - -RecordStream::~RecordStream() -{ -} - - -status_t -RecordStream::Start() -{ - uint32 ESO = ((fBufferSize * 2) - 1) & 0xffff; - uint32 Delta = ((48000 << 12) / 48000) & 0xffff; - uint32 FMControl = 0x03; -// uint32 ReverbVolume = 0x7f; -// uint32 ChorusVolume = 0x7f; - uint32 Control = 0x0f; // 16.bit, stereo, signed, loop enabled -// uint32 ChannelVolume = fIsInput ? 0xff : 0x00; - uint32 Rec = 0x8880; - - uint32 ChannelRegs[5] = {0}; - - // CSO, Sample interpolation coefficient and FMS - ChannelRegs[0] = 0; - // Loop Begin Address - ChannelRegs[1] = uint32(fBuffersPhysAddress) & 0x3fffffff; - // ESO & Delta Sample Rate Ratio - ChannelRegs[2] = Delta | (ESO << 16); - // FM control, Reverb and Chorus Volume - ChannelRegs[3] = (Rec << 16) / *| (FMControl << 14)/ * | (ReverbVolume << 7) | ChorusVolume* /; - // GVSEL, PAN. VOL. Control and curr. Envelope - ChannelRegs[4] = / *(ChannelVolume << 16) |* / (Control << 12)/ * | 0x80000000* /; - - TRACE("ChannelRegs:%#010x %#010x %#010x %#010x %#010x\n", - ChannelRegs[0], ChannelRegs[1], ChannelRegs[2], - ChannelRegs[3], ChannelRegs[4]); - -uint32 CIRs[3] = {0}; - cpu_status cst = fDevice->Lock(); - - // select current channel - uint32 CIR = fDevice->ReadPCI32(TrChIndexReg); - CIRs[0] = CIR; - CIR = fDevice->ReadPCI32(TrChIndexReg) & ~0x3f; - CIRs[1] = CIR; - CIR |= (fHWChannel + 32) & 0x3f; // we use Bank B for PCM! - CIRs[2] = CIR; - fDevice->WritePCI32(TrChIndexReg, CIR); - - // write registers... - for(size_t i = 0; i < _countof(ChannelRegs); i++) { - fDevice->WritePCI32(0xe0 + i * 4, ChannelRegs[i]); + if(fProcessedBuffers <= 0) { + // looks like somebody else has processed buffers but this stream + release_sem_etc(fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE); + return false; } -/// fDevice->WritePCI32(0xa8, 0x0000); - fDevice->WritePCI32(0xf4, 0x0000); - fDevice->WritePCI32(0xf8, 0x0000); + Info->played_real_time = system_time();//TODO fRealTime; + Info->played_frames_count += fSamplesCount / kSamplesBufferCount; + Info->playback_buffer_cycle = fCurrentBuffer; - // enable INT for current channel - uint32 ChIntMask = fDevice->ReadPCI32(TrEnableINTBReg); - ChIntMask |= 1 << fHWChannel; - fDevice->WritePCI32(TrAddressINTBReg, 1 << fHWChannel); // clear INT for current channel - fDevice->WritePCI32(TrEnableINTBReg, ChIntMask); // enable it + fCurrentBuffer++; + fCurrentBuffer %= kSamplesBufferCount; - // start current channel - fDevice->WritePCI32(TrStartBReg, 1 << fHWChannel); + atomic_add(&fProcessedBuffers, -1); - fDevice->Unlock(cst); - -TRACE("Rec:CIRS:%#010x %#010x %#010x \n", CIRs[0], CIRs[1], CIRs[2]); - - return B_OK; + return true; } -*/ /* ASInterfaceDescriptor* Modified: haiku/branches/developer/siarzhuk/usb_audio/Stream.h =================================================================== --- haiku/branches/developer/siarzhuk/usb_audio/Stream.h 2010-01-19 20:45:20 UTC (rev 35182) +++ haiku/branches/developer/siarzhuk/usb_audio/Stream.h 2010-01-19 21:08:52 UTC (rev 35183) @@ -38,11 +38,8 @@ status_t OnSetConfiguration(usb_device device, const usb_configuration_info *config); + bool ExchangeBuffer(multi_buffer_info* Info); /* - void ExchangeBuffers(bigtime_t& RealTime, - bigtime_t& FramesCount, - int32& BufferCycle); - int32 InterruptHandler(uint32 SignaledChannelsMask); */ // ASInterfaceDescriptor* ASInterface(); @@ -71,7 +68,8 @@ size_t fDescriptorsCount; size_t fCurrentBuffer; uint32 fStartingFrame; - size_t fSamplesCount; + size_t fSamplesCount; + int32 fProcessedBuffers; // void* fBuffersPhysAddress; /* bigtime_t fRealTime; bigtime_t fFramesCount; @@ -79,7 +77,7 @@ public: uint32 fCSP; */ private: - status_t _QueueNextTransfer(); + status_t _QueueNextTransfer(size_t buffer); static void _TransferCallback(void *cookie, int32 status, void *data, uint32 actualLength); };