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