1#include "driver.h"
2
3multi_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
14static int32
15format2size(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
27static status_t
28get_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
65static status_t
66get_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
77static status_t
78get_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
93static status_t
94set_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
107static int32
108create_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
121static status_t
122list_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
134static status_t
135list_mix_connections(sb16_dev_t* dev, multi_mix_connection_info * data)
136{
137	return B_ERROR;
138}
139
140static status_t
141list_mix_channels(sb16_dev_t* dev, multi_mix_channel_info *data)
142{
143	return B_ERROR;
144}
145
146static status_t
147get_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
231static status_t
232buffer_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
267static status_t
268buffer_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
279status_t
280multi_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