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