hda: use user_memcpy to read/write the user buffers.
also check buffer addresses passed through structures. Sponsored-by: https://liberapay.com/korli
This commit is contained in:
@@ -11,6 +11,8 @@
|
|||||||
#include "hmulti_audio.h"
|
#include "hmulti_audio.h"
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
|
|
||||||
|
#include <kernel.h>
|
||||||
|
|
||||||
|
|
||||||
#ifdef TRACE
|
#ifdef TRACE
|
||||||
# undef TRACE
|
# undef TRACE
|
||||||
@@ -140,12 +142,21 @@ get_description(hda_audio_group* audioGroup, multi_description* data)
|
|||||||
static status_t
|
static status_t
|
||||||
get_enabled_channels(hda_audio_group* audioGroup, multi_channel_enable* data)
|
get_enabled_channels(hda_audio_group* audioGroup, multi_channel_enable* data)
|
||||||
{
|
{
|
||||||
B_SET_CHANNEL(data->enable_bits, 0, true);
|
|
||||||
B_SET_CHANNEL(data->enable_bits, 1, true);
|
|
||||||
B_SET_CHANNEL(data->enable_bits, 2, true);
|
|
||||||
B_SET_CHANNEL(data->enable_bits, 3, true);
|
|
||||||
data->lock_source = B_MULTI_LOCK_INTERNAL;
|
data->lock_source = B_MULTI_LOCK_INTERNAL;
|
||||||
|
|
||||||
|
int32 inChannels = 0;
|
||||||
|
if (audioGroup->record_stream != NULL)
|
||||||
|
inChannels = 2;
|
||||||
|
|
||||||
|
int32 outChannels = 0;
|
||||||
|
if (audioGroup->playback_stream != NULL)
|
||||||
|
outChannels = 2;
|
||||||
|
|
||||||
|
uint32 enable_bits = 0;
|
||||||
|
uint32 maxChannels = min_c(32, inChannels + outChannels);
|
||||||
|
for (uint32 i = 0; i < maxChannels; i++)
|
||||||
|
B_SET_CHANNEL(&enable_bits, i, true);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -947,13 +958,18 @@ get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
|
|||||||
uint32 playbackSampleSize = audioGroup->playback_stream->sample_size;
|
uint32 playbackSampleSize = audioGroup->playback_stream->sample_size;
|
||||||
|
|
||||||
for (int32 i = 0; i < data->return_playback_buffers; i++) {
|
for (int32 i = 0; i < data->return_playback_buffers; i++) {
|
||||||
|
struct buffer_desc descs[data->return_playback_channels];
|
||||||
for (int32 channelIndex = 0;
|
for (int32 channelIndex = 0;
|
||||||
channelIndex < data->return_playback_channels; channelIndex++) {
|
channelIndex < data->return_playback_channels; channelIndex++) {
|
||||||
data->playback_buffers[i][channelIndex].base
|
descs[channelIndex].base = (char*)audioGroup->playback_stream->buffers[i]
|
||||||
= (char*)audioGroup->playback_stream->buffers[i]
|
|
||||||
+ playbackSampleSize * channelIndex;
|
+ playbackSampleSize * channelIndex;
|
||||||
data->playback_buffers[i][channelIndex].stride
|
descs[channelIndex].stride = playbackSampleSize
|
||||||
= playbackSampleSize * data->return_playback_channels;
|
* data->return_playback_channels;
|
||||||
|
}
|
||||||
|
if (!IS_USER_ADDRESS(data->playback_buffers[i])
|
||||||
|
|| user_memcpy(data->playback_buffers[i], descs, sizeof(descs))
|
||||||
|
< B_OK) {
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -962,13 +978,18 @@ get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
|
|||||||
uint32 recordSampleSize = audioGroup->record_stream->sample_size;
|
uint32 recordSampleSize = audioGroup->record_stream->sample_size;
|
||||||
|
|
||||||
for (int32 i = 0; i < data->return_record_buffers; i++) {
|
for (int32 i = 0; i < data->return_record_buffers; i++) {
|
||||||
|
struct buffer_desc descs[data->return_record_channels];
|
||||||
for (int32 channelIndex = 0;
|
for (int32 channelIndex = 0;
|
||||||
channelIndex < data->return_record_channels; channelIndex++) {
|
channelIndex < data->return_record_channels; channelIndex++) {
|
||||||
data->record_buffers[i][channelIndex].base
|
descs[channelIndex].base = (char*)audioGroup->record_stream->buffers[i]
|
||||||
= (char*)audioGroup->record_stream->buffers[i]
|
|
||||||
+ recordSampleSize * channelIndex;
|
+ recordSampleSize * channelIndex;
|
||||||
data->record_buffers[i][channelIndex].stride
|
descs[channelIndex].stride = recordSampleSize
|
||||||
= recordSampleSize * data->return_record_channels;
|
* data->return_record_channels;
|
||||||
|
}
|
||||||
|
if (!IS_USER_ADDRESS(data->record_buffers[i])
|
||||||
|
|| user_memcpy(data->record_buffers[i], descs, sizeof(descs))
|
||||||
|
< B_OK) {
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1071,6 +1092,10 @@ buffer_force_stop(hda_audio_group* audioGroup)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define cookie_type hda_audio_group
|
||||||
|
#include "../generic/multi.c"
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
|
multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
|
||||||
{
|
{
|
||||||
@@ -1083,79 +1108,5 @@ multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
|
|||||||
|
|
||||||
audioGroup = codec->audio_groups[0];
|
audioGroup = codec->audio_groups[0];
|
||||||
|
|
||||||
// TODO: make userland-safe when built for Haiku!
|
return multi_audio_control_generic(audioGroup, op, arg, len);
|
||||||
|
|
||||||
switch (op) {
|
|
||||||
case B_MULTI_GET_DESCRIPTION:
|
|
||||||
{
|
|
||||||
#ifdef __HAIKU__
|
|
||||||
multi_description description;
|
|
||||||
multi_channel_info channels[16];
|
|
||||||
multi_channel_info* originalChannels;
|
|
||||||
|
|
||||||
if (user_memcpy(&description, arg, sizeof(multi_description))
|
|
||||||
!= B_OK)
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
|
|
||||||
originalChannels = description.channels;
|
|
||||||
description.channels = channels;
|
|
||||||
if (description.request_channel_count > 16)
|
|
||||||
description.request_channel_count = 16;
|
|
||||||
|
|
||||||
status_t status = get_description(audioGroup, &description);
|
|
||||||
if (status != B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
description.channels = originalChannels;
|
|
||||||
if (user_memcpy(arg, &description, sizeof(multi_description))
|
|
||||||
!= B_OK)
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
return user_memcpy(originalChannels, channels,
|
|
||||||
sizeof(multi_channel_info) * description.request_channel_count);
|
|
||||||
#else
|
|
||||||
return get_description(audioGroup, (multi_description*)arg);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
case B_MULTI_GET_ENABLED_CHANNELS:
|
|
||||||
return get_enabled_channels(audioGroup, (multi_channel_enable*)arg);
|
|
||||||
case B_MULTI_SET_ENABLED_CHANNELS:
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
case B_MULTI_GET_GLOBAL_FORMAT:
|
|
||||||
return get_global_format(audioGroup, (multi_format_info*)arg);
|
|
||||||
case B_MULTI_SET_GLOBAL_FORMAT:
|
|
||||||
return set_global_format(audioGroup, (multi_format_info*)arg);
|
|
||||||
|
|
||||||
case B_MULTI_LIST_MIX_CHANNELS:
|
|
||||||
return list_mix_channels(audioGroup, (multi_mix_channel_info*)arg);
|
|
||||||
case B_MULTI_LIST_MIX_CONTROLS:
|
|
||||||
return list_mix_controls(audioGroup, (multi_mix_control_info*)arg);
|
|
||||||
case B_MULTI_LIST_MIX_CONNECTIONS:
|
|
||||||
return list_mix_connections(audioGroup,
|
|
||||||
(multi_mix_connection_info*)arg);
|
|
||||||
case B_MULTI_GET_MIX:
|
|
||||||
return get_mix(audioGroup, (multi_mix_value_info *)arg);
|
|
||||||
case B_MULTI_SET_MIX:
|
|
||||||
return set_mix(audioGroup, (multi_mix_value_info *)arg);
|
|
||||||
|
|
||||||
case B_MULTI_GET_BUFFERS:
|
|
||||||
return get_buffers(audioGroup, (multi_buffer_list*)arg);
|
|
||||||
|
|
||||||
case B_MULTI_BUFFER_EXCHANGE:
|
|
||||||
return buffer_exchange(audioGroup, (multi_buffer_info*)arg);
|
|
||||||
case B_MULTI_BUFFER_FORCE_STOP:
|
|
||||||
return buffer_force_stop(audioGroup);
|
|
||||||
|
|
||||||
case B_MULTI_GET_EVENT_INFO:
|
|
||||||
case B_MULTI_SET_EVENT_INFO:
|
|
||||||
case B_MULTI_GET_EVENT:
|
|
||||||
case B_MULTI_GET_CHANNEL_FORMATS:
|
|
||||||
case B_MULTI_SET_CHANNEL_FORMATS:
|
|
||||||
case B_MULTI_SET_BUFFERS:
|
|
||||||
case B_MULTI_SET_START_TIME:
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user