1/*
2 * Auich BeOS Driver for Intel Southbridge audio
3 *
4 * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <KernelExport.h>
29#include <PCI.h>
30#include <driver_settings.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include "auich.h"
35#include "debug.h"
36#include "config.h"
37#include "util.h"
38#include "io.h"
39#include <fcntl.h>
40#include <unistd.h>
41#include "ac97.h"
42
43status_t init_hardware(void);
44status_t init_driver(void);
45void uninit_driver(void);
46const char ** publish_devices(void);
47device_hooks * find_device(const char *);
48int32 auich_int(void *arg);
49status_t auich_init(auich_dev * card);
50
51pci_module_info	*pci;
52
53int32 num_cards;
54auich_dev cards[NUM_CARDS];
55int32 num_names;
56char * names[NUM_CARDS*20+1];
57
58volatile bool	int_thread_exit = false;
59thread_id 		int_thread_id = -1;
60
61extern device_hooks multi_hooks;
62
63auich_settings current_settings = {
64	48000,	// sample rate
65	4096,	// buffer frames
66	4,	// buffer count
67	false	// use thread
68};
69
70/* The SIS7012 chipset has SR and PICB registers swapped when compared to Intel */
71#define	GET_REG_PICB(x)		(IS_SIS7012(x) ? AUICH_REG_X_SR : AUICH_REG_X_PICB)
72#define	GET_REG_SR(x)		(IS_SIS7012(x) ? AUICH_REG_X_PICB : AUICH_REG_X_SR)
73
74static void
75dump_hardware_regs(device_config *config)
76{
77	LOG(("GLOB_CNT = %#08x\n", auich_reg_read_32(config, AUICH_REG_GLOB_CNT)));
78	LOG(("GLOB_STA = %#08x\n", auich_reg_read_32(config, AUICH_REG_GLOB_STA)));
79	LOG(("PI AUICH_REG_X_BDBAR = %#x\n", auich_reg_read_32(config, AUICH_REG_X_BDBAR + AUICH_REG_PI_BASE)));
80	LOG(("PI AUICH_REG_X_CIV = %#x\n", auich_reg_read_8(config, AUICH_REG_X_CIV + AUICH_REG_PI_BASE)));
81	LOG(("PI AUICH_REG_X_LVI = %#x\n", auich_reg_read_8(config, AUICH_REG_X_LVI + AUICH_REG_PI_BASE)));
82	LOG(("PI     REG_X_SR = %#x\n", auich_reg_read_16(config, AUICH_REG_X_SR + AUICH_REG_PI_BASE)));
83	LOG(("PI     REG_X_PICB = %#x\n", auich_reg_read_16(config, AUICH_REG_X_PICB + AUICH_REG_PI_BASE)));
84	LOG(("PI AUICH_REG_X_PIV = %#x\n", auich_reg_read_8(config, AUICH_REG_X_PIV + AUICH_REG_PI_BASE)));
85	LOG(("PI AUICH_REG_X_CR = %#x\n", auich_reg_read_8(config, AUICH_REG_X_CR + AUICH_REG_PI_BASE)));
86	LOG(("PO AUICH_REG_X_BDBAR = %#x\n", auich_reg_read_32(config, AUICH_REG_X_BDBAR + AUICH_REG_PO_BASE)));
87	LOG(("PO AUICH_REG_X_CIV = %#x\n", auich_reg_read_8(config, AUICH_REG_X_CIV + AUICH_REG_PO_BASE)));
88	LOG(("PO AUICH_REG_X_LVI = %#x\n", auich_reg_read_8(config, AUICH_REG_X_LVI + AUICH_REG_PO_BASE)));
89	LOG(("PO     REG_X_SR = %#x\n", auich_reg_read_16(config, AUICH_REG_X_SR + AUICH_REG_PO_BASE)));
90	LOG(("PO     REG_X_PICB = %#x\n", auich_reg_read_16(config, AUICH_REG_X_PICB + AUICH_REG_PO_BASE)));
91	LOG(("PO AUICH_REG_X_PIV = %#x\n", auich_reg_read_8(config, AUICH_REG_X_PIV + AUICH_REG_PO_BASE)));
92	LOG(("PO AUICH_REG_X_CR = %#x\n", auich_reg_read_8(config, AUICH_REG_X_CR + AUICH_REG_PO_BASE)));
93}
94
95/* auich Memory management */
96
97static auich_mem *
98auich_mem_new(auich_dev *card, size_t size)
99{
100	auich_mem *mem;
101
102	if ((mem = malloc(sizeof(*mem))) == NULL)
103		return (NULL);
104
105	mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "auich buffer",
106		true);
107	mem->size = size;
108	if (mem->area < B_OK) {
109		free(mem);
110		return NULL;
111	}
112	return mem;
113}
114
115
116static void
117auich_mem_delete(auich_mem *mem)
118{
119	if (mem->area > B_OK)
120		delete_area(mem->area);
121	free(mem);
122}
123
124
125static void *
126auich_mem_alloc(auich_dev *card, size_t size)
127{
128	auich_mem *mem;
129
130	mem = auich_mem_new(card, size);
131	if (mem == NULL)
132		return (NULL);
133
134	LIST_INSERT_HEAD(&(card->mems), mem, next);
135
136	return mem;
137}
138
139
140static void
141auich_mem_free(auich_dev *card, void *ptr)
142{
143	auich_mem 		*mem;
144
145	LIST_FOREACH(mem, &card->mems, next) {
146		if (mem->log_base != ptr)
147			continue;
148		LIST_REMOVE(mem, next);
149
150		auich_mem_delete(mem);
151		break;
152	}
153}
154
155/*	auich stream functions */
156
157status_t
158auich_stream_set_audioparms(auich_stream *stream, uint8 channels,
159     uint8 b16, uint32 sample_rate)
160{
161	uint8 			sample_size, frame_size;
162	LOG(("auich_stream_set_audioparms\n"));
163
164	if ((stream->channels == channels)
165		&& (stream->b16 == b16)
166		&& (stream->sample_rate == sample_rate))
167		return B_OK;
168
169	if (stream->buffer)
170		auich_mem_free(stream->card, stream->buffer->log_base);
171
172	stream->b16 = b16;
173	stream->sample_rate = sample_rate;
174	stream->channels = channels;
175
176	sample_size = stream->b16 + 1;
177	frame_size = sample_size * stream->channels;
178
179	stream->buffer = auich_mem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount);
180
181	stream->trigblk = 0;	/* This shouldn't be needed */
182	stream->blkmod = stream->bufcount;
183	stream->blksize = stream->bufframes * frame_size;
184
185	return B_OK;
186}
187
188
189status_t
190auich_stream_commit_parms(auich_stream *stream)
191{
192	uint32 *page;
193	uint32 i;
194	LOG(("auich_stream_commit_parms\n"));
195
196	auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR, 0);
197	snooze(10000); // 10 ms
198
199	auich_reg_write_8(&stream->card->config,
200		stream->base + AUICH_REG_X_CR, CR_RR);
201	for (i = 10000; i > 0; i--) {
202		if (0 == auich_reg_read_8(&stream->card->config,
203			stream->base + AUICH_REG_X_CR)) {
204			LOG(("channel reset finished, %x, %d\n", stream->base, i));
205			break;
206		}
207		spin(1);
208	}
209
210	if (i == 0)
211		PRINT(("channel reset failed after 10ms\n"));
212
213	page = stream->dmaops_log_base;
214
215	for (i = 0; i < AUICH_DMALIST_MAX; i++) {
216		page[2 * i] = ((uint32)stream->buffer->phy_base)
217			+ (i % stream->bufcount) * stream->blksize;
218		page[2 * i + 1] = AUICH_DMAF_IOC | (stream->blksize
219			/ (IS_SIS7012(&stream->card->config) ? 1 : 2));
220	}
221
222	// set physical buffer descriptor base address
223	auich_reg_write_32(&stream->card->config, stream->base + AUICH_REG_X_BDBAR,
224		(uint32)stream->dmaops_phy_base);
225
226	if (stream->use & AUICH_USE_RECORD)
227		auich_codec_write(&stream->card->config, AC97_PCM_L_R_ADC_RATE, (uint16)stream->sample_rate);
228	else
229		auich_codec_write(&stream->card->config, AC97_PCM_FRONT_DAC_RATE, (uint16)stream->sample_rate);
230
231	if (stream->use & AUICH_USE_RECORD)
232		LOG(("rate : %d\n", auich_codec_read(&stream->card->config, AC97_PCM_L_R_ADC_RATE)));
233	else
234		LOG(("rate : %d\n", auich_codec_read(&stream->card->config, AC97_PCM_FRONT_DAC_RATE)));
235	return B_OK;
236}
237
238
239status_t
240auich_stream_get_nth_buffer(auich_stream *stream, uint8 chan, uint8 buf,
241					char** buffer, size_t *stride)
242{
243	uint8 			sample_size, frame_size;
244	LOG(("auich_stream_get_nth_buffer\n"));
245
246	sample_size = stream->b16 + 1;
247	frame_size = sample_size * stream->channels;
248
249	*buffer = (char*)stream->buffer->log_base
250		+ (buf * stream->bufframes * frame_size) + chan * sample_size;
251	*stride = frame_size;
252
253	return B_OK;
254}
255
256
257static uint8
258auich_stream_curaddr(auich_stream *stream)
259{
260	uint8 index = auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CIV);
261	TRACE(("stream_curaddr %d\n", index));
262	return index;
263}
264
265
266void
267auich_stream_start(auich_stream *stream, void (*inth) (void *), void *inthparam)
268{
269	int32 civ;
270	LOG(("auich_stream_start\n"));
271
272	stream->inth = inth;
273	stream->inthparam = inthparam;
274
275	stream->state |= AUICH_STATE_STARTED;
276
277	civ = auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CIV);
278
279	// step 1: clear status bits
280	auich_reg_write_16(&stream->card->config,
281		stream->base + GET_REG_SR(&stream->card->config),
282		auich_reg_read_16(&stream->card->config, stream->base + GET_REG_SR(&stream->card->config)));
283	auich_reg_read_16(&stream->card->config, stream->base + GET_REG_SR(&stream->card->config));
284	// step 2: prepare buffer transfer
285	auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_LVI, (civ + 2) % AUICH_DMALIST_MAX);
286	auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_LVI);
287	// step 3: enable interrupts & busmaster transfer
288	auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR, CR_RPBM | CR_LVBIE | CR_FEIE | CR_IOCE);
289	auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CR);
290
291#ifdef DEBUG
292	dump_hardware_regs(&stream->card->config);
293#endif
294}
295
296
297void
298auich_stream_halt(auich_stream *stream)
299{
300	LOG(("auich_stream_halt\n"));
301
302	stream->state &= ~AUICH_STATE_STARTED;
303
304	auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR,
305		auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CR) & ~CR_RPBM);
306}
307
308
309auich_stream *
310auich_stream_new(auich_dev *card, uint8 use, uint32 bufframes, uint8 bufcount)
311{
312	auich_stream *stream;
313	cpu_status status;
314	LOG(("auich_stream_new\n"));
315
316	stream = malloc(sizeof(auich_stream));
317	if (stream == NULL)
318		return (NULL);
319	stream->card = card;
320	stream->use = use;
321	stream->state = !AUICH_STATE_STARTED;
322	stream->b16 = 0;
323	stream->sample_rate = 0;
324	stream->channels = 0;
325	stream->bufframes = bufframes;
326	stream->bufcount = bufcount;
327	stream->inth = NULL;
328	stream->inthparam = NULL;
329	stream->buffer = NULL;
330	stream->blksize = 0;
331	stream->trigblk = 0;
332	stream->blkmod = 0;
333
334	if (use & AUICH_USE_PLAY) {
335		stream->base = AUICH_REG_PO_BASE;
336		stream->sta = STA_POINT;
337	} else {
338		stream->base = AUICH_REG_PI_BASE;
339		stream->sta = STA_PIINT;
340	}
341
342	stream->frames_count = 0;
343	stream->real_time = 0;
344	stream->buffer_cycle = 0;
345	stream->update_needed = false;
346
347	/* allocate memory for our dma ops */
348	stream->dmaops_area = alloc_mem(&stream->dmaops_phy_base, &stream->dmaops_log_base,
349		sizeof(auich_dmalist) * AUICH_DMALIST_MAX, "auich dmaops", false);
350
351	if (stream->dmaops_area < B_OK) {
352		PRINT(("couldn't allocate memory\n"));
353		free(stream);
354		return NULL;
355	}
356
357	status = lock();
358	LIST_INSERT_HEAD((&card->streams), stream, next);
359	unlock(status);
360
361	return stream;
362}
363
364
365void
366auich_stream_delete(auich_stream *stream)
367{
368	cpu_status status;
369	int32 i;
370	LOG(("auich_stream_delete\n"));
371
372	auich_stream_halt(stream);
373
374	auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR, 0);
375	snooze(10000); // 10 ms
376
377	auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR, CR_RR);
378	for (i = 10000; i>=0; i--) {
379		if (0 == auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CR)) {
380			LOG(("channel reset finished, %x, %d\n", stream->base, i));
381			break;
382		}
383		spin(1);
384	}
385
386	if (i < 0) {
387		LOG(("channel reset failed after 10ms\n"));
388	}
389
390	auich_reg_write_32(&stream->card->config, stream->base + AUICH_REG_X_BDBAR, 0);
391
392	if (stream->dmaops_area > B_OK)
393		delete_area(stream->dmaops_area);
394
395	if (stream->buffer)
396		auich_mem_free(stream->card, stream->buffer->log_base);
397
398	status = lock();
399	LIST_REMOVE(stream, next);
400	unlock(status);
401
402	free(stream);
403}
404
405/* auich interrupt */
406
407int32
408auich_int(void *arg)
409{
410	auich_dev	 	*card = arg;
411	bool 			gotone 	= false;
412	uint8       	curblk;
413	auich_stream 	*stream = NULL;
414	uint32			sta;
415	uint16 			sr;
416
417	// TRACE(("auich_int(%p)\n", card));
418
419	sta = auich_reg_read_32(&card->config, AUICH_REG_GLOB_STA) & STA_INTMASK;
420	if (sta & (STA_S0RI | STA_S1RI | STA_S2RI)) {
421		// ignore and clear resume interrupt(s)
422		auich_reg_write_32(&card->config, AUICH_REG_GLOB_STA, sta & (STA_S0RI | STA_S1RI | STA_S2RI));
423		TRACE(("interrupt !! %x\n", sta));
424		gotone = true;
425		sta &= ~(STA_S0RI | STA_S1RI | STA_S2RI);
426	}
427
428	if (sta & card->interrupt_mask) {
429		//TRACE(("interrupt !! %x\n", sta));
430
431		LIST_FOREACH(stream, &card->streams, next)
432			if (sta & stream->sta) {
433				sr = auich_reg_read_16(&card->config,
434					stream->base + GET_REG_SR(&stream->card->config));
435				sr &= SR_MASK;
436
437				if (!sr)
438					continue;
439
440				gotone = true;
441
442				if (sr & SR_BCIS) {
443					curblk = auich_stream_curaddr(stream);
444
445					auich_reg_write_8(&card->config, stream->base + AUICH_REG_X_LVI,
446						(curblk + 2) % AUICH_DMALIST_MAX);
447
448					stream->trigblk = (curblk) % stream->blkmod;
449
450					if (stream->inth)
451						stream->inth(stream->inthparam);
452				} else {
453					TRACE(("interrupt !! sta %x, sr %x\n", sta, sr));
454				}
455
456				auich_reg_write_16(&card->config,
457					stream->base + GET_REG_SR(&stream->card->config), sr);
458				auich_reg_write_32(&card->config, AUICH_REG_GLOB_STA, stream->sta);
459				sta &= ~stream->sta;
460			}
461
462		if (sta != 0) {
463			dprintf("global status not fully handled %" B_PRIx32 "!\n", sta);
464			auich_reg_write_32(&card->config, AUICH_REG_GLOB_STA, sta);
465		}
466	} else if (sta != 0) {
467		dprintf("interrupt masked %" B_PRIx32 ", sta %" B_PRIx32 "\n",
468			card->interrupt_mask, sta);
469	}
470
471	if (gotone)
472		return B_INVOKE_SCHEDULER;
473
474	TRACE(("Got unhandled interrupt\n"));
475	return B_UNHANDLED_INTERRUPT;
476}
477
478
479static int32
480auich_int_thread(void *data)
481{
482	cpu_status status;
483	while (!int_thread_exit) {
484		status = disable_interrupts();
485		auich_int(data);
486		restore_interrupts(status);
487		snooze(1500);
488	}
489	return 0;
490}
491
492
493/*	auich driver functions */
494
495static status_t
496map_io_memory(device_config *config)
497{
498	if ((config->type & TYPE_ICH4) == 0)
499		return B_OK;
500
501	config->area_mmbar = map_mem(&config->log_mmbar, config->mmbar, ICH4_MMBAR_SIZE, "auich mmbar io");
502	if (config->area_mmbar <= B_OK) {
503		LOG(("mapping of mmbar io failed, error = %#x\n",config->area_mmbar));
504		return B_ERROR;
505	}
506	LOG(("mapping of mmbar: area %#x, phys %#x, log %#x\n", config->area_mmbar, config->mmbar, config->log_mmbar));
507
508	config->area_mbbar = map_mem(&config->log_mbbar, config->mbbar, ICH4_MBBAR_SIZE, "auich mbbar io");
509	if (config->area_mbbar <= B_OK) {
510		LOG(("mapping of mbbar io failed, error = %#x\n",config->area_mbbar));
511		delete_area(config->area_mmbar);
512		config->area_mmbar = -1;
513		return B_ERROR;
514	}
515	LOG(("mapping of mbbar: area %#x, phys %#x, log %#x\n", config->area_mbbar, config->mbbar, config->log_mbbar));
516
517	return B_OK;
518}
519
520
521static status_t
522unmap_io_memory(device_config *config)
523{
524	status_t rv;
525	if ((config->type & TYPE_ICH4) == 0)
526		return B_OK;
527	rv  = delete_area(config->area_mmbar);
528	rv |= delete_area(config->area_mbbar);
529	return rv;
530}
531
532/* detect presence of our hardware */
533status_t
534init_hardware(void)
535{
536	int ix=0;
537	pci_info info;
538	status_t err = ENODEV;
539
540	LOG_CREATE();
541
542	PRINT(("init_hardware()\n"));
543
544	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci))
545		return ENOSYS;
546
547	while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
548		if ((info.vendor_id == INTEL_VENDOR_ID &&
549			(info.device_id == INTEL_82443MX_AC97_DEVICE_ID
550			|| info.device_id == INTEL_82801AA_AC97_DEVICE_ID
551			|| info.device_id == INTEL_82801AB_AC97_DEVICE_ID
552			|| info.device_id == INTEL_82801BA_AC97_DEVICE_ID
553			|| info.device_id == INTEL_82801CA_AC97_DEVICE_ID
554			|| info.device_id == INTEL_82801DB_AC97_DEVICE_ID
555			|| info.device_id == INTEL_82801EB_AC97_DEVICE_ID
556			|| info.device_id == INTEL_82801FB_AC97_DEVICE_ID
557			|| info.device_id == INTEL_82801GB_AC97_DEVICE_ID
558			|| info.device_id == INTEL_6300ESB_AC97_DEVICE_ID
559			|| info.device_id == INTEL_631xESB_AC97_DEVICE_ID
560			))
561		|| (info.vendor_id == SIS_VENDOR_ID &&
562			(info.device_id == SIS_SI7012_AC97_DEVICE_ID
563			))
564		|| (info.vendor_id == NVIDIA_VENDOR_ID &&
565			(info.device_id == NVIDIA_nForce_AC97_DEVICE_ID
566			|| info.device_id == NVIDIA_nForce2_AC97_DEVICE_ID
567			|| info.device_id == NVIDIA_nForce2_400_AC97_DEVICE_ID
568			|| info.device_id == NVIDIA_nForce3_AC97_DEVICE_ID
569			|| info.device_id == NVIDIA_nForce3_250_AC97_DEVICE_ID
570			|| info.device_id == NVIDIA_CK804_AC97_DEVICE_ID
571			|| info.device_id == NVIDIA_MCP51_AC97_DEVICE_ID
572			|| info.device_id == NVIDIA_MCP04_AC97_DEVICE_ID
573			))
574		|| (info.vendor_id == AMD_VENDOR_ID &&
575			(info.device_id == AMD_AMD8111_AC97_DEVICE_ID
576			|| info.device_id == AMD_AMD768_AC97_DEVICE_ID
577			))
578			)
579		 {
580			err = B_OK;
581		}
582		ix++;
583	}
584
585	put_module(B_PCI_MODULE_NAME);
586
587	return err;
588}
589
590
591static void
592make_device_names(
593	auich_dev * card)
594{
595	sprintf(card->name, "audio/hmulti/auich/%ld", card-cards+1);
596	names[num_names++] = card->name;
597
598	names[num_names] = NULL;
599}
600
601
602status_t
603auich_init(auich_dev * card)
604{
605	card->interrupt_mask = STA_PIINT | STA_POINT; //STA_INTMASK;
606
607	/* Init streams list */
608	LIST_INIT(&(card->streams));
609
610	/* Init mems list */
611	LIST_INIT(&(card->mems));
612
613	return B_OK;
614}
615
616
617static status_t
618auich_setup(auich_dev * card)
619{
620	status_t err = B_OK;
621	status_t rv;
622	unsigned char cmd;
623	int i;
624
625	PRINT(("auich_setup(%p)\n", card));
626
627	make_device_names(card);
628
629	card->config.subvendor_id = card->info.u.h0.subsystem_vendor_id;
630	card->config.subsystem_id = card->info.u.h0.subsystem_id;
631	card->config.nabmbar = card->info.u.h0.base_registers[0];
632	card->config.irq = card->info.u.h0.interrupt_line;
633	card->config.type = 0;
634	if ((card->info.device_id == INTEL_82801DB_AC97_DEVICE_ID)
635		|| (card->info.device_id == INTEL_82801EB_AC97_DEVICE_ID)
636		|| (card->info.device_id == INTEL_82801FB_AC97_DEVICE_ID)
637		|| (card->info.device_id == INTEL_82801GB_AC97_DEVICE_ID)
638		|| (card->info.device_id == INTEL_6300ESB_AC97_DEVICE_ID))
639		card->config.type |= TYPE_ICH4;
640	if (card->info.device_id == SIS_SI7012_AC97_DEVICE_ID)
641		card->config.type |= TYPE_SIS7012;
642
643	PRINT(("%s deviceid = %#04x chiprev = %x model = %x "
644		"enhanced at %" B_PRIx32 "lx\n",
645		card->name, card->info.device_id, card->info.revision,
646		card->info.u.h0.subsystem_id, card->config.nabmbar));
647
648	if (IS_ICH4(&card->config)) {
649		// memory mapped access
650		card->config.mmbar = 0xfffffffe & (*pci->read_pci_config)
651			(card->info.bus, card->info.device, card->info.function, 0x18, 4);
652		card->config.mbbar = 0xfffffffe & (*pci->read_pci_config)
653			(card->info.bus, card->info.device, card->info.function, 0x1C, 4);
654		if (card->config.mmbar == 0 || card->config.mbbar == 0) {
655			PRINT(("memory mapped IO not configured\n"));
656			return B_ERROR;
657		}
658	} else {
659		// pio access
660		card->config.nambar = 0xfffffffe & (*pci->read_pci_config)
661			(card->info.bus, card->info.device, card->info.function, 0x10, 4);
662		card->config.nabmbar = 0xfffffffe & (*pci->read_pci_config)
663			(card->info.bus, card->info.device, card->info.function, 0x14, 4);
664		if (card->config.nambar == 0 || card->config.nabmbar == 0) {
665			PRINT(("IO space not configured\n"));
666			return B_ERROR;
667		}
668	}
669
670	/* before doing anything else, map the IO memory */
671	rv = map_io_memory(&card->config);
672	if (rv != B_OK) {
673		PRINT(("mapping of memory IO space failed\n"));
674		return B_ERROR;
675	}
676
677	cmd = (*pci->read_pci_config)(card->info.bus, card->info.device,
678		card->info.function, PCI_command, 2);
679	PRINT(("PCI command before: %x\n", cmd));
680	cmd |= PCI_command_master;
681	if (IS_ICH4(&card->config)) {
682		(*pci->write_pci_config)(card->info.bus, card->info.device,
683			card->info.function, PCI_command, 2, cmd | PCI_command_memory);
684	} else {
685		(*pci->write_pci_config)(card->info.bus, card->info.device,
686			card->info.function, PCI_command, 2, cmd | PCI_command_io);
687	}
688	cmd = (*pci->read_pci_config)(card->info.bus, card->info.device,
689		card->info.function, PCI_command, 2);
690	PRINT(("PCI command after: %x\n", cmd));
691
692	/* do a cold reset */
693	LOG(("cold reset\n"));
694	auich_reg_write_32(&card->config, AUICH_REG_GLOB_CNT, 0);
695	snooze(50000); // 50 ms
696	auich_reg_write_32(&card->config, AUICH_REG_GLOB_CNT, CNT_COLD | CNT_PRIE);
697	LOG(("cold reset finished\n"));
698	rv = auich_reg_read_32(&card->config, AUICH_REG_GLOB_CNT);
699	if ((rv & CNT_COLD) == 0) {
700		LOG(("cold reset failed\n"));
701	}
702
703	for (i = 0; i < 500; i++) {
704		rv = auich_reg_read_32(&card->config, AUICH_REG_GLOB_STA);
705		if (rv & STA_S0CR)
706			break;
707		snooze(1000);
708	}
709
710	if (!(rv & STA_S0CR)) { /* reset failure */
711		/* It never return STA_S0CR in some cases */
712		PRINT(("reset failure\n"));
713	}
714
715	/* attach the codec */
716	PRINT(("codec attach\n"));
717	ac97_attach(&card->config.ac97, (codec_reg_read)auich_codec_read,
718		(codec_reg_write)auich_codec_write, &card->config,
719		card->config.subvendor_id, card->config.subsystem_id);
720
721	/* Print capabilities though there are no supports for now */
722	if ((rv & STA_SAMPLE_CAP) == STA_POM20) {
723		LOG(("20 bit precision support\n"));
724	}
725	if ((rv & STA_CHAN_CAP) == STA_PCM4) {
726		LOG(("4ch PCM output support\n"));
727	}
728	if ((rv & STA_CHAN_CAP) == STA_PCM6) {
729		LOG(("6ch PCM output support\n"));
730	}
731
732	if (current_settings.use_thread || card->config.irq == 0
733		|| card->config.irq == 0xff) {
734		int_thread_id = spawn_kernel_thread(auich_int_thread,
735			"auich interrupt poller", B_REAL_TIME_PRIORITY, card);
736		resume_thread(int_thread_id);
737	} else {
738		PRINT(("installing interrupt : %" B_PRIx32 "\n", card->config.irq));
739		err = install_io_interrupt_handler(card->config.irq, auich_int,
740			card, 0);
741		if (err != B_OK) {
742			PRINT(("failed to install interrupt\n"));
743			ac97_detach(card->config.ac97);
744			unmap_io_memory(&card->config);
745			return err;
746		}
747	}
748
749	if ((err = auich_init(card)) != B_OK)
750		return err;
751
752	PRINT(("init_driver done\n"));
753
754	return err;
755}
756
757
758status_t
759init_driver(void)
760{
761	int ix = 0;
762	void *settings_handle;
763	pci_info info;
764	status_t err;
765	num_cards = 0;
766
767	PRINT(("init_driver()\n"));
768
769	// get driver settings
770	settings_handle = load_driver_settings(AUICH_SETTINGS);
771	if (settings_handle != NULL) {
772		current_settings.use_thread = get_driver_boolean_parameter (settings_handle, "use_thread", false, false);
773		unload_driver_settings (settings_handle);
774	}
775
776	if (get_module(B_PCI_MODULE_NAME, (module_info **) &pci))
777		return ENOSYS;
778
779	while ((*pci->get_nth_pci_info)(ix++, &info) == B_OK) {
780		if ((info.vendor_id == INTEL_VENDOR_ID
781			&& (info.device_id == INTEL_82443MX_AC97_DEVICE_ID
782			|| info.device_id == INTEL_82801AA_AC97_DEVICE_ID
783			|| info.device_id == INTEL_82801AB_AC97_DEVICE_ID
784			|| info.device_id == INTEL_82801BA_AC97_DEVICE_ID
785			|| info.device_id == INTEL_82801CA_AC97_DEVICE_ID
786			|| info.device_id == INTEL_82801DB_AC97_DEVICE_ID
787			|| info.device_id == INTEL_82801EB_AC97_DEVICE_ID
788			|| info.device_id == INTEL_82801FB_AC97_DEVICE_ID
789			|| info.device_id == INTEL_82801GB_AC97_DEVICE_ID
790			|| info.device_id == INTEL_6300ESB_AC97_DEVICE_ID
791			))
792		|| (info.vendor_id == SIS_VENDOR_ID
793			&& (info.device_id == SIS_SI7012_AC97_DEVICE_ID
794			))
795		|| (info.vendor_id == NVIDIA_VENDOR_ID
796			&& (info.device_id == NVIDIA_nForce_AC97_DEVICE_ID
797			|| info.device_id == NVIDIA_nForce2_AC97_DEVICE_ID
798			|| info.device_id == NVIDIA_nForce2_400_AC97_DEVICE_ID
799			|| info.device_id == NVIDIA_nForce3_AC97_DEVICE_ID
800			|| info.device_id == NVIDIA_nForce3_250_AC97_DEVICE_ID
801			|| info.device_id == NVIDIA_CK804_AC97_DEVICE_ID
802			|| info.device_id == NVIDIA_MCP51_AC97_DEVICE_ID
803			|| info.device_id == NVIDIA_MCP04_AC97_DEVICE_ID
804			))
805		|| (info.vendor_id == AMD_VENDOR_ID
806			&& (info.device_id == AMD_AMD8111_AC97_DEVICE_ID
807			|| info.device_id == AMD_AMD768_AC97_DEVICE_ID
808			))
809			) {
810			if (num_cards == NUM_CARDS) {
811				PRINT(("Too many auich cards installed!\n"));
812				break;
813			}
814			memset(&cards[num_cards], 0, sizeof(auich_dev));
815			cards[num_cards].info = info;
816#ifdef __HAIKU__
817			if ((err = (*pci->reserve_device)(info.bus, info.device, info.function,
818				DRIVER_NAME, &cards[num_cards])) < B_OK) {
819				dprintf("%s: failed to reserve_device(%d, %d, %d,): %s\n",
820					DRIVER_NAME, info.bus, info.device, info.function,
821					strerror(err));
822				continue;
823			}
824#endif
825			if (auich_setup(&cards[num_cards])) {
826				PRINT(("Setup of auich %" B_PRId32 " failed\n",
827					num_cards + 1));
828#ifdef __HAIKU__
829				(*pci->unreserve_device)(info.bus, info.device, info.function,
830					DRIVER_NAME, &cards[num_cards]);
831#endif
832			}
833			else {
834				num_cards++;
835			}
836		}
837	}
838	if (!num_cards) {
839		PRINT(("no cards\n"));
840		put_module(B_PCI_MODULE_NAME);
841		PRINT(("no suitable cards found\n"));
842		return ENODEV;
843	}
844
845
846#if DEBUG
847	//add_debugger_command("auich", auich_debug, "auich [card# (1-n)]");
848#endif
849	return B_OK;
850}
851
852
853static void
854auich_shutdown(auich_dev *card)
855{
856	PRINT(("shutdown(%p)\n", card));
857	ac97_detach(card->config.ac97);
858
859	card->interrupt_mask = 0;
860
861	if (current_settings.use_thread) {
862		status_t exit_value;
863		int_thread_exit = true;
864		wait_for_thread(int_thread_id, &exit_value);
865	} else
866		remove_io_interrupt_handler(card->config.irq, auich_int, card);
867
868	unmap_io_memory(&card->config);
869}
870
871
872void
873uninit_driver(void)
874{
875	int ix, cnt = num_cards;
876	num_cards = 0;
877
878	PRINT(("uninit_driver()\n"));
879	//remove_debugger_command("auich", auich_debug);
880
881	for (ix=0; ix<cnt; ix++) {
882		auich_shutdown(&cards[ix]);
883#ifdef __HAIKU__
884		(*pci->unreserve_device)(cards[ix].info.bus,
885			cards[ix].info.device, cards[ix].info.function,
886			DRIVER_NAME, &cards[ix]);
887#endif
888	}
889	memset(&cards, 0, sizeof(cards));
890	put_module(B_PCI_MODULE_NAME);
891}
892
893
894const char **
895publish_devices(void)
896{
897	int ix = 0;
898	PRINT(("publish_devices()\n"));
899
900	for (ix=0; names[ix]; ix++) {
901		PRINT(("publish %s\n", names[ix]));
902	}
903	return (const char **)names;
904}
905
906
907device_hooks *
908find_device(const char * name)
909{
910	int ix;
911
912	PRINT(("find_device(%s)\n", name));
913
914	for (ix=0; ix<num_cards; ix++) {
915		if (!strcmp(cards[ix].name, name)) {
916			return &multi_hooks;
917		}
918	}
919	PRINT(("find_device(%s) failed\n", name));
920	return NULL;
921}
922
923int32	api_version = B_CUR_DRIVER_API_VERSION;
924