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:
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user