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