1/*
2 *	Driver for USB Audio Device Class devices.
3 *	Copyright (c) 2009-13 S.Zharski <imker@gmx.li>
4 *	Distributed under the terms of the MIT license.
5 *
6 */
7
8
9#include "Device.h"
10
11#include <kernel.h>
12#include <usb/USB_audio.h>
13
14#include "Driver.h"
15#include "Settings.h"
16
17
18Device::Device(usb_device device)
19	:
20	fStatus(B_ERROR),
21	fOpen(false),
22	fRemoved(false),
23	fDevice(device),
24	fNonBlocking(false),
25	fAudioControl(this),
26	fBuffersReadySem(-1)
27{
28	const usb_device_descriptor* deviceDescriptor
29		= gUSBModule->get_device_descriptor(device);
30
31	if (deviceDescriptor == NULL) {
32		TRACE(ERR, "Error of getting USB device descriptor.\n");
33		return;
34	}
35
36	fVendorID = deviceDescriptor->vendor_id;
37	fProductID = deviceDescriptor->product_id;
38	fUSBVersion = deviceDescriptor->usb_version;
39
40	fBuffersReadySem = create_sem(0, DRIVER_NAME "_buffers_ready");
41	if (fBuffersReadySem < B_OK) {
42		TRACE(ERR, "Error of creating ready "
43			"buffers semaphore:%#010x\n", fBuffersReadySem);
44		return;
45	}
46
47	if (_SetupEndpoints() != B_OK)
48		return;
49
50	// must be set in derived class constructor
51	fStatus = B_OK;
52}
53
54
55Device::~Device()
56{
57	for (Vector<Stream*>::Iterator I = fStreams.Begin();
58			I != fStreams.End(); I++)
59		delete *I;
60
61	fStreams.MakeEmpty();
62
63	if (fBuffersReadySem > B_OK)
64		delete_sem(fBuffersReadySem);
65}
66
67
68status_t
69Device::Open(uint32 flags)
70{
71	if (fOpen)
72		return B_BUSY;
73	if (fRemoved)
74		return B_ERROR;
75
76	status_t result = StartDevice();
77	if (result != B_OK)
78		return result;
79
80	// TODO: are we need this???
81	fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK;
82	fOpen = true;
83	return result;
84}
85
86
87status_t
88Device::Close()
89{
90	if (fRemoved) {
91		fOpen = false;
92		return B_OK;
93	}
94
95	for (int i = 0; i < fStreams.Count(); i++)
96		fStreams[i]->Stop();
97
98	fOpen = false;
99
100	return StopDevice();
101}
102
103
104status_t
105Device::Free()
106{
107	return B_OK;
108}
109
110
111status_t
112Device::Read(uint8* buffer, size_t* numBytes)
113{
114	*numBytes = 0;
115	return B_IO_ERROR;
116}
117
118
119status_t
120Device::Write(const uint8* buffer, size_t* numBytes)
121{
122	*numBytes = 0;
123	return B_IO_ERROR;
124}
125
126
127status_t
128Device::Control(uint32 op, void* buffer, size_t length)
129{
130	switch (op) {
131		case B_MULTI_GET_DESCRIPTION:
132		{
133			multi_description description;
134			multi_channel_info channels[16];
135			multi_channel_info* originalChannels;
136
137			if (user_memcpy(&description, buffer, sizeof(multi_description))
138					!= B_OK)
139				return B_BAD_ADDRESS;
140
141			originalChannels = description.channels;
142			description.channels = channels;
143			if (description.request_channel_count > 16)
144				description.request_channel_count = 16;
145
146			status_t status = _MultiGetDescription(&description);
147			if (status != B_OK)
148				return status;
149
150			description.channels = originalChannels;
151			if (user_memcpy(buffer, &description, sizeof(multi_description))
152					!= B_OK)
153				return B_BAD_ADDRESS;
154			return user_memcpy(originalChannels, channels,
155				sizeof(multi_channel_info) * description.request_channel_count);
156		}
157		case B_MULTI_GET_EVENT_INFO:
158			TRACE(ERR, "B_MULTI_GET_EVENT_INFO n/i\n");
159			return B_ERROR;
160
161		case B_MULTI_SET_EVENT_INFO:
162			TRACE(ERR, "B_MULTI_SET_EVENT_INFO n/i\n");
163			return B_ERROR;
164
165		case B_MULTI_GET_EVENT:
166			TRACE(ERR, "B_MULTI_GET_EVENT n/i\n");
167			return B_ERROR;
168
169		case B_MULTI_GET_ENABLED_CHANNELS:
170		{
171			multi_channel_enable enable;
172			uint32 enable_bits;
173			uchar* orig_enable_bits;
174
175			if (user_memcpy(&enable, buffer, sizeof(enable)) != B_OK
176					|| !IS_USER_ADDRESS(enable.enable_bits)) {
177				return B_BAD_ADDRESS;
178			}
179
180			orig_enable_bits = enable.enable_bits;
181			enable.enable_bits = (uchar*)&enable_bits;
182			status_t status = _MultiGetEnabledChannels(&enable);
183			if (status != B_OK)
184				return status;
185
186			enable.enable_bits = orig_enable_bits;
187			if (user_memcpy(enable.enable_bits, &enable_bits,
188					sizeof(enable_bits)) != B_OK
189				|| user_memcpy(buffer, &enable,
190					sizeof(multi_channel_enable)) != B_OK) {
191				return B_BAD_ADDRESS;
192			}
193
194			return B_OK;
195		}
196		case B_MULTI_SET_ENABLED_CHANNELS:
197		{
198			multi_channel_enable enable;
199			uint32 enable_bits;
200			uchar* orig_enable_bits;
201
202			if (user_memcpy(&enable, buffer, sizeof(enable)) != B_OK
203				|| !IS_USER_ADDRESS(enable.enable_bits)) {
204				return B_BAD_ADDRESS;
205			}
206
207			orig_enable_bits = enable.enable_bits;
208			enable.enable_bits = (uchar*)&enable_bits;
209			status_t status = _MultiSetEnabledChannels(&enable);
210			if (status != B_OK)
211				return status;
212
213			enable.enable_bits = orig_enable_bits;
214			if (user_memcpy(enable.enable_bits, &enable_bits,
215					sizeof(enable_bits)) < B_OK
216				|| user_memcpy(buffer, &enable, sizeof(multi_channel_enable))
217					< B_OK) {
218				return B_BAD_ADDRESS;
219			}
220
221			return B_OK;
222		}
223		case B_MULTI_GET_GLOBAL_FORMAT:
224		{
225			multi_format_info info;
226			if (user_memcpy(&info, buffer, sizeof(multi_format_info)) != B_OK)
227				return B_BAD_ADDRESS;
228
229			status_t status = _MultiGetGlobalFormat(&info);
230			if (status != B_OK)
231				return status;
232			if (user_memcpy(buffer, &info, sizeof(multi_format_info)) != B_OK)
233				return B_BAD_ADDRESS;
234			return B_OK;
235		}
236		case B_MULTI_SET_GLOBAL_FORMAT:
237		{
238			multi_format_info info;
239			if (user_memcpy(&info, buffer, sizeof(multi_format_info)) != B_OK)
240				return B_BAD_ADDRESS;
241
242			status_t status = _MultiSetGlobalFormat(&info);
243			if (status != B_OK)
244				return status;
245			return user_memcpy(buffer, &info, sizeof(multi_format_info));
246		}
247		case B_MULTI_GET_CHANNEL_FORMATS:
248			TRACE(ERR, "B_MULTI_GET_CHANNEL_FORMATS n/i\n");
249			return B_ERROR;
250
251		case B_MULTI_SET_CHANNEL_FORMATS:
252			TRACE(ERR, "B_MULTI_SET_CHANNEL_FORMATS n/i\n");
253			return B_ERROR;
254
255		case B_MULTI_GET_MIX:
256		case B_MULTI_SET_MIX: {
257			multi_mix_value_info info;
258			if (user_memcpy(&info, buffer, sizeof(multi_mix_value_info)) != B_OK)
259				return B_BAD_ADDRESS;
260
261			multi_mix_value* originalValues = info.values;
262			size_t mixValueSize = info.item_count * sizeof(multi_mix_value);
263			multi_mix_value* values = (multi_mix_value*)alloca(mixValueSize);
264			if (user_memcpy(values, info.values, mixValueSize) != B_OK)
265				return B_BAD_ADDRESS;
266			info.values = values;
267
268			status_t status;
269			if (op == B_MULTI_GET_MIX)
270				status = _MultiGetMix(&info);
271			else
272				status = _MultiSetMix(&info);
273			if (status != B_OK)
274				return status;
275			// the multi_mix_value_info is not modified
276			return user_memcpy(originalValues, values, mixValueSize);
277		}
278
279		case B_MULTI_LIST_MIX_CHANNELS:
280			TRACE(ERR, "B_MULTI_LIST_MIX_CHANNELS n/i\n");
281			return B_ERROR;
282
283		case B_MULTI_LIST_MIX_CONTROLS:
284		{
285			multi_mix_control_info info;
286			multi_mix_control* original_controls;
287			size_t allocSize;
288			multi_mix_control *controls;
289
290			if (user_memcpy(&info, buffer, sizeof(multi_mix_control_info))
291				!= B_OK) {
292				return B_BAD_ADDRESS;
293			}
294
295			original_controls = info.controls;
296			allocSize = sizeof(multi_mix_control) * info.control_count;
297			controls = (multi_mix_control *)malloc(allocSize);
298			if (controls == NULL)
299				return B_NO_MEMORY;
300
301			if (!IS_USER_ADDRESS(info.controls)
302				|| user_memcpy(controls, info.controls, allocSize) < B_OK) {
303				free(controls);
304				return B_BAD_ADDRESS;
305			}
306			info.controls = controls;
307
308			status_t status = _MultiListMixControls(&info);
309			if (status != B_OK) {
310				free(controls);
311				return status;
312			}
313
314			info.controls = original_controls;
315			status = user_memcpy(info.controls, controls, allocSize);
316			if (status == B_OK) {
317				status = user_memcpy(buffer, &info,
318					sizeof(multi_mix_control_info));
319			}
320			if (status != B_OK)
321				status = B_BAD_ADDRESS;
322			free(controls);
323			return status;
324		}
325		case B_MULTI_LIST_MIX_CONNECTIONS:
326			TRACE(ERR, "B_MULTI_LIST_MIX_CONNECTIONS n/i\n");
327			return B_ERROR;
328
329		case B_MULTI_GET_BUFFERS:
330			// Fill out the struct for the first time; doesn't start anything.
331		{
332			multi_buffer_list list;
333			if (user_memcpy(&list, buffer, sizeof(multi_buffer_list)) != B_OK)
334				return B_BAD_ADDRESS;
335			buffer_desc **original_playback_descs = list.playback_buffers;
336			buffer_desc **original_record_descs = list.record_buffers;
337
338			buffer_desc *playback_descs[list.request_playback_buffers];
339			buffer_desc *record_descs[list.request_record_buffers];
340
341			if (!IS_USER_ADDRESS(list.playback_buffers)
342				|| user_memcpy(playback_descs, list.playback_buffers,
343					sizeof(buffer_desc*) * list.request_playback_buffers)
344					< B_OK
345				|| !IS_USER_ADDRESS(list.record_buffers)
346				|| user_memcpy(record_descs, list.record_buffers,
347					sizeof(buffer_desc*) * list.request_record_buffers)
348					< B_OK) {
349				return B_BAD_ADDRESS;
350			}
351
352			list.playback_buffers = playback_descs;
353			list.record_buffers = record_descs;
354			status_t status = _MultiGetBuffers(&list);
355			if (status != B_OK)
356				return status;
357
358			list.playback_buffers = original_playback_descs;
359			list.record_buffers = original_record_descs;
360
361			if (user_memcpy(buffer, &list, sizeof(multi_buffer_list)) < B_OK
362				|| user_memcpy(original_playback_descs, playback_descs,
363					sizeof(buffer_desc*) * list.request_playback_buffers)
364					< B_OK
365				|| user_memcpy(original_record_descs, record_descs,
366					sizeof(buffer_desc*) * list.request_record_buffers)
367					< B_OK) {
368				status = B_BAD_ADDRESS;
369			}
370
371			return status;
372		}
373
374		case B_MULTI_SET_BUFFERS:
375			// Set what buffers to use, if the driver supports soft buffers.
376			TRACE(ERR, "B_MULTI_SET_BUFFERS n/i\n");
377			return B_ERROR; /* we do not support soft buffers */
378
379		case B_MULTI_SET_START_TIME:
380			// When to actually start
381			TRACE(ERR, "B_MULTI_SET_START_TIME n/i\n");
382			return B_ERROR;
383
384		case B_MULTI_BUFFER_EXCHANGE:
385			// stop and go are derived from this being called
386			return _MultiBufferExchange((multi_buffer_info*)buffer);
387
388		case B_MULTI_BUFFER_FORCE_STOP:
389			// force stop of playback, nothing in data
390			return _MultiBufferForceStop();
391
392		default:
393			TRACE(ERR, "Unhandled IOCTL catched: %#010x\n", op);
394	}
395
396	return B_DEV_INVALID_IOCTL;
397}
398
399
400void
401Device::Removed()
402{
403	fRemoved = true;
404
405	for (int i = 0; i < fStreams.Count(); i++)
406		fStreams[i]->OnRemove();
407}
408
409
410status_t
411Device::SetupDevice(bool deviceReplugged)
412{
413	return B_OK;
414}
415
416
417status_t
418Device::CompareAndReattach(usb_device device)
419{
420	const usb_device_descriptor* deviceDescriptor
421		= gUSBModule->get_device_descriptor(device);
422
423	if (deviceDescriptor == NULL) {
424		TRACE(ERR, "Error of getting USB device descriptor.\n");
425		return B_ERROR;
426	}
427
428	if (deviceDescriptor->vendor_id != fVendorID
429		&& deviceDescriptor->product_id != fProductID)
430		// this certainly isn't the same device
431		return B_BAD_VALUE;
432
433	// this is the same device that was replugged - clear the removed state,
434	// re- setup the endpoints and transfers and open the device if it was
435	// previously opened
436	fDevice = device;
437	fRemoved = false;
438	status_t result = _SetupEndpoints();
439	if (result != B_OK) {
440		fRemoved = true;
441		return result;
442	}
443
444	// we need to setup hardware on device replug
445	result = SetupDevice(true);
446	if (result != B_OK)
447		return result;
448
449	if (fOpen) {
450		fOpen = false;
451		result = Open(fNonBlocking ? O_NONBLOCK : 0);
452	}
453
454	return result;
455}
456
457
458status_t
459Device::_MultiGetDescription(multi_description* multiDescription)
460{
461	multi_description Description;
462	if (user_memcpy(&Description, multiDescription,
463			sizeof(multi_description)) != B_OK)
464		return B_BAD_ADDRESS;
465
466	Description.interface_version = B_CURRENT_INTERFACE_VERSION;
467	Description.interface_minimum = B_CURRENT_INTERFACE_VERSION;
468
469	strlcpy(Description.friendly_name, "USB Audio",
470		sizeof(Description.friendly_name));
471
472	strlcpy(Description.vendor_info, "S.Zharski",
473		sizeof(Description.vendor_info));
474
475	Description.output_channel_count = 0;
476	Description.input_channel_count = 0;
477	Description.output_bus_channel_count = 0;
478	Description.input_bus_channel_count = 0;
479	Description.aux_bus_channel_count = 0;
480
481	Description.output_rates = 0;
482	Description.input_rates = 0;
483
484	Description.min_cvsr_rate = 0;
485	Description.max_cvsr_rate = 0;
486
487	Description.output_formats = 0;
488	Description.input_formats = 0;
489	Description.lock_sources = B_MULTI_LOCK_INTERNAL;
490	Description.timecode_sources = 0;
491	Description.interface_flags = 0;
492	Description.start_latency = 3000;
493
494	Description.control_panel[0] = '\0';
495
496	Vector<_AudioControl*>	USBTerminals;
497
498	// channels (USB I/O  terminals) are already in fStreams
499	// in outputs->inputs order, use them.
500	for (int i = 0; i < fStreams.Count(); i++) {
501		uint8 id = fStreams[i]->TerminalLink();
502		_AudioControl* control = fAudioControl.Find(id);
503		// if (control->SubType() == USB_AUDIO_AC_OUTPUT_TERMINAL) {
504		// if (control->SubType() == USB_AUDIO_AC_INPUT_TERMINAL) {
505		//	USBTerminals.PushFront(control);
506		//	fStreams[i]->GetFormatsAndRates(Description);
507		// } else
508		// if (control->SubType() == IDSInputTerminal) {
509			USBTerminals.PushBack(control);
510			fStreams[i]->GetFormatsAndRates(&Description);
511		// }
512	}
513
514	Vector<multi_channel_info> Channels;
515	fAudioControl.GetChannelsDescription(Channels, &Description, USBTerminals);
516	fAudioControl.GetBusChannelsDescription(Channels, &Description );
517
518	// Description.request_channel_count = channels + bus_channels;
519
520	TraceMultiDescription(&Description, Channels);
521
522	if (user_memcpy(multiDescription, &Description,
523			sizeof(multi_description)) != B_OK)
524		return B_BAD_ADDRESS;
525
526	if (user_memcpy(multiDescription->channels,
527			&Channels[0], sizeof(multi_channel_info) * min_c(Channels.Count(),
528			Description.request_channel_count)) != B_OK)
529		return B_BAD_ADDRESS;
530
531	return B_OK;
532}
533
534
535void
536Device::TraceMultiDescription(multi_description* Description,
537		Vector<multi_channel_info>& Channels)
538{
539	TRACE(API, "interface_version:%d\n", Description->interface_version);
540	TRACE(API, "interface_minimum:%d\n", Description->interface_minimum);
541	TRACE(API, "friendly_name:%s\n", Description->friendly_name);
542	TRACE(API, "vendor_info:%s\n", Description->vendor_info);
543	TRACE(API, "output_channel_count:%d\n", Description->output_channel_count);
544	TRACE(API, "input_channel_count:%d\n", Description->input_channel_count);
545	TRACE(API, "output_bus_channel_count:%d\n",
546		Description->output_bus_channel_count);
547	TRACE(API, "input_bus_channel_count:%d\n",
548		Description->input_bus_channel_count);
549	TRACE(API, "aux_bus_channel_count:%d\n", Description->aux_bus_channel_count);
550	TRACE(API, "output_rates:%#08x\n", Description->output_rates);
551	TRACE(API, "input_rates:%#08x\n", Description->input_rates);
552	TRACE(API, "min_cvsr_rate:%f\n", Description->min_cvsr_rate);
553	TRACE(API, "max_cvsr_rate:%f\n", Description->max_cvsr_rate);
554	TRACE(API, "output_formats:%#08x\n", Description->output_formats);
555	TRACE(API, "input_formats:%#08x\n", Description->input_formats);
556	TRACE(API, "lock_sources:%d\n", Description->lock_sources);
557	TRACE(API, "timecode_sources:%d\n", Description->timecode_sources);
558	TRACE(API, "interface_flags:%#08x\n", Description->interface_flags);
559	TRACE(API, "start_latency:%d\n", Description->start_latency);
560	TRACE(API, "control_panel:%s\n", Description->control_panel);
561
562	// multi_channel_info* Channels = Description->channels;
563	// for (int i = 0; i < Description->request_channel_count; i++) {
564	for (int i = 0; i < Channels.Count(); i++) {
565		TRACE(API, " channel_id:%d\n", Channels[i].channel_id);
566		TRACE(API, "  kind:%#02x\n", Channels[i].kind);
567		TRACE(API, "  designations:%#08x\n", Channels[i].designations);
568		TRACE(API, "  connectors:%#08x\n", Channels[i].connectors);
569	}
570
571	TRACE(API, "request_channel_count:%d\n\n",
572		Description->request_channel_count);
573}
574
575
576status_t
577Device::_MultiGetEnabledChannels(multi_channel_enable* Enable)
578{
579	status_t status = B_OK;
580
581	Enable->lock_source = B_MULTI_LOCK_INTERNAL;
582
583	uint32 offset = 0;
584	for (int i = 0; i < fStreams.Count() && status == B_OK; i++)
585		status = fStreams[i]->GetEnabledChannels(offset, Enable);
586
587	return status;
588}
589
590
591status_t
592Device::_MultiSetEnabledChannels(multi_channel_enable* Enable)
593{
594	status_t status = B_OK;
595	uint32 offset = 0;
596	for (int i = 0; i < fStreams.Count() && status == B_OK; i++)
597		status = fStreams[i]->SetEnabledChannels(offset, Enable);
598
599	return status;
600}
601
602
603status_t
604Device::_MultiGetGlobalFormat(multi_format_info* Format)
605{
606	status_t status = B_OK;
607
608	Format->output_latency = 0;
609	Format->input_latency = 0;
610	Format->timecode_kind = 0;
611
612	// uint32 offset = 0;
613	for (int i = 0; i < fStreams.Count() && status == B_OK; i++)
614		status = fStreams[i]->GetGlobalFormat(Format);
615
616	return status;
617}
618
619
620status_t
621Device::_MultiSetGlobalFormat(multi_format_info* Format)
622{
623	status_t status = B_OK;
624
625	TRACE(API, "output_latency:%lld\n", Format->output_latency);
626	TRACE(API, "input_latency:%lld\n",  Format->input_latency);
627	TRACE(API, "timecode_kind:%#08x\n", Format->timecode_kind);
628
629	// uint32 offset = 0;
630	for (int i = 0; i < fStreams.Count() && status == B_OK; i++)
631		status = fStreams[i]->SetGlobalFormat(Format);
632
633	return status;
634}
635
636
637status_t
638Device::_MultiGetBuffers(multi_buffer_list* List)
639{
640	status_t status = B_OK;
641
642	TRACE(API, "info_size:%d\n"
643	"request_playback_buffers:%d\n"
644	"request_playback_channels:%d\n"
645	"request_playback_buffer_size:%d\n"
646	"request_record_buffers:%d\n"
647	"request_record_channels:%d\n"
648	"request_record_buffer_size:%d\n",
649		List->info_size,
650		List->request_playback_buffers,
651		List->request_playback_channels,
652		List->request_playback_buffer_size,
653		List->request_record_buffers,
654		List->request_record_channels,
655		List->request_record_buffer_size);
656
657	List->flags = 0;
658	List->return_playback_channels = 0;
659	List->return_record_channels = 0;
660
661	for (int i = 0; i < fStreams.Count() && status == B_OK; i++)
662		status = fStreams[i]->GetBuffers(List);
663
664	TRACE(API, "flags:%#x\n"
665	"return_playback_buffers:%d\n"
666	"return_playback_channels:%d\n"
667	"return_playback_buffer_size:%d\n"
668	"return_record_buffers:%d\n"
669	"return_record_channels:%d\n"
670	"return_record_buffer_size:%d\n",
671		List->flags,
672		List->return_playback_buffers,
673		List->return_playback_channels,
674		List->return_playback_buffer_size,
675		List->return_record_buffers,
676		List->return_record_channels,
677		List->return_record_buffer_size);
678
679#if 0
680	TRACE(API, "playback buffers\n");
681	for (int32_t b = 0; b <  List->return_playback_buffers; b++)
682		for (int32 c = 0; c < List->return_playback_channels; c++)
683			TRACE(API, "%d:%d %08x:%d\n", b, c, List->playback_buffers[b][c].base,
684				List->playback_buffers[b][c].stride);
685
686	TRACE(API, "record buffers:\n");
687	for (int32_t b = 0; b <  List->return_record_buffers; b++)
688		for (int32 c = 0; c < List->return_record_channels; c++)
689			TRACE(API, "%d:%d %08x:%d\n", b, c, List->record_buffers[b][c].base,
690				List->record_buffers[b][c].stride);
691#endif
692	return B_OK;
693}
694
695
696status_t
697Device::_MultiBufferExchange(multi_buffer_info* multiInfo)
698{
699	multi_buffer_info Info;
700	if (!IS_USER_ADDRESS(multiInfo)
701		|| user_memcpy(&Info, multiInfo, sizeof(multi_buffer_info)) != B_OK) {
702		return B_BAD_ADDRESS;
703	}
704
705	for (int i = 0; i < fStreams.Count(); i++)
706		if (!fStreams[i]->IsRunning())
707			fStreams[i]->Start();
708
709	status_t status = acquire_sem_etc(fBuffersReadySem, 1,
710		B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, 50000);
711	if (status == B_TIMED_OUT) {
712		TRACE(ERR, "Timeout during buffers exchange.\n");
713		return status;
714	}
715
716	status = B_ERROR;
717	for (int i = 0; i < fStreams.Count(); i++)
718		if (fStreams[i]->ExchangeBuffer(&Info)) {
719			status = B_OK;
720			break;
721		}
722
723	if (status != B_OK) {
724		TRACE(ERR, "Error processing buffers:%08x.\n", status);
725		return status;
726	}
727
728	if (user_memcpy(multiInfo, &Info, sizeof(multi_buffer_info)) != B_OK)
729		return B_BAD_ADDRESS;
730
731	return status;
732}
733
734
735status_t
736Device::_MultiBufferForceStop()
737{
738	for (int i = 0; i < fStreams.Count(); i++)
739		fStreams[i]->Stop();
740	return B_OK;
741}
742
743
744status_t
745Device::_MultiGetMix(multi_mix_value_info* Info)
746{
747	return fAudioControl.GetMix(Info);
748}
749
750
751status_t
752Device::_MultiSetMix(multi_mix_value_info* Info)
753{
754	return fAudioControl.SetMix(Info);
755}
756
757
758status_t
759Device::_MultiListMixControls(multi_mix_control_info* Info)
760{
761	status_t status = fAudioControl.ListMixControls(Info);
762	TraceListMixControls(Info);
763	return status;
764}
765
766
767void
768Device::TraceListMixControls(multi_mix_control_info* Info)
769{
770	TRACE(MIX, "control_count:%d\n.", Info->control_count);
771
772	int32 i = 0;
773	while (Info->controls[i].id > 0) {
774		multi_mix_control &c = Info->controls[i];
775		TRACE(MIX, "id:%#08x\n",		c.id);
776		TRACE(MIX, "flags:%#08x\n",	c.flags);
777		TRACE(MIX, "master:%#08x\n", c.master);
778		TRACE(MIX, "parent:%#08x\n", c.parent);
779		TRACE(MIX, "string:%d\n",	c.string);
780		TRACE(MIX, "name:%s\n",		c.name);
781		i++;
782	}
783}
784
785
786status_t
787Device::_SetupEndpoints()
788{
789	const usb_configuration_info* config
790		= gUSBModule->get_nth_configuration(fDevice, 0);
791
792	if (config == NULL) {
793		TRACE(ERR, "Error of getting USB device configuration.\n");
794		return B_ERROR;
795	}
796
797	if (config->interface_count <= 0) {
798		TRACE(ERR, "Error:no interfaces found in USB device configuration\n");
799		return B_ERROR;
800	}
801
802	for (size_t i = 0; i < config->interface_count; i++) {
803		usb_interface_info* Interface = config->interface[i].active;
804		if (Interface->descr->interface_class != USB_AUDIO_INTERFACE_AUDIO_CLASS)
805			continue;
806
807		switch (Interface->descr->interface_subclass) {
808			case USB_AUDIO_INTERFACE_AUDIOCONTROL_SUBCLASS:
809				fAudioControl.Init(i, Interface);
810				break;
811			case USB_AUDIO_INTERFACE_AUDIOSTREAMING_SUBCLASS:
812				{
813					Stream* stream = new(std::nothrow) Stream(this, i,
814						&config->interface[i]);
815					if (B_OK == stream->Init()) {
816						// put the stream in the correct order:
817						// first output that input ones.
818						if (stream->IsInput())
819							fStreams.PushBack(stream);
820						else
821							fStreams.PushFront(stream);
822					} else
823						delete stream;
824				}
825				break;
826			default:
827				TRACE(ERR, "Ignore interface of unsupported subclass %#x.\n",
828					Interface->descr->interface_subclass);
829				break;
830		}
831	}
832
833	if (fAudioControl.InitCheck() == B_OK && fStreams.Count() > 0) {
834		TRACE(INF, "Found device %#06x:%#06x\n", fVendorID, fProductID);
835
836		status_t status = gUSBModule->set_configuration(fDevice, config);
837		if (status != B_OK)
838			return status;
839
840		for (int i = 0; i < fStreams.Count(); i++)
841			fStreams[i]->OnSetConfiguration(fDevice, config);
842
843		return B_OK;
844	}
845
846	return B_NO_INIT;
847}
848
849
850status_t
851Device::StopDevice()
852{
853	status_t result = B_OK;
854
855	if (result != B_OK)
856		TRACE(ERR, "Error of writing %#04x RX Control:%#010x\n", 0, result);
857
858	//TRACE_RET(result);
859	return result;
860}
861
862