USB audio: fInsideNotify guard added to Remote/Close callbacks

This commit is contained in:
Siarzhuk Zharski 2013-06-27 16:14:02 +02:00
parent 673ef2cbaf
commit b42544e71d
4 changed files with 29 additions and 56 deletions

View File

@ -17,7 +17,6 @@ Device::Device(usb_device device)
fStatus(B_ERROR), fStatus(B_ERROR),
fOpen(false), fOpen(false),
fRemoved(false), fRemoved(false),
// fInsideNotify(0),
fDevice(device), fDevice(device),
fNonBlocking(false), fNonBlocking(false),
fAudioControl(this), fAudioControl(this),
@ -93,13 +92,6 @@ Device::Close()
for (int i = 0; i < fStreams.Count(); i++) for (int i = 0; i < fStreams.Count(); i++)
fStreams[i]->Stop(); 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; fOpen = false;
return StopDevice(); return StopDevice();
@ -220,19 +212,8 @@ Device::Removed()
{ {
fRemoved = true; fRemoved = true;
// the notify hook is different from the read and write hooks as it does for (int i = 0; i < fStreams.Count(); i++)
// itself schedule traffic (while the other hooks only release a semaphore fStreams[i]->OnRemove();
// 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);
} }
@ -645,33 +626,3 @@ Device::StopDevice()
return result; 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);
}
*/

View File

@ -57,7 +57,6 @@ private:
status_t fStatus; status_t fStatus;
bool fOpen; bool fOpen;
bool fRemoved; bool fRemoved;
// int32 fInsideNotify; // TODO: move to Stream!
usb_device fDevice; usb_device fDevice;
uint16 fUSBVersion; uint16 fUSBVersion;
uint16 fVendorID; uint16 fVendorID;

View File

@ -29,7 +29,8 @@ Stream::Stream(Device* device, size_t interface, usb_interface_list* List)
fStartingFrame(0), fStartingFrame(0),
fSamplesCount(0), fSamplesCount(0),
fPacketSize(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 status_t
Stream::_SetupBuffers() Stream::_SetupBuffers()
{ {
@ -252,6 +267,9 @@ status_t
Stream::Stop() Stream::Stop()
{ {
if (fIsRunning) { if (fIsRunning) {
// wait until possible notification handling finished...
while (atomic_add(&fInsideNotify, 0) != 0)
snooze(100);
gUSBModule->cancel_queued_transfers(fStreamEndpoint); gUSBModule->cancel_queued_transfers(fStreamEndpoint);
fIsRunning = false; fIsRunning = false;
} }
@ -292,13 +310,14 @@ void
Stream::_TransferCallback(void* cookie, int32 status, void* data, Stream::_TransferCallback(void* cookie, int32 status, void* data,
uint32 actualLength) 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", TRACE_ALWAYS("Cancelled: c:%p st:%#010x, data:%#010x, len:%d\n",
cookie, status, data, actualLength); cookie, status, data, actualLength);
return; return;
} }
Stream* stream = (Stream*)cookie;
stream->fCurrentBuffer = (stream->fCurrentBuffer + 1) % kSamplesBufferCount; 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_ALWAYS("st:%#010x, len:%d -> %#010x\n", status, actualLength, result);
TRACE("st:%#010x, data:%#010x, len:%d\n", status, data, actualLength); TRACE("st:%#010x, data:%#010x, len:%d\n", status, data, actualLength);
atomic_add(&stream->fInsideNotify, -1);
} }

View File

@ -26,6 +26,7 @@ public:
status_t Start(); status_t Start();
status_t Stop(); status_t Stop();
bool IsRunning() { return fIsRunning; } bool IsRunning() { return fIsRunning; }
void OnRemove();
status_t GetBuffers(multi_buffer_list* List); status_t GetBuffers(multi_buffer_list* List);
@ -57,6 +58,7 @@ protected:
size_t fSamplesCount; size_t fSamplesCount;
size_t fPacketSize; size_t fPacketSize;
int32 fProcessedBuffers; int32 fProcessedBuffers;
int32 fInsideNotify;
private: private:
status_t _ChooseAlternate(); status_t _ChooseAlternate();