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