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