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