BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / audio / ac97 / auich / auich.c
blob7c1da40f7814f4fbe220479bcb494c7bde01eb28
1 /*
2 * Auich BeOS Driver for Intel Southbridge audio
4 * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
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.
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.
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"
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);
51 pci_module_info *pci;
53 int32 num_cards;
54 auich_dev cards[NUM_CARDS];
55 int32 num_names;
56 char * names[NUM_CARDS*20+1];
58 volatile bool int_thread_exit = false;
59 thread_id int_thread_id = -1;
61 extern device_hooks multi_hooks;
63 auich_settings current_settings = {
64 48000, // sample rate
65 4096, // buffer frames
66 4, // buffer count
67 false // use thread
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)
74 static void
75 dump_hardware_regs(device_config *config)
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)));
95 /* auich Memory management */
97 static auich_mem *
98 auich_mem_new(auich_dev *card, size_t size)
100 auich_mem *mem;
102 if ((mem = malloc(sizeof(*mem))) == NULL)
103 return (NULL);
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;
111 return mem;
115 static void
116 auich_mem_delete(auich_mem *mem)
118 if (mem->area > B_OK)
119 delete_area(mem->area);
120 free(mem);
124 static void *
125 auich_mem_alloc(auich_dev *card, size_t size)
127 auich_mem *mem;
129 mem = auich_mem_new(card, size);
130 if (mem == NULL)
131 return (NULL);
133 LIST_INSERT_HEAD(&(card->mems), mem, next);
135 return mem;
139 static void
140 auich_mem_free(auich_dev *card, void *ptr)
142 auich_mem *mem;
144 LIST_FOREACH(mem, &card->mems, next) {
145 if (mem->log_base != ptr)
146 continue;
147 LIST_REMOVE(mem, next);
149 auich_mem_delete(mem);
150 break;
154 /* auich stream functions */
156 status_t
157 auich_stream_set_audioparms(auich_stream *stream, uint8 channels,
158 uint8 b16, uint32 sample_rate)
160 uint8 sample_size, frame_size;
161 LOG(("auich_stream_set_audioparms\n"));
163 if ((stream->channels == channels)
164 && (stream->b16 == b16)
165 && (stream->sample_rate == sample_rate))
166 return B_OK;
168 if (stream->buffer)
169 auich_mem_free(stream->card, stream->buffer->log_base);
171 stream->b16 = b16;
172 stream->sample_rate = sample_rate;
173 stream->channels = channels;
175 sample_size = stream->b16 + 1;
176 frame_size = sample_size * stream->channels;
178 stream->buffer = auich_mem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount);
180 stream->trigblk = 0; /* This shouldn't be needed */
181 stream->blkmod = stream->bufcount;
182 stream->blksize = stream->bufframes * frame_size;
184 return B_OK;
188 status_t
189 auich_stream_commit_parms(auich_stream *stream)
191 uint32 *page;
192 uint32 i;
193 LOG(("auich_stream_commit_parms\n"));
195 auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR, 0);
196 snooze(10000); // 10 ms
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;
206 spin(1);
209 if (i == 0)
210 PRINT(("channel reset failed after 10ms\n"));
212 page = stream->dmaops_log_base;
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));
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);
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);
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;
238 status_t
239 auich_stream_get_nth_buffer(auich_stream *stream, uint8 chan, uint8 buf,
240 char** buffer, size_t *stride)
242 uint8 sample_size, frame_size;
243 LOG(("auich_stream_get_nth_buffer\n"));
245 sample_size = stream->b16 + 1;
246 frame_size = sample_size * stream->channels;
248 *buffer = stream->buffer->log_base + (buf * stream->bufframes * frame_size)
249 + chan * sample_size;
250 *stride = frame_size;
252 return B_OK;
256 static uint8
257 auich_stream_curaddr(auich_stream *stream)
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;
265 void
266 auich_stream_start(auich_stream *stream, void (*inth) (void *), void *inthparam)
268 int32 civ;
269 LOG(("auich_stream_start\n"));
271 stream->inth = inth;
272 stream->inthparam = inthparam;
274 stream->state |= AUICH_STATE_STARTED;
276 civ = auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CIV);
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);
290 #ifdef DEBUG
291 dump_hardware_regs(&stream->card->config);
292 #endif
296 void
297 auich_stream_halt(auich_stream *stream)
299 LOG(("auich_stream_halt\n"));
301 stream->state &= ~AUICH_STATE_STARTED;
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);
308 auich_stream *
309 auich_stream_new(auich_dev *card, uint8 use, uint32 bufframes, uint8 bufcount)
311 auich_stream *stream;
312 cpu_status status;
313 LOG(("auich_stream_new\n"));
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;
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;
341 stream->frames_count = 0;
342 stream->real_time = 0;
343 stream->buffer_cycle = 0;
344 stream->update_needed = false;
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");
350 if (stream->dmaops_area < B_OK) {
351 PRINT(("couldn't allocate memory\n"));
352 free(stream);
353 return NULL;
356 status = lock();
357 LIST_INSERT_HEAD((&card->streams), stream, next);
358 unlock(status);
360 return stream;
364 void
365 auich_stream_delete(auich_stream *stream)
367 cpu_status status;
368 int32 i;
369 LOG(("auich_stream_delete\n"));
371 auich_stream_halt(stream);
373 auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR, 0);
374 snooze(10000); // 10 ms
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;
382 spin(1);
385 if (i < 0) {
386 LOG(("channel reset failed after 10ms\n"));
389 auich_reg_write_32(&stream->card->config, stream->base + AUICH_REG_X_BDBAR, 0);
391 if (stream->dmaops_area > B_OK)
392 delete_area(stream->dmaops_area);
394 if (stream->buffer)
395 auich_mem_free(stream->card, stream->buffer->log_base);
397 status = lock();
398 LIST_REMOVE(stream, next);
399 unlock(status);
401 free(stream);
404 /* auich interrupt */
406 int32
407 auich_int(void *arg)
409 auich_dev *card = arg;
410 bool gotone = false;
411 uint8 curblk;
412 auich_stream *stream = NULL;
413 uint32 sta;
414 uint16 sr;
416 // TRACE(("auich_int(%p)\n", card));
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);
427 if (sta & card->interrupt_mask) {
428 //TRACE(("interrupt !! %x\n", sta));
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;
436 if (!sr)
437 continue;
439 gotone = true;
441 if (sr & SR_BCIS) {
442 curblk = auich_stream_curaddr(stream);
444 auich_reg_write_8(&card->config, stream->base + AUICH_REG_X_LVI,
445 (curblk + 2) % AUICH_DMALIST_MAX);
447 stream->trigblk = (curblk) % stream->blkmod;
449 if (stream->inth)
450 stream->inth(stream->inthparam);
451 } else {
452 TRACE(("interrupt !! sta %x, sr %x\n", sta, sr));
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;
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);
465 } else if (sta != 0) {
466 dprintf("interrupt masked %lx, sta %lx\n", card->interrupt_mask, sta);
469 if (gotone)
470 return B_INVOKE_SCHEDULER;
472 TRACE(("Got unhandled interrupt\n"));
473 return B_UNHANDLED_INTERRUPT;
477 static int32
478 auich_int_thread(void *data)
480 cpu_status status;
481 while (!int_thread_exit) {
482 status = disable_interrupts();
483 auich_int(data);
484 restore_interrupts(status);
485 snooze(1500);
487 return 0;
491 /* auich driver functions */
493 static status_t
494 map_io_memory(device_config *config)
496 if ((config->type & TYPE_ICH4) == 0)
497 return B_OK;
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;
504 LOG(("mapping of mmbar: area %#x, phys %#x, log %#x\n", config->area_mmbar, config->mmbar, config->log_mmbar));
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;
513 LOG(("mapping of mbbar: area %#x, phys %#x, log %#x\n", config->area_mbbar, config->mbbar, config->log_mbbar));
515 return B_OK;
519 static status_t
520 unmap_io_memory(device_config *config)
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;
530 /* detect presence of our hardware */
531 status_t
532 init_hardware(void)
534 int ix=0;
535 pci_info info;
536 status_t err = ENODEV;
538 LOG_CREATE();
540 PRINT(("init_hardware()\n"));
542 if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci))
543 return ENOSYS;
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
558 || (info.vendor_id == SIS_VENDOR_ID &&
559 (info.device_id == SIS_SI7012_AC97_DEVICE_ID
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
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
577 err = B_OK;
579 ix++;
582 put_module(B_PCI_MODULE_NAME);
584 return err;
588 static void
589 make_device_names(
590 auich_dev * card)
592 sprintf(card->name, "audio/hmulti/auich/%ld", card-cards+1);
593 names[num_names++] = card->name;
595 names[num_names] = NULL;
599 status_t
600 auich_init(auich_dev * card)
602 card->interrupt_mask = STA_PIINT | STA_POINT; //STA_INTMASK;
604 /* Init streams list */
605 LIST_INIT(&(card->streams));
607 /* Init mems list */
608 LIST_INIT(&(card->mems));
610 return B_OK;
614 static status_t
615 auich_setup(auich_dev * card)
617 status_t err = B_OK;
618 status_t rv;
619 unsigned char cmd;
620 int i;
622 PRINT(("auich_setup(%p)\n", card));
624 make_device_names(card);
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;
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));
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;
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;
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;
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);
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));
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"));
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);
705 if (!(rv & STA_S0CR)) { /* reset failure */
706 /* It never return STA_S0CR in some cases */
707 PRINT(("reset failure\n"));
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);
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"));
720 if ((rv & STA_CHAN_CAP) == STA_PCM4) {
721 LOG(("4ch PCM output support\n"));
723 if ((rv & STA_CHAN_CAP) == STA_PCM6) {
724 LOG(("6ch PCM output support\n"));
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;
744 if ((err = auich_init(card)) != B_OK)
745 return err;
747 PRINT(("init_driver done\n"));
749 return err;
753 status_t
754 init_driver(void)
756 int ix = 0;
757 void *settings_handle;
758 pci_info info;
759 status_t err;
760 num_cards = 0;
762 PRINT(("init_driver()\n"));
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);
771 if (get_module(B_PCI_MODULE_NAME, (module_info **) &pci))
772 return ENOSYS;
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
787 || (info.vendor_id == SIS_VENDOR_ID
788 && (info.device_id == SIS_SI7012_AC97_DEVICE_ID
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
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
805 if (num_cards == NUM_CARDS) {
806 PRINT(("Too many auich cards installed!\n"));
807 break;
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;
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
827 else {
828 num_cards++;
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;
840 #if DEBUG
841 //add_debugger_command("auich", auich_debug, "auich [card# (1-n)]");
842 #endif
843 return B_OK;
847 static void
848 auich_shutdown(auich_dev *card)
850 PRINT(("shutdown(%p)\n", card));
851 ac97_detach(card->config.ac97);
853 card->interrupt_mask = 0;
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);
862 unmap_io_memory(&card->config);
866 void
867 uninit_driver(void)
869 int ix, cnt = num_cards;
870 num_cards = 0;
872 PRINT(("uninit_driver()\n"));
873 //remove_debugger_command("auich", auich_debug);
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
883 memset(&cards, 0, sizeof(cards));
884 put_module(B_PCI_MODULE_NAME);
888 const char **
889 publish_devices(void)
891 int ix = 0;
892 PRINT(("publish_devices()\n"));
894 for (ix=0; names[ix]; ix++) {
895 PRINT(("publish %s\n", names[ix]));
897 return (const char **)names;
901 device_hooks *
902 find_device(const char * name)
904 int ix;
906 PRINT(("find_device(%s)\n", name));
908 for (ix=0; ix<num_cards; ix++) {
909 if (!strcmp(cards[ix].name, name)) {
910 return &multi_hooks;
913 PRINT(("find_device(%s) failed\n", name));
914 return NULL;
917 int32 api_version = B_CUR_DRIVER_API_VERSION;