vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / audio / sb16 / sb16_multi_audio.c
blobc7de2955190fcc647f3e608110f5889dde6b0233
1 #include "driver.h"
3 multi_channel_info chans[] = {
4 { 0, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
5 { 1, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
6 { 2, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
7 { 3, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
8 { 4, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
9 { 5, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
10 { 6, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
11 { 7, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
14 static int32
15 format2size(uint32 format)
17 switch(format) {
18 case B_FMT_8BIT_S:
19 case B_FMT_16BIT:
20 return 2;
22 default:
23 return -1;
27 static status_t
28 get_description(sb16_dev_t* dev, multi_description* data)
30 data->interface_version = B_CURRENT_INTERFACE_VERSION;
31 data->interface_minimum = B_CURRENT_INTERFACE_VERSION;
33 strcpy(data->friendly_name,"SoundBlaster 16");
34 strcpy(data->vendor_info,"Haiku");
36 data->output_channel_count = 2;
37 data->input_channel_count = 2;
38 data->output_bus_channel_count = 2;
39 data->input_bus_channel_count = 2;
40 data->aux_bus_channel_count = 0;
42 if (data->request_channel_count >= (int)(sizeof(chans) / sizeof(chans[0]))) {
43 memcpy(data->channels,&chans,sizeof(chans));
46 /* determine output/input rates */
47 data->output_rates =
48 data->input_rates = B_SR_44100 | B_SR_22050 | B_SR_11025;
50 data->max_cvsr_rate = 0;
51 data->min_cvsr_rate = 0;
53 data->output_formats =
54 data->input_formats = B_FMT_8BIT_S | B_FMT_16BIT;
55 data->lock_sources = B_MULTI_LOCK_INTERNAL;
56 data->timecode_sources = 0;
57 data->interface_flags = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
58 data->start_latency = 30000;
60 strcpy(data->control_panel,"");
62 return B_OK;
65 static status_t
66 get_enabled_channels(sb16_dev_t* dev, multi_channel_enable* data)
68 B_SET_CHANNEL(data->enable_bits, 0, true);
69 B_SET_CHANNEL(data->enable_bits, 1, true);
70 B_SET_CHANNEL(data->enable_bits, 2, true);
71 B_SET_CHANNEL(data->enable_bits, 3, true);
72 data->lock_source = B_MULTI_LOCK_INTERNAL;
74 return B_OK;
77 static status_t
78 get_global_format(sb16_dev_t* dev, multi_format_info* data)
80 data->output_latency = 0;
81 data->input_latency = 0;
82 data->timecode_kind = 0;
84 data->output.format = dev->playback_stream.sampleformat;
85 data->output.rate = dev->playback_stream.samplerate;
87 data->input.format = dev->record_stream.sampleformat;
88 data->input.rate = dev->record_stream.samplerate;
90 return B_OK;
93 static status_t
94 set_global_format(sb16_dev_t* dev, multi_format_info* data)
96 dev->playback_stream.sampleformat = data->output.format;
97 dev->playback_stream.samplerate = data->output.rate;
98 dev->playback_stream.sample_size = format2size(dev->playback_stream.sampleformat);
100 dev->record_stream.sampleformat = data->input.format;
101 dev->record_stream.samplerate = data->input.rate;
102 dev->record_stream.sample_size = format2size(dev->record_stream.sampleformat);
104 return B_OK;
107 static int32
108 create_group_control(multi_mix_control* multi, int32 idx, int32 parent, int32 string, const char* name)
110 multi->id = SB16_MULTI_CONTROL_FIRSTID + idx;
111 multi->parent = parent;
112 multi->flags = B_MULTI_MIX_GROUP;
113 multi->master = SB16_MULTI_CONTROL_MASTERID;
114 multi->string = string;
115 if(name)
116 strcpy(multi->name, name);
118 return multi->id;
121 static status_t
122 list_mix_controls(sb16_dev_t* dev, multi_mix_control_info * data)
124 int32 parent;
126 parent = create_group_control(data->controls +0, 0, 0, 0, "Record");
127 parent = create_group_control(data->controls +1, 1, 0, 0, "AC97 Mixer");
128 parent = create_group_control(data->controls +2, 2, 0, S_SETUP, NULL);
129 data->control_count = 3;
131 return B_OK;
134 static status_t
135 list_mix_connections(sb16_dev_t* dev, multi_mix_connection_info * data)
137 return B_ERROR;
140 static status_t
141 list_mix_channels(sb16_dev_t* dev, multi_mix_channel_info *data)
143 return B_ERROR;
146 static status_t
147 get_buffers(sb16_dev_t* dev, multi_buffer_list* data)
149 uint32 playback_sample_size = dev->playback_stream.sample_size;
150 uint32 record_sample_size = dev->record_stream.sample_size;
151 uint32 cidx, bidx;
152 status_t rc;
154 dprintf("%s: playback: %ld buffers, %ld channels, %ld samples\n", __func__,
155 data->request_playback_buffers, data->request_playback_channels, data->request_playback_buffer_size);
156 dprintf("%s: record: %ld buffers, %ld channels, %ld samples\n", __func__,
157 data->request_record_buffers, data->request_record_channels, data->request_record_buffer_size);
159 /* Workaround for Haiku multi_audio API, since it prefers to let the driver pick
160 values, while the BeOS multi_audio actually gives the user's defaults. */
161 if (data->request_playback_buffers > STRMAXBUF ||
162 data->request_playback_buffers < STRMINBUF) {
163 data->request_playback_buffers = STRMINBUF;
166 if (data->request_record_buffers > STRMAXBUF ||
167 data->request_record_buffers < STRMINBUF) {
168 data->request_record_buffers = STRMINBUF;
171 if (data->request_playback_buffer_size == 0)
172 data->request_playback_buffer_size = DEFAULT_FRAMESPERBUF;
174 if (data->request_record_buffer_size == 0)
175 data->request_record_buffer_size = DEFAULT_FRAMESPERBUF;
177 /* ... from here on, we can assume again that a reasonable request is being made */
179 data->flags = 0;
181 /* Copy the requested settings into the streams */
182 dev->playback_stream.num_buffers = data->request_playback_buffers;
183 dev->playback_stream.num_channels = data->request_playback_channels;
184 dev->playback_stream.buffer_length = data->request_playback_buffer_size;
185 if ((rc=sb16_stream_setup_buffers(dev, &dev->playback_stream, "Playback")) != B_OK) {
186 dprintf("%s: Error setting up playback buffers (%s)\n", __func__, strerror(rc));
187 return rc;
190 dev->record_stream.num_buffers = data->request_record_buffers;
191 dev->record_stream.num_channels = data->request_record_channels;
192 dev->record_stream.buffer_length = data->request_record_buffer_size;
193 if ((rc=sb16_stream_setup_buffers(dev, &dev->record_stream, "Recording")) != B_OK) {
194 dprintf("%s: Error setting up recording buffers (%s)\n", __func__, strerror(rc));
195 return rc;
198 /* Setup data structure for multi_audio API... */
199 data->return_playback_buffers = data->request_playback_buffers;
200 data->return_playback_channels = data->request_playback_channels;
201 data->return_playback_buffer_size = data->request_playback_buffer_size; /* frames */
203 for (bidx=0; bidx < data->return_playback_buffers; bidx++) {
204 for (cidx=0; cidx < data->return_playback_channels; cidx++) {
205 data->playback_buffers[bidx][cidx].base = dev->playback_stream.buffers[bidx] + (playback_sample_size * cidx);
206 data->playback_buffers[bidx][cidx].stride = playback_sample_size * data->return_playback_channels;
210 data->return_record_buffers = data->request_record_buffers;
211 data->return_record_channels = data->request_record_channels;
212 data->return_record_buffer_size = data->request_record_buffer_size; /* frames */
214 for (bidx=0; bidx < data->return_record_buffers; bidx++) {
215 for (cidx=0; cidx < data->return_record_channels; cidx++) {
216 data->record_buffers[bidx][cidx].base = dev->record_stream.buffers[bidx] + (record_sample_size * cidx);
217 data->record_buffers[bidx][cidx].stride = record_sample_size * data->return_record_channels;
221 return B_OK;
224 static status_t
225 buffer_exchange(sb16_dev_t* dev, multi_buffer_info* data)
227 static int debug_buffers_exchanged = 0;
228 cpu_status status;
229 status_t rc;
231 if (!dev->playback_stream.running)
232 sb16_stream_start(dev, &dev->playback_stream);
234 /* do playback */
235 rc=acquire_sem(dev->playback_stream.buffer_ready_sem);
236 if (rc != B_OK) {
237 dprintf("%s: Error waiting for playback buffer to finish (%s)!\n", __func__,
238 strerror(rc));
239 return rc;
242 status = disable_interrupts();
243 acquire_spinlock(&dev->playback_stream.lock);
245 data->playback_buffer_cycle = dev->playback_stream.buffer_cycle;
246 data->played_real_time = dev->playback_stream.real_time;
247 data->played_frames_count = dev->playback_stream.frames_count;
249 release_spinlock(&dev->playback_stream.lock);
250 restore_interrupts(status);
252 debug_buffers_exchanged++;
253 if (((debug_buffers_exchanged % 100) == 1) && (debug_buffers_exchanged < 1111)) {
254 dprintf("%s: %d buffers processed\n", __func__, debug_buffers_exchanged);
257 return B_OK;
260 static status_t
261 buffer_force_stop(sb16_dev_t* dev)
263 sb16_stream_stop(dev, &dev->playback_stream);
264 sb16_stream_stop(dev, &dev->record_stream);
266 delete_sem(dev->playback_stream.buffer_ready_sem);
267 delete_sem(dev->record_stream.buffer_ready_sem);
269 return B_OK;
272 status_t
273 multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
275 switch(op) {
276 case B_MULTI_GET_DESCRIPTION: return get_description(cookie, arg);
277 case B_MULTI_GET_EVENT_INFO: return B_ERROR;
278 case B_MULTI_SET_EVENT_INFO: return B_ERROR;
279 case B_MULTI_GET_EVENT: return B_ERROR;
280 case B_MULTI_GET_ENABLED_CHANNELS: return get_enabled_channels(cookie, arg);
281 case B_MULTI_SET_ENABLED_CHANNELS: return B_OK;
282 case B_MULTI_GET_GLOBAL_FORMAT: return get_global_format(cookie, arg);
283 case B_MULTI_SET_GLOBAL_FORMAT: return set_global_format(cookie, arg);
284 case B_MULTI_GET_CHANNEL_FORMATS: return B_ERROR;
285 case B_MULTI_SET_CHANNEL_FORMATS: return B_ERROR;
286 case B_MULTI_GET_MIX: return B_ERROR;
287 case B_MULTI_SET_MIX: return B_ERROR;
288 case B_MULTI_LIST_MIX_CHANNELS: return list_mix_channels(cookie, arg);
289 case B_MULTI_LIST_MIX_CONTROLS: return list_mix_controls(cookie, arg);
290 case B_MULTI_LIST_MIX_CONNECTIONS: return list_mix_connections(cookie, arg);
291 case B_MULTI_GET_BUFFERS: return get_buffers(cookie, arg);
292 case B_MULTI_SET_BUFFERS: return B_ERROR;
293 case B_MULTI_SET_START_TIME: return B_ERROR;
294 case B_MULTI_BUFFER_EXCHANGE: return buffer_exchange(cookie, arg);
295 case B_MULTI_BUFFER_FORCE_STOP: return buffer_force_stop(cookie);
298 return B_BAD_VALUE;