* Playback can now be restarted after B_MULTI_BUFFER_FORCE_STOP again; the

hda_stream::buffer_ready_sem was deleted but not recreated again. Moved its
  maintenance to hda_stream_{start|stop}().
* Replaced snooze(10) with spin(10) because that's probably what's wanted here.
* Added hda_stream::type field.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24122 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-02-25 19:34:37 +00:00
parent 1cf41b6de1
commit 629ab634f5
3 changed files with 30 additions and 19 deletions
@@ -52,17 +52,17 @@ enum {
STREAM_RECORD STREAM_RECORD
}; };
/* hda_stream_info /* hda_stream
* *
* This structure describes a single stream of audio data, * This structure describes a single stream of audio data,
* which is can have multiple channels (for stereo or better). * which is can have multiple channels (for stereo or better).
*/ */
typedef struct hda_stream {
typedef struct hda_stream_info {
uint32 id; /* HDA controller stream # */ uint32 id; /* HDA controller stream # */
uint32 off; /* HDA I/O/B descriptor offset */ uint32 off; /* HDA I/O/B descriptor offset */
bool running; /* Is this stream active? */ bool running; /* Is this stream active? */
spinlock lock; /* Write lock */ spinlock lock; /* Write lock */
uint32 type;
uint32 pin_widget; /* PIN Widget ID */ uint32 pin_widget; /* PIN Widget ID */
uint32 io_widget; /* Input/Output Converter Widget ID */ uint32 io_widget; /* Input/Output Converter Widget ID */
@@ -35,21 +35,19 @@ hda_stream_new(hda_controller* controller, int type)
if (stream == NULL) if (stream == NULL)
return NULL; return NULL;
stream->buffer_ready_sem = B_ERROR;
stream->buffer_area = B_ERROR; stream->buffer_area = B_ERROR;
stream->buffer_descriptors_area = B_ERROR; stream->buffer_descriptors_area = B_ERROR;
stream->type = type;
switch (type) { switch (type) {
case STREAM_PLAYBACK: case STREAM_PLAYBACK:
stream->buffer_ready_sem = create_sem(0, "hda_playback_sem");
stream->id = 1; stream->id = 1;
stream->off = (controller->num_input_streams * HDAC_SDSIZE); stream->off = (controller->num_input_streams * HDAC_SDSIZE);
controller->streams[controller->num_input_streams] = stream; controller->streams[controller->num_input_streams] = stream;
break; break;
case STREAM_RECORD: case STREAM_RECORD:
stream->buffer_area = B_ERROR;
stream->buffer_descriptors_area = B_ERROR;
stream->buffer_ready_sem = create_sem(0, "hda_record_sem");
stream->id = 2; stream->id = 2;
stream->off = 0; stream->off = 0;
controller->streams[0] = stream; controller->streams[0] = stream;
@@ -69,6 +67,11 @@ hda_stream_new(hda_controller* controller, int type)
status_t status_t
hda_stream_start(hda_controller* controller, hda_stream* stream) hda_stream_start(hda_controller* controller, hda_stream* stream)
{ {
stream->buffer_ready_sem = create_sem(0,
stream->type == STREAM_PLAYBACK ? "hda_playback_sem" : "hda_record_sem");
if (stream->buffer_ready_sem < B_OK)
return stream->buffer_ready_sem;
OREG8(controller, stream->off, CTL0) |= CTL0_RUN; OREG8(controller, stream->off, CTL0) |= CTL0_RUN;
while (!(OREG8(controller, stream->off, CTL0) & CTL0_RUN)) while (!(OREG8(controller, stream->off, CTL0) & CTL0_RUN))
@@ -121,6 +124,8 @@ hda_stream_stop(hda_controller* controller, hda_stream* stream)
snooze(1); snooze(1);
stream->running = false; stream->running = false;
delete_sem(stream->buffer_ready_sem);
stream->buffer_ready_sem = -1;
return B_OK; return B_OK;
} }
@@ -211,11 +216,12 @@ dprintf("HDA: sample size %ld, num channels %ld, buffer length %ld *************
dprintf("%s(%s): Allocated %ld bytes for %ld BDLEs\n", __func__, desc, dprintf("%s(%s): Allocated %ld bytes for %ld BDLEs\n", __func__, desc,
alloc, stream->num_buffers); alloc, stream->num_buffers);
/* Setup BDL entries */ /* Setup buffer descriptor list (BDL) entries */
for (index = 0; index < stream->num_buffers; index++, bufferDescriptors++) { for (index = 0; index < stream->num_buffers; index++, bufferDescriptors++) {
bufferDescriptors->address = stream->physical_buffers[index]; bufferDescriptors->address = stream->physical_buffers[index];
bufferDescriptors->length = bufferSize; bufferDescriptors->length = bufferSize;
bufferDescriptors->ioc = 1; bufferDescriptors->ioc = 1;
// we want an interrupt after every buffer
} }
/* Configure stream registers */ /* Configure stream registers */
@@ -502,7 +508,7 @@ hda_hw_corb_rirb_init(hda_controller* controller)
/* NOTE: See HDA011 for corrected procedure! */ /* NOTE: See HDA011 for corrected procedure! */
REG16(controller, CORBRP) = CORBRP_RST; REG16(controller, CORBRP) = CORBRP_RST;
do { do {
snooze(10); spin(10);
} while ( !(REG16(controller, CORBRP) & CORBRP_RST) ); } while ( !(REG16(controller, CORBRP) & CORBRP_RST) );
REG16(controller, CORBRP) = 0; REG16(controller, CORBRP) = 0;
@@ -631,10 +637,11 @@ hda_hw_stop(hda_controller* controller)
int index; int index;
/* Stop all audio streams */ /* Stop all audio streams */
for (index = 0; index < HDA_MAX_STREAMS; index++) for (index = 0; index < HDA_MAX_STREAMS; index++) {
if (controller->streams[index] && controller->streams[index]->running) if (controller->streams[index] && controller->streams[index]->running)
hda_stream_stop(controller, controller->streams[index]); hda_stream_stop(controller, controller->streams[index]);
} }
}
/*! Free resources */ /*! Free resources */
@@ -140,6 +140,13 @@ get_global_format(hda_audio_group* audioGroup, multi_format_info* data)
static status_t static status_t
set_global_format(hda_audio_group* audioGroup, multi_format_info* data) set_global_format(hda_audio_group* audioGroup, multi_format_info* data)
{ {
// TODO: it looks like we're not supposed to fail; fix this!
#if 0
if ((data->output.format & audioGroup->supported_formats) == 0)
|| (data->output.rate & audioGroup->supported_rates) == 0)
return B_BAD_VALUE;
#endif
audioGroup->playback_stream->sample_format = data->output.format; audioGroup->playback_stream->sample_format = data->output.format;
audioGroup->playback_stream->sample_rate = data->output.rate; audioGroup->playback_stream->sample_rate = data->output.rate;
audioGroup->playback_stream->sample_size = format2size( audioGroup->playback_stream->sample_size = format2size(
@@ -181,8 +188,8 @@ list_mix_channels(hda_audio_group* audioGroup, multi_mix_channel_info *data)
static status_t static status_t
get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data) get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
{ {
uint32 playback_sample_size = audioGroup->playback_stream->sample_size; uint32 playbackSampleSize = audioGroup->playback_stream->sample_size;
uint32 record_sample_size = audioGroup->record_stream->sample_size; uint32 recordSampleSize = audioGroup->record_stream->sample_size;
uint32 cidx, bidx; uint32 cidx, bidx;
status_t status; status_t status;
@@ -257,9 +264,9 @@ get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
for (cidx = 0; cidx < data->return_playback_channels; cidx++) { for (cidx = 0; cidx < data->return_playback_channels; cidx++) {
data->playback_buffers[bidx][cidx].base data->playback_buffers[bidx][cidx].base
= audioGroup->playback_stream->buffers[bidx] = audioGroup->playback_stream->buffers[bidx]
+ (playback_sample_size * cidx); + playbackSampleSize * cidx;
data->playback_buffers[bidx][cidx].stride data->playback_buffers[bidx][cidx].stride
= playback_sample_size * data->return_playback_channels; = playbackSampleSize * data->return_playback_channels;
} }
} }
@@ -267,9 +274,9 @@ get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
for (cidx = 0; cidx < data->return_record_channels; cidx++) { for (cidx = 0; cidx < data->return_record_channels; cidx++) {
data->record_buffers[bidx][cidx].base data->record_buffers[bidx][cidx].base
= audioGroup->record_stream->buffers[bidx] = audioGroup->record_stream->buffers[bidx]
+ (record_sample_size * cidx); + recordSampleSize * cidx;
data->record_buffers[bidx][cidx].stride data->record_buffers[bidx][cidx].stride
= record_sample_size * data->return_record_channels; = recordSampleSize * data->return_record_channels;
} }
} }
@@ -323,9 +330,6 @@ buffer_force_stop(hda_audio_group* audioGroup)
hda_stream_stop(audioGroup->codec->controller, audioGroup->playback_stream); hda_stream_stop(audioGroup->codec->controller, audioGroup->playback_stream);
//hda_stream_stop(audioGroup->codec->controller, audioGroup->record_stream); //hda_stream_stop(audioGroup->codec->controller, audioGroup->record_stream);
delete_sem(audioGroup->playback_stream->buffer_ready_sem);
// delete_sem(audioGroup->record_stream->buffer_ready_sem);
return B_OK; return B_OK;
} }