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