xref: /haiku/src/add-ons/kernel/drivers/audio/usb/Stream.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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 "Stream.h"
10 
11 #include <kernel.h>
12 #include <usb/USB_audio.h>
13 
14 #include "Device.h"
15 #include "Driver.h"
16 #include "Settings.h"
17 
18 
19 Stream::Stream(Device* device, size_t interface, usb_interface_list* List)
20 	:
21 	AudioStreamingInterface(&device->AudioControl(), interface, List),
22 	fDevice(device),
23 	fStatus(B_NO_INIT),
24 	fStreamEndpoint(0),
25 	fIsRunning(false),
26 	fArea(-1),
27 	fKernelArea(-1),
28 	fAreaSize(0),
29 	fDescriptors(NULL),
30 	fDescriptorsCount(0),
31 	fCurrentBuffer(0),
32 	fSamplesCount(0),
33 	fRealTime(0),
34 	fStartingFrame(0),
35 	fProcessedBuffers(0),
36 	fInsideNotify(0)
37 {
38 }
39 
40 
41 Stream::~Stream()
42 {
43 	delete_area(fArea);
44 	delete_area(fKernelArea);
45 	delete fDescriptors;
46 }
47 
48 
49 status_t
50 Stream::_ChooseAlternate()
51 {
52 	// lookup alternate with maximal (ch * 100 + resolution)
53 	uint16 maxChxRes = 0;
54 	for (int i = 0; i < fAlternates.Count(); i++) {
55 		if (fAlternates[i]->Interface() == 0) {
56 			TRACE(INF, "Ignore alternate %d - zero interface description.\n", i);
57 			continue;
58 		}
59 
60 		if (fAlternates[i]->Format() == 0) {
61 			TRACE(INF, "Ignore alternate %d - zero format description.\n", i);
62 			continue;
63 		}
64 
65 		if (fAlternates[i]->Format()->fFormatType
66 				!= USB_AUDIO_FORMAT_TYPE_I) {
67 			TRACE(ERR, "Ignore alternate %d - format type %#02x "
68 				"is not supported.\n", i, fAlternates[i]->Format()->fFormatType);
69 			continue;
70 		}
71 
72 		switch (fAlternates[i]->Interface()->fFormatTag) {
73 			case USB_AUDIO_FORMAT_PCM:
74 			case USB_AUDIO_FORMAT_PCM8:
75 			case USB_AUDIO_FORMAT_IEEE_FLOAT:
76 		//	case USB_AUDIO_FORMAT_ALAW:
77 		//	case USB_AUDIO_FORMAT_MULAW:
78 				break;
79 			default:
80 				TRACE(ERR, "Ignore alternate %d - format %#04x is not "
81 					"supported.\n", i, fAlternates[i]->Interface()->fFormatTag);
82 			continue;
83 		}
84 
85 		TypeIFormatDescriptor* format
86 			= static_cast<TypeIFormatDescriptor*>(fAlternates[i]->Format());
87 
88 		if (format->fNumChannels > 2) {
89 			TRACE(ERR, "Ignore alternate %d - channel count %d "
90 				"is not supported.\n", i, format->fNumChannels);
91 			continue;
92 		}
93 
94 		if (fAlternates[i]->Interface()->fFormatTag == USB_AUDIO_FORMAT_PCM) {
95 			switch(format->fBitResolution) {
96 				default:
97 				TRACE(ERR, "Ignore alternate %d - bit resolution %d "
98 					"is not supported.\n", i, format->fBitResolution);
99 					continue;
100 				case 8: case 16: case 18: case 20: case 24: case 32:
101 					break;
102 			}
103 		}
104 
105 		uint16 chxRes = format->fNumChannels * 100 + format->fBitResolution;
106 		if (chxRes > maxChxRes) {
107 			maxChxRes = chxRes;
108 			fActiveAlternate = i;
109 		}
110 	}
111 
112 	if (maxChxRes <= 0) {
113 		TRACE(ERR, "No compatible alternate found. "
114 			"Stream initialization failed.\n");
115 		return B_NO_INIT;
116 	}
117 
118 	const ASEndpointDescriptor* endpoint
119 		= fAlternates[fActiveAlternate]->Endpoint();
120 	fIsInput = (endpoint->fEndpointAddress & USB_ENDPOINT_ADDR_DIR_IN)
121 		== USB_ENDPOINT_ADDR_DIR_IN;
122 
123 	if (fIsInput)
124 		fCurrentBuffer = (size_t)-1;
125 
126 	TRACE(INF, "Alternate %d EP:%x selected for %s!\n",
127 		fActiveAlternate, endpoint->fEndpointAddress,
128 		fIsInput ? "recording" : "playback");
129 
130 	return B_OK;
131 }
132 
133 
134 status_t
135 Stream::Init()
136 {
137 	fStatus = _ChooseAlternate();
138 	return fStatus;
139 }
140 
141 
142 void
143 Stream::OnRemove()
144 {
145 	// the transfer callback schedule traffic - so we must ensure that we are
146 	// not inside the callback anymore before returning, as we would otherwise
147 	// violate the promise not to use any of the pipes after returning from the
148 	// removed callback
149 	while (atomic_get(&fInsideNotify) != 0)
150 		snooze(100);
151 
152 	gUSBModule->cancel_queued_transfers(fStreamEndpoint);
153 }
154 
155 
156 status_t
157 Stream::_SetupBuffers()
158 {
159 	// allocate buffer for worst (maximal size) case
160 	TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(
161 		fAlternates[fActiveAlternate]->Format());
162 
163 	uint32 samplingRate = fAlternates[fActiveAlternate]->GetSamplingRate();
164 	uint32 sampleSize = format->fNumChannels * format->fSubframeSize;
165 
166 	// data size pro 1 ms USB 1 frame or 1/8 ms USB 2 microframe
167 	size_t packetSize = samplingRate * sampleSize
168 		/ (fDevice->fUSBVersion < 0x0200 ? 1000 : 8000);
169 	TRACE(INF, "packetSize:%ld\n", packetSize);
170 
171 	if (packetSize == 0) {
172 		TRACE(ERR, "computed packet size is 0!");
173 		return B_BAD_VALUE;
174 	}
175 
176 	if (fArea != -1) {
177 		Stop();
178 		delete_area(fArea);
179 		delete_area(fKernelArea);
180 		delete fDescriptors;
181 	}
182 
183 	fAreaSize = sampleSize * kSamplesBufferSize * kSamplesBufferCount;
184 	TRACE(INF, "estimate fAreaSize:%d\n", fAreaSize);
185 
186 	// round up to B_PAGE_SIZE and create area
187 	fAreaSize = (fAreaSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1);
188 	TRACE(INF, "rounded up fAreaSize:%d\n", fAreaSize);
189 
190 	fArea = create_area(fIsInput ? DRIVER_NAME "_record_area"
191 		: DRIVER_NAME "_playback_area", (void**)&fBuffers,
192 		B_ANY_ADDRESS, fAreaSize, B_NO_LOCK,
193 		B_READ_AREA | B_WRITE_AREA);
194 	if (fArea < 0) {
195 		TRACE(ERR, "Error of creating %#x - "
196 			"bytes size buffer area:%#010x\n", fAreaSize, fArea);
197 		fStatus = fArea;
198 		return fStatus;
199 	}
200 
201 	// The kernel is not allowed to touch userspace areas, so we clone our
202 	// area into kernel space.
203 	fKernelArea = clone_area("usb_audio cloned area", (void**)&fKernelBuffers,
204 		B_ANY_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, fArea);
205 	if (fKernelArea < 0) {
206 		fStatus = fKernelArea;
207 		return fStatus;
208 	}
209 
210 	TRACE(INF, "Created area id:%d at addr:%#010x size:%#010lx\n",
211 		fArea, fDescriptors, fAreaSize);
212 
213 	fDescriptorsCount = fAreaSize / packetSize;
214 	// we need same size sub-buffers. round it
215 	fDescriptorsCount = ROUNDDOWN(fDescriptorsCount, kSamplesBufferCount);
216 	fDescriptors = new usb_iso_packet_descriptor[fDescriptorsCount];
217 	TRACE(INF, "descriptorsCount:%d\n", fDescriptorsCount);
218 
219 	// samples count
220 	fSamplesCount = fDescriptorsCount * packetSize / sampleSize;
221 	TRACE(INF, "samplesCount:%d\n", fSamplesCount);
222 
223 	// initialize descriptors array
224 	for (size_t i = 0; i < fDescriptorsCount; i++) {
225 		fDescriptors[i].request_length = packetSize;
226 		fDescriptors[i].actual_length = 0;
227 		fDescriptors[i].status = B_OK;
228 	}
229 
230 	return fStatus;
231 }
232 
233 
234 status_t
235 Stream::OnSetConfiguration(usb_device device,
236 		const usb_configuration_info* config)
237 {
238 	if (config == NULL) {
239 		TRACE(ERR, "NULL configuration. Not set.\n");
240 		return B_ERROR;
241 	}
242 
243 	usb_interface_info* interface
244 		= &config->interface[fInterface].alt[fActiveAlternate];
245 	if (interface == NULL) {
246 		TRACE(ERR, "NULL interface. Not set.\n");
247 		return B_ERROR;
248 	}
249 
250 	status_t status = gUSBModule->set_alt_interface(device, interface);
251 	uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress;
252 
253 	TRACE(INF, "set_alt_interface %x\n", status);
254 
255 	for (size_t i = 0; i < interface->endpoint_count; i++) {
256 		if (address == interface->endpoint[i].descr->endpoint_address) {
257 			fStreamEndpoint = interface->endpoint[i].handle;
258 			TRACE(INF, "%s Stream Endpoint [address %#04x] handle is: %#010x.\n",
259 				fIsInput ? "Input" : "Output", address, fStreamEndpoint);
260 			return B_OK;
261 		}
262 	}
263 
264 	TRACE(INF, "%s Stream Endpoint [address %#04x] was not found.\n",
265 		fIsInput ? "Input" : "Output", address);
266 	return B_ERROR;
267 }
268 
269 
270 status_t
271 Stream::Start()
272 {
273 	status_t result = B_BUSY;
274 	if (!fIsRunning) {
275 		for (size_t i = 0; i < kSamplesBufferCount; i++)
276 			result = _QueueNextTransfer(i, i == 0);
277 		fIsRunning = result == B_OK;
278 	}
279 	return result;
280 }
281 
282 
283 status_t
284 Stream::Stop()
285 {
286 	if (fIsRunning) {
287 		// wait until possible notification handling finished...
288 		while (atomic_get(&fInsideNotify) != 0)
289 			snooze(100);
290 		fIsRunning = false;
291 	}
292 	gUSBModule->cancel_queued_transfers(fStreamEndpoint);
293 
294 	return B_OK;
295 }
296 
297 
298 status_t
299 Stream::_QueueNextTransfer(size_t queuedBuffer, bool start)
300 {
301 	TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(
302 		fAlternates[fActiveAlternate]->Format());
303 
304 	size_t bufferSize = format->fNumChannels * format->fSubframeSize;
305 	bufferSize *= fSamplesCount / kSamplesBufferCount;
306 
307 	size_t packetsCount = fDescriptorsCount / kSamplesBufferCount;
308 
309 	TRACE(DTA, "buffers:%#010x[%#x]\ndescrs:%#010x[%#x]\n",
310 		fKernelBuffers + bufferSize * queuedBuffer, bufferSize,
311 		fDescriptors + queuedBuffer * packetsCount, packetsCount);
312 
313 	status_t status = gUSBModule->queue_isochronous(fStreamEndpoint,
314 		fKernelBuffers + bufferSize * queuedBuffer, bufferSize,
315 		fDescriptors + queuedBuffer * packetsCount, packetsCount,
316 		&fStartingFrame, start ? USB_ISO_ASAP : 0,
317 		Stream::_TransferCallback, this);
318 
319 	TRACE(DTA, "frame:%#010x\n", fStartingFrame);
320 	return status;
321 }
322 
323 
324 void
325 Stream::_TransferCallback(void* cookie, status_t status, void* data,
326 	size_t actualLength)
327 {
328 	TRACE(DTA, "st:%#010x, data:%#010x, len:%d\n", status, data, actualLength);
329 
330 	Stream* stream = (Stream*)cookie;
331 	atomic_add(&stream->fInsideNotify, 1);
332 	if (status == B_CANCELED || stream->fDevice->fRemoved || !stream->fIsRunning) {
333 		TRACE(ERR, "Cancelled: c:%p st:%#010x, data:%#010x, len:%d\n",
334 			cookie, status, data, actualLength);
335 		atomic_add(&stream->fInsideNotify, -1);
336 		return;
337 	}
338 
339 	stream->_DumpDescriptors();
340 
341 	if (atomic_add(&stream->fProcessedBuffers, 1) > (int32)kSamplesBufferCount)
342 		TRACE(ERR, "Processed buffers overflow:%d\n", stream->fProcessedBuffers);
343 	stream->fRealTime = system_time();
344 
345 	release_sem_etc(stream->fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE);
346 
347 	stream->fCurrentBuffer = (stream->fCurrentBuffer + 1) % kSamplesBufferCount;
348 	status = stream->_QueueNextTransfer(stream->fCurrentBuffer, false);
349 
350 	atomic_add(&stream->fInsideNotify, -1);
351 }
352 
353 
354 void
355 Stream::_DumpDescriptors()
356 {
357 	for (size_t i = 0; i < fDescriptorsCount; i++)
358 		TRACE(ISO, "%d:req_len:%d; act_len:%d; stat:%#010x\n", i,
359 			fDescriptors[i].request_length,	fDescriptors[i].actual_length,
360 			fDescriptors[i].status);
361 }
362 
363 
364 status_t
365 Stream::GetEnabledChannels(uint32& offset, multi_channel_enable* Enable)
366 {
367 	AudioChannelCluster* cluster = ChannelCluster();
368 	if (cluster == 0)
369 		return B_ERROR;
370 
371 	for (size_t i = 0; i < cluster->ChannelsCount(); i++) {
372 		B_SET_CHANNEL(Enable->enable_bits, offset++, true);
373 		TRACE(INF, "Report channel %d as enabled.\n", offset);
374 	}
375 
376 	return B_OK;
377 }
378 
379 
380 status_t
381 Stream::SetEnabledChannels(uint32& offset, multi_channel_enable* Enable)
382 {
383 	AudioChannelCluster* cluster = ChannelCluster();
384 	if (cluster == 0)
385 		return B_ERROR;
386 
387 	for (size_t i = 0; i < cluster->ChannelsCount(); i++, offset++) {
388 		TRACE(INF, "%s channel %d.\n",
389 			(B_TEST_CHANNEL(Enable->enable_bits, offset)
390 			? "Enable" : "Disable"), offset + 1);
391 	}
392 
393 	return B_OK;
394 }
395 
396 
397 status_t
398 Stream::GetGlobalFormat(multi_format_info* Format)
399 {
400 	_multi_format* format = fIsInput ? &Format->input : &Format->output;
401 	format->cvsr = fAlternates[fActiveAlternate]->GetSamplingRate();
402 	format->rate = fAlternates[fActiveAlternate]->GetSamplingRateId(0);
403 	format->format = fAlternates[fActiveAlternate]->GetFormatId();
404 	TRACE(INF, "%s.rate:%d cvsr:%f format:%#08x\n",
405 		fIsInput ? "input" : "ouput",
406 		format->rate, format->cvsr, format->format);
407 	return B_OK;
408 }
409 
410 
411 status_t
412 Stream::SetGlobalFormat(multi_format_info* Format)
413 {
414 	_multi_format* format = fIsInput ? &Format->input : &Format->output;
415 	AudioStreamAlternate* alternate = fAlternates[fActiveAlternate];
416 	if (format->rate == alternate->GetSamplingRateId(0)
417 			&& format->format == alternate->GetFormatId()) {
418 		TRACE(INF, "No changes required\n");
419 		return B_OK;
420 	}
421 
422 	alternate->SetSamplingRateById(format->rate);
423 	alternate->SetFormatId(format->format);
424 	TRACE(INF, "%s.rate:%d cvsr:%f format:%#08x\n",
425 		fIsInput ? "input" : "ouput",
426 		format->rate, format->cvsr, format->format);
427 
428 	// cancel data flow - it will be rewaked at next buffer exchange call
429 	Stop();
430 
431 	// TODO: wait for cancelling?
432 
433 	// layout of buffers should be adjusted after changing sampling rate/format
434 	status_t status = _SetupBuffers();
435 
436 	if (status != B_OK)
437 		return status;
438 
439 	// set endpoint speed
440 	uint32 samplingRate = fAlternates[fActiveAlternate]->GetSamplingRate();
441 	size_t actualLength = 0;
442 	usb_audio_sampling_freq freq = _ASFormatDescriptor::GetSamFreq(samplingRate);
443 	uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress;
444 
445 	status = gUSBModule->send_request(fDevice->fDevice,
446 		USB_REQTYPE_CLASS | USB_REQTYPE_ENDPOINT_OUT,
447 		USB_AUDIO_SET_CUR, USB_AUDIO_SAMPLING_FREQ_CONTROL << 8,
448 		address, sizeof(freq), &freq, &actualLength);
449 
450 	TRACE(ERR, "set_speed %02x%02x%02x for ep %#x %d: %s\n",
451 		freq.bytes[0], freq.bytes[1], freq.bytes[2],
452 		address, actualLength, strerror(status));
453 	return status;
454 }
455 
456 
457 status_t
458 Stream::GetBuffers(multi_buffer_list* List)
459 {
460 // TODO: check the available buffers count!
461 	if (fAreaSize == 0)
462 		return B_NO_INIT;
463 
464 	int32 startChannel = List->return_playback_channels;
465 	buffer_desc** Buffers = List->playback_buffers;
466 
467 	if (fIsInput) {
468 		List->flags |= B_MULTI_BUFFER_RECORD;
469 		List->return_record_buffer_size = fSamplesCount / kSamplesBufferCount;
470 		List->return_record_buffers = kSamplesBufferCount;
471 		startChannel = List->return_record_channels;
472 		Buffers = List->record_buffers;
473 
474 		TRACE(DTA, "flags:%#10x\nreturn_record_buffer_size:%#010x\n"
475 			"return_record_buffers:%#010x\n", List->flags,
476 			List->return_record_buffer_size, List->return_record_buffers);
477 	} else {
478 		List->flags |= B_MULTI_BUFFER_PLAYBACK;
479 		List->return_playback_buffer_size = fSamplesCount / kSamplesBufferCount;
480 		List->return_playback_buffers = kSamplesBufferCount;
481 
482 		TRACE(DTA, "flags:%#10x\nreturn_playback_buffer_size:%#010x\n"
483 			"return_playback_buffers:%#010x\n", List->flags,
484 			List->return_playback_buffer_size, List->return_playback_buffers);
485 	}
486 
487 	TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(
488 		fAlternates[fActiveAlternate]->Format());
489 
490 	// [buffer][channel] init buffers
491 	for (size_t buffer = 0; buffer < kSamplesBufferCount; buffer++) {
492 		TRACE(DTA, "%s buffer #%d:\n", fIsInput ? "input" : "output", buffer + 1);
493 
494 		struct buffer_desc descs[format->fNumChannels];
495 		for (size_t channel = startChannel;
496 				channel < format->fNumChannels; channel++) {
497 			// init stride to the same for all buffers
498 			uint32 stride = format->fSubframeSize * format->fNumChannels;
499 			descs[channel].stride = stride;
500 
501 			size_t bufferSize = (fSamplesCount / kSamplesBufferCount) * stride;
502 			descs[channel].base = (char*)fBuffers;
503 			descs[channel].base += buffer * bufferSize;
504 			descs[channel].base += channel * format->fSubframeSize;
505 
506 			TRACE(DTA, "%d:%d: base:%#010x; stride:%#010x\n", buffer, channel,
507 				descs[channel].base, descs[channel].stride);
508 		}
509 		if (!IS_USER_ADDRESS(Buffers[buffer])
510 				|| user_memcpy(Buffers[buffer], descs, sizeof(descs)) < B_OK) {
511 			return B_BAD_ADDRESS;
512 		}
513 	}
514 
515 	if (fIsInput) {
516 		List->return_record_channels += format->fNumChannels;
517 		TRACE(MIX, "return_record_channels:%#010x\n",
518 			List->return_record_channels);
519 	} else {
520 		List->return_playback_channels += format->fNumChannels;
521 		TRACE(MIX, "return_playback_channels:%#010x\n",
522 			List->return_playback_channels);
523 	}
524 
525 	return B_OK;
526 }
527 
528 
529 bool
530 Stream::ExchangeBuffer(multi_buffer_info* Info)
531 {
532 	if (atomic_get(&fProcessedBuffers) <= 0)
533 		return false;
534 
535 	if (fIsInput) {
536 		Info->recorded_real_time = fRealTime;
537 		Info->recorded_frames_count += fSamplesCount / kSamplesBufferCount;
538 		Info->record_buffer_cycle = fCurrentBuffer;
539 	} else {
540 		Info->played_real_time = fRealTime;
541 		Info->played_frames_count += fSamplesCount / kSamplesBufferCount;
542 		Info->playback_buffer_cycle = fCurrentBuffer;
543 	}
544 
545 	atomic_add(&fProcessedBuffers, -1);
546 
547 	return true;
548 }
549