xref: /haiku/src/add-ons/kernel/drivers/audio/echo/echo.cpp (revision b06a48ab8f30b45916a9c157b992827779182163)
1 //------------------------------------------------------------------------------
2 //
3 //  EchoGals/Echo24 BeOS Driver for Echo audio cards
4 //
5 //	Copyright (c) 2003, Jérôme Duval
6 //
7 //	Permission is hereby granted, free of charge, to any person obtaining a
8 //	copy of this software and associated documentation files (the "Software"),
9 //	to deal in the Software without restriction, including without limitation
10 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 //	and/or sell copies of the Software, and to permit persons to whom the
12 //	Software is furnished to do so, subject to the following conditions:
13 //
14 //	The above copyright notice and this permission notice shall be included in
15 //	all copies or substantial portions of the Software.
16 //
17 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 //	DEALINGS IN THE SOFTWARE.
24 
25 #include <KernelExport.h>
26 #include <Drivers.h>
27 #include <driver_settings.h>
28 #include <malloc.h>
29 #include <unistd.h>
30 #include "OsSupportBeOS.h"
31 #include "EchoGalsXface.h"
32 #include "C3g.h"
33 #include "CDarla24.h"
34 #include "CDarla.h"
35 #include "CGina.h"
36 #include "CGina24.h"
37 #include "CIndigo.h"
38 #include "CIndigoDJ.h"
39 #include "CIndigoIO.h"
40 #include "CLayla.h"
41 #include "CLayla24.h"
42 #include "CMia.h"
43 #include "CMona.h"
44 #include "echo.h"
45 #include "debug.h"
46 #include "util.h"
47 
48 #ifdef CARDBUS
49 static cb_enabler_module_info	*cbemi;
50 struct _echodevs				devices;
51 static char						*names[NUM_CARDS];
52 int32 							num_names = 0;
53 static uint32					device_index = 0;
54 static sem_id					device_lock = 0;
55 
56 static const cb_device_descriptor	descriptors[] = {
57 	{VENDOR_ID, DEVICE_ID_56301, 0xff, 0xff, 0xff}
58 };
59 
60 #define COUNT_DESCRIPTOR			1
61 
62 status_t cardbus_device_added(pci_info *info, void **cookie);
63 void cardbus_device_removed(void *cookie);
64 
65 static cb_notify_hooks	cardbus_hooks = {
66 	cardbus_device_added, 		// Add entry point
67 	cardbus_device_removed 		// Remove entry point
68 };
69 
70 #else // CARDBUS
71 static pci_module_info	*pci;
72 int32 num_cards;
73 echo_dev cards[NUM_CARDS];
74 int32 num_names;
75 char * names[NUM_CARDS*20+1];
76 #endif // CARDBUS
77 
78 echo_settings current_settings = {
79 	2,	// channels
80 	16,	// bits per sample
81 	48000,	// sample rate
82 	512,	// buffer frames
83 	2	// buffer count
84 };
85 
86 extern device_hooks multi_hooks;
87 #ifdef MIDI_SUPPORT
88 extern device_hooks midi_hooks;
89 #endif
90 
91 int32 echo_int(void *arg);
92 status_t init_hardware(void);
93 status_t init_driver(void);
94 static void make_device_names(echo_dev * card);
95 
96 static status_t echo_setup(echo_dev * card);
97 static void echo_shutdown(echo_dev *card);
98 
99 void uninit_driver(void);
100 const char ** publish_devices(void);
101 device_hooks * find_device(const char * name);
102 
103 
104 /* Echo Memory management */
105 
106 echo_mem *
107 echo_mem_new(echo_dev *card, size_t size)
108 {
109 	echo_mem *mem;
110 
111 	if ((mem = (echo_mem *) malloc(sizeof(*mem))) == NULL)
112 		return (NULL);
113 
114 	mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "echo buffer");
115 	mem->size = size;
116 	if (mem->area < B_OK) {
117 		free(mem);
118 		return NULL;
119 	}
120 	return mem;
121 }
122 
123 void
124 echo_mem_delete(echo_mem *mem)
125 {
126 	if (mem->area > B_OK)
127 		delete_area(mem->area);
128 	free(mem);
129 }
130 
131 echo_mem *
132 echo_mem_alloc(echo_dev *card, size_t size)
133 {
134 	echo_mem *mem;
135 
136 	mem = echo_mem_new(card, size);
137 	if (mem == NULL)
138 		return (NULL);
139 
140 	LIST_INSERT_HEAD(&(card->mems), mem, next);
141 
142 	return mem;
143 }
144 
145 void
146 echo_mem_free(echo_dev *card, void *ptr)
147 {
148 	echo_mem 		*mem;
149 
150 	LIST_FOREACH(mem, &card->mems, next) {
151 		if (mem->log_base != ptr)
152 			continue;
153 		LIST_REMOVE(mem, next);
154 
155 		echo_mem_delete(mem);
156 		break;
157 	}
158 }
159 
160 /*	Echo stream functions */
161 
162 extern char *pStatusStrs[ECHOSTATUS_LAST];
163 
164 status_t
165 echo_stream_set_audioparms(echo_stream *stream, uint8 channels,
166 	uint8 bitsPerSample, uint32 sample_rate, uint8 index)
167 {
168 	int32 			i;
169 	uint8 			sample_size, frame_size;
170 	ECHOGALS_OPENAUDIOPARAMETERS	open_params;
171 	ECHOGALS_CLOSEAUDIOPARAMETERS  close_params;
172 	ECHOGALS_AUDIOFORMAT			format_params;
173 	ECHOSTATUS status;
174 
175 	LOG(("echo_stream_set_audioparms\n"));
176 
177 	if (stream->pipe >= 0) {
178 		close_params.wPipeIndex = stream->pipe;
179 		status = stream->card->pEG->CloseAudio(&close_params);
180 		if (status != ECHOSTATUS_OK && status != ECHOSTATUS_CHANNEL_NOT_OPEN) {
181 			PRINT(("echo_stream_set_audioparms : CloseAudio failed\n"));
182 			PRINT((" status: %s \n", pStatusStrs[status]));
183 			return B_ERROR;
184 		}
185 	}
186 
187 	open_params.bIsCyclic = TRUE;
188 	open_params.Pipe.nPipe = index;
189 	open_params.Pipe.bIsInput = stream->use == ECHO_USE_RECORD ? TRUE : FALSE;
190 	open_params.Pipe.wInterleave = channels;
191 	open_params.ProcessId = NULL;
192 
193 	status = stream->card->pEG->OpenAudio(&open_params, &stream->pipe);
194 	if (status != ECHOSTATUS_OK) {
195 		PRINT(("echo_stream_set_audioparms : OpenAudio failed\n"));
196 		PRINT((" status: %s \n", pStatusStrs[status]));
197 		return B_ERROR;
198 	}
199 
200 	//PRINT(("VerifyAudioOpen\n"));
201 	status = stream->card->pEG->VerifyAudioOpen(stream->pipe);
202 	if (status != ECHOSTATUS_OK) {
203 		PRINT(("echo_stream_set_audioparms : VerifyAudioOpen failed\n"));
204 		PRINT(("  status: %s \n", pStatusStrs[status]));
205 		return B_ERROR;
206 	}
207 
208 	if ((stream->channels == channels) &&
209 		(stream->bitsPerSample == bitsPerSample) &&
210 		(stream->sample_rate == sample_rate))
211 		return B_OK;
212 
213 	format_params.wBitsPerSample = bitsPerSample;
214 	format_params.byDataAreBigEndian = 0;
215 	format_params.byMonoToStereo = 0;
216 	format_params.wDataInterleave = channels == 1 ? 1 : 2;
217 
218 	status = stream->card->pEG->QueryAudioFormat(stream->pipe, &format_params);
219 	if (status != ECHOSTATUS_OK) {
220 		PRINT(("echo_stream_set_audioparms : bad format when querying\n"));
221 		PRINT(("  status: %s \n", pStatusStrs[status]));
222 		return B_ERROR;
223 	}
224 
225 	status = stream->card->pEG->SetAudioFormat(stream->pipe, &format_params);
226 	if (status != ECHOSTATUS_OK) {
227 		PRINT(("echo_stream_set_audioparms : bad format when setting\n"));
228 		PRINT(("  status: %s \n", pStatusStrs[status]));
229 		return B_ERROR;
230 	}
231 
232 	/* XXXX : setting sample rate is global in this driver */
233 	status = stream->card->pEG->QueryAudioSampleRate(sample_rate);
234 	if (status != ECHOSTATUS_OK) {
235 		PRINT(("echo_stream_set_audioparms : bad sample rate when querying\n"));
236 		PRINT(("  status: %s \n", pStatusStrs[status]));
237 		return B_ERROR;
238 	}
239 
240 	/* XXXX : setting sample rate is global in this driver */
241 	status = stream->card->pEG->SetAudioSampleRate(sample_rate);
242 	if (status != ECHOSTATUS_OK) {
243 		PRINT(("echo_stream_set_audioparms : bad sample rate when setting\n"));
244 		PRINT(("  status: %s \n", pStatusStrs[status]));
245 		return B_ERROR;
246 	}
247 
248 	if (stream->buffer)
249 		echo_mem_free(stream->card, stream->buffer->log_base);
250 
251 	stream->bitsPerSample = bitsPerSample;
252 	stream->sample_rate = sample_rate;
253 	stream->channels = channels;
254 
255 	sample_size = stream->bitsPerSample / 8;
256 	frame_size = sample_size * stream->channels;
257 
258 	stream->buffer = echo_mem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount);
259 
260 	stream->trigblk = 1;
261 	stream->blkmod = stream->bufcount;
262 	stream->blksize = stream->bufframes * frame_size;
263 
264 	CDaffyDuck *duck = stream->card->pEG->GetDaffyDuck(stream->pipe);
265 	if (duck == NULL) {
266 		PRINT(("echo_stream_set_audioparms : Could not get daffy duck pointer\n"));
267 		return B_ERROR;
268 	}
269 
270 	uint32 dwNumFreeEntries = 0;
271 
272 	for (i=0; i<stream->bufcount; i++) {
273 		duck->AddMapping(((uint32)stream->buffer->phy_base) +
274 			i * stream->blksize, stream->blksize, 0, TRUE, dwNumFreeEntries);
275 	}
276 
277 	duck->Wrap();
278 
279 	if (stream->card->pEG->GetAudioPositionPtr(stream->pipe, stream->position)!=ECHOSTATUS_OK) {
280 		PRINT(("echo_stream_set_audioparms : Could not get audio position ptr\n"));
281 		return B_ERROR;
282 	}
283 
284 	return B_OK;
285 }
286 
287 
288 status_t
289 echo_stream_get_nth_buffer(echo_stream *stream, uint8 chan, uint8 buf,
290 	char** buffer, size_t *stride)
291 {
292 	uint8 			sample_size, frame_size;
293 	LOG(("echo_stream_get_nth_buffer\n"));
294 
295 	sample_size = stream->bitsPerSample / 8;
296 	frame_size = sample_size * stream->channels;
297 
298 	*buffer = (char*)stream->buffer->log_base + (buf * stream->bufframes * frame_size)
299 		+ chan * sample_size;
300 	*stride = frame_size;
301 
302 	return B_OK;
303 }
304 
305 
306 static uint32
307 echo_stream_curaddr(echo_stream *stream)
308 {
309 	uint32 addr = B_LENDIAN_TO_HOST_INT32(*stream->position);
310 //	TRACE(("stream_curaddr %p, phy_base %p\n", addr));
311 	return (addr / stream->blksize) % stream->blkmod;
312 }
313 
314 
315 void
316 echo_stream_start(echo_stream *stream, void (*inth) (void *), void *inthparam)
317 {
318 	LOG(("echo_stream_start\n"));
319 	ECHOSTATUS status;
320 
321 	stream->inth = inth;
322 	stream->inthparam = inthparam;
323 
324 	stream->state |= ECHO_STATE_STARTED;
325 
326 	status = stream->card->pEG->Start(stream->pipe);
327 	if (status!=ECHOSTATUS_OK) {
328 		PRINT(("echo_stream_start : Could not start the pipe %s\n", pStatusStrs[status]));
329 	}
330 }
331 
332 void
333 echo_stream_halt(echo_stream *stream)
334 {
335 	LOG(("echo_stream_halt\n"));
336 	ECHOSTATUS status;
337 
338 	stream->state &= ~ECHO_STATE_STARTED;
339 
340 	status = stream->card->pEG->Stop(stream->pipe);
341 	if (status!=ECHOSTATUS_OK) {
342 		PRINT(("echo_stream_halt : Could not stop the pipe %s\n", pStatusStrs[status]));
343 	}
344 }
345 
346 echo_stream *
347 echo_stream_new(echo_dev *card, uint8 use, uint32 bufframes, uint8 bufcount)
348 {
349 	echo_stream *stream;
350 	cpu_status status;
351 	LOG(("echo_stream_new\n"));
352 
353 	stream = (echo_stream *) malloc(sizeof(echo_stream));
354 	if (stream == NULL)
355 		return (NULL);
356 	stream->card = card;
357 	stream->use = use;
358 	stream->state = !ECHO_STATE_STARTED;
359 	stream->bitsPerSample = 0;
360 	stream->sample_rate = 0;
361 	stream->channels = 0;
362 	stream->bufframes = bufframes;
363 	stream->bufcount = bufcount;
364 	stream->inth = NULL;
365 	stream->inthparam = NULL;
366 	stream->buffer = NULL;
367 	stream->blksize = 0;
368 	stream->trigblk = 0;
369 	stream->blkmod = 0;
370 
371 	stream->pipe = -1;
372 
373 	stream->frames_count = 0;
374 	stream->real_time = 0;
375 	stream->buffer_cycle = 0;
376 	stream->update_needed = false;
377 
378 	status = lock();
379 	LIST_INSERT_HEAD((&card->streams), stream, next);
380 	unlock(status);
381 
382 	return stream;
383 }
384 
385 void
386 echo_stream_delete(echo_stream *stream)
387 {
388 	cpu_status status;
389 	ECHOGALS_CLOSEAUDIOPARAMETERS close_params;
390 	LOG(("echo_stream_delete\n"));
391 
392 	echo_stream_halt(stream);
393 
394 	if (stream->pipe >= 0) {
395 		close_params.wPipeIndex = stream->pipe;
396 		status = stream->card->pEG->CloseAudio(&close_params);
397 		if (status != ECHOSTATUS_OK && status != ECHOSTATUS_CHANNEL_NOT_OPEN) {
398 			PRINT(("echo_stream_set_audioparms : CloseAudio failed\n"));
399 			PRINT((" status: %s \n", pStatusStrs[status]));
400 		}
401 	}
402 
403 	if (stream->buffer)
404 		echo_mem_free(stream->card, stream->buffer->log_base);
405 
406 	status = lock();
407 	LIST_REMOVE(stream, next);
408 	unlock(status);
409 
410 	free(stream);
411 }
412 
413 
414 /* Echo interrupt */
415 
416 int32 echo_int(void *arg)
417 {
418 	echo_dev* card = (echo_dev*)arg;
419 	BOOL midiReceived;
420 	ECHOSTATUS err;
421 	echo_stream* stream;
422 	uint32 curblk;
423 
424 	err = card->pEG->ServiceIrq(midiReceived);
425 
426 	if (err != ECHOSTATUS_OK) {
427 		return B_UNHANDLED_INTERRUPT;
428 	}
429 
430 #ifdef MIDI_SUPPORT
431 	if (midiReceived)
432 		release_sem_etc(card->midi.midi_ready_sem, 1, B_DO_NOT_RESCHEDULE);
433 #endif
434 
435 	LIST_FOREACH(stream, &card->streams, next) {
436 		if ((stream->state & ECHO_STATE_STARTED) == 0 ||
437 			(stream->inth == NULL))
438 				continue;
439 
440 		curblk = echo_stream_curaddr(stream);
441 		//TRACE(("echo_int stream %p at trigblk %lu at stream->trigblk %lu\n",
442 		//	   stream, curblk, stream->trigblk));
443 		if (curblk == stream->trigblk) {
444 			if (stream->inth)
445 				stream->inth(stream->inthparam);
446 
447 			stream->trigblk++;
448 			stream->trigblk %= stream->blkmod;
449 		}
450 	}
451 
452 	return B_INVOKE_SCHEDULER;
453 }
454 
455 /* dumps card capabilities */
456 void
457 echo_dump_caps(echo_dev *card)
458 {
459 	PECHOGALS_CAPS caps = &card->caps;
460 	PRINT(("name: %s\n", caps->szName));
461 	PRINT(("out pipes: %d, in pipes: %d, out busses: %d, in busses: %d, out midi: %d, in midi: %d\n",
462 		caps->wNumPipesOut, caps->wNumPipesIn, caps->wNumBussesOut, caps->wNumBussesIn, caps->wNumMidiOut, caps->wNumMidiIn));
463 
464 }
465 
466 
467 /* detect presence of our hardware */
468 status_t
469 init_hardware(void)
470 {
471 #ifdef CARDBUS
472 	return B_OK;
473 #else
474 	int ix=0;
475 	pci_info info;
476 	status_t err = ENODEV;
477 
478 	LOG_CREATE();
479 
480 	PRINT(("init_hardware()\n"));
481 
482 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci))
483 		return ENOSYS;
484 
485 	while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
486 
487 		ushort card_type = info.u.h0.subsystem_id & 0xfff0;
488 
489 		if (info.vendor_id == VENDOR_ID &&
490 			((info.device_id == DEVICE_ID_56301)
491 			|| (info.device_id == DEVICE_ID_56361)) &&
492 			(info.u.h0.subsystem_vendor_id == SUBVENDOR_ID) &&
493 			(
494 #ifdef ECHOGALS_FAMILY
495 			(card_type == DARLA)
496 			|| (card_type == GINA)
497 			|| (card_type == LAYLA)
498 			|| (card_type == DARLA24)
499 #endif
500 #ifdef ECHO24_FAMILY
501 			(card_type == GINA24)
502 			|| (card_type == LAYLA24)
503 			|| (card_type == MONA)
504 			|| (card_type == MIA)
505 #endif
506 #ifdef INDIGO_FAMILY
507 			(card_type == INDIGO)
508 			|| (card_type == INDIGO_IO)
509 			|| (card_type == INDIGO_DJ)
510 #endif
511 #ifdef ECHO3G_FAMILY
512 			(card_type == ECHO3G)
513 #endif
514 			 )) {
515 			err = B_OK;
516 		}
517 		ix++;
518 	}
519 
520 	put_module(B_PCI_MODULE_NAME);
521 
522 	if (err != B_OK) {
523 		PRINT(("no card found\n"));
524 	}
525 
526 	return err;
527 #endif
528 }
529 
530 
531 status_t
532 init_driver(void)
533 {
534 	PRINT(("init_driver()\n"));
535 
536 	void *settings_handle;
537 	// get driver settings
538 	settings_handle = load_driver_settings ("echo.settings");
539 	if (settings_handle != NULL) {
540 		const char* item;
541 		char* end;
542 		uint32 value;
543 
544 		item = get_driver_parameter (settings_handle, "channels", NULL, NULL);
545 		if (item) {
546 			value = strtoul (item, &end, 0);
547 			if (*end == '\0') current_settings.channels = value;
548 		}
549 		PRINT(("channels %lu\n", current_settings.channels));
550 
551 		item = get_driver_parameter (settings_handle, "bitsPerSample", NULL, NULL);
552 		if (item) {
553 			value = strtoul (item, &end, 0);
554 			if (*end == '\0') current_settings.bitsPerSample = value;
555 		}
556 		PRINT(("bitsPerSample %lu\n", current_settings.bitsPerSample));
557 
558 		item = get_driver_parameter (settings_handle, "sample_rate", NULL, NULL);
559 		if (item) {
560 			value = strtoul (item, &end, 0);
561 			if (*end == '\0') current_settings.sample_rate = value;
562 		}
563 		PRINT(("sample_rate %lu\n", current_settings.sample_rate));
564 
565 		item = get_driver_parameter (settings_handle, "buffer_frames", NULL, NULL);
566 		if (item) {
567 			value = strtoul (item, &end, 0);
568 			if (*end == '\0') current_settings.buffer_frames = value;
569 		}
570 		PRINT(("buffer_frames %lu\n", current_settings.buffer_frames));
571 
572 		item = get_driver_parameter (settings_handle, "buffer_count", NULL, NULL);
573 		if (item) {
574 			value = strtoul (item, &end, 0);
575 			if (*end == '\0') current_settings.buffer_count = value;
576 		}
577 		PRINT(("buffer_count %lu\n", current_settings.buffer_count));
578 
579 		unload_driver_settings (settings_handle);
580 	}
581 
582 #ifdef CARDBUS
583 	// Get card services client module
584 	if (get_module(CB_ENABLER_MODULE_NAME, (module_info **)&cbemi) != B_OK) {
585 		dprintf(DRIVER_NAME ": cardbus enabler module error\n");
586 		return B_ERROR;
587 	}
588 	// Create the devices lock
589 	device_lock = create_sem(1, DRIVER_NAME " device");
590 	if (device_lock < B_OK) {
591 		dprintf(DRIVER_NAME ": create device semaphore error 0x%.8x\n", device_lock);
592 		put_module(CB_ENABLER_MODULE_NAME);
593 		return B_ERROR;
594 	}
595 	// Register driver
596 	cbemi->register_driver(DRIVER_NAME, descriptors, COUNT_DESCRIPTOR);
597 	cbemi->install_notify(DRIVER_NAME, &cardbus_hooks);
598 	LIST_INIT(&(devices));
599 	return B_OK;
600 #else
601 	int ix=0;
602 
603 	pci_info info;
604 	num_cards = 0;
605 
606 	if (get_module(B_PCI_MODULE_NAME, (module_info **) &pci))
607 		return ENOSYS;
608 
609 	while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
610 		ushort card_type = info.u.h0.subsystem_id & 0xfff0;
611 
612 		if (info.vendor_id == VENDOR_ID &&
613 			((info.device_id == DEVICE_ID_56301)
614 			|| (info.device_id == DEVICE_ID_56361)) &&
615 			(info.u.h0.subsystem_vendor_id == SUBVENDOR_ID) &&
616 			(
617 #ifdef ECHOGALS_FAMILY
618 			(card_type == DARLA)
619 			|| (card_type == GINA)
620 			|| (card_type == LAYLA)
621 			|| (card_type == DARLA24)
622 #endif
623 #ifdef ECHO24_FAMILY
624 			(card_type == GINA24)
625 			|| (card_type == LAYLA24)
626 			|| (card_type == MONA)
627 			|| (card_type == MIA)
628 #endif
629 #ifdef INDIGO_FAMILY
630 			(card_type == INDIGO)
631 			|| (card_type == INDIGO_IO)
632 			|| (card_type == INDIGO_DJ)
633 #endif
634 #ifdef ECHO3G_FAMILY
635 			(card_type == ECHO3G)
636 #endif
637 			)) {
638 
639 			if (num_cards == NUM_CARDS) {
640 				PRINT(("Too many "DRIVER_NAME" cards installed!\n"));
641 				break;
642 			}
643 			memset(&cards[num_cards], 0, sizeof(echo_dev));
644 			cards[num_cards].info = info;
645 			cards[num_cards].type = card_type;
646 			if (echo_setup(&cards[num_cards])) {
647 				PRINT(("Setup of "DRIVER_NAME" %ld failed\n", num_cards+1));
648 			}
649 			else {
650 				num_cards++;
651 			}
652 		}
653 		ix++;
654 	}
655 	if (!num_cards) {
656 		PRINT(("no cards\n"));
657 		put_module(B_PCI_MODULE_NAME);
658 		PRINT(("no suitable cards found\n"));
659 		return ENODEV;
660 	}
661 
662 	return B_OK;
663 #endif
664 }
665 
666 
667 #ifndef CARDBUS
668 static void
669 make_device_names(
670 	echo_dev * card)
671 {
672 #ifdef MIDI_SUPPORT
673 	sprintf(card->midi.name, "midi/"DRIVER_NAME"/%ld", card-cards+1);
674 	names[num_names++] = card->midi.name;
675 #endif
676 	sprintf(card->name, "audio/hmulti/"DRIVER_NAME"/%ld", card-cards+1);
677 	names[num_names++] = card->name;
678 
679 	names[num_names] = NULL;
680 }
681 #else
682 
683 status_t
684 cardbus_device_added(pci_info *info, void **cookie) {
685 	echo_dev 			* card, *dev;
686 	uint32				index;
687 	char				buffer[32];
688 
689 	LOG(("cardbus_device_added at %.2d:%.2d:%.2d\n", info->bus, info->device, info->function));
690 	// Allocate cookie
691 	if (!(*cookie = card = (echo_dev *)malloc(sizeof(echo_dev)))) {
692 		return B_NO_MEMORY;
693 	}
694 	// Clear cookie
695 	memset(card, 0, sizeof(echo_dev));
696 	// Initialize cookie
697 	card->info = *info;
698 	card->plugged = true;
699 	card->index = 0;
700 
701 	LIST_FOREACH(dev, &devices, next) {
702 		if (dev->index == card->index) {
703 			card->index++;
704 			dev = LIST_FIRST(&devices);
705 		}
706 	}
707 
708 	// Format device name
709 	sprintf(card->name, "audio/hmulti/" DRIVER_NAME "/%ld", card->index);
710 	// Lock the devices
711 	acquire_sem(device_lock);
712 	LIST_INSERT_HEAD((&devices), card, next);
713 	// Unlock the devices
714 	release_sem(device_lock);
715 
716 	echo_setup(card);
717 	return B_OK;
718 }
719 
720 
721 // cardbus_device_removed - handle cardbus device removal.
722 // status : OK
723 void
724 cardbus_device_removed(void *cookie)
725 {
726 	echo_dev		*card = (echo_dev *) cookie;
727 
728 	LOG((": cardbus_device_removed\n"));
729 	// Check
730 	if (card == NULL) {
731 		LOG((": null device 0x%.8x\n", card));
732 		return;
733 	}
734 
735 	echo_shutdown(card);
736 
737 	// Lock the devices
738 	acquire_sem(device_lock);
739 	// Finalize
740 	card->plugged = false;
741 	// Check if the device is opened
742 	if (card->opened) {
743 		LOG(("device 0x%.8x %s still in use\n", card, card->name));
744 	} else {
745 		LOG(("free device 0x%.8x %s\n", card, card->name));
746 		LIST_REMOVE(card, next);
747 		free(card);
748 	}
749 	// Unlock the devices
750 	release_sem(device_lock);
751 }
752 
753 #endif
754 
755 
756 static status_t
757 echo_setup(echo_dev * card)
758 {
759 	status_t err = B_OK;
760 	unsigned char cmd;
761 	char *name;
762 
763 	PRINT(("echo_setup(%p)\n", card));
764 
765 #ifndef CARDBUS
766 	(*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function,
767 		PCI_latency, 1, 0xc0 );
768 
769 	make_device_names(card);
770 #endif
771 	card->bmbar = card->info.u.h0.base_registers[0];
772 	card->irq = card->info.u.h0.interrupt_line;
773 
774 
775 	card->pOSS = new COsSupport(card->info.device_id, card->info.revision);
776 	if (card->pOSS == NULL)
777 		return B_ERROR;
778 
779 	switch (card->type) {
780 #ifdef ECHOGALS_FAMILY
781 		case DARLA:
782 			card->pEG = new CDarla(card->pOSS);
783 			name = "Echo Darla";
784 			break;
785 		case GINA:
786 			card->pEG = new CGina(card->pOSS);
787 			name = "Echo Gina";
788 			break;
789 		case LAYLA:
790 			card->pEG = new CLayla(card->pOSS);
791 			name = "Echo Layla";
792 			break;
793 		case DARLA24:
794 			card->pEG = new CDarla24(card->pOSS);
795 			name = "Echo Darla24";
796 			break;
797 #endif
798 #ifdef ECHO24_FAMILY
799 		case GINA24:
800 			card->pEG = new CGina24(card->pOSS);
801 			name = "Echo Gina24";
802 			break;
803 		case LAYLA24:
804 			card->pEG = new CLayla24(card->pOSS);
805 			name = "Echo Layla24";
806 			break;
807 		case MONA:
808 			card->pEG = new CMona(card->pOSS);
809 			name = "Echo Mona";
810 			break;
811 		case MIA:
812 			card->pEG = new CMia(card->pOSS);
813 			name = "Echo Mia";
814 			break;
815 #endif
816 #ifdef INDIGO_FAMILY
817 		case INDIGO:
818 			card->pEG = new CIndigo(card->pOSS);
819 			name = "Echo Indigo";
820 			break;
821 		case INDIGO_IO:
822 			card->pEG = new CIndigoIO(card->pOSS);
823 			name = "Echo IndigoIO";
824 			break;
825 		case INDIGO_DJ:
826 			card->pEG = new CIndigoDJ(card->pOSS);
827 			name = "Echo IndigoDJ";
828 			break;
829 #endif
830 #ifdef ECHO3G_FAMILY
831 		case ECHO3G:
832 			card->pEG = new C3g(card->pOSS);
833 			name = "Echo 3g";
834 			break;
835 #endif
836 		default:
837 			PRINT(("card type 0x%x not supported by "DRIVER_NAME"\n", card->type));
838 			delete card->pOSS;
839 			return B_ERROR;
840 	}
841 
842 	if (card->pEG == NULL)
843 		return B_ERROR;
844 
845 	card->area_bmbar = map_mem(&card->log_bmbar, (void *)card->bmbar,
846 		card->info.u.h0.base_register_sizes[0], DRIVER_NAME" bmbar io");
847 	if (card->area_bmbar <= B_OK) {
848 		LOG(("mapping of bmbar io failed, error = %#x\n",card->area_bmbar));
849 		return B_ERROR;
850 	}
851 	LOG(("mapping of bmbar: area %#x, phys %#x, log %#x\n", card->area_bmbar, card->bmbar, card->log_bmbar));
852 
853 #ifndef CARDBUS
854 	cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2);
855 	PRINT(("PCI command before: %x\n", cmd));
856 	(*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2, cmd | PCI_command_io);
857 	cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2);
858 	PRINT(("PCI command after: %x\n", cmd));
859 #endif
860 
861 	card->pEG->AssignResources(card->log_bmbar, name);
862 
863 	ECHOSTATUS status;
864 	status = card->pEG->InitHw();
865 	if (status != ECHOSTATUS_OK)
866 		return B_ERROR;
867 
868 	card->pEG->GetCapabilities(&card->caps);
869 
870 	/* Init streams list */
871 	LIST_INIT(&(card->streams));
872 
873 	/* Init mems list */
874 	LIST_INIT(&(card->mems));
875 
876 #ifdef MIDI_SUPPORT
877 	card->midi.midi_ready_sem = create_sem(0, "midi sem");
878 #endif
879 
880 	PRINT(("installing interrupt : %x\n", card->irq));
881 	install_io_interrupt_handler(card->irq, echo_int, card, 0);
882 
883 	PRINT(("echo_setup done\n"));
884 
885 	echo_dump_caps(card);
886 
887 #ifdef ECHO3G_FAMILY
888 	if (card->type == ECHO3G) {
889 		strncpy(card->caps.szName, ((C3g*)card->pEG)->Get3gBoxName(), ECHO_MAXNAMELEN);
890 	}
891 #endif
892 
893 	status = card->pEG->OpenMixer(card->mixer);
894 	if (status != ECHOSTATUS_OK)
895 		return B_ERROR;
896 
897 	return err;
898 }
899 
900 static void
901 echo_shutdown(echo_dev *card)
902 {
903 	ECHOSTATUS status;
904 
905 	PRINT(("shutdown(%p)\n", card));
906 	status = card->pEG->CloseMixer(card->mixer);
907 	if (status != ECHOSTATUS_OK)
908 		PRINT(("echo_shutdown: error when CloseMixer\n"));
909 
910 	remove_io_interrupt_handler(card->irq, echo_int, card);
911 
912 #ifdef MIDI_SUPPORT
913 	delete_sem(card->midi.midi_ready_sem);
914 #endif
915 
916 	delete card->pEG;
917 	delete card->pOSS;
918 
919 	delete_area(card->area_bmbar);
920 }
921 
922 
923 
924 void
925 uninit_driver(void)
926 {
927 	PRINT(("uninit_driver()\n"));
928 
929 #ifdef CARDBUS
930 	echo_dev			*dev;
931 
932 	LIST_FOREACH(dev, &devices, next) {
933 		echo_shutdown(dev);
934 	}
935 	put_module(CB_ENABLER_MODULE_NAME);
936 #else
937 	int ix, cnt = num_cards;
938 	num_cards = 0;
939 	for (ix=0; ix<cnt; ix++) {
940 		echo_shutdown(&cards[ix]);
941 	}
942 
943 	memset(&cards, 0, sizeof(cards));
944 	put_module(B_PCI_MODULE_NAME);
945 #endif
946 }
947 
948 
949 const char **
950 publish_devices(void)
951 {
952 #ifdef CARDBUS
953 	echo_dev			*dev;
954 	int			ix = 0;
955 
956 	// Lock the devices
957 	acquire_sem(device_lock);
958 	// Loop
959 	LIST_FOREACH(dev, &devices, next) {
960 		if (dev->plugged == true) {
961 			names[ix] = dev->name;
962 			ix++;
963 		}
964 	}
965 	names[ix] = NULL;
966 	release_sem(device_lock);
967 #else
968 	int ix = 0;
969 	PRINT(("publish_devices()\n"));
970 
971 	for (ix=0; names[ix]; ix++) {
972 		PRINT(("publish %s\n", names[ix]));
973 	}
974 #endif
975 	return (const char **)names;
976 }
977 
978 
979 device_hooks *
980 find_device(const char * name)
981 {
982 	echo_dev *dev;
983 #ifdef CARDBUS
984 	LIST_FOREACH(dev, &devices, next) {
985 		if (!strcmp(dev->name, name)) {
986 			return &multi_hooks;
987 		}
988 	}
989 
990 #else
991 	int ix;
992 
993 	PRINT(("find_device(%s)\n", name));
994 
995 	for (ix=0; ix<num_cards; ix++) {
996 #ifdef MIDI_SUPPORT
997 		if (!strcmp(cards[ix].midi.name, name)) {
998 			return &midi_hooks;
999 		}
1000 #endif
1001 		if (!strcmp(cards[ix].name, name)) {
1002 			return &multi_hooks;
1003 		}
1004 	}
1005 #endif
1006 	PRINT(("find_device(%s) failed\n", name));
1007 	return NULL;
1008 }
1009 
1010 int32	api_version = B_CUR_DRIVER_API_VERSION;
1011