xref: /haiku/src/add-ons/kernel/drivers/audio/echo/echo.cpp (revision d3503944f052536d75afff2b89c0a9f0fdc9e83e)
15adb129eSJérôme Duval //------------------------------------------------------------------------------
25adb129eSJérôme Duval //
35adb129eSJérôme Duval //  EchoGals/Echo24 BeOS Driver for Echo audio cards
45adb129eSJérôme Duval //
55adb129eSJérôme Duval //	Copyright (c) 2003, Jérôme Duval
65adb129eSJérôme Duval //
75adb129eSJérôme Duval //	Permission is hereby granted, free of charge, to any person obtaining a
85adb129eSJérôme Duval //	copy of this software and associated documentation files (the "Software"),
95adb129eSJérôme Duval //	to deal in the Software without restriction, including without limitation
105adb129eSJérôme Duval //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
115adb129eSJérôme Duval //	and/or sell copies of the Software, and to permit persons to whom the
125adb129eSJérôme Duval //	Software is furnished to do so, subject to the following conditions:
135adb129eSJérôme Duval //
145adb129eSJérôme Duval //	The above copyright notice and this permission notice shall be included in
155adb129eSJérôme Duval //	all copies or substantial portions of the Software.
165adb129eSJérôme Duval //
175adb129eSJérôme Duval //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
185adb129eSJérôme Duval //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
195adb129eSJérôme Duval //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
205adb129eSJérôme Duval //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
215adb129eSJérôme Duval //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
225adb129eSJérôme Duval //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
235adb129eSJérôme Duval //	DEALINGS IN THE SOFTWARE.
245adb129eSJérôme Duval 
255adb129eSJérôme Duval #include <KernelExport.h>
265adb129eSJérôme Duval #include <Drivers.h>
275adb129eSJérôme Duval #include <unistd.h>
285adb129eSJérôme Duval #include "OsSupportBeOS.h"
295adb129eSJérôme Duval #include "EchoGalsXface.h"
30c2ddc71cSJérôme Duval #include "C3g.h"
315adb129eSJérôme Duval #include "CDarla24.h"
325adb129eSJérôme Duval #include "CDarla.h"
335adb129eSJérôme Duval #include "CGina.h"
345adb129eSJérôme Duval #include "CGina24.h"
3508661eb2SJérôme Duval #include "CIndigo.h"
3608661eb2SJérôme Duval #include "CIndigoDJ.h"
3708661eb2SJérôme Duval #include "CIndigoIO.h"
385adb129eSJérôme Duval #include "CLayla.h"
395adb129eSJérôme Duval #include "CLayla24.h"
405adb129eSJérôme Duval #include "CMia.h"
415adb129eSJérôme Duval #include "CMona.h"
425adb129eSJérôme Duval #include "echo.h"
435adb129eSJérôme Duval #include "debug.h"
445adb129eSJérôme Duval #include "util.h"
455adb129eSJérôme Duval 
46ec816dffSJérôme Duval #ifdef CARDBUS
47ec816dffSJérôme Duval static cb_enabler_module_info	*cbemi;
48ec816dffSJérôme Duval struct _echodevs				devices;
49ec816dffSJérôme Duval static char						*names[NUM_CARDS];
50ec816dffSJérôme Duval int32 							num_names = 0;
51ec816dffSJérôme Duval static uint32					device_index = 0;
52ec816dffSJérôme Duval static sem_id					device_lock = 0;
53ec816dffSJérôme Duval 
54ec816dffSJérôme Duval static const cb_device_descriptor	descriptors[] = {
55ec816dffSJérôme Duval 	{VENDOR_ID, DEVICE_ID_56301, 0xff, 0xff, 0xff}
56ec816dffSJérôme Duval };
57ec816dffSJérôme Duval 
58ec816dffSJérôme Duval #define COUNT_DESCRIPTOR			1
59ec816dffSJérôme Duval 
60ec816dffSJérôme Duval status_t cardbus_device_added(pci_info *info, void **cookie);
61ec816dffSJérôme Duval void cardbus_device_removed(void *cookie);
62ec816dffSJérôme Duval 
63ec816dffSJérôme Duval static cb_notify_hooks	cardbus_hooks = {
64ec816dffSJérôme Duval 	cardbus_device_added, 		// Add entry point
65ec816dffSJérôme Duval 	cardbus_device_removed 		// Remove entry point
66ec816dffSJérôme Duval };
67ec816dffSJérôme Duval 
68ec816dffSJérôme Duval #else // CARDBUS
695adb129eSJérôme Duval static pci_module_info	*pci;
705adb129eSJérôme Duval int32 num_cards;
715adb129eSJérôme Duval echo_dev cards[NUM_CARDS];
725adb129eSJérôme Duval int32 num_names;
735adb129eSJérôme Duval char * names[NUM_CARDS*20+1];
74ec816dffSJérôme Duval #endif // CARDBUS
755adb129eSJérôme Duval 
765adb129eSJérôme Duval extern device_hooks multi_hooks;
770bb683faSJérôme Duval #ifdef MIDI_SUPPORT
780bb683faSJérôme Duval extern device_hooks midi_hooks;
790bb683faSJérôme Duval #endif
805adb129eSJérôme Duval 
815adb129eSJérôme Duval int32 echo_int(void *arg);
825adb129eSJérôme Duval status_t init_hardware(void);
835adb129eSJérôme Duval status_t init_driver(void);
845adb129eSJérôme Duval static void make_device_names(echo_dev * card);
855adb129eSJérôme Duval 
865adb129eSJérôme Duval static status_t echo_setup(echo_dev * card);
875adb129eSJérôme Duval static void echo_shutdown(echo_dev *card);
885adb129eSJérôme Duval 
895adb129eSJérôme Duval void uninit_driver(void);
905adb129eSJérôme Duval const char ** publish_devices(void);
915adb129eSJérôme Duval device_hooks * find_device(const char * name);
925adb129eSJérôme Duval 
935adb129eSJérôme Duval 
945adb129eSJérôme Duval /* Echo Memory management */
955adb129eSJérôme Duval 
965adb129eSJérôme Duval echo_mem *
echo_mem_new(echo_dev * card,size_t size)975adb129eSJérôme Duval echo_mem_new(echo_dev *card, size_t size)
985adb129eSJérôme Duval {
995adb129eSJérôme Duval 	echo_mem *mem;
1005adb129eSJérôme Duval 
1015adb129eSJérôme Duval 	if ((mem = (echo_mem *) malloc(sizeof(*mem))) == NULL)
1025adb129eSJérôme Duval 		return (NULL);
1035adb129eSJérôme Duval 
104*d3503944SPulkoMandy 	mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "echo buffer", true);
1055adb129eSJérôme Duval 	mem->size = size;
1065adb129eSJérôme Duval 	if (mem->area < B_OK) {
1075adb129eSJérôme Duval 		free(mem);
1085adb129eSJérôme Duval 		return NULL;
1095adb129eSJérôme Duval 	}
1105adb129eSJérôme Duval 	return mem;
1115adb129eSJérôme Duval }
1125adb129eSJérôme Duval 
113e480c1b6SPhilippe Saint-Pierre 
1145adb129eSJérôme Duval void
echo_mem_delete(echo_mem * mem)1155adb129eSJérôme Duval echo_mem_delete(echo_mem *mem)
1165adb129eSJérôme Duval {
1175adb129eSJérôme Duval 	if (mem->area > B_OK)
1185adb129eSJérôme Duval 		delete_area(mem->area);
1195adb129eSJérôme Duval 	free(mem);
1205adb129eSJérôme Duval }
1215adb129eSJérôme Duval 
122e480c1b6SPhilippe Saint-Pierre 
1235adb129eSJérôme Duval echo_mem *
echo_mem_alloc(echo_dev * card,size_t size)1245adb129eSJérôme Duval echo_mem_alloc(echo_dev *card, size_t size)
1255adb129eSJérôme Duval {
1265adb129eSJérôme Duval 	echo_mem *mem;
1275adb129eSJérôme Duval 
1285adb129eSJérôme Duval 	mem = echo_mem_new(card, size);
1295adb129eSJérôme Duval 	if (mem == NULL)
1305adb129eSJérôme Duval 		return (NULL);
1315adb129eSJérôme Duval 
1325adb129eSJérôme Duval 	LIST_INSERT_HEAD(&(card->mems), mem, next);
1335adb129eSJérôme Duval 
1345adb129eSJérôme Duval 	return mem;
1355adb129eSJérôme Duval }
1365adb129eSJérôme Duval 
137e480c1b6SPhilippe Saint-Pierre 
1385adb129eSJérôme Duval void
echo_mem_free(echo_dev * card,void * ptr)1395adb129eSJérôme Duval echo_mem_free(echo_dev *card, void *ptr)
1405adb129eSJérôme Duval {
1415adb129eSJérôme Duval 	echo_mem 		*mem;
1425adb129eSJérôme Duval 
1435adb129eSJérôme Duval 	LIST_FOREACH(mem, &card->mems, next) {
1445adb129eSJérôme Duval 		if (mem->log_base != ptr)
1455adb129eSJérôme Duval 			continue;
1465adb129eSJérôme Duval 		LIST_REMOVE(mem, next);
1475adb129eSJérôme Duval 
1485adb129eSJérôme Duval 		echo_mem_delete(mem);
1495adb129eSJérôme Duval 		break;
1505adb129eSJérôme Duval 	}
1515adb129eSJérôme Duval }
1525adb129eSJérôme Duval 
1535adb129eSJérôme Duval /*	Echo stream functions */
1545adb129eSJérôme Duval 
1559524098cSshatty extern char *pStatusStrs[ECHOSTATUS_LAST];
1569524098cSshatty 
1575adb129eSJérôme Duval status_t
echo_stream_set_audioparms(echo_stream * stream,uint8 channels,uint8 bitsPerSample,uint32 sample_rate,uint8 index)1585adb129eSJérôme Duval echo_stream_set_audioparms(echo_stream *stream, uint8 channels,
159c9002531SJérôme Duval 	uint8 bitsPerSample, uint32 sample_rate, uint8 index)
1605adb129eSJérôme Duval {
1615adb129eSJérôme Duval 	int32 			i;
1625adb129eSJérôme Duval 	uint8 			sample_size, frame_size;
1635adb129eSJérôme Duval 	ECHOGALS_OPENAUDIOPARAMETERS	open_params;
1645adb129eSJérôme Duval 	ECHOGALS_CLOSEAUDIOPARAMETERS  close_params;
1655adb129eSJérôme Duval 	ECHOGALS_AUDIOFORMAT			format_params;
1669524098cSshatty 	ECHOSTATUS status;
1675adb129eSJérôme Duval 
1685adb129eSJérôme Duval 	LOG(("echo_stream_set_audioparms\n"));
1695adb129eSJérôme Duval 
1704aeaaaaeSJérôme Duval 	if (stream->pipe >= 0) {
1715adb129eSJérôme Duval 		close_params.wPipeIndex = stream->pipe;
1729524098cSshatty 		status = stream->card->pEG->CloseAudio(&close_params);
1732eabcdebSshatty 		if (status != ECHOSTATUS_OK && status != ECHOSTATUS_CHANNEL_NOT_OPEN) {
1749524098cSshatty 			PRINT(("echo_stream_set_audioparms : CloseAudio failed\n"));
1755608ef1aSJérôme Duval 			PRINT((" status: %s \n", pStatusStrs[status]));
1769524098cSshatty 			return B_ERROR;
1779524098cSshatty 		}
1784aeaaaaeSJérôme Duval 	}
1795adb129eSJérôme Duval 
1805adb129eSJérôme Duval 	open_params.bIsCyclic = TRUE;
181c9002531SJérôme Duval 	open_params.Pipe.nPipe = index;
1825adb129eSJérôme Duval 	open_params.Pipe.bIsInput = stream->use == ECHO_USE_RECORD ? TRUE : FALSE;
18304980002Sshatty 	open_params.Pipe.wInterleave = channels;
18404980002Sshatty 	open_params.ProcessId = NULL;
1855adb129eSJérôme Duval 
1869524098cSshatty 	status = stream->card->pEG->OpenAudio(&open_params, &stream->pipe);
1879524098cSshatty 	if (status != ECHOSTATUS_OK) {
1889524098cSshatty 		PRINT(("echo_stream_set_audioparms : OpenAudio failed\n"));
189c9002531SJérôme Duval 		PRINT((" status: %s \n", pStatusStrs[status]));
1909524098cSshatty 		return B_ERROR;
1919524098cSshatty 	}
1925adb129eSJérôme Duval 
19392b10541Sshatty 	//PRINT(("VerifyAudioOpen\n"));
1942eabcdebSshatty 	status = stream->card->pEG->VerifyAudioOpen(stream->pipe);
1952eabcdebSshatty 	if (status != ECHOSTATUS_OK) {
1962eabcdebSshatty 		PRINT(("echo_stream_set_audioparms : VerifyAudioOpen failed\n"));
197c9002531SJérôme Duval 		PRINT(("  status: %s \n", pStatusStrs[status]));
1982eabcdebSshatty 		return B_ERROR;
1992eabcdebSshatty 	}
200f0a85f97SJérôme Duval 
201f0a85f97SJérôme Duval 	if (bitsPerSample == 24)
202f0a85f97SJérôme Duval 		bitsPerSample = 32;
2032eabcdebSshatty 
204ac0b3253SJérôme Duval 	if ((stream->channels == channels)
205ac0b3253SJérôme Duval 		&& (stream->bitsPerSample == bitsPerSample)
206ac0b3253SJérôme Duval 		&& (stream->sample_rate == sample_rate))
2075adb129eSJérôme Duval 		return B_OK;
2085adb129eSJérôme Duval 
20904980002Sshatty 	format_params.wBitsPerSample = bitsPerSample;
2105adb129eSJérôme Duval 	format_params.byDataAreBigEndian = 0;
2115adb129eSJérôme Duval 	format_params.byMonoToStereo = 0;
2125adb129eSJérôme Duval 	format_params.wDataInterleave = channels == 1 ? 1 : 2;
2135adb129eSJérôme Duval 
2149524098cSshatty 	status = stream->card->pEG->QueryAudioFormat(stream->pipe, &format_params);
2159524098cSshatty 	if (status != ECHOSTATUS_OK) {
2165adb129eSJérôme Duval 		PRINT(("echo_stream_set_audioparms : bad format when querying\n"));
217c9002531SJérôme Duval 		PRINT(("  status: %s \n", pStatusStrs[status]));
2185adb129eSJérôme Duval 		return B_ERROR;
2195adb129eSJérôme Duval 	}
2205adb129eSJérôme Duval 
22104980002Sshatty 	status = stream->card->pEG->SetAudioFormat(stream->pipe, &format_params);
2229524098cSshatty 	if (status != ECHOSTATUS_OK) {
22304980002Sshatty 		PRINT(("echo_stream_set_audioparms : bad format when setting\n"));
224c9002531SJérôme Duval 		PRINT(("  status: %s \n", pStatusStrs[status]));
2255adb129eSJérôme Duval 		return B_ERROR;
2265adb129eSJérôme Duval 	}
2275adb129eSJérôme Duval 
22804980002Sshatty 	/* XXXX : setting sample rate is global in this driver */
22904980002Sshatty 	status = stream->card->pEG->QueryAudioSampleRate(sample_rate);
2309524098cSshatty 	if (status != ECHOSTATUS_OK) {
23104980002Sshatty 		PRINT(("echo_stream_set_audioparms : bad sample rate when querying\n"));
232c9002531SJérôme Duval 		PRINT(("  status: %s \n", pStatusStrs[status]));
2335adb129eSJérôme Duval 		return B_ERROR;
2345adb129eSJérôme Duval 	}
2355adb129eSJérôme Duval 
2365adb129eSJérôme Duval 	/* XXXX : setting sample rate is global in this driver */
2379524098cSshatty 	status = stream->card->pEG->SetAudioSampleRate(sample_rate);
2389524098cSshatty 	if (status != ECHOSTATUS_OK) {
2395adb129eSJérôme Duval 		PRINT(("echo_stream_set_audioparms : bad sample rate when setting\n"));
2409524098cSshatty 		PRINT(("  status: %s \n", pStatusStrs[status]));
2415adb129eSJérôme Duval 		return B_ERROR;
2425adb129eSJérôme Duval 	}
2435adb129eSJérôme Duval 
2445adb129eSJérôme Duval 	if (stream->buffer)
2455adb129eSJérôme Duval 		echo_mem_free(stream->card, stream->buffer->log_base);
2465adb129eSJérôme Duval 
24704980002Sshatty 	stream->bitsPerSample = bitsPerSample;
2485adb129eSJérôme Duval 	stream->sample_rate = sample_rate;
2495adb129eSJérôme Duval 	stream->channels = channels;
2505adb129eSJérôme Duval 
25104980002Sshatty 	sample_size = stream->bitsPerSample / 8;
2525adb129eSJérôme Duval 	frame_size = sample_size * stream->channels;
2535adb129eSJérôme Duval 
254e480c1b6SPhilippe Saint-Pierre 	stream->buffer = echo_mem_alloc(stream->card,
255e480c1b6SPhilippe Saint-Pierre 		stream->bufframes * frame_size * stream->bufcount);
2565adb129eSJérôme Duval 
25792b10541Sshatty 	stream->trigblk = 1;
2585adb129eSJérôme Duval 	stream->blkmod = stream->bufcount;
2595adb129eSJérôme Duval 	stream->blksize = stream->bufframes * frame_size;
2605adb129eSJérôme Duval 
2615adb129eSJérôme Duval 	CDaffyDuck *duck = stream->card->pEG->GetDaffyDuck(stream->pipe);
2625adb129eSJérôme Duval 	if (duck == NULL) {
2635adb129eSJérôme Duval 		PRINT(("echo_stream_set_audioparms : Could not get daffy duck pointer\n"));
2645adb129eSJérôme Duval 		return B_ERROR;
2655adb129eSJérôme Duval 	}
2665adb129eSJérôme Duval 
2675adb129eSJérôme Duval 	uint32 dwNumFreeEntries = 0;
2685adb129eSJérôme Duval 
2695adb129eSJérôme Duval 	for (i = 0; i < stream->bufcount; i++) {
2705adb129eSJérôme Duval 		duck->AddMapping(((uint32)stream->buffer->phy_base) +
2715adb129eSJérôme Duval 			i * stream->blksize, stream->blksize, 0, TRUE, dwNumFreeEntries);
2725adb129eSJérôme Duval 	}
2735adb129eSJérôme Duval 
2745adb129eSJérôme Duval 	duck->Wrap();
2755adb129eSJérôme Duval 
2765adb129eSJérôme Duval 	if (stream->card->pEG->GetAudioPositionPtr(stream->pipe, stream->position)!=ECHOSTATUS_OK) {
2775adb129eSJérôme Duval 		PRINT(("echo_stream_set_audioparms : Could not get audio position ptr\n"));
2785adb129eSJérôme Duval 		return B_ERROR;
2795adb129eSJérôme Duval 	}
2805adb129eSJérôme Duval 
2815adb129eSJérôme Duval 	return B_OK;
2825adb129eSJérôme Duval }
2835adb129eSJérôme Duval 
2845adb129eSJérôme Duval 
2855adb129eSJérôme Duval status_t
echo_stream_get_nth_buffer(echo_stream * stream,uint8 chan,uint8 buf,char ** buffer,size_t * stride)2865adb129eSJérôme Duval echo_stream_get_nth_buffer(echo_stream *stream, uint8 chan, uint8 buf,
2875adb129eSJérôme Duval 	char** buffer, size_t *stride)
2885adb129eSJérôme Duval {
2895adb129eSJérôme Duval 	uint8 			sample_size, frame_size;
2905adb129eSJérôme Duval 	LOG(("echo_stream_get_nth_buffer\n"));
2915adb129eSJérôme Duval 
29204980002Sshatty 	sample_size = stream->bitsPerSample / 8;
2935adb129eSJérôme Duval 	frame_size = sample_size * stream->channels;
2945adb129eSJérôme Duval 
2955adb129eSJérôme Duval 	*buffer = (char*)stream->buffer->log_base + (buf * stream->bufframes * frame_size)
2965adb129eSJérôme Duval 		+ chan * sample_size;
2975adb129eSJérôme Duval 	*stride = frame_size;
2985adb129eSJérôme Duval 
2995adb129eSJérôme Duval 	return B_OK;
3005adb129eSJérôme Duval }
3015adb129eSJérôme Duval 
3025adb129eSJérôme Duval 
3035adb129eSJérôme Duval static uint32
echo_stream_curaddr(echo_stream * stream)3045adb129eSJérôme Duval echo_stream_curaddr(echo_stream *stream)
3055adb129eSJérôme Duval {
30692b10541Sshatty 	uint32 addr = B_LENDIAN_TO_HOST_INT32(*stream->position);
30792b10541Sshatty //	TRACE(("stream_curaddr %p, phy_base %p\n", addr));
308da249551Sshatty 	return (addr / stream->blksize) % stream->blkmod;
3095adb129eSJérôme Duval }
3105adb129eSJérôme Duval 
3115adb129eSJérôme Duval 
3125adb129eSJérôme Duval void
echo_stream_start(echo_stream * stream,void (* inth)(void *),void * inthparam)3135adb129eSJérôme Duval echo_stream_start(echo_stream *stream, void (*inth) (void *), void *inthparam)
3145adb129eSJérôme Duval {
3155adb129eSJérôme Duval 	LOG(("echo_stream_start\n"));
3165608ef1aSJérôme Duval 	ECHOSTATUS status;
3175adb129eSJérôme Duval 
3185adb129eSJérôme Duval 	stream->inth = inth;
3195adb129eSJérôme Duval 	stream->inthparam = inthparam;
3205adb129eSJérôme Duval 
3215adb129eSJérôme Duval 	stream->state |= ECHO_STATE_STARTED;
3225adb129eSJérôme Duval 
3235608ef1aSJérôme Duval 	status = stream->card->pEG->Start(stream->pipe);
3245608ef1aSJérôme Duval 	if (status!=ECHOSTATUS_OK) {
3255608ef1aSJérôme Duval 		PRINT(("echo_stream_start : Could not start the pipe %s\n", pStatusStrs[status]));
3265adb129eSJérôme Duval 	}
3275adb129eSJérôme Duval }
3285adb129eSJérôme Duval 
329e480c1b6SPhilippe Saint-Pierre 
3305adb129eSJérôme Duval void
echo_stream_halt(echo_stream * stream)3315adb129eSJérôme Duval echo_stream_halt(echo_stream *stream)
3325adb129eSJérôme Duval {
3335adb129eSJérôme Duval 	LOG(("echo_stream_halt\n"));
3345608ef1aSJérôme Duval 	ECHOSTATUS status;
3355adb129eSJérôme Duval 
3365adb129eSJérôme Duval 	stream->state &= ~ECHO_STATE_STARTED;
3375adb129eSJérôme Duval 
3385608ef1aSJérôme Duval 	status = stream->card->pEG->Stop(stream->pipe);
3395608ef1aSJérôme Duval 	if (status!=ECHOSTATUS_OK) {
3405608ef1aSJérôme Duval 		PRINT(("echo_stream_halt : Could not stop the pipe %s\n", pStatusStrs[status]));
3415adb129eSJérôme Duval 	}
3425adb129eSJérôme Duval }
3435adb129eSJérôme Duval 
344e480c1b6SPhilippe Saint-Pierre 
3455adb129eSJérôme Duval echo_stream *
echo_stream_new(echo_dev * card,uint8 use,uint32 bufframes,uint8 bufcount)3465adb129eSJérôme Duval echo_stream_new(echo_dev *card, uint8 use, uint32 bufframes, uint8 bufcount)
3475adb129eSJérôme Duval {
3485adb129eSJérôme Duval 	echo_stream *stream;
3495adb129eSJérôme Duval 	cpu_status status;
3505adb129eSJérôme Duval 	LOG(("echo_stream_new\n"));
3515adb129eSJérôme Duval 
3525adb129eSJérôme Duval 	stream = (echo_stream *) malloc(sizeof(echo_stream));
3535adb129eSJérôme Duval 	if (stream == NULL)
3545adb129eSJérôme Duval 		return (NULL);
3555adb129eSJérôme Duval 	stream->card = card;
3565adb129eSJérôme Duval 	stream->use = use;
357*d3503944SPulkoMandy 	stream->state = 0;
35804980002Sshatty 	stream->bitsPerSample = 0;
3595adb129eSJérôme Duval 	stream->sample_rate = 0;
3605adb129eSJérôme Duval 	stream->channels = 0;
3615adb129eSJérôme Duval 	stream->bufframes = bufframes;
3625adb129eSJérôme Duval 	stream->bufcount = bufcount;
3635adb129eSJérôme Duval 	stream->inth = NULL;
3645adb129eSJérôme Duval 	stream->inthparam = NULL;
3655adb129eSJérôme Duval 	stream->buffer = NULL;
3665adb129eSJérôme Duval 	stream->blksize = 0;
3675adb129eSJérôme Duval 	stream->trigblk = 0;
3685adb129eSJérôme Duval 	stream->blkmod = 0;
3695adb129eSJérôme Duval 
3705608ef1aSJérôme Duval 	stream->pipe = -1;
3715adb129eSJérôme Duval 
3725adb129eSJérôme Duval 	stream->frames_count = 0;
3735adb129eSJérôme Duval 	stream->real_time = 0;
37481a7deddSJérôme Duval 	stream->buffer_cycle = 0;
3755adb129eSJérôme Duval 	stream->update_needed = false;
3765adb129eSJérôme Duval 
3775adb129eSJérôme Duval 	status = lock();
3785adb129eSJérôme Duval 	LIST_INSERT_HEAD((&card->streams), stream, next);
3795adb129eSJérôme Duval 	unlock(status);
3805adb129eSJérôme Duval 
3815adb129eSJérôme Duval 	return stream;
3825adb129eSJérôme Duval }
3835adb129eSJérôme Duval 
384e480c1b6SPhilippe Saint-Pierre 
3855adb129eSJérôme Duval void
echo_stream_delete(echo_stream * stream)3865adb129eSJérôme Duval echo_stream_delete(echo_stream *stream)
3875adb129eSJérôme Duval {
3885adb129eSJérôme Duval 	cpu_status status;
389b5f75a7eSJérôme Duval 	ECHOGALS_CLOSEAUDIOPARAMETERS close_params;
3905adb129eSJérôme Duval 	LOG(("echo_stream_delete\n"));
3915adb129eSJérôme Duval 
3925adb129eSJérôme Duval 	echo_stream_halt(stream);
3935adb129eSJérôme Duval 
394b5f75a7eSJérôme Duval 	if (stream->pipe >= 0) {
395b5f75a7eSJérôme Duval 		close_params.wPipeIndex = stream->pipe;
396b5f75a7eSJérôme Duval 		status = stream->card->pEG->CloseAudio(&close_params);
397b5f75a7eSJérôme Duval 		if (status != ECHOSTATUS_OK && status != ECHOSTATUS_CHANNEL_NOT_OPEN) {
398b5f75a7eSJérôme Duval 			PRINT(("echo_stream_set_audioparms : CloseAudio failed\n"));
399b5f75a7eSJérôme Duval 			PRINT((" status: %s \n", pStatusStrs[status]));
400b5f75a7eSJérôme Duval 		}
401b5f75a7eSJérôme Duval 	}
402b5f75a7eSJérôme Duval 
4035adb129eSJérôme Duval 	if (stream->buffer)
4045adb129eSJérôme Duval 		echo_mem_free(stream->card, stream->buffer->log_base);
4055adb129eSJérôme Duval 
4065adb129eSJérôme Duval 	status = lock();
4075adb129eSJérôme Duval 	LIST_REMOVE(stream, next);
4085adb129eSJérôme Duval 	unlock(status);
4095adb129eSJérôme Duval 
4105adb129eSJérôme Duval 	free(stream);
4115adb129eSJérôme Duval }
4125adb129eSJérôme Duval 
4135adb129eSJérôme Duval 
4145adb129eSJérôme Duval /* Echo interrupt */
4155adb129eSJérôme Duval 
echo_int(void * arg)4165adb129eSJérôme Duval int32 echo_int(void *arg)
4175adb129eSJérôme Duval {
4185adb129eSJérôme Duval 	echo_dev* card = (echo_dev*)arg;
4195adb129eSJérôme Duval 	BOOL midiReceived;
4205adb129eSJérôme Duval 	ECHOSTATUS err;
4215adb129eSJérôme Duval 	echo_stream* stream;
4225adb129eSJérôme Duval 	uint32 curblk;
4235adb129eSJérôme Duval 
4245adb129eSJérôme Duval 	err = card->pEG->ServiceIrq(midiReceived);
4255adb129eSJérôme Duval 
42692b10541Sshatty 	if (err != ECHOSTATUS_OK) {
42792b10541Sshatty 		return B_UNHANDLED_INTERRUPT;
42892b10541Sshatty 	}
42992b10541Sshatty 
4300bb683faSJérôme Duval #ifdef MIDI_SUPPORT
4310bb683faSJérôme Duval 	if (midiReceived)
43289f3467fSJérôme Duval 		release_sem_etc(card->midi.midi_ready_sem, 1, B_DO_NOT_RESCHEDULE);
4330bb683faSJérôme Duval #endif
4340bb683faSJérôme Duval 
4355adb129eSJérôme Duval 	LIST_FOREACH(stream, &card->streams, next) {
43692b10541Sshatty 		if ((stream->state & ECHO_STATE_STARTED) == 0 ||
4375adb129eSJérôme Duval 			(stream->inth == NULL))
4385adb129eSJérôme Duval 				continue;
4395adb129eSJérôme Duval 
440da249551Sshatty 		curblk = echo_stream_curaddr(stream);
441da249551Sshatty 		//TRACE(("echo_int stream %p at trigblk %lu at stream->trigblk %lu\n",
442da249551Sshatty 		//	   stream, curblk, stream->trigblk));
4435adb129eSJérôme Duval 		if (curblk == stream->trigblk) {
4445adb129eSJérôme Duval 			if (stream->inth)
4455adb129eSJérôme Duval 				stream->inth(stream->inthparam);
4465adb129eSJérôme Duval 
4475adb129eSJérôme Duval 			stream->trigblk++;
448da249551Sshatty 			stream->trigblk %= stream->blkmod;
4495adb129eSJérôme Duval 		}
4505adb129eSJérôme Duval 	}
4515adb129eSJérôme Duval 
45292b10541Sshatty 	return B_INVOKE_SCHEDULER;
4535adb129eSJérôme Duval }
4545adb129eSJérôme Duval 
455c9002531SJérôme Duval /* dumps card capabilities */
456c9002531SJérôme Duval void
echo_dump_caps(echo_dev * card)457c9002531SJérôme Duval echo_dump_caps(echo_dev *card)
458c9002531SJérôme Duval {
459c9002531SJérôme Duval 	PECHOGALS_CAPS caps = &card->caps;
460c9002531SJérôme Duval 	PRINT(("name: %s\n", caps->szName));
461c9002531SJérôme Duval 	PRINT(("out pipes: %d, in pipes: %d, out busses: %d, in busses: %d, out midi: %d, in midi: %d\n",
462c9002531SJérôme Duval 		caps->wNumPipesOut, caps->wNumPipesIn, caps->wNumBussesOut, caps->wNumBussesIn, caps->wNumMidiOut, caps->wNumMidiIn));
463c9002531SJérôme Duval 
464c9002531SJérôme Duval }
465c9002531SJérôme Duval 
466c9002531SJérôme Duval 
4675adb129eSJérôme Duval /* detect presence of our hardware */
4685adb129eSJérôme Duval status_t
init_hardware(void)4695adb129eSJérôme Duval init_hardware(void)
4705adb129eSJérôme Duval {
471ec816dffSJérôme Duval #ifdef CARDBUS
472ec816dffSJérôme Duval 	return B_OK;
473ec816dffSJérôme Duval #else
4745adb129eSJérôme Duval 	int ix = 0;
4755adb129eSJérôme Duval 	pci_info info;
4765adb129eSJérôme Duval 	status_t err = ENODEV;
4775adb129eSJérôme Duval 
4785adb129eSJérôme Duval 	LOG_CREATE();
4795adb129eSJérôme Duval 
4805adb129eSJérôme Duval 	PRINT(("init_hardware()\n"));
4815adb129eSJérôme Duval 
48215a2aa68SJérôme Duval 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci))
4835adb129eSJérôme Duval 		return ENOSYS;
4845adb129eSJérôme Duval 
4855adb129eSJérôme Duval 	while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
4865adb129eSJérôme Duval 
4875adb129eSJérôme Duval 		ushort card_type = info.u.h0.subsystem_id & 0xfff0;
4885adb129eSJérôme Duval 
489ac0b3253SJérôme Duval 		if (info.vendor_id == VENDOR_ID
490ac0b3253SJérôme Duval 			&& ((info.device_id == DEVICE_ID_56301)
491ac0b3253SJérôme Duval 			|| (info.device_id == DEVICE_ID_56361))
492ac0b3253SJérôme Duval 			&& (info.u.h0.subsystem_vendor_id == SUBVENDOR_ID)
493ac0b3253SJérôme Duval 			&& (
4945adb129eSJérôme Duval #ifdef ECHOGALS_FAMILY
4955adb129eSJérôme Duval 			(card_type == DARLA)
4965adb129eSJérôme Duval 			|| (card_type == GINA)
4975adb129eSJérôme Duval 			|| (card_type == LAYLA)
4985adb129eSJérôme Duval 			|| (card_type == DARLA24)
4995adb129eSJérôme Duval #endif
5005adb129eSJérôme Duval #ifdef ECHO24_FAMILY
5015adb129eSJérôme Duval 			(card_type == GINA24)
5025adb129eSJérôme Duval 			|| (card_type == LAYLA24)
5035adb129eSJérôme Duval 			|| (card_type == MONA)
5045adb129eSJérôme Duval 			|| (card_type == MIA)
50508661eb2SJérôme Duval #endif
50608661eb2SJérôme Duval #ifdef INDIGO_FAMILY
50708661eb2SJérôme Duval 			(card_type == INDIGO)
508c2ddc71cSJérôme Duval 			|| (card_type == INDIGO_IO)
509c2ddc71cSJérôme Duval 			|| (card_type == INDIGO_DJ)
51008661eb2SJérôme Duval #endif
51108661eb2SJérôme Duval #ifdef ECHO3G_FAMILY
51208661eb2SJérôme Duval 			(card_type == ECHO3G)
5135adb129eSJérôme Duval #endif
5145adb129eSJérôme Duval 			 )) {
5155adb129eSJérôme Duval 			err = B_OK;
5165adb129eSJérôme Duval 		}
5175adb129eSJérôme Duval 		ix++;
5185adb129eSJérôme Duval 	}
5195adb129eSJérôme Duval 
52015a2aa68SJérôme Duval 	put_module(B_PCI_MODULE_NAME);
5215adb129eSJérôme Duval 
5225adb129eSJérôme Duval 	if (err != B_OK) {
5235adb129eSJérôme Duval 		PRINT(("no card found\n"));
5245adb129eSJérôme Duval 	}
5255adb129eSJérôme Duval 
5265adb129eSJérôme Duval 	return err;
527ec816dffSJérôme Duval #endif
5285adb129eSJérôme Duval }
5295adb129eSJérôme Duval 
5305adb129eSJérôme Duval 
5315adb129eSJérôme Duval status_t
init_driver(void)5325adb129eSJérôme Duval init_driver(void)
5335adb129eSJérôme Duval {
534bd9d5861SJérôme Duval 	PRINT(("init_driver()\n"));
535bd9d5861SJérôme Duval 
536ec816dffSJérôme Duval #ifdef CARDBUS
537ec816dffSJérôme Duval 	// Get card services client module
538ec816dffSJérôme Duval 	if (get_module(CB_ENABLER_MODULE_NAME, (module_info **)&cbemi) != B_OK) {
539ec816dffSJérôme Duval 		dprintf(DRIVER_NAME ": cardbus enabler module error\n");
54015a2aa68SJérôme Duval 		return B_ERROR;
541ec816dffSJérôme Duval 	}
542ec816dffSJérôme Duval 	// Create the devices lock
543ec816dffSJérôme Duval 	device_lock = create_sem(1, DRIVER_NAME " device");
544ec816dffSJérôme Duval 	if (device_lock < B_OK) {
545ec816dffSJérôme Duval 		dprintf(DRIVER_NAME ": create device semaphore error 0x%.8x\n", device_lock);
546ec816dffSJérôme Duval 		put_module(CB_ENABLER_MODULE_NAME);
54715a2aa68SJérôme Duval 		return B_ERROR;
548ec816dffSJérôme Duval 	}
549ec816dffSJérôme Duval 	// Register driver
550ec816dffSJérôme Duval 	cbemi->register_driver(DRIVER_NAME, descriptors, COUNT_DESCRIPTOR);
551ec816dffSJérôme Duval 	cbemi->install_notify(DRIVER_NAME, &cardbus_hooks);
552ec816dffSJérôme Duval 	LIST_INIT(&(devices));
553ec816dffSJérôme Duval 	return B_OK;
554ec816dffSJérôme Duval #else
5555adb129eSJérôme Duval 	int ix = 0;
5565adb129eSJérôme Duval 
5575adb129eSJérôme Duval 	pci_info info;
558bbb55d15SFrançois Revol 	status_t err;
5595adb129eSJérôme Duval 	num_cards = 0;
5605adb129eSJérôme Duval 
56115a2aa68SJérôme Duval 	if (get_module(B_PCI_MODULE_NAME, (module_info **) &pci))
5625adb129eSJérôme Duval 		return ENOSYS;
5635adb129eSJérôme Duval 
564ee9a07fcSFrançois Revol 	while ((*pci->get_nth_pci_info)(ix++, &info) == B_OK) {
5655adb129eSJérôme Duval 		ushort card_type = info.u.h0.subsystem_id & 0xfff0;
5665adb129eSJérôme Duval 
567ac0b3253SJérôme Duval 		if (info.vendor_id == VENDOR_ID
568ac0b3253SJérôme Duval 			&& ((info.device_id == DEVICE_ID_56301)
569ac0b3253SJérôme Duval 			|| (info.device_id == DEVICE_ID_56361))
570ac0b3253SJérôme Duval 			&& (info.u.h0.subsystem_vendor_id == SUBVENDOR_ID)
571ac0b3253SJérôme Duval 			&& (
5725adb129eSJérôme Duval #ifdef ECHOGALS_FAMILY
5735adb129eSJérôme Duval 			(card_type == DARLA)
5745adb129eSJérôme Duval 			|| (card_type == GINA)
5755adb129eSJérôme Duval 			|| (card_type == LAYLA)
5765adb129eSJérôme Duval 			|| (card_type == DARLA24)
5775adb129eSJérôme Duval #endif
5785adb129eSJérôme Duval #ifdef ECHO24_FAMILY
5795adb129eSJérôme Duval 			(card_type == GINA24)
5805adb129eSJérôme Duval 			|| (card_type == LAYLA24)
5815adb129eSJérôme Duval 			|| (card_type == MONA)
5825adb129eSJérôme Duval 			|| (card_type == MIA)
58308661eb2SJérôme Duval #endif
58408661eb2SJérôme Duval #ifdef INDIGO_FAMILY
58508661eb2SJérôme Duval 			(card_type == INDIGO)
586c2ddc71cSJérôme Duval 			|| (card_type == INDIGO_IO)
587c2ddc71cSJérôme Duval 			|| (card_type == INDIGO_DJ)
58808661eb2SJérôme Duval #endif
58908661eb2SJérôme Duval #ifdef ECHO3G_FAMILY
59008661eb2SJérôme Duval 			(card_type == ECHO3G)
5915adb129eSJérôme Duval #endif
5925adb129eSJérôme Duval 			)) {
5935adb129eSJérôme Duval 
5945adb129eSJérôme Duval 			if (num_cards == NUM_CARDS) {
5955adb129eSJérôme Duval 				PRINT(("Too many " DRIVER_NAME " cards installed!\n"));
5965adb129eSJérôme Duval 				break;
5975adb129eSJérôme Duval 			}
5985adb129eSJérôme Duval 			memset(&cards[num_cards], 0, sizeof(echo_dev));
5995adb129eSJérôme Duval 			cards[num_cards].info = info;
6005adb129eSJérôme Duval 			cards[num_cards].type = card_type;
601bbb55d15SFrançois Revol #ifdef __HAIKU__
602bbb55d15SFrançois Revol 			if ((err = (*pci->reserve_device)(info.bus, info.device, info.function,
603bbb55d15SFrançois Revol 				DRIVER_NAME, &cards[num_cards])) < B_OK) {
604bbb55d15SFrançois Revol 				dprintf("%s: failed to reserve_device(%d, %d, %d,): %s\n",
605bbb55d15SFrançois Revol 					DRIVER_NAME, info.bus, info.device, info.function,
606bbb55d15SFrançois Revol 					strerror(err));
607bbb55d15SFrançois Revol 				continue;
608bbb55d15SFrançois Revol 			}
609bbb55d15SFrançois Revol #endif
6105adb129eSJérôme Duval 			if (echo_setup(&cards[num_cards])) {
611*d3503944SPulkoMandy 				PRINT(("Setup of " DRIVER_NAME " %" B_PRId32 " failed\n", num_cards + 1));
612bbb55d15SFrançois Revol #ifdef __HAIKU__
613bbb55d15SFrançois Revol 				(*pci->unreserve_device)(info.bus, info.device, info.function,
614bbb55d15SFrançois Revol 					DRIVER_NAME, &cards[num_cards]);
615bbb55d15SFrançois Revol #endif
6165adb129eSJérôme Duval 			}
6175adb129eSJérôme Duval 			else {
6185adb129eSJérôme Duval 				num_cards++;
6195adb129eSJérôme Duval 			}
6205adb129eSJérôme Duval 		}
6215adb129eSJérôme Duval 	}
6225adb129eSJérôme Duval 	if (!num_cards) {
6235adb129eSJérôme Duval 		PRINT(("no cards\n"));
62415a2aa68SJérôme Duval 		put_module(B_PCI_MODULE_NAME);
6255adb129eSJérôme Duval 		PRINT(("no suitable cards found\n"));
6265adb129eSJérôme Duval 		return ENODEV;
6275adb129eSJérôme Duval 	}
6285adb129eSJérôme Duval 
6295adb129eSJérôme Duval 	return B_OK;
630ec816dffSJérôme Duval #endif
6315adb129eSJérôme Duval }
6325adb129eSJérôme Duval 
6335adb129eSJérôme Duval 
634ec816dffSJérôme Duval #ifndef CARDBUS
6355adb129eSJérôme Duval static void
make_device_names(echo_dev * card)636e480c1b6SPhilippe Saint-Pierre make_device_names(echo_dev * card)
6375adb129eSJérôme Duval {
6380bb683faSJérôme Duval #ifdef MIDI_SUPPORT
6390bb683faSJérôme Duval 	sprintf(card->midi.name, "midi/" DRIVER_NAME "/%ld", card-cards + 1);
6400bb683faSJérôme Duval 	names[num_names++] = card->midi.name;
6410bb683faSJérôme Duval #endif
6423f047e87SJérôme Duval 	sprintf(card->name, "audio/hmulti/" DRIVER_NAME "/%ld", card-cards + 1);
6435adb129eSJérôme Duval 	names[num_names++] = card->name;
6445adb129eSJérôme Duval 
6455adb129eSJérôme Duval 	names[num_names] = NULL;
6465adb129eSJérôme Duval }
647ec816dffSJérôme Duval #else
648ec816dffSJérôme Duval 
649ec816dffSJérôme Duval status_t
cardbus_device_added(pci_info * info,void ** cookie)650ec816dffSJérôme Duval cardbus_device_added(pci_info *info, void **cookie) {
651ec816dffSJérôme Duval 	echo_dev 			* card, *dev;
652ec816dffSJérôme Duval 	uint32				index;
653ec816dffSJérôme Duval 	char				buffer[32];
654ec816dffSJérôme Duval 
655ec816dffSJérôme Duval 	LOG(("cardbus_device_added at %.2d:%.2d:%.2d\n", info->bus, info->device, info->function));
656ec816dffSJérôme Duval 	// Allocate cookie
657ec816dffSJérôme Duval 	if (!(*cookie = card = (echo_dev *)malloc(sizeof(echo_dev)))) {
658ec816dffSJérôme Duval 		return B_NO_MEMORY;
659ec816dffSJérôme Duval 	}
660ec816dffSJérôme Duval 	// Clear cookie
661ec816dffSJérôme Duval 	memset(card, 0, sizeof(echo_dev));
662ec816dffSJérôme Duval 	// Initialize cookie
663ec816dffSJérôme Duval 	card->info = *info;
664ec816dffSJérôme Duval 	card->plugged = true;
665ec816dffSJérôme Duval 	card->index = 0;
666ec816dffSJérôme Duval 
667ec816dffSJérôme Duval 	LIST_FOREACH(dev, &devices, next) {
668ec816dffSJérôme Duval 		if (dev->index == card->index) {
669ec816dffSJérôme Duval 			card->index++;
670ec816dffSJérôme Duval 			dev = LIST_FIRST(&devices);
671ec816dffSJérôme Duval 		}
672ec816dffSJérôme Duval 	}
673ec816dffSJérôme Duval 
674ec816dffSJérôme Duval 	// Format device name
6753f047e87SJérôme Duval 	sprintf(card->name, "audio/hmulti/" DRIVER_NAME "/%ld", card->index);
676ec816dffSJérôme Duval 	// Lock the devices
677ec816dffSJérôme Duval 	acquire_sem(device_lock);
678ec816dffSJérôme Duval 	LIST_INSERT_HEAD((&devices), card, next);
679ec816dffSJérôme Duval 	// Unlock the devices
680ec816dffSJérôme Duval 	release_sem(device_lock);
681ec816dffSJérôme Duval 
682ec816dffSJérôme Duval 	echo_setup(card);
683ec816dffSJérôme Duval 	return B_OK;
684ec816dffSJérôme Duval }
685ec816dffSJérôme Duval 
686ec816dffSJérôme Duval 
687ec816dffSJérôme Duval // cardbus_device_removed - handle cardbus device removal.
688ec816dffSJérôme Duval // status : OK
689ec816dffSJérôme Duval void
cardbus_device_removed(void * cookie)690ec816dffSJérôme Duval cardbus_device_removed(void *cookie)
691ec816dffSJérôme Duval {
692ec816dffSJérôme Duval 	echo_dev		*card = (echo_dev *) cookie;
693ec816dffSJérôme Duval 
694ec816dffSJérôme Duval 	LOG((": cardbus_device_removed\n"));
695ec816dffSJérôme Duval 	// Check
696ec816dffSJérôme Duval 	if (card == NULL) {
697ec816dffSJérôme Duval 		LOG((": null device 0x%.8x\n", card));
698ec816dffSJérôme Duval 		return;
699ec816dffSJérôme Duval 	}
700ec816dffSJérôme Duval 
701ec816dffSJérôme Duval 	echo_shutdown(card);
702ec816dffSJérôme Duval 
703ec816dffSJérôme Duval 	// Lock the devices
704ec816dffSJérôme Duval 	acquire_sem(device_lock);
705ec816dffSJérôme Duval 	// Finalize
706ec816dffSJérôme Duval 	card->plugged = false;
707ec816dffSJérôme Duval 	// Check if the device is opened
708ec816dffSJérôme Duval 	if (card->opened) {
709ec816dffSJérôme Duval 		LOG(("device 0x%.8x %s still in use\n", card, card->name));
710ec816dffSJérôme Duval 	} else {
711ec816dffSJérôme Duval 		LOG(("free device 0x%.8x %s\n", card, card->name));
712ec816dffSJérôme Duval 		LIST_REMOVE(card, next);
713ec816dffSJérôme Duval 		free(card);
714ec816dffSJérôme Duval 	}
715ec816dffSJérôme Duval 	// Unlock the devices
716ec816dffSJérôme Duval 	release_sem(device_lock);
717ec816dffSJérôme Duval }
718ec816dffSJérôme Duval 
719ec816dffSJérôme Duval #endif
7205adb129eSJérôme Duval 
7215adb129eSJérôme Duval 
7225adb129eSJérôme Duval static status_t
echo_setup(echo_dev * card)7235adb129eSJérôme Duval echo_setup(echo_dev* card)
7245adb129eSJérôme Duval {
7255adb129eSJérôme Duval 	unsigned char cmd;
726*d3503944SPulkoMandy 	const char* name;
7275adb129eSJérôme Duval 
7285adb129eSJérôme Duval 	PRINT(("echo_setup(%p)\n", card));
7295adb129eSJérôme Duval 
730ec816dffSJérôme Duval #ifndef CARDBUS
731b5d91600SJérôme Duval 	(*pci->write_pci_config)(card->info.bus, card->info.device,
732b5d91600SJérôme Duval 		card->info.function, PCI_latency, 1, 0xc0 );
7335adb129eSJérôme Duval 
7345adb129eSJérôme Duval 	make_device_names(card);
735ec816dffSJérôme Duval #endif
7365adb129eSJérôme Duval 	card->bmbar = card->info.u.h0.base_registers[0];
7375adb129eSJérôme Duval 	card->irq = card->info.u.h0.interrupt_line;
7385adb129eSJérôme Duval 
739ac0b3253SJérôme Duval 	card->area_bmbar = map_mem(&card->log_bmbar, card->bmbar,
740b5d91600SJérôme Duval 		card->info.u.h0.base_register_sizes[0], DRIVER_NAME" bmbar io");
741b5d91600SJérôme Duval 	if (card->area_bmbar <= B_OK) {
742b5d91600SJérôme Duval 		LOG(("mapping of bmbar io failed, error = %#x\n",card->area_bmbar));
743b5d91600SJérôme Duval 		goto err5;
744b5d91600SJérôme Duval 	}
745b5d91600SJérôme Duval 	LOG(("mapping of bmbar: area %#x, phys %#x, log %#x\n", card->area_bmbar,
746b5d91600SJérôme Duval 		card->bmbar, card->log_bmbar));
747ec816dffSJérôme Duval 
748c2ddc71cSJérôme Duval 	card->pOSS = new COsSupport(card->info.device_id, card->info.revision);
7495adb129eSJérôme Duval 	if (card->pOSS == NULL)
750b5d91600SJérôme Duval 		goto err4;
7515adb129eSJérôme Duval 
7525adb129eSJérôme Duval 	switch (card->type) {
7535adb129eSJérôme Duval #ifdef ECHOGALS_FAMILY
7545adb129eSJérôme Duval 		case DARLA:
7555adb129eSJérôme Duval 			card->pEG = new CDarla(card->pOSS);
756c9002531SJérôme Duval 			name = "Echo Darla";
7575adb129eSJérôme Duval 			break;
7585adb129eSJérôme Duval 		case GINA:
7595adb129eSJérôme Duval 			card->pEG = new CGina(card->pOSS);
760c9002531SJérôme Duval 			name = "Echo Gina";
7615adb129eSJérôme Duval 			break;
7625adb129eSJérôme Duval 		case LAYLA:
7635adb129eSJérôme Duval 			card->pEG = new CLayla(card->pOSS);
764c9002531SJérôme Duval 			name = "Echo Layla";
7655adb129eSJérôme Duval 			break;
7665adb129eSJérôme Duval 		case DARLA24:
7675adb129eSJérôme Duval 			card->pEG = new CDarla24(card->pOSS);
768c9002531SJérôme Duval 			name = "Echo Darla24";
7695adb129eSJérôme Duval 			break;
7705adb129eSJérôme Duval #endif
7715adb129eSJérôme Duval #ifdef ECHO24_FAMILY
7725adb129eSJérôme Duval 		case GINA24:
7735adb129eSJérôme Duval 			card->pEG = new CGina24(card->pOSS);
774c9002531SJérôme Duval 			name = "Echo Gina24";
7755adb129eSJérôme Duval 			break;
7765adb129eSJérôme Duval 		case LAYLA24:
7775adb129eSJérôme Duval 			card->pEG = new CLayla24(card->pOSS);
778ec816dffSJérôme Duval 			name = "Echo Layla24";
7795adb129eSJérôme Duval 			break;
7805adb129eSJérôme Duval 		case MONA:
7815adb129eSJérôme Duval 			card->pEG = new CMona(card->pOSS);
782c9002531SJérôme Duval 			name = "Echo Mona";
7835adb129eSJérôme Duval 			break;
7845adb129eSJérôme Duval 		case MIA:
7855adb129eSJérôme Duval 			card->pEG = new CMia(card->pOSS);
786c9002531SJérôme Duval 			name = "Echo Mia";
7875adb129eSJérôme Duval 			break;
78808661eb2SJérôme Duval #endif
78908661eb2SJérôme Duval #ifdef INDIGO_FAMILY
79008661eb2SJérôme Duval 		case INDIGO:
79108661eb2SJérôme Duval 			card->pEG = new CIndigo(card->pOSS);
792ec816dffSJérôme Duval 			name = "Echo Indigo";
79308661eb2SJérôme Duval 			break;
79408661eb2SJérôme Duval 		case INDIGO_IO:
79508661eb2SJérôme Duval 			card->pEG = new CIndigoIO(card->pOSS);
796ec816dffSJérôme Duval 			name = "Echo IndigoIO";
79708661eb2SJérôme Duval 			break;
79808661eb2SJérôme Duval 		case INDIGO_DJ:
79908661eb2SJérôme Duval 			card->pEG = new CIndigoDJ(card->pOSS);
800ec816dffSJérôme Duval 			name = "Echo IndigoDJ";
80108661eb2SJérôme Duval 			break;
80208661eb2SJérôme Duval #endif
80308661eb2SJérôme Duval #ifdef ECHO3G_FAMILY
804c2ddc71cSJérôme Duval 		case ECHO3G:
805c2ddc71cSJérôme Duval 			card->pEG = new C3g(card->pOSS);
806c9002531SJérôme Duval 			name = "Echo 3g";
807c2ddc71cSJérôme Duval 			break;
8085adb129eSJérôme Duval #endif
8095adb129eSJérôme Duval 		default:
810b5d91600SJérôme Duval 			PRINT(("card type 0x%x not supported by " DRIVER_NAME "\n",
811b5d91600SJérôme Duval 				card->type));
812*d3503944SPulkoMandy 			name = "Unknown";
8135adb129eSJérôme Duval 	}
8145adb129eSJérôme Duval 
8155adb129eSJérôme Duval 	if (card->pEG == NULL)
816b5d91600SJérôme Duval 		goto err2;
8175adb129eSJérôme Duval 
818ec816dffSJérôme Duval #ifndef CARDBUS
819b5d91600SJérôme Duval 	cmd = (*pci->read_pci_config)(card->info.bus, card->info.device,
820b5d91600SJérôme Duval 		card->info.function, PCI_command, 2);
8215adb129eSJérôme Duval 	PRINT(("PCI command before: %x\n", cmd));
822b5d91600SJérôme Duval 	(*pci->write_pci_config)(card->info.bus, card->info.device,
823b5d91600SJérôme Duval 		card->info.function, PCI_command, 2, cmd | PCI_command_io);
824b5d91600SJérôme Duval 	cmd = (*pci->read_pci_config)(card->info.bus, card->info.device,
825b5d91600SJérôme Duval 		card->info.function, PCI_command, 2);
8265adb129eSJérôme Duval 	PRINT(("PCI command after: %x\n", cmd));
827ec816dffSJérôme Duval #endif
8285adb129eSJérôme Duval 
829c9002531SJérôme Duval 	card->pEG->AssignResources(card->log_bmbar, name);
8305adb129eSJérôme Duval 
8315adb129eSJérôme Duval 	ECHOSTATUS status;
8325adb129eSJérôme Duval 	status = card->pEG->InitHw();
8335adb129eSJérôme Duval 	if (status != ECHOSTATUS_OK)
834b5d91600SJérôme Duval 		goto err3;
8355adb129eSJérôme Duval 
836c9002531SJérôme Duval 	card->pEG->GetCapabilities(&card->caps);
837c9002531SJérôme Duval 
8385adb129eSJérôme Duval 	/* Init streams list */
8395adb129eSJérôme Duval 	LIST_INIT(&(card->streams));
8405adb129eSJérôme Duval 
8415adb129eSJérôme Duval 	/* Init mems list */
8425adb129eSJérôme Duval 	LIST_INIT(&(card->mems));
8435adb129eSJérôme Duval 
8440bb683faSJérôme Duval #ifdef MIDI_SUPPORT
8450bb683faSJérôme Duval 	card->midi.midi_ready_sem = create_sem(0, "midi sem");
8460bb683faSJérôme Duval #endif
8470bb683faSJérôme Duval 
8485adb129eSJérôme Duval 	PRINT(("installing interrupt : %x\n", card->irq));
849b5d91600SJérôme Duval 	status = install_io_interrupt_handler(card->irq, echo_int, card, 0);
850b5d91600SJérôme Duval 	if (status != B_OK) {
851b5d91600SJérôme Duval 		PRINT(("failed to install interrupt\n"));
852b5d91600SJérôme Duval 		goto err2;
853b5d91600SJérôme Duval 	}
8545adb129eSJérôme Duval 
8555adb129eSJérôme Duval 	PRINT(("echo_setup done\n"));
8565adb129eSJérôme Duval 
857c9002531SJérôme Duval 	echo_dump_caps(card);
858c9002531SJérôme Duval 
85908661eb2SJérôme Duval #ifdef ECHO3G_FAMILY
860a2f1c2e0SJérôme Duval 	if (card->type == ECHO3G) {
861e480c1b6SPhilippe Saint-Pierre 		strlcpy(card->caps.szName, ((C3g*)card->pEG)->Get3gBoxName(),
862b5d91600SJérôme Duval 			ECHO_MAXNAMELEN);
863a2f1c2e0SJérôme Duval 	}
864a2f1c2e0SJérôme Duval #endif
865a2f1c2e0SJérôme Duval 
866c9002531SJérôme Duval 	status = card->pEG->OpenMixer(card->mixer);
867b5d91600SJérôme Duval 	if (status != ECHOSTATUS_OK) {
868b5d91600SJérôme Duval 		PRINT(("failed to open mixer\n"));
869b5d91600SJérôme Duval 		goto err1;
870b5d91600SJérôme Duval 	}
871c9002531SJérôme Duval 
872b5d91600SJérôme Duval 	return B_OK;
873b5d91600SJérôme Duval 
874b5d91600SJérôme Duval err1:
875b5d91600SJérôme Duval 	remove_io_interrupt_handler(card->irq, echo_int, card);
876b5d91600SJérôme Duval err2:
877b5d91600SJérôme Duval #ifdef MIDI_SUPPORT
878b5d91600SJérôme Duval 	delete_sem(card->midi.midi_ready_sem);
879b5d91600SJérôme Duval #endif
880b5d91600SJérôme Duval err3:
881b5d91600SJérôme Duval 	delete card->pEG;
882b5d91600SJérôme Duval err4:
883b5d91600SJérôme Duval 	delete card->pOSS;
884b5d91600SJérôme Duval err5:
885b5d91600SJérôme Duval 	delete_area(card->area_bmbar);
886b5d91600SJérôme Duval 	return B_ERROR;
8875adb129eSJérôme Duval }
8885adb129eSJérôme Duval 
8895adb129eSJérôme Duval static void
echo_shutdown(echo_dev * card)8905adb129eSJérôme Duval echo_shutdown(echo_dev *card)
8915adb129eSJérôme Duval {
892c9002531SJérôme Duval 	ECHOSTATUS status;
893c9002531SJérôme Duval 
8945adb129eSJérôme Duval 	PRINT(("shutdown(%p)\n", card));
895c9002531SJérôme Duval 	status = card->pEG->CloseMixer(card->mixer);
896c9002531SJérôme Duval 	if (status != ECHOSTATUS_OK)
897c9002531SJérôme Duval 		PRINT(("echo_shutdown: error when CloseMixer\n"));
898c9002531SJérôme Duval 
8995adb129eSJérôme Duval 	remove_io_interrupt_handler(card->irq, echo_int, card);
9005adb129eSJérôme Duval 
9010bb683faSJérôme Duval #ifdef MIDI_SUPPORT
9020bb683faSJérôme Duval 	delete_sem(card->midi.midi_ready_sem);
9030bb683faSJérôme Duval #endif
9040bb683faSJérôme Duval 
9055adb129eSJérôme Duval 	delete card->pEG;
9065adb129eSJérôme Duval 	delete card->pOSS;
9075adb129eSJérôme Duval 
9085adb129eSJérôme Duval 	delete_area(card->area_bmbar);
9095adb129eSJérôme Duval }
9105adb129eSJérôme Duval 
9115adb129eSJérôme Duval 
9125adb129eSJérôme Duval 
9135adb129eSJérôme Duval void
uninit_driver(void)9145adb129eSJérôme Duval uninit_driver(void)
9155adb129eSJérôme Duval {
9165adb129eSJérôme Duval 	PRINT(("uninit_driver()\n"));
9175adb129eSJérôme Duval 
918ec816dffSJérôme Duval #ifdef CARDBUS
919ec816dffSJérôme Duval 	echo_dev			*dev;
920ec816dffSJérôme Duval 
921ec816dffSJérôme Duval 	LIST_FOREACH(dev, &devices, next) {
922ec816dffSJérôme Duval 		echo_shutdown(dev);
923ec816dffSJérôme Duval 	}
924ec816dffSJérôme Duval 	put_module(CB_ENABLER_MODULE_NAME);
925ec816dffSJérôme Duval #else
926ec816dffSJérôme Duval 	int ix, cnt = num_cards;
927ec816dffSJérôme Duval 	num_cards = 0;
9285adb129eSJérôme Duval 	for (ix=0; ix<cnt; ix++) {
9295adb129eSJérôme Duval 		echo_shutdown(&cards[ix]);
93012a9da01SJérôme Duval #ifdef __HAIKU__
93112a9da01SJérôme Duval 		(*pci->unreserve_device)(cards[ix].info.bus,
93212a9da01SJérôme Duval 			cards[ix].info.device, cards[ix].info.function,
93312a9da01SJérôme Duval 			DRIVER_NAME, &cards[ix]);
93412a9da01SJérôme Duval #endif
9355adb129eSJérôme Duval 	}
936ec816dffSJérôme Duval 
9375adb129eSJérôme Duval 	memset(&cards, 0, sizeof(cards));
93815a2aa68SJérôme Duval 	put_module(B_PCI_MODULE_NAME);
939ec816dffSJérôme Duval #endif
9405adb129eSJérôme Duval }
9415adb129eSJérôme Duval 
9425adb129eSJérôme Duval 
9435adb129eSJérôme Duval const char **
publish_devices(void)9445adb129eSJérôme Duval publish_devices(void)
9455adb129eSJérôme Duval {
946ec816dffSJérôme Duval #ifdef CARDBUS
947ec816dffSJérôme Duval 	echo_dev			*dev;
948ec816dffSJérôme Duval 	int			ix = 0;
949ec816dffSJérôme Duval 
950ec816dffSJérôme Duval 	// Lock the devices
951ec816dffSJérôme Duval 	acquire_sem(device_lock);
952ec816dffSJérôme Duval 	// Loop
953ec816dffSJérôme Duval 	LIST_FOREACH(dev, &devices, next) {
954ec816dffSJérôme Duval 		if (dev->plugged == true) {
955ec816dffSJérôme Duval 			names[ix] = dev->name;
956ec816dffSJérôme Duval 			ix++;
957ec816dffSJérôme Duval 		}
958ec816dffSJérôme Duval 	}
959ec816dffSJérôme Duval 	names[ix] = NULL;
960ec816dffSJérôme Duval 	release_sem(device_lock);
961ec816dffSJérôme Duval #else
9625adb129eSJérôme Duval 	int ix = 0;
9635adb129eSJérôme Duval 	PRINT(("publish_devices()\n"));
9645adb129eSJérôme Duval 
9655adb129eSJérôme Duval 	for (ix=0; names[ix]; ix++) {
9665adb129eSJérôme Duval 		PRINT(("publish %s\n", names[ix]));
9675adb129eSJérôme Duval 	}
968ec816dffSJérôme Duval #endif
9695adb129eSJérôme Duval 	return (const char **)names;
9705adb129eSJérôme Duval }
9715adb129eSJérôme Duval 
9725adb129eSJérôme Duval 
9735adb129eSJérôme Duval device_hooks *
find_device(const char * name)9745adb129eSJérôme Duval find_device(const char * name)
9755adb129eSJérôme Duval {
976ec816dffSJérôme Duval #ifdef CARDBUS
977*d3503944SPulkoMandy 	echo_dev *dev;
978ec816dffSJérôme Duval 	LIST_FOREACH(dev, &devices, next) {
979ec816dffSJérôme Duval 		if (!strcmp(dev->name, name)) {
980ec816dffSJérôme Duval 			return &multi_hooks;
981ec816dffSJérôme Duval 		}
982ec816dffSJérôme Duval 	}
983ec816dffSJérôme Duval 
984ec816dffSJérôme Duval #else
9855adb129eSJérôme Duval 	int ix;
9865adb129eSJérôme Duval 
9875adb129eSJérôme Duval 	PRINT(("find_device(%s)\n", name));
9885adb129eSJérôme Duval 
9895adb129eSJérôme Duval 	for (ix=0; ix<num_cards; ix++) {
9900bb683faSJérôme Duval #ifdef MIDI_SUPPORT
9910bb683faSJérôme Duval 		if (!strcmp(cards[ix].midi.name, name)) {
9920bb683faSJérôme Duval 			return &midi_hooks;
9930bb683faSJérôme Duval 		}
9940bb683faSJérôme Duval #endif
9955adb129eSJérôme Duval 		if (!strcmp(cards[ix].name, name)) {
9965adb129eSJérôme Duval 			return &multi_hooks;
9975adb129eSJérôme Duval 		}
9985adb129eSJérôme Duval 	}
999ec816dffSJérôme Duval #endif
10005adb129eSJérôme Duval 	PRINT(("find_device(%s) failed\n", name));
10015adb129eSJérôme Duval 	return NULL;
10025adb129eSJérôme Duval }
10035adb129eSJérôme Duval 
10045adb129eSJérôme Duval int32	api_version = B_CUR_DRIVER_API_VERSION;
1005