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...
This commit is contained in:
Siarzhuk Zharski
2013-08-18 14:48:11 +02:00
parent 291e40c309
commit 2cc4703b91
6 changed files with 447 additions and 201 deletions
@@ -11,6 +11,29 @@
#include "audio.h" #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 // Audio Stream information entities
// //
@@ -44,28 +67,31 @@ ASInterfaceDescriptor::~ASInterfaceDescriptor()
ASEndpointDescriptor::ASEndpointDescriptor(usb_endpoint_descriptor* Endpoint, ASEndpointDescriptor::ASEndpointDescriptor(usb_endpoint_descriptor* Endpoint,
usb_as_cs_endpoint_descriptor* Descriptor) usb_as_cs_endpoint_descriptor* Descriptor)
: :
fAttributes(0), fCSAttributes(0),
fLockDelayUnits(0), fLockDelayUnits(0),
fLockDelay(0), fLockDelay(0),
fMaxPacketSize(0), fMaxPacketSize(0),
fEndpointAddress(0) fEndpointAddress(0),
fEndpointAttributes(0)
{ {
// usb_audiocontrol_header_descriptor *Header // usb_audiocontrol_header_descriptor *Header
// = (usb_audiocontrol_header_descriptor *)Interface->generic[i]; // = (usb_audiocontrol_header_descriptor *)Interface->generic[i];
fAttributes = Descriptor->attributes; fCSAttributes = Descriptor->attributes;
fLockDelayUnits = Descriptor->lock_delay_units; fLockDelayUnits = Descriptor->lock_delay_units;
fLockDelay = Descriptor->lock_delay; fLockDelay = Descriptor->lock_delay;
// usb_endpoint_descriptor* endpoint = Interface->endpoint[0]->descr; // usb_endpoint_descriptor* endpoint = Interface->endpoint[0]->descr;
fEndpointAttributes = Endpoint->attributes;
fEndpointAddress = Endpoint->endpoint_address; fEndpointAddress = Endpoint->endpoint_address;
fMaxPacketSize = Endpoint->max_packet_size; fMaxPacketSize = Endpoint->max_packet_size;
TRACE("fAttributes:%d\n", fAttributes); TRACE("fCSAttributes:%d\n", fCSAttributes);
TRACE("fLockDelayUnits:%d\n", fLockDelayUnits); TRACE("fLockDelayUnits:%d\n", fLockDelayUnits);
TRACE("fLockDelay:%d\n", fLockDelay); TRACE("fLockDelay:%d\n", fLockDelay);
TRACE("fMaxPacketSize:%d\n", fMaxPacketSize); TRACE("fMaxPacketSize:%d\n", fMaxPacketSize);
TRACE("fEndpointAddress:%#02x\n", fEndpointAddress); TRACE("fEndpointAddress:%#02x\n", fEndpointAddress);
TRACE("fEndpointAttributes:%d\n", fEndpointAttributes);
} }
@@ -186,8 +212,10 @@ AudioStreamAlternate::AudioStreamAlternate(size_t alternate,
fAlternate(alternate), fAlternate(alternate),
fInterface(interface), fInterface(interface),
fEndpoint(endpoint), 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( AudioStreamingInterface::AudioStreamingInterface(
AudioControlInterface* controlInterface, AudioControlInterface* controlInterface,
size_t interface, usb_interface_list *List) size_t interface, usb_interface_list *List)
@@ -329,9 +517,8 @@ AudioStreamingInterface::GetFormatsAndRates(multi_description *Description)
Description->interface_flags Description->interface_flags
|= fIsInput ? B_MULTI_INTERFACE_RECORD : B_MULTI_INTERFACE_PLAYBACK; |= fIsInput ? B_MULTI_INTERFACE_RECORD : B_MULTI_INTERFACE_PLAYBACK;
uint32 rates = 0; // uint32 rates = 0;
uint32 formats = 0; /*
TypeIFormatDescriptor* format TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>( = static_cast<TypeIFormatDescriptor*>(
fAlternates[fActiveAlternate]->Format()); fAlternates[fActiveAlternate]->Format());
@@ -373,27 +560,9 @@ AudioStreamingInterface::GetFormatsAndRates(multi_description *Description)
} }
} }
} }
*/
switch (fAlternates[fActiveAlternate]->Interface()->fFormatTag) { uint32 rates = fAlternates[fActiveAlternate]->GetSamplingRateIds();
case UAF_PCM8: formats = B_FMT_8BIT_U; break; uint32 formats = fAlternates[fActiveAlternate]->GetFormatId();
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;
}
if (fIsInput) { if (fIsInput) {
Description->input_rates = rates; Description->input_rates = rates;
@@ -40,11 +40,12 @@ public:
~ASEndpointDescriptor(); ~ASEndpointDescriptor();
// protected: // protected:
uint8 fAttributes; uint8 fCSAttributes;
uint8 fLockDelayUnits; uint8 fLockDelayUnits;
uint16 fLockDelay; uint16 fLockDelay;
uint16 fMaxPacketSize; uint16 fMaxPacketSize;
uint8 fEndpointAddress; uint8 fEndpointAddress;
uint8 fEndpointAttributes;
}; };
@@ -113,11 +114,22 @@ public:
ASEndpointDescriptor* Endpoint() { return fEndpoint; } ASEndpointDescriptor* Endpoint() { return fEndpoint; }
_ASFormatDescriptor* Format() { return fFormat; } _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: protected:
size_t fAlternate; size_t fAlternate;
ASInterfaceDescriptor* fInterface; ASInterfaceDescriptor* fInterface;
ASEndpointDescriptor* fEndpoint; ASEndpointDescriptor* fEndpoint;
_ASFormatDescriptor* fFormat; _ASFormatDescriptor* fFormat;
uint32 fSamplingRate;
}; };
@@ -23,9 +23,9 @@ Device::Device(usb_device device)
fDevice(device), fDevice(device),
fNonBlocking(false), fNonBlocking(false),
fAudioControl(this), fAudioControl(this),
fControlEndpoint(0), // fControlEndpoint(0),
fInStreamEndpoint(0), // fInStreamEndpoint(0),
fOutStreamEndpoint(0), // fOutStreamEndpoint(0),
fNotifyReadSem(-1), fNotifyReadSem(-1),
fNotifyWriteSem(-1), fNotifyWriteSem(-1),
fNotifyBuffer(NULL), fNotifyBuffer(NULL),
@@ -42,6 +42,7 @@ Device::Device(usb_device device)
fVendorID = deviceDescriptor->vendor_id; fVendorID = deviceDescriptor->vendor_id;
fProductID = deviceDescriptor->product_id; fProductID = deviceDescriptor->product_id;
fUSBVersion = deviceDescriptor->usb_version;
fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read"); fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read");
if (fNotifyReadSem < B_OK) { if (fNotifyReadSem < B_OK) {
@@ -155,9 +156,9 @@ Device::Close()
// wait until possible notification handling finished... // wait until possible notification handling finished...
while (atomic_add(&fInsideNotify, 0) != 0) while (atomic_add(&fInsideNotify, 0) != 0)
snooze(100); snooze(100);
gUSBModule->cancel_queued_transfers(fControlEndpoint); // gUSBModule->cancel_queued_transfers(fControlEndpoint);
gUSBModule->cancel_queued_transfers(fInStreamEndpoint); // gUSBModule->cancel_queued_transfers(fInStreamEndpoint);
gUSBModule->cancel_queued_transfers(fOutStreamEndpoint); // gUSBModule->cancel_queued_transfers(fOutStreamEndpoint);
fOpen = false; fOpen = false;
@@ -289,9 +290,9 @@ Device::Removed()
while (atomic_add(&fInsideNotify, 0) != 0) while (atomic_add(&fInsideNotify, 0) != 0)
snooze(100); snooze(100);
gUSBModule->cancel_queued_transfers(fControlEndpoint); // gUSBModule->cancel_queued_transfers(fControlEndpoint);
gUSBModule->cancel_queued_transfers(fInStreamEndpoint); // gUSBModule->cancel_queued_transfers(fInStreamEndpoint);
gUSBModule->cancel_queued_transfers(fOutStreamEndpoint); // gUSBModule->cancel_queued_transfers(fOutStreamEndpoint);
/* /*
if (fLinkStateChangeSem >= B_OK) if (fLinkStateChangeSem >= B_OK)
release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE);
@@ -415,7 +416,7 @@ Device::_MultiGetDescription(multi_description *multiDescription)
TraceMultiDescription(&Description, Channels); TraceMultiDescription(&Description, Channels);
if (user_memcpy(multiDescription, &Description, if (user_memcpy(multiDescription, &Description,
sizeof(multi_description)) != B_OK) { sizeof(multi_description)) != B_OK) {
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
} }
@@ -555,6 +556,10 @@ Device::_MultiGetBuffers(multi_buffer_list* List)
List->request_record_channels, List->request_record_channels,
List->request_record_buffer_size); 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++) { for (int i = 0; i < fStreams.Count() && status == B_OK; i++) {
status = fStreams[i]->GetBuffers(List); status = fStreams[i]->GetBuffers(List);
} }
@@ -564,18 +569,23 @@ Device::_MultiGetBuffers(multi_buffer_list* List)
status_t 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++) { for (int i = 0; i < fStreams.Count(); i++) {
if (!fStreams[i]->IsRunning()) { if (!fStreams[i]->IsRunning()) {
fStreams[i]->Start(); fStreams[i]->Start();
} }
} }
TRACE_ALWAYS("Exchange!\n"); // TRACE_ALWAYS("Exchange!\n");
/*
snooze(1000000); snooze(1000000);
return B_OK; return B_OK;
*/
status_t status = B_ERROR; status_t status = B_ERROR;
bool anyBufferProcessed = false; bool anyBufferProcessed = false;
for (int i = 0; i < fStreams.Count() && !anyBufferProcessed; i++) { for (int i = 0; i < fStreams.Count() && !anyBufferProcessed; i++) {
@@ -586,10 +596,13 @@ Device::_MultiBufferExchange(multi_buffer_info* Info)
break; break;
} }
anyBufferProcessed = fStreams[i]->ExchangeBuffer(Info); anyBufferProcessed = fStreams[i]->ExchangeBuffer(&Info);
status = anyBufferProcessed ? B_OK : B_ERROR; status = anyBufferProcessed ? B_OK : B_ERROR;
} }
if (user_memcpy(multiInfo, &Info, sizeof(multi_buffer_info)) != B_OK)
return B_BAD_ADDRESS;
return status; return status;
} }
@@ -713,7 +726,7 @@ Device::_SetupEndpoints()
status_t status_t
Device::StopDevice() Device::StopDevice()
{ {
status_t result = B_OK; // WriteRXControlRegister(0); status_t result = B_OK;
if (result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result); TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result);
@@ -81,6 +81,7 @@ virtual status_t StopDevice();
bool fRemoved; bool fRemoved;
vint32 fInsideNotify; vint32 fInsideNotify;
usb_device fDevice; usb_device fDevice;
uint16 fUSBVersion;
uint16 fVendorID; uint16 fVendorID;
uint16 fProductID; uint16 fProductID;
const char * fDescription; const char * fDescription;
@@ -116,9 +117,9 @@ protected:
// uint16 fFrameSize; // uint16 fFrameSize;
// pipes for notifications and data io // pipes for notifications and data io
usb_pipe fControlEndpoint; // usb_pipe fControlEndpoint;
usb_pipe fInStreamEndpoint; // usb_pipe fInStreamEndpoint;
usb_pipe fOutStreamEndpoint; // usb_pipe fOutStreamEndpoint;
// data stores for async usb transfers // data stores for async usb transfers
uint32 fActualLengthRead; uint32 fActualLengthRead;
@@ -21,18 +21,16 @@ Stream::Stream(Device *device, size_t interface, usb_interface_list *List
fStreamEndpoint(0), fStreamEndpoint(0),
fIsRunning(false), fIsRunning(false),
fArea(-1), fArea(-1),
fDescriptors(0), fAreaSize(0),
fDescriptors(NULL),
fDescriptorsCount(0), fDescriptorsCount(0),
fCurrentBuffer(0), fCurrentBuffer(0),
fStartingFrame(0), fStartingFrame(0),
fSamplesCount(0), fSamplesCount(0),
fProcessedBuffers(0)/*, fPacketSize(0),
fBuffersPhysAddress(0)/ *, fProcessedBuffers(0)
fRealTime(0),
fFramesCount(0),
fBufferCycle(0)*/
{ {
memset(&fFormat, 0, sizeof(_multi_format));
} }
@@ -43,7 +41,7 @@ Stream::~Stream()
status_t status_t
Stream::Init() Stream::_ChooseAlternate()
{ {
// lookup alternate with maximal (ch * 100 + resolution) // lookup alternate with maximal (ch * 100 + resolution)
uint16 maxChxRes = 0; uint16 maxChxRes = 0;
@@ -80,6 +78,12 @@ Stream::Init()
TypeIFormatDescriptor* format TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>(fAlternates[i]->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) { if (fAlternates[i]->Interface()->fFormatTag == UAF_PCM) {
switch(format->fBitResolution) { switch(format->fBitResolution) {
default: default:
@@ -100,80 +104,94 @@ Stream::Init()
if (maxChxRes <= 0) { if (maxChxRes <= 0) {
TRACE("No compatible alternate found. Stream initialization failed.\n"); TRACE("No compatible alternate found. Stream initialization failed.\n");
return fStatus; return B_NO_INIT;
} }
const ASEndpointDescriptor* endpoint = fAlternates[ const ASEndpointDescriptor* endpoint = fAlternates[
fActiveAlternate]->Endpoint(); fActiveAlternate]->Endpoint();
fIsInput = (endpoint->fEndpointAddress & USB_ENDPOINT_ADDR_DIR_IN) fIsInput = (endpoint->fEndpointAddress & USB_ENDPOINT_ADDR_DIR_IN)
== 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 return B_OK;
= static_cast<TypeIFormatDescriptor*>(fAlternates[ }
fActiveAlternate]->Format());
size_t bufferSize = format->fNumChannels * format->fSubframeSize;
TRACE("bufferSize:%d\n", bufferSize);
bufferSize *= kSamplesBufferSize; status_t
TRACE("bufferSize:%d\n", bufferSize); Stream::Init()
{
fStatus = _ChooseAlternate();
//if (fStatus != B_OK)
return fStatus;
}
bufferSize *= (sizeof(usb_iso_packet_descriptor) + endpoint->fMaxPacketSize);
TRACE("bufferSize:%d\n", bufferSize);
bufferSize /= endpoint->fMaxPacketSize; status_t
TRACE("bufferSize:%d\n", bufferSize); 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);
bufferSize = (bufferSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1); if (fArea == -1) {
TRACE("bufferSize:%d\n", bufferSize); fAreaSize = (sizeof(usb_iso_packet_descriptor) + fPacketSize)
* sampleSize * 1024 / fPacketSize;
TRACE("estimate fAreaSize:%d\n", fAreaSize);
fArea = create_area( (fIsInput) ? DRIVER_NAME "_record_area" : // round up to B_PAGE_SIZE and create area
DRIVER_NAME "_playback_area", fAreaSize = (fAreaSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1);
(void**)&fDescriptors, B_ANY_KERNEL_ADDRESS, TRACE("rounded up fAreaSize:%d\n", fAreaSize);
bufferSize, B_CONTIGUOUS,
B_READ_AREA | B_WRITE_AREA); fArea = create_area( (fIsInput) ? DRIVER_NAME "_record_area"
if (fArea < 0) { : DRIVER_NAME "_playback_area", (void**)&fDescriptors,
TRACE_ALWAYS("Error of creating %#x - bytes size buffer area:%#010x\n", B_ANY_KERNEL_ADDRESS, fAreaSize, B_CONTIGUOUS,
bufferSize, fArea); B_READ_AREA | B_WRITE_AREA);
fStatus = fArea;
return fStatus; 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);
} }
physical_entry PhysEntry; // descriptors count
get_memory_map(fDescriptors, bufferSize, &PhysEntry, 1); fDescriptorsCount = fAreaSize
/ (sizeof(usb_iso_packet_descriptor) + fPacketSize);
TRACE_ALWAYS("Created area id: "
"%d\naddress:%#010x[phys:%#010x]\nsize:%#010x\n", // we need same size sub-buffers. round it
fArea, fDescriptors, PhysEntry.address, bufferSize);
fDescriptorsCount = bufferSize;
fDescriptorsCount /= (sizeof(usb_iso_packet_descriptor)
+ endpoint->fMaxPacketSize);
fDescriptorsCount /= kSamplesBufferCount; fDescriptorsCount /= kSamplesBufferCount;
// we need same size buffers. round it!
fDescriptorsCount *= kSamplesBufferCount; fDescriptorsCount *= kSamplesBufferCount;
TRACE("descriptorsCount:%d\n", fDescriptorsCount);
fSamplesCount = fDescriptorsCount * endpoint->fMaxPacketSize; // samples count
TRACE("samplesCount:%d\n", fSamplesCount); fSamplesCount = fDescriptorsCount * fPacketSize / sampleSize;
fSamplesCount /= format->fNumChannels * format->fSubframeSize;
TRACE("samplesCount:%d\n", fSamplesCount); TRACE("samplesCount:%d\n", fSamplesCount);
// initialize descriptors array
for (size_t i = 0; i < fDescriptorsCount; i++) { 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].actual_length = 0;
fDescriptors[i].status = B_OK; fDescriptors[i].status = B_OK;
} }
/* uint32* b = (uint32*)(fDescriptors + fDescriptorsCount); return fStatus;
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;
} }
@@ -193,14 +211,32 @@ Stream::OnSetConfiguration(usb_device device,
return B_ERROR; 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; uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress;
TRACE_ALWAYS("set_alt_interface %x\n", status);
for (size_t i = 0; i < interface->endpoint_count; i++) { for (size_t i = 0; i < interface->endpoint_count; i++) {
if (address == interface->endpoint[i].descr->endpoint_address) { if (address == interface->endpoint[i].descr->endpoint_address) {
fStreamEndpoint = interface->endpoint[i].handle; fStreamEndpoint = interface->endpoint[i].handle;
TRACE("%s Stream Endpoint [address %#04x] handle is: %#010x.\n", TRACE("%s Stream Endpoint [address %#04x] handle is: %#010x.\n",
fIsInput ? "Input" : "Output", address, fStreamEndpoint); 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; return B_OK;
} }
} }
@@ -216,12 +252,9 @@ Stream::Start()
{ {
status_t result = B_BUSY; status_t result = B_BUSY;
if (!fIsRunning) { if (!fIsRunning) {
if (!fIsInput) { if (!fIsInput) { // TODO: recording
// for (size_t i = 0; i < kSamplesBufferCount; i++) for (size_t i = 0; i < kSamplesBufferCount; i++)
// result = _QueueNextTransfer(i); result = _QueueNextTransfer(i, true);
// TODO
// result = _QueueNextTransfer(0);
result = B_OK;
} else } else
result = B_OK; result = B_OK;
fIsRunning = result == B_OK; fIsRunning = result == B_OK;
@@ -243,7 +276,7 @@ Stream::Stop()
status_t status_t
Stream::_QueueNextTransfer(size_t queuedBuffer) Stream::_QueueNextTransfer(size_t queuedBuffer, bool start)
{ {
TypeIFormatDescriptor* format TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>(fAlternates[ = static_cast<TypeIFormatDescriptor*>(fAlternates[
@@ -259,14 +292,35 @@ Stream::_QueueNextTransfer(size_t queuedBuffer)
TRACE("buffers:%#010x[%#x]\ndescrs:%#010x[%#x]\n", TRACE("buffers:%#010x[%#x]\ndescrs:%#010x[%#x]\n",
buffers + bufferSize * queuedBuffer, bufferSize, buffers + bufferSize * queuedBuffer, bufferSize,
fDescriptors + queuedBuffer * packetsCount, packetsCount); 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, buffers + bufferSize * queuedBuffer, bufferSize,
fDescriptors + queuedBuffer * packetsCount, packetsCount, fDescriptors + queuedBuffer * packetsCount, packetsCount,
NULL/*&fStartingFrame*/, USB_ISO_ASAP, &fStartingFrame, start ? USB_ISO_ASAP : 0,
Stream::_TransferCallback, this); 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, Stream::_TransferCallback(void *cookie, int32 status, void *data,
uint32 actualLength) uint32 actualLength)
{ {
Stream *stream = (Stream *)cookie; if (status == B_CANCELED) {
TRACE_ALWAYS("Cancelled: c:%p st:%#010x, data:%#010x, len:%d\n",
stream->fCurrentBuffer++; cookie, status, data, actualLength);
if (stream->fCurrentBuffer >= kSamplesBufferCount) { return;
stream->fCurrentBuffer = 0;
} }
stream->_DumpDescriptors(); Stream *stream = (Stream *)cookie;
stream->fCurrentBuffer = (stream->fCurrentBuffer + 1) % kSamplesBufferCount;
stream->_DumpDescriptors(); stream->_DumpDescriptors();
/* /*status_t result =*/ stream->_QueueNextTransfer(stream->fCurrentBuffer, false);
status_t result = stream->_QueueNextTransfer(stream->fCurrentBuffer);
if (atomic_add(&stream->fProcessedBuffers, 1) > (int32)kSamplesBufferCount) { if (atomic_add(&stream->fProcessedBuffers, 1) > (int32)kSamplesBufferCount) {
TRACE_ALWAYS("Processed buffers overflow:%d\n", stream->fProcessedBuffers); TRACE_ALWAYS("Processed buffers overflow:%d\n", stream->fProcessedBuffers);
} }
*/
release_sem_etc(stream->fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE); 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, len:%d -> %#010x\n", status, actualLength, result);
TRACE_ALWAYS("st:%#010x, data:%#010x, len:%d\n", status, data, actualLength); TRACE("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);
}
*/
} }
void void
Stream::_DumpDescriptors() Stream::_DumpDescriptors()
{ {
size_t packetsCount = fDescriptorsCount / kSamplesBufferCount; //size_t packetsCount = fDescriptorsCount / kSamplesBufferCount;
size_t from = /*fCurrentBuffer > 0 ? packetsCount :*/ 0 ; size_t from = /*fCurrentBuffer > 0 ? packetsCount :*/ 0 ;
size_t to = /*fCurrentBuffer > 0 ?*/ fDescriptorsCount /*: packetsCount*/ ; size_t to = /*fCurrentBuffer > 0 ?*/ fDescriptorsCount /*: packetsCount*/ ;
for (size_t i = from; i < to; i++) { 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].request_length, fDescriptors[i].actual_length,
fDescriptors[i].status); fDescriptors[i].status);
} }
@@ -359,18 +404,13 @@ Stream::SetEnabledChannels(uint32& offset, multi_channel_enable *Enable)
status_t status_t
Stream::GetGlobalFormat(multi_format_info *Format) Stream::GetGlobalFormat(multi_format_info *Format)
{ {
if (IsInput()) { _multi_format* format = fIsInput ? &Format->input : &Format->output;
// TODO format->cvsr = fAlternates[fActiveAlternate]->GetSamplingRate();
Format->input.rate = B_SR_48000; format->rate = fAlternates[fActiveAlternate]->GetSamplingRateId(0);
Format->input.cvsr = 48000; format->format = fAlternates[fActiveAlternate]->GetFormatId();
Format->input.format = B_FMT_16BIT; TRACE("%s.rate:%d cvsr:%f format:%#08x\n",
} else { fIsInput ? "input" : "ouput",
// TODO format->rate, format->cvsr, format->format);
Format->output.rate = B_SR_48000;
Format->output.cvsr = 48000;
Format->output.format = B_FMT_16BIT;
}
return B_OK; return B_OK;
} }
@@ -378,19 +418,49 @@ Stream::GetGlobalFormat(multi_format_info *Format)
status_t status_t
Stream::SetGlobalFormat(multi_format_info *Format) Stream::SetGlobalFormat(multi_format_info *Format)
{ {
if (IsInput()) { _multi_format* format = fIsInput ? &Format->input : &Format->output;
// TODO AudioStreamAlternate* alternate = fAlternates[fActiveAlternate];
TRACE("input.rate:%d\n", Format->input.rate); if (format->rate == alternate->GetSamplingRateId(0)
TRACE("input.cvsr:%f\n", Format->input.cvsr); && format->format == alternate->GetFormatId()) {
TRACE("input.format:%#08x\n", Format->input.format); TRACE("No changes required\n");
} else { return B_OK;
// 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);
} }
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) Stream::GetBuffers(multi_buffer_list* List)
{ {
// TODO: check the available buffers count! // TODO: check the available buffers count!
if (fAreaSize == 0)
return B_NO_INIT;
int32 startChannel = List->return_playback_channels; int32 startChannel = List->return_playback_channels;
buffer_desc** Buffers = List->playback_buffers; buffer_desc** Buffers = List->playback_buffers;
@@ -425,8 +497,8 @@ Stream::GetBuffers(multi_buffer_list* List)
TypeIFormatDescriptor* format TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>( = static_cast<TypeIFormatDescriptor*>(
fAlternates[fActiveAlternate]->Format()); fAlternates[fActiveAlternate]->Format());
const ASEndpointDescriptor* endpoint // const ASEndpointDescriptor* endpoint
= fAlternates[fActiveAlternate]->Endpoint(); // = fAlternates[fActiveAlternate]->Endpoint();
// [buffer][channel] init buffers // [buffer][channel] init buffers
for (size_t buffer = 0; buffer < kSamplesBufferCount; buffer++) { for (size_t buffer = 0; buffer < kSamplesBufferCount; buffer++) {
@@ -443,7 +515,7 @@ Stream::GetBuffers(multi_buffer_list* List)
Buffers[buffer][channel].base Buffers[buffer][channel].base
= (char*)(fDescriptors + fDescriptorsCount); = (char*)(fDescriptors + fDescriptorsCount);
// shift for whole buffer if required // shift for whole buffer if required
size_t bufferSize = endpoint->fMaxPacketSize size_t bufferSize = fPacketSize/*endpoint->fMaxPacketSize*/
* (fDescriptorsCount / kSamplesBufferCount); * (fDescriptorsCount / kSamplesBufferCount);
Buffers[buffer][channel].base += buffer * bufferSize; Buffers[buffer][channel].base += buffer * bufferSize;
// shift for channel if required // 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 bool
Stream::ExchangeBuffer(multi_buffer_info* Info) Stream::ExchangeBuffer(multi_buffer_info* Info)
{ {
@@ -499,12 +548,15 @@ Stream::ExchangeBuffer(multi_buffer_info* Info)
return false; return false;
} }
Info->played_real_time = system_time();// TODO fRealTime; if (fIsInput) {
Info->played_frames_count += fSamplesCount / kSamplesBufferCount; Info->recorded_real_time = system_time();// TODO fRealTime;
Info->playback_buffer_cycle = fCurrentBuffer; Info->recorded_frames_count += fSamplesCount / kSamplesBufferCount;
Info->record_buffer_cycle = fCurrentBuffer;
fCurrentBuffer++; } else {
fCurrentBuffer %= kSamplesBufferCount; Info->played_real_time = system_time();// TODO fRealTime;
Info->played_frames_count += fSamplesCount / kSamplesBufferCount;
Info->playback_buffer_cycle = fCurrentBuffer;
}
atomic_add(&fProcessedBuffers, -1); atomic_add(&fProcessedBuffers, -1);
@@ -62,22 +62,21 @@ protected:
uint8 fTerminalID; uint8 fTerminalID;
usb_pipe fStreamEndpoint; usb_pipe fStreamEndpoint;
bool fIsRunning; bool fIsRunning;
/* uint32 fHWChannel;*/
area_id fArea; area_id fArea;
size_t fAreaSize;
usb_iso_packet_descriptor* fDescriptors; usb_iso_packet_descriptor* fDescriptors;
size_t fDescriptorsCount; size_t fDescriptorsCount;
size_t fCurrentBuffer; size_t fCurrentBuffer;
uint32 fStartingFrame; uint32 fStartingFrame;
size_t fSamplesCount; size_t fSamplesCount;
size_t fPacketSize;
int32 fProcessedBuffers; int32 fProcessedBuffers;
// void* fBuffersPhysAddress; _multi_format fFormat;
/* bigtime_t fRealTime;
bigtime_t fFramesCount;
int32 fBufferCycle;
public:
uint32 fCSP; */
private: 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, static void _TransferCallback(void *cookie, int32 status,
void *data, uint32 actualLength); void *data, uint32 actualLength);
void _DumpDescriptors(); void _DumpDescriptors();