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