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 95ae75436a..46e8a56da5 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Device.cpp +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Device.cpp @@ -17,7 +17,6 @@ Device::Device(usb_device device) fStatus(B_ERROR), fOpen(false), fRemoved(false), -// fInsideNotify(0), fDevice(device), fNonBlocking(false), fAudioControl(this), @@ -93,13 +92,6 @@ Device::Close() for (int i = 0; i < fStreams.Count(); i++) fStreams[i]->Stop(); - // 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); - fOpen = false; return StopDevice(); @@ -220,19 +212,8 @@ Device::Removed() { fRemoved = true; - // the notify hook is different from the read and write hooks as it does - // itself schedule traffic (while the other hooks only release a semaphore - // to notify another thread which in turn safly checks for the removed - // case) - so we must ensure that we are not inside the notify hook anymore - // before returning, as we would otherwise violate the promise not to use - // any of the pipes after returning from the removed hook -// TODO?????? -// while (atomic_add(&fInsideNotify, 0) != 0) -// snooze(100); - -// gUSBModule->cancel_queued_transfers(fControlEndpoint); -// gUSBModule->cancel_queued_transfers(fInStreamEndpoint); -// gUSBModule->cancel_queued_transfers(fOutStreamEndpoint); + for (int i = 0; i < fStreams.Count(); i++) + fStreams[i]->OnRemove(); } @@ -645,33 +626,3 @@ Device::StopDevice() return result; } - -/*void -Device::_NotifyCallback(void* cookie, int32 status, void* data, - uint32 actualLength) -{ - Device* device = (Device*)cookie; - 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, - USB_FEATURE_ENDPOINT_HALT); - if (result != B_OK) - 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); -} -*/ - 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 94d4f736ff..5f52566bb5 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Device.h +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Device.h @@ -57,7 +57,6 @@ private: status_t fStatus; bool fOpen; bool fRemoved; -// int32 fInsideNotify; // TODO: move to Stream! usb_device fDevice; uint16 fUSBVersion; uint16 fVendorID; 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 9c813861d6..ad9578374c 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Stream.cpp +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Stream.cpp @@ -29,7 +29,8 @@ Stream::Stream(Device* device, size_t interface, usb_interface_list* List) fStartingFrame(0), fSamplesCount(0), fPacketSize(0), - fProcessedBuffers(0) + fProcessedBuffers(0), + fInsideNotify(0) { } @@ -129,6 +130,20 @@ Stream::Init() } +void +Stream::OnRemove() +{ + // the transfer callback schedule traffic - so we must ensure that we are + // not inside the callback anymore before returning, as we would otherwise + // violate the promise not to use any of the pipes after returning from the + // removed callback + while (atomic_add(&fInsideNotify, 0) != 0) + snooze(100); + + gUSBModule->cancel_queued_transfers(fStreamEndpoint); +} + + status_t Stream::_SetupBuffers() { @@ -252,6 +267,9 @@ status_t Stream::Stop() { if (fIsRunning) { + // wait until possible notification handling finished... + while (atomic_add(&fInsideNotify, 0) != 0) + snooze(100); gUSBModule->cancel_queued_transfers(fStreamEndpoint); fIsRunning = false; } @@ -292,13 +310,14 @@ void Stream::_TransferCallback(void* cookie, int32 status, void* data, uint32 actualLength) { - if (status == B_CANCELED) { + Stream* stream = (Stream*)cookie; + atomic_add(&stream->fInsideNotify, 1); + if (status == B_CANCELED || stream->fDevice->fRemoved) { + atomic_add(&stream->fInsideNotify, -1); TRACE_ALWAYS("Cancelled: c:%p st:%#010x, data:%#010x, len:%d\n", cookie, status, data, actualLength); return; } - - Stream* stream = (Stream*)cookie; stream->fCurrentBuffer = (stream->fCurrentBuffer + 1) % kSamplesBufferCount; @@ -313,6 +332,8 @@ Stream::_TransferCallback(void* cookie, int32 status, void* data, // TRACE_ALWAYS("st:%#010x, len:%d -> %#010x\n", status, actualLength, result); TRACE("st:%#010x, data:%#010x, len:%d\n", status, data, actualLength); + + atomic_add(&stream->fInsideNotify, -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 fb0fe65373..0635f70950 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Stream.h +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Stream.h @@ -26,6 +26,7 @@ public: status_t Start(); status_t Stop(); bool IsRunning() { return fIsRunning; } + void OnRemove(); status_t GetBuffers(multi_buffer_list* List); @@ -57,6 +58,7 @@ protected: size_t fSamplesCount; size_t fPacketSize; int32 fProcessedBuffers; + int32 fInsideNotify; private: status_t _ChooseAlternate();