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