xref: /haiku/src/add-ons/kernel/drivers/audio/sb16/sb16_multi_audio.c (revision 99351a72d3638705c3323c36fd551f1d3cd2111c)
1 #include "driver.h"
2 
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 },
12 };
13 
14 static int32
format2size(uint32 format)15 format2size(uint32 format)
16 {
17 	switch(format) {
18 		case B_FMT_8BIT_S:
19 		case B_FMT_16BIT:
20 			return 2;
21 
22 		default:
23 			return -1;
24 	}
25 }
26 
27 static status_t
get_description(sb16_dev_t * dev,multi_description * data)28 get_description(sb16_dev_t* dev, multi_description* data)
29 {
30 	data->interface_version = B_CURRENT_INTERFACE_VERSION;
31 	data->interface_minimum = B_CURRENT_INTERFACE_VERSION;
32 
33 	strcpy(data->friendly_name,"SoundBlaster 16");
34 	strcpy(data->vendor_info,"Haiku");
35 
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;
41 
42 	if (data->request_channel_count >= (int)(sizeof(chans) / sizeof(chans[0]))) {
43 		memcpy(data->channels,&chans,sizeof(chans));
44 	}
45 
46 	/* determine output/input rates */
47 	data->output_rates =
48 	data->input_rates = B_SR_44100 | B_SR_22050 | B_SR_11025;
49 
50 	data->max_cvsr_rate = 0;
51 	data->min_cvsr_rate = 0;
52 
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;
59 
60 	strcpy(data->control_panel,"");
61 
62 	return B_OK;
63 }
64 
65 static status_t
get_enabled_channels(sb16_dev_t * dev,multi_channel_enable * data)66 get_enabled_channels(sb16_dev_t* dev, multi_channel_enable* data)
67 {
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;
73 
74 	return B_OK;
75 }
76 
77 static status_t
get_global_format(sb16_dev_t * dev,multi_format_info * data)78 get_global_format(sb16_dev_t* dev, multi_format_info* data)
79 {
80 	data->output_latency = 0;
81 	data->input_latency = 0;
82 	data->timecode_kind = 0;
83 
84 	data->output.format = dev->playback_stream.sampleformat;
85 	data->output.rate = dev->playback_stream.samplerate;
86 
87 	data->input.format = dev->record_stream.sampleformat;
88 	data->input.rate = dev->record_stream.samplerate;
89 
90 	return B_OK;
91 }
92 
93 static status_t
set_global_format(sb16_dev_t * dev,multi_format_info * data)94 set_global_format(sb16_dev_t* dev, multi_format_info* data)
95 {
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);
99 
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);
103 
104 	return B_OK;
105 }
106 
107 static int32
create_group_control(multi_mix_control * multi,int32 idx,int32 parent,int32 string,const char * name)108 create_group_control(multi_mix_control* multi, int32 idx, int32 parent, int32 string, const char* name)
109 {
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);
117 
118        return multi->id;
119 }
120 
121 static status_t
list_mix_controls(sb16_dev_t * dev,multi_mix_control_info * data)122 list_mix_controls(sb16_dev_t* dev, multi_mix_control_info * data)
123 {
124 	int32 parent;
125 
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;
130 
131 	return B_OK;
132 }
133 
134 static status_t
list_mix_connections(sb16_dev_t * dev,multi_mix_connection_info * data)135 list_mix_connections(sb16_dev_t* dev, multi_mix_connection_info * data)
136 {
137 	return B_ERROR;
138 }
139 
140 static status_t
list_mix_channels(sb16_dev_t * dev,multi_mix_channel_info * data)141 list_mix_channels(sb16_dev_t* dev, multi_mix_channel_info *data)
142 {
143 	return B_ERROR;
144 }
145 
146 static status_t
get_buffers(sb16_dev_t * dev,multi_buffer_list * data)147 get_buffers(sb16_dev_t* dev, multi_buffer_list* data)
148 {
149 	uint32 playback_sample_size = dev->playback_stream.sample_size;
150 	uint32 record_sample_size = dev->record_stream.sample_size;
151 	int32 bidx;
152 	int32 cidx;
153 	status_t rc;
154 
155 	dprintf("%s: playback: %" B_PRId32 " buffers, %" B_PRIu32 " channels, %" B_PRIu32 " samples\n",
156 		__func__,  data->request_playback_buffers, data->request_playback_channels,
157 		data->request_playback_buffer_size);
158 	dprintf("%s: record: %" B_PRId32 " buffers, %" B_PRIu32 " channels, %" B_PRIu32 " samples\n",
159 		__func__, data->request_record_buffers, data->request_record_channels,
160 		data->request_record_buffer_size);
161 
162 	/* Workaround for Haiku multi_audio API, since it prefers to let the driver pick
163 		values, while the BeOS multi_audio actually gives the user's defaults. */
164 	if (data->request_playback_buffers > STRMAXBUF ||
165 		data->request_playback_buffers < STRMINBUF) {
166 		data->request_playback_buffers = STRMINBUF;
167 	}
168 
169 	if (data->request_record_buffers > STRMAXBUF ||
170 		data->request_record_buffers < STRMINBUF) {
171 		data->request_record_buffers = STRMINBUF;
172 	}
173 
174 	if (data->request_playback_buffer_size == 0)
175 		data->request_playback_buffer_size  = DEFAULT_FRAMESPERBUF;
176 
177 	if (data->request_record_buffer_size == 0)
178 		data->request_record_buffer_size  = DEFAULT_FRAMESPERBUF;
179 
180 	/* ... from here on, we can assume again that a reasonable request is being made */
181 
182 	data->flags = 0;
183 
184 	/* Copy the requested settings into the streams */
185 	dev->playback_stream.num_buffers = data->request_playback_buffers;
186 	dev->playback_stream.num_channels = data->request_playback_channels;
187 	dev->playback_stream.buffer_length = data->request_playback_buffer_size;
188 	if ((rc=sb16_stream_setup_buffers(dev, &dev->playback_stream, "Playback")) != B_OK) {
189 		dprintf("%s: Error setting up playback buffers (%s)\n", __func__, strerror(rc));
190 		return rc;
191 	}
192 
193 	dev->record_stream.num_buffers = data->request_record_buffers;
194 	dev->record_stream.num_channels = data->request_record_channels;
195 	dev->record_stream.buffer_length = data->request_record_buffer_size;
196 	if ((rc=sb16_stream_setup_buffers(dev, &dev->record_stream, "Recording")) != B_OK) {
197 		dprintf("%s: Error setting up recording buffers (%s)\n", __func__, strerror(rc));
198 		return rc;
199 	}
200 
201 	/* Setup data structure for multi_audio API... */
202 	data->return_playback_buffers = data->request_playback_buffers;
203 	data->return_playback_channels = data->request_playback_channels;
204 	data->return_playback_buffer_size = data->request_playback_buffer_size;		/* frames */
205 
206 	for (bidx=0; bidx < data->return_playback_buffers; bidx++) {
207 		for (cidx=0; cidx < data->return_playback_channels; cidx++) {
208 			data->playback_buffers[bidx][cidx].base
209 				= (char*)dev->playback_stream.buffers[bidx] + (playback_sample_size * cidx);
210 			data->playback_buffers[bidx][cidx].stride
211 				= playback_sample_size * data->return_playback_channels;
212 		}
213 	}
214 
215 	data->return_record_buffers = data->request_record_buffers;
216 	data->return_record_channels = data->request_record_channels;
217 	data->return_record_buffer_size = data->request_record_buffer_size;			/* frames */
218 
219 	for (bidx=0; bidx < data->return_record_buffers; bidx++) {
220 		for (cidx=0; cidx < data->return_record_channels; cidx++) {
221 			data->record_buffers[bidx][cidx].base
222 				= (char*)dev->record_stream.buffers[bidx] + (record_sample_size * cidx);
223 			data->record_buffers[bidx][cidx].stride
224 				= record_sample_size * data->return_record_channels;
225 		}
226 	}
227 
228 	return B_OK;
229 }
230 
231 static status_t
buffer_exchange(sb16_dev_t * dev,multi_buffer_info * data)232 buffer_exchange(sb16_dev_t* dev, multi_buffer_info* data)
233 {
234 	static int debug_buffers_exchanged = 0;
235 	cpu_status status;
236 	status_t rc;
237 
238 	if (!dev->playback_stream.running)
239 		sb16_stream_start(dev, &dev->playback_stream);
240 
241 	/* do playback */
242 	rc=acquire_sem(dev->playback_stream.buffer_ready_sem);
243 	if (rc != B_OK) {
244 		dprintf("%s: Error waiting for playback buffer to finish (%s)!\n", __func__,
245 			strerror(rc));
246 		return rc;
247 	}
248 
249 	status = disable_interrupts();
250 	acquire_spinlock(&dev->playback_stream.lock);
251 
252 	data->playback_buffer_cycle = dev->playback_stream.buffer_cycle;
253 	data->played_real_time = dev->playback_stream.real_time;
254 	data->played_frames_count = dev->playback_stream.frames_count;
255 
256 	release_spinlock(&dev->playback_stream.lock);
257 	restore_interrupts(status);
258 
259 	debug_buffers_exchanged++;
260 	if (((debug_buffers_exchanged % 100) == 1) && (debug_buffers_exchanged < 1111)) {
261 		dprintf("%s: %d buffers processed\n", __func__, debug_buffers_exchanged);
262 	}
263 
264 	return B_OK;
265 }
266 
267 static status_t
buffer_force_stop(sb16_dev_t * dev)268 buffer_force_stop(sb16_dev_t* dev)
269 {
270 	sb16_stream_stop(dev, &dev->playback_stream);
271 	sb16_stream_stop(dev, &dev->record_stream);
272 
273 	delete_sem(dev->playback_stream.buffer_ready_sem);
274 	delete_sem(dev->record_stream.buffer_ready_sem);
275 
276 	return B_OK;
277 }
278 
279 status_t
multi_audio_control(void * cookie,uint32 op,void * arg,size_t len)280 multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
281 {
282 	switch(op) {
283 		case B_MULTI_GET_DESCRIPTION:			return get_description(cookie, arg);
284 		case B_MULTI_GET_EVENT_INFO:			return B_ERROR;
285 		case B_MULTI_SET_EVENT_INFO:			return B_ERROR;
286 		case B_MULTI_GET_EVENT:					return B_ERROR;
287 		case B_MULTI_GET_ENABLED_CHANNELS:		return get_enabled_channels(cookie, arg);
288 		case B_MULTI_SET_ENABLED_CHANNELS:		return B_OK;
289 		case B_MULTI_GET_GLOBAL_FORMAT:			return get_global_format(cookie, arg);
290 		case B_MULTI_SET_GLOBAL_FORMAT:			return set_global_format(cookie, arg);
291 		case B_MULTI_GET_CHANNEL_FORMATS:		return B_ERROR;
292 		case B_MULTI_SET_CHANNEL_FORMATS:		return B_ERROR;
293 		case B_MULTI_GET_MIX:					return B_ERROR;
294 		case B_MULTI_SET_MIX:					return B_ERROR;
295 		case B_MULTI_LIST_MIX_CHANNELS:			return list_mix_channels(cookie, arg);
296 		case B_MULTI_LIST_MIX_CONTROLS:			return list_mix_controls(cookie, arg);
297 		case B_MULTI_LIST_MIX_CONNECTIONS:		return list_mix_connections(cookie, arg);
298 		case B_MULTI_GET_BUFFERS:				return get_buffers(cookie, arg);
299 		case B_MULTI_SET_BUFFERS:				return B_ERROR;
300 		case B_MULTI_SET_START_TIME:			return B_ERROR;
301 		case B_MULTI_BUFFER_EXCHANGE:			return buffer_exchange(cookie, arg);
302 		case B_MULTI_BUFFER_FORCE_STOP:			return buffer_force_stop(cookie);
303 	}
304 
305 	return B_BAD_VALUE;
306 }
307