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