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 <unistd.h>
28#include "OsSupportBeOS.h"
29#include "EchoGalsXface.h"
30#include "C3g.h"
31#include "CDarla24.h"
32#include "CDarla.h"
33#include "CGina.h"
34#include "CGina24.h"
35#include "CIndigo.h"
36#include "CIndigoDJ.h"
37#include "CIndigoIO.h"
38#include "CLayla.h"
39#include "CLayla24.h"
40#include "CMia.h"
41#include "CMona.h"
42#include "echo.h"
43#include "debug.h"
44#include "util.h"
45
46#ifdef CARDBUS
47static cb_enabler_module_info	*cbemi;
48struct _echodevs				devices;
49static char						*names[NUM_CARDS];
50int32 							num_names = 0;
51static uint32					device_index = 0;
52static sem_id					device_lock = 0;
53
54static const cb_device_descriptor	descriptors[] = {
55	{VENDOR_ID, DEVICE_ID_56301, 0xff, 0xff, 0xff}
56};
57
58#define COUNT_DESCRIPTOR			1
59
60status_t cardbus_device_added(pci_info *info, void **cookie);
61void cardbus_device_removed(void *cookie);
62
63static cb_notify_hooks	cardbus_hooks = {
64	cardbus_device_added, 		// Add entry point
65	cardbus_device_removed 		// Remove entry point
66};
67
68#else // CARDBUS
69static pci_module_info	*pci;
70int32 num_cards;
71echo_dev cards[NUM_CARDS];
72int32 num_names;
73char * names[NUM_CARDS*20+1];
74#endif // CARDBUS
75
76extern device_hooks multi_hooks;
77#ifdef MIDI_SUPPORT
78extern device_hooks midi_hooks;
79#endif
80
81int32 echo_int(void *arg);
82status_t init_hardware(void);
83status_t init_driver(void);
84static void make_device_names(echo_dev * card);
85
86static status_t echo_setup(echo_dev * card);
87static void echo_shutdown(echo_dev *card);
88
89void uninit_driver(void);
90const char ** publish_devices(void);
91device_hooks * find_device(const char * name);
92
93
94/* Echo Memory management */
95
96echo_mem *
97echo_mem_new(echo_dev *card, size_t size)
98{
99	echo_mem *mem;
100
101	if ((mem = (echo_mem *) malloc(sizeof(*mem))) == NULL)
102		return (NULL);
103
104	mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "echo buffer", true);
105	mem->size = size;
106	if (mem->area < B_OK) {
107		free(mem);
108		return NULL;
109	}
110	return mem;
111}
112
113
114void
115echo_mem_delete(echo_mem *mem)
116{
117	if (mem->area > B_OK)
118		delete_area(mem->area);
119	free(mem);
120}
121
122
123echo_mem *
124echo_mem_alloc(echo_dev *card, size_t size)
125{
126	echo_mem *mem;
127
128	mem = echo_mem_new(card, size);
129	if (mem == NULL)
130		return (NULL);
131
132	LIST_INSERT_HEAD(&(card->mems), mem, next);
133
134	return mem;
135}
136
137
138void
139echo_mem_free(echo_dev *card, void *ptr)
140{
141	echo_mem 		*mem;
142
143	LIST_FOREACH(mem, &card->mems, next) {
144		if (mem->log_base != ptr)
145			continue;
146		LIST_REMOVE(mem, next);
147
148		echo_mem_delete(mem);
149		break;
150	}
151}
152
153/*	Echo stream functions */
154
155extern char *pStatusStrs[ECHOSTATUS_LAST];
156
157status_t
158echo_stream_set_audioparms(echo_stream *stream, uint8 channels,
159	uint8 bitsPerSample, uint32 sample_rate, uint8 index)
160{
161	int32 			i;
162	uint8 			sample_size, frame_size;
163	ECHOGALS_OPENAUDIOPARAMETERS	open_params;
164	ECHOGALS_CLOSEAUDIOPARAMETERS  close_params;
165	ECHOGALS_AUDIOFORMAT			format_params;
166	ECHOSTATUS status;
167
168	LOG(("echo_stream_set_audioparms\n"));
169
170	if (stream->pipe >= 0) {
171		close_params.wPipeIndex = stream->pipe;
172		status = stream->card->pEG->CloseAudio(&close_params);
173		if (status != ECHOSTATUS_OK && status != ECHOSTATUS_CHANNEL_NOT_OPEN) {
174			PRINT(("echo_stream_set_audioparms : CloseAudio failed\n"));
175			PRINT((" status: %s \n", pStatusStrs[status]));
176			return B_ERROR;
177		}
178	}
179
180	open_params.bIsCyclic = TRUE;
181	open_params.Pipe.nPipe = index;
182	open_params.Pipe.bIsInput = stream->use == ECHO_USE_RECORD ? TRUE : FALSE;
183	open_params.Pipe.wInterleave = channels;
184	open_params.ProcessId = NULL;
185
186	status = stream->card->pEG->OpenAudio(&open_params, &stream->pipe);
187	if (status != ECHOSTATUS_OK) {
188		PRINT(("echo_stream_set_audioparms : OpenAudio failed\n"));
189		PRINT((" status: %s \n", pStatusStrs[status]));
190		return B_ERROR;
191	}
192
193	//PRINT(("VerifyAudioOpen\n"));
194	status = stream->card->pEG->VerifyAudioOpen(stream->pipe);
195	if (status != ECHOSTATUS_OK) {
196		PRINT(("echo_stream_set_audioparms : VerifyAudioOpen failed\n"));
197		PRINT(("  status: %s \n", pStatusStrs[status]));
198		return B_ERROR;
199	}
200
201	if (bitsPerSample == 24)
202		bitsPerSample = 32;
203
204	if ((stream->channels == channels)
205		&& (stream->bitsPerSample == bitsPerSample)
206		&& (stream->sample_rate == sample_rate))
207		return B_OK;
208
209	format_params.wBitsPerSample = bitsPerSample;
210	format_params.byDataAreBigEndian = 0;
211	format_params.byMonoToStereo = 0;
212	format_params.wDataInterleave = channels == 1 ? 1 : 2;
213
214	status = stream->card->pEG->QueryAudioFormat(stream->pipe, &format_params);
215	if (status != ECHOSTATUS_OK) {
216		PRINT(("echo_stream_set_audioparms : bad format when querying\n"));
217		PRINT(("  status: %s \n", pStatusStrs[status]));
218		return B_ERROR;
219	}
220
221	status = stream->card->pEG->SetAudioFormat(stream->pipe, &format_params);
222	if (status != ECHOSTATUS_OK) {
223		PRINT(("echo_stream_set_audioparms : bad format when setting\n"));
224		PRINT(("  status: %s \n", pStatusStrs[status]));
225		return B_ERROR;
226	}
227
228	/* XXXX : setting sample rate is global in this driver */
229	status = stream->card->pEG->QueryAudioSampleRate(sample_rate);
230	if (status != ECHOSTATUS_OK) {
231		PRINT(("echo_stream_set_audioparms : bad sample rate when querying\n"));
232		PRINT(("  status: %s \n", pStatusStrs[status]));
233		return B_ERROR;
234	}
235
236	/* XXXX : setting sample rate is global in this driver */
237	status = stream->card->pEG->SetAudioSampleRate(sample_rate);
238	if (status != ECHOSTATUS_OK) {
239		PRINT(("echo_stream_set_audioparms : bad sample rate when setting\n"));
240		PRINT(("  status: %s \n", pStatusStrs[status]));
241		return B_ERROR;
242	}
243
244	if (stream->buffer)
245		echo_mem_free(stream->card, stream->buffer->log_base);
246
247	stream->bitsPerSample = bitsPerSample;
248	stream->sample_rate = sample_rate;
249	stream->channels = channels;
250
251	sample_size = stream->bitsPerSample / 8;
252	frame_size = sample_size * stream->channels;
253
254	stream->buffer = echo_mem_alloc(stream->card,
255		stream->bufframes * frame_size * stream->bufcount);
256
257	stream->trigblk = 1;
258	stream->blkmod = stream->bufcount;
259	stream->blksize = stream->bufframes * frame_size;
260
261	CDaffyDuck *duck = stream->card->pEG->GetDaffyDuck(stream->pipe);
262	if (duck == NULL) {
263		PRINT(("echo_stream_set_audioparms : Could not get daffy duck pointer\n"));
264		return B_ERROR;
265	}
266
267	uint32 dwNumFreeEntries = 0;
268
269	for (i = 0; i < stream->bufcount; i++) {
270		duck->AddMapping(((uint32)stream->buffer->phy_base) +
271			i * stream->blksize, stream->blksize, 0, TRUE, dwNumFreeEntries);
272	}
273
274	duck->Wrap();
275
276	if (stream->card->pEG->GetAudioPositionPtr(stream->pipe, stream->position)!=ECHOSTATUS_OK) {
277		PRINT(("echo_stream_set_audioparms : Could not get audio position ptr\n"));
278		return B_ERROR;
279	}
280
281	return B_OK;
282}
283
284
285status_t
286echo_stream_get_nth_buffer(echo_stream *stream, uint8 chan, uint8 buf,
287	char** buffer, size_t *stride)
288{
289	uint8 			sample_size, frame_size;
290	LOG(("echo_stream_get_nth_buffer\n"));
291
292	sample_size = stream->bitsPerSample / 8;
293	frame_size = sample_size * stream->channels;
294
295	*buffer = (char*)stream->buffer->log_base + (buf * stream->bufframes * frame_size)
296		+ chan * sample_size;
297	*stride = frame_size;
298
299	return B_OK;
300}
301
302
303static uint32
304echo_stream_curaddr(echo_stream *stream)
305{
306	uint32 addr = B_LENDIAN_TO_HOST_INT32(*stream->position);
307//	TRACE(("stream_curaddr %p, phy_base %p\n", addr));
308	return (addr / stream->blksize) % stream->blkmod;
309}
310
311
312void
313echo_stream_start(echo_stream *stream, void (*inth) (void *), void *inthparam)
314{
315	LOG(("echo_stream_start\n"));
316	ECHOSTATUS status;
317
318	stream->inth = inth;
319	stream->inthparam = inthparam;
320
321	stream->state |= ECHO_STATE_STARTED;
322
323	status = stream->card->pEG->Start(stream->pipe);
324	if (status!=ECHOSTATUS_OK) {
325		PRINT(("echo_stream_start : Could not start the pipe %s\n", pStatusStrs[status]));
326	}
327}
328
329
330void
331echo_stream_halt(echo_stream *stream)
332{
333	LOG(("echo_stream_halt\n"));
334	ECHOSTATUS status;
335
336	stream->state &= ~ECHO_STATE_STARTED;
337
338	status = stream->card->pEG->Stop(stream->pipe);
339	if (status!=ECHOSTATUS_OK) {
340		PRINT(("echo_stream_halt : Could not stop the pipe %s\n", pStatusStrs[status]));
341	}
342}
343
344
345echo_stream *
346echo_stream_new(echo_dev *card, uint8 use, uint32 bufframes, uint8 bufcount)
347{
348	echo_stream *stream;
349	cpu_status status;
350	LOG(("echo_stream_new\n"));
351
352	stream = (echo_stream *) malloc(sizeof(echo_stream));
353	if (stream == NULL)
354		return (NULL);
355	stream->card = card;
356	stream->use = use;
357	stream->state = 0;
358	stream->bitsPerSample = 0;
359	stream->sample_rate = 0;
360	stream->channels = 0;
361	stream->bufframes = bufframes;
362	stream->bufcount = bufcount;
363	stream->inth = NULL;
364	stream->inthparam = NULL;
365	stream->buffer = NULL;
366	stream->blksize = 0;
367	stream->trigblk = 0;
368	stream->blkmod = 0;
369
370	stream->pipe = -1;
371
372	stream->frames_count = 0;
373	stream->real_time = 0;
374	stream->buffer_cycle = 0;
375	stream->update_needed = false;
376
377	status = lock();
378	LIST_INSERT_HEAD((&card->streams), stream, next);
379	unlock(status);
380
381	return stream;
382}
383
384
385void
386echo_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
416int32 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 */
456void
457echo_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 */
468status_t
469init_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
531status_t
532init_driver(void)
533{
534	PRINT(("init_driver()\n"));
535
536#ifdef CARDBUS
537	// Get card services client module
538	if (get_module(CB_ENABLER_MODULE_NAME, (module_info **)&cbemi) != B_OK) {
539		dprintf(DRIVER_NAME ": cardbus enabler module error\n");
540		return B_ERROR;
541	}
542	// Create the devices lock
543	device_lock = create_sem(1, DRIVER_NAME " device");
544	if (device_lock < B_OK) {
545		dprintf(DRIVER_NAME ": create device semaphore error 0x%.8x\n", device_lock);
546		put_module(CB_ENABLER_MODULE_NAME);
547		return B_ERROR;
548	}
549	// Register driver
550	cbemi->register_driver(DRIVER_NAME, descriptors, COUNT_DESCRIPTOR);
551	cbemi->install_notify(DRIVER_NAME, &cardbus_hooks);
552	LIST_INIT(&(devices));
553	return B_OK;
554#else
555	int ix = 0;
556
557	pci_info info;
558	status_t err;
559	num_cards = 0;
560
561	if (get_module(B_PCI_MODULE_NAME, (module_info **) &pci))
562		return ENOSYS;
563
564	while ((*pci->get_nth_pci_info)(ix++, &info) == B_OK) {
565		ushort card_type = info.u.h0.subsystem_id & 0xfff0;
566
567		if (info.vendor_id == VENDOR_ID
568			&& ((info.device_id == DEVICE_ID_56301)
569			|| (info.device_id == DEVICE_ID_56361))
570			&& (info.u.h0.subsystem_vendor_id == SUBVENDOR_ID)
571			&& (
572#ifdef ECHOGALS_FAMILY
573			(card_type == DARLA)
574			|| (card_type == GINA)
575			|| (card_type == LAYLA)
576			|| (card_type == DARLA24)
577#endif
578#ifdef ECHO24_FAMILY
579			(card_type == GINA24)
580			|| (card_type == LAYLA24)
581			|| (card_type == MONA)
582			|| (card_type == MIA)
583#endif
584#ifdef INDIGO_FAMILY
585			(card_type == INDIGO)
586			|| (card_type == INDIGO_IO)
587			|| (card_type == INDIGO_DJ)
588#endif
589#ifdef ECHO3G_FAMILY
590			(card_type == ECHO3G)
591#endif
592			)) {
593
594			if (num_cards == NUM_CARDS) {
595				PRINT(("Too many " DRIVER_NAME " cards installed!\n"));
596				break;
597			}
598			memset(&cards[num_cards], 0, sizeof(echo_dev));
599			cards[num_cards].info = info;
600			cards[num_cards].type = card_type;
601#ifdef __HAIKU__
602			if ((err = (*pci->reserve_device)(info.bus, info.device, info.function,
603				DRIVER_NAME, &cards[num_cards])) < B_OK) {
604				dprintf("%s: failed to reserve_device(%d, %d, %d,): %s\n",
605					DRIVER_NAME, info.bus, info.device, info.function,
606					strerror(err));
607				continue;
608			}
609#endif
610			if (echo_setup(&cards[num_cards])) {
611				PRINT(("Setup of " DRIVER_NAME " %" B_PRId32 " failed\n", num_cards + 1));
612#ifdef __HAIKU__
613				(*pci->unreserve_device)(info.bus, info.device, info.function,
614					DRIVER_NAME, &cards[num_cards]);
615#endif
616			}
617			else {
618				num_cards++;
619			}
620		}
621	}
622	if (!num_cards) {
623		PRINT(("no cards\n"));
624		put_module(B_PCI_MODULE_NAME);
625		PRINT(("no suitable cards found\n"));
626		return ENODEV;
627	}
628
629	return B_OK;
630#endif
631}
632
633
634#ifndef CARDBUS
635static void
636make_device_names(echo_dev * card)
637{
638#ifdef MIDI_SUPPORT
639	sprintf(card->midi.name, "midi/" DRIVER_NAME "/%ld", card-cards + 1);
640	names[num_names++] = card->midi.name;
641#endif
642	sprintf(card->name, "audio/hmulti/" DRIVER_NAME "/%ld", card-cards + 1);
643	names[num_names++] = card->name;
644
645	names[num_names] = NULL;
646}
647#else
648
649status_t
650cardbus_device_added(pci_info *info, void **cookie) {
651	echo_dev 			* card, *dev;
652	uint32				index;
653	char				buffer[32];
654
655	LOG(("cardbus_device_added at %.2d:%.2d:%.2d\n", info->bus, info->device, info->function));
656	// Allocate cookie
657	if (!(*cookie = card = (echo_dev *)malloc(sizeof(echo_dev)))) {
658		return B_NO_MEMORY;
659	}
660	// Clear cookie
661	memset(card, 0, sizeof(echo_dev));
662	// Initialize cookie
663	card->info = *info;
664	card->plugged = true;
665	card->index = 0;
666
667	LIST_FOREACH(dev, &devices, next) {
668		if (dev->index == card->index) {
669			card->index++;
670			dev = LIST_FIRST(&devices);
671		}
672	}
673
674	// Format device name
675	sprintf(card->name, "audio/hmulti/" DRIVER_NAME "/%ld", card->index);
676	// Lock the devices
677	acquire_sem(device_lock);
678	LIST_INSERT_HEAD((&devices), card, next);
679	// Unlock the devices
680	release_sem(device_lock);
681
682	echo_setup(card);
683	return B_OK;
684}
685
686
687// cardbus_device_removed - handle cardbus device removal.
688// status : OK
689void
690cardbus_device_removed(void *cookie)
691{
692	echo_dev		*card = (echo_dev *) cookie;
693
694	LOG((": cardbus_device_removed\n"));
695	// Check
696	if (card == NULL) {
697		LOG((": null device 0x%.8x\n", card));
698		return;
699	}
700
701	echo_shutdown(card);
702
703	// Lock the devices
704	acquire_sem(device_lock);
705	// Finalize
706	card->plugged = false;
707	// Check if the device is opened
708	if (card->opened) {
709		LOG(("device 0x%.8x %s still in use\n", card, card->name));
710	} else {
711		LOG(("free device 0x%.8x %s\n", card, card->name));
712		LIST_REMOVE(card, next);
713		free(card);
714	}
715	// Unlock the devices
716	release_sem(device_lock);
717}
718
719#endif
720
721
722static status_t
723echo_setup(echo_dev* card)
724{
725	unsigned char cmd;
726	const char* name;
727
728	PRINT(("echo_setup(%p)\n", card));
729
730#ifndef CARDBUS
731	(*pci->write_pci_config)(card->info.bus, card->info.device,
732		card->info.function, PCI_latency, 1, 0xc0 );
733
734	make_device_names(card);
735#endif
736	card->bmbar = card->info.u.h0.base_registers[0];
737	card->irq = card->info.u.h0.interrupt_line;
738
739	card->area_bmbar = map_mem(&card->log_bmbar, card->bmbar,
740		card->info.u.h0.base_register_sizes[0], DRIVER_NAME" bmbar io");
741	if (card->area_bmbar <= B_OK) {
742		LOG(("mapping of bmbar io failed, error = %#x\n",card->area_bmbar));
743		goto err5;
744	}
745	LOG(("mapping of bmbar: area %#x, phys %#x, log %#x\n", card->area_bmbar,
746		card->bmbar, card->log_bmbar));
747
748	card->pOSS = new COsSupport(card->info.device_id, card->info.revision);
749	if (card->pOSS == NULL)
750		goto err4;
751
752	switch (card->type) {
753#ifdef ECHOGALS_FAMILY
754		case DARLA:
755			card->pEG = new CDarla(card->pOSS);
756			name = "Echo Darla";
757			break;
758		case GINA:
759			card->pEG = new CGina(card->pOSS);
760			name = "Echo Gina";
761			break;
762		case LAYLA:
763			card->pEG = new CLayla(card->pOSS);
764			name = "Echo Layla";
765			break;
766		case DARLA24:
767			card->pEG = new CDarla24(card->pOSS);
768			name = "Echo Darla24";
769			break;
770#endif
771#ifdef ECHO24_FAMILY
772		case GINA24:
773			card->pEG = new CGina24(card->pOSS);
774			name = "Echo Gina24";
775			break;
776		case LAYLA24:
777			card->pEG = new CLayla24(card->pOSS);
778			name = "Echo Layla24";
779			break;
780		case MONA:
781			card->pEG = new CMona(card->pOSS);
782			name = "Echo Mona";
783			break;
784		case MIA:
785			card->pEG = new CMia(card->pOSS);
786			name = "Echo Mia";
787			break;
788#endif
789#ifdef INDIGO_FAMILY
790		case INDIGO:
791			card->pEG = new CIndigo(card->pOSS);
792			name = "Echo Indigo";
793			break;
794		case INDIGO_IO:
795			card->pEG = new CIndigoIO(card->pOSS);
796			name = "Echo IndigoIO";
797			break;
798		case INDIGO_DJ:
799			card->pEG = new CIndigoDJ(card->pOSS);
800			name = "Echo IndigoDJ";
801			break;
802#endif
803#ifdef ECHO3G_FAMILY
804		case ECHO3G:
805			card->pEG = new C3g(card->pOSS);
806			name = "Echo 3g";
807			break;
808#endif
809		default:
810			PRINT(("card type 0x%x not supported by " DRIVER_NAME "\n",
811				card->type));
812			name = "Unknown";
813	}
814
815	if (card->pEG == NULL)
816		goto err2;
817
818#ifndef CARDBUS
819	cmd = (*pci->read_pci_config)(card->info.bus, card->info.device,
820		card->info.function, PCI_command, 2);
821	PRINT(("PCI command before: %x\n", cmd));
822	(*pci->write_pci_config)(card->info.bus, card->info.device,
823		card->info.function, PCI_command, 2, cmd | PCI_command_io);
824	cmd = (*pci->read_pci_config)(card->info.bus, card->info.device,
825		card->info.function, PCI_command, 2);
826	PRINT(("PCI command after: %x\n", cmd));
827#endif
828
829	card->pEG->AssignResources(card->log_bmbar, name);
830
831	ECHOSTATUS status;
832	status = card->pEG->InitHw();
833	if (status != ECHOSTATUS_OK)
834		goto err3;
835
836	card->pEG->GetCapabilities(&card->caps);
837
838	/* Init streams list */
839	LIST_INIT(&(card->streams));
840
841	/* Init mems list */
842	LIST_INIT(&(card->mems));
843
844#ifdef MIDI_SUPPORT
845	card->midi.midi_ready_sem = create_sem(0, "midi sem");
846#endif
847
848	PRINT(("installing interrupt : %x\n", card->irq));
849	status = install_io_interrupt_handler(card->irq, echo_int, card, 0);
850	if (status != B_OK) {
851		PRINT(("failed to install interrupt\n"));
852		goto err2;
853	}
854
855	PRINT(("echo_setup done\n"));
856
857	echo_dump_caps(card);
858
859#ifdef ECHO3G_FAMILY
860	if (card->type == ECHO3G) {
861		strlcpy(card->caps.szName, ((C3g*)card->pEG)->Get3gBoxName(),
862			ECHO_MAXNAMELEN);
863	}
864#endif
865
866	status = card->pEG->OpenMixer(card->mixer);
867	if (status != ECHOSTATUS_OK) {
868		PRINT(("failed to open mixer\n"));
869		goto err1;
870	}
871
872	return B_OK;
873
874err1:
875	remove_io_interrupt_handler(card->irq, echo_int, card);
876err2:
877#ifdef MIDI_SUPPORT
878	delete_sem(card->midi.midi_ready_sem);
879#endif
880err3:
881	delete card->pEG;
882err4:
883	delete card->pOSS;
884err5:
885	delete_area(card->area_bmbar);
886	return B_ERROR;
887}
888
889static void
890echo_shutdown(echo_dev *card)
891{
892	ECHOSTATUS status;
893
894	PRINT(("shutdown(%p)\n", card));
895	status = card->pEG->CloseMixer(card->mixer);
896	if (status != ECHOSTATUS_OK)
897		PRINT(("echo_shutdown: error when CloseMixer\n"));
898
899	remove_io_interrupt_handler(card->irq, echo_int, card);
900
901#ifdef MIDI_SUPPORT
902	delete_sem(card->midi.midi_ready_sem);
903#endif
904
905	delete card->pEG;
906	delete card->pOSS;
907
908	delete_area(card->area_bmbar);
909}
910
911
912
913void
914uninit_driver(void)
915{
916	PRINT(("uninit_driver()\n"));
917
918#ifdef CARDBUS
919	echo_dev			*dev;
920
921	LIST_FOREACH(dev, &devices, next) {
922		echo_shutdown(dev);
923	}
924	put_module(CB_ENABLER_MODULE_NAME);
925#else
926	int ix, cnt = num_cards;
927	num_cards = 0;
928	for (ix=0; ix<cnt; ix++) {
929		echo_shutdown(&cards[ix]);
930#ifdef __HAIKU__
931		(*pci->unreserve_device)(cards[ix].info.bus,
932			cards[ix].info.device, cards[ix].info.function,
933			DRIVER_NAME, &cards[ix]);
934#endif
935	}
936
937	memset(&cards, 0, sizeof(cards));
938	put_module(B_PCI_MODULE_NAME);
939#endif
940}
941
942
943const char **
944publish_devices(void)
945{
946#ifdef CARDBUS
947	echo_dev			*dev;
948	int			ix = 0;
949
950	// Lock the devices
951	acquire_sem(device_lock);
952	// Loop
953	LIST_FOREACH(dev, &devices, next) {
954		if (dev->plugged == true) {
955			names[ix] = dev->name;
956			ix++;
957		}
958	}
959	names[ix] = NULL;
960	release_sem(device_lock);
961#else
962	int ix = 0;
963	PRINT(("publish_devices()\n"));
964
965	for (ix=0; names[ix]; ix++) {
966		PRINT(("publish %s\n", names[ix]));
967	}
968#endif
969	return (const char **)names;
970}
971
972
973device_hooks *
974find_device(const char * name)
975{
976#ifdef CARDBUS
977	echo_dev *dev;
978	LIST_FOREACH(dev, &devices, next) {
979		if (!strcmp(dev->name, name)) {
980			return &multi_hooks;
981		}
982	}
983
984#else
985	int ix;
986
987	PRINT(("find_device(%s)\n", name));
988
989	for (ix=0; ix<num_cards; ix++) {
990#ifdef MIDI_SUPPORT
991		if (!strcmp(cards[ix].midi.name, name)) {
992			return &midi_hooks;
993		}
994#endif
995		if (!strcmp(cards[ix].name, name)) {
996			return &multi_hooks;
997		}
998	}
999#endif
1000	PRINT(("find_device(%s) failed\n", name));
1001	return NULL;
1002}
1003
1004int32	api_version = B_CUR_DRIVER_API_VERSION;
1005