1 /* 2 * Auvia BeOS Driver for Via VT82xx Southbridge audio 3 * 4 * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr) 5 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Tyler C. Sarna 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <KernelExport.h> 39 #include <PCI.h> 40 #include <string.h> 41 #include <stdio.h> 42 #include "auvia.h" 43 #include "debug.h" 44 #include "config.h" 45 #include "util.h" 46 #include "io.h" 47 #include <fcntl.h> 48 #include <unistd.h> 49 #include <malloc.h> 50 #include "ac97.h" 51 52 status_t init_hardware(void); 53 status_t init_driver(void); 54 void uninit_driver(void); 55 const char ** publish_devices(void); 56 device_hooks * find_device(const char *); 57 58 static char pci_name[] = B_PCI_MODULE_NAME; 59 pci_module_info *pci; 60 61 int32 num_cards; 62 auvia_dev cards[NUM_CARDS]; 63 int32 num_names; 64 char * names[NUM_CARDS*20+1]; 65 66 extern device_hooks multi_hooks; 67 68 /* Auvia Memory management */ 69 70 static auvia_mem * 71 auvia_mem_new(auvia_dev *card, size_t size) 72 { 73 auvia_mem *mem; 74 75 if ((mem = malloc(sizeof(*mem))) == NULL) 76 return (NULL); 77 78 mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "auvia buffer"); 79 mem->size = size; 80 if (mem->area < B_OK) { 81 free(mem); 82 return NULL; 83 } 84 return mem; 85 } 86 87 static void 88 auvia_mem_delete(auvia_mem *mem) 89 { 90 if(mem->area > B_OK) 91 delete_area(mem->area); 92 free(mem); 93 } 94 95 static void * 96 auvia_mem_alloc(auvia_dev *card, size_t size) 97 { 98 auvia_mem *mem; 99 100 mem = auvia_mem_new(card, size); 101 if (mem == NULL) 102 return (NULL); 103 104 LIST_INSERT_HEAD(&(card->mems), mem, next); 105 106 return mem; 107 } 108 109 static void 110 auvia_mem_free(auvia_dev *card, void *ptr) 111 { 112 auvia_mem *mem; 113 114 LIST_FOREACH(mem, &card->mems, next) { 115 if (mem->log_base != ptr) 116 continue; 117 LIST_REMOVE(mem, next); 118 119 auvia_mem_delete(mem); 120 break; 121 } 122 } 123 124 /* Auvia stream functions */ 125 126 status_t 127 auvia_stream_set_audioparms(auvia_stream *stream, uint8 channels, 128 uint8 b16, uint32 sample_rate) 129 { 130 uint8 sample_size, frame_size; 131 LOG(("auvia_stream_set_audioparms\n")); 132 133 if ((stream->channels == channels) && 134 (stream->b16 == b16) && 135 (stream->sample_rate == sample_rate)) 136 return B_OK; 137 138 if(stream->buffer) 139 auvia_mem_free(stream->card, stream->buffer->log_base); 140 141 stream->b16 = b16; 142 stream->sample_rate = sample_rate; 143 stream->channels = channels; 144 145 sample_size = stream->b16 + 1; 146 frame_size = sample_size * stream->channels; 147 148 stream->buffer = auvia_mem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount); 149 150 stream->trigblk = 0; /* This shouldn't be needed */ 151 stream->blkmod = stream->bufcount; 152 stream->blksize = stream->bufframes * frame_size; 153 154 return B_OK; 155 } 156 157 status_t 158 auvia_stream_commit_parms(auvia_stream *stream) 159 { 160 int i; 161 uint32 *page; 162 uint32 value; 163 LOG(("auvia_stream_commit_parms\n")); 164 165 page = stream->dmaops_log_base; 166 167 for(i=0; i<stream->bufcount; i++) { 168 page[2*i] = ((uint32)stream->buffer->phy_base) + 169 i * stream->blksize; 170 page[2*i + 1] = AUVIA_DMAOP_FLAG | stream->blksize; 171 } 172 173 page[2*stream->bufcount - 1] &= ~AUVIA_DMAOP_FLAG; 174 page[2*stream->bufcount - 1] |= AUVIA_DMAOP_EOL; 175 176 auvia_reg_write_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE, 177 (uint32)stream->dmaops_phy_base); 178 179 if(stream->use & AUVIA_USE_RECORD) 180 auvia_codec_write(&stream->card->config, AC97_PCM_LR_ADC_RATE, (uint16)stream->sample_rate); 181 else 182 auvia_codec_write(&stream->card->config, AC97_PCM_FRONT_DAC_RATE, (uint16)stream->sample_rate); 183 184 if(IS_8233(&stream->card->config)) { 185 if(stream->base != AUVIA_8233_MP_BASE) { 186 value = auvia_reg_read_32(&stream->card->config, stream->base + AUVIA_8233_RP_RATEFMT); 187 value &= ~(AUVIA_8233_RATEFMT_48K | AUVIA_8233_RATEFMT_STEREO | AUVIA_8233_RATEFMT_16BIT); 188 if(stream->use & AUVIA_USE_PLAY) 189 value |= AUVIA_8233_RATEFMT_48K * (stream->sample_rate / 20) / (48000 / 20); 190 value |= (stream->channels == 2 ? AUVIA_8233_RATEFMT_STEREO : 0) 191 | (stream->b16 ? AUVIA_8233_RATEFMT_16BIT : 0); 192 auvia_reg_write_32(&stream->card->config, stream->base + AUVIA_8233_RP_RATEFMT, value); 193 } else { 194 static const uint32 slottab[7] = {0, 0xff000011, 0xff000021, 0xff000521, 195 0xff004321, 0xff054321, 0xff654321}; 196 value = (stream->b16 ? AUVIA_8233_MP_FORMAT_16BIT : AUVIA_8233_MP_FORMAT_8BIT) 197 | ((stream->channels << 4) & AUVIA_8233_MP_FORMAT_CHANNEL_MASK) ; 198 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_8233_OFF_MP_FORMAT, value); 199 auvia_reg_write_32(&stream->card->config, stream->base + AUVIA_8233_OFF_MP_STOP, 200 slottab[stream->channels]); 201 } 202 } 203 //auvia_codec_write(&stream->card->config, AC97_SPDIF_CONTROL, (uint16)stream->sample_rate); 204 205 return B_OK; 206 } 207 208 status_t 209 auvia_stream_get_nth_buffer(auvia_stream *stream, uint8 chan, uint8 buf, 210 char** buffer, size_t *stride) 211 { 212 uint8 sample_size, frame_size; 213 LOG(("auvia_stream_get_nth_buffer\n")); 214 215 sample_size = stream->b16 + 1; 216 frame_size = sample_size * stream->channels; 217 218 *buffer = stream->buffer->log_base + (buf * stream->bufframes * frame_size) 219 + chan * sample_size; 220 *stride = frame_size; 221 222 return B_OK; 223 } 224 225 static uint32 226 auvia_stream_curaddr(auvia_stream *stream) 227 { 228 uint32 addr; 229 if(IS_8233(&stream->card->config)) { 230 addr = auvia_reg_read_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE); 231 TRACE(("stream_curaddr %p, phy_base %p\n", addr, (uint32)stream->dmaops_phy_base)); 232 return (addr - (uint32)stream->dmaops_phy_base - 4) / 8; 233 } else { 234 addr = auvia_reg_read_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE); 235 TRACE(("stream_curaddr %p, phy_base %p\n", addr, (uint32)stream->dmaops_phy_base)); 236 return (addr - (uint32)stream->dmaops_phy_base - 8) / 8; 237 } 238 } 239 240 void 241 auvia_stream_start(auvia_stream *stream, void (*inth) (void *), void *inthparam) 242 { 243 LOG(("auvia_stream_start\n")); 244 245 stream->inth = inth; 246 stream->inthparam = inthparam; 247 248 stream->state |= AUVIA_STATE_STARTED; 249 250 if(IS_8233(&stream->card->config)) { 251 if(stream->base != AUVIA_8233_MP_BASE) { 252 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_8233_RP_DXS_LVOL, 0); 253 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_8233_RP_DXS_RVOL, 0); 254 } 255 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_CONTROL, 256 AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART | AUVIA_RPCTRL_STOP 257 | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG); 258 } else { 259 uint8 regvalue = (stream->channels > 1 ? AUVIA_RPMODE_STEREO : 0) 260 | (stream->b16 == 1 ? AUVIA_RPMODE_16BIT : 0) 261 | AUVIA_RPMODE_INTR_FLAG | AUVIA_RPMODE_INTR_EOL | AUVIA_RPMODE_AUTOSTART; 262 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_MODE, regvalue); 263 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_CONTROL, AUVIA_RPCTRL_START); 264 } 265 } 266 267 void 268 auvia_stream_halt(auvia_stream *stream) 269 { 270 LOG(("auvia_stream_halt\n")); 271 272 stream->state &= ~AUVIA_STATE_STARTED; 273 274 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE); 275 } 276 277 auvia_stream * 278 auvia_stream_new(auvia_dev *card, uint8 use, uint32 bufframes, uint8 bufcount) 279 { 280 auvia_stream *stream; 281 cpu_status status; 282 LOG(("auvia_stream_new\n")); 283 284 stream = malloc(sizeof(auvia_stream)); 285 if (stream == NULL) 286 return (NULL); 287 stream->card = card; 288 stream->use = use; 289 stream->state = !AUVIA_STATE_STARTED; 290 stream->b16 = 0; 291 stream->sample_rate = 0; 292 stream->channels = 0; 293 stream->bufframes = bufframes; 294 stream->bufcount = bufcount; 295 stream->inth = NULL; 296 stream->inthparam = NULL; 297 stream->buffer = NULL; 298 stream->blksize = 0; 299 stream->trigblk = 0; 300 stream->blkmod = 0; 301 302 if(use & AUVIA_USE_PLAY) { 303 if(IS_8233(&card->config)) 304 stream->base = AUVIA_8233_MP_BASE; 305 //stream->base = AUVIA_PLAY_BASE; 306 else 307 stream->base = AUVIA_PLAY_BASE; 308 } else { 309 if(IS_8233(&card->config)) 310 stream->base = AUVIA_8233_RECORD_BASE; 311 else 312 stream->base = AUVIA_RECORD_BASE; 313 } 314 315 stream->frames_count = 0; 316 stream->real_time = 0; 317 stream->update_needed = false; 318 319 /* allocate memory for our dma ops */ 320 stream->dmaops_area = alloc_mem(&stream->dmaops_phy_base, &stream->dmaops_log_base, 321 VIA_TABLE_SIZE, "auvia dmaops"); 322 323 if (stream->dmaops_area < B_OK) { 324 PRINT(("couldn't allocate memory\n")); 325 free(stream); 326 return NULL; 327 } 328 329 status = lock(); 330 LIST_INSERT_HEAD((&card->streams), stream, next); 331 unlock(status); 332 333 return stream; 334 } 335 336 void 337 auvia_stream_delete(auvia_stream *stream) 338 { 339 cpu_status status; 340 LOG(("auvia_stream_delete\n")); 341 342 auvia_stream_halt(stream); 343 344 auvia_reg_write_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE, 0); 345 346 if (stream->dmaops_area > B_OK) 347 delete_area(stream->dmaops_area); 348 349 if(stream->buffer) 350 auvia_mem_free(stream->card, stream->buffer->log_base); 351 352 status = lock(); 353 LIST_REMOVE(stream, next); 354 unlock(status); 355 356 free(stream); 357 } 358 359 /* Auvia interrupt */ 360 361 static int32 362 auvia_int(void *arg) 363 { 364 auvia_dev *card = arg; 365 bool gotone = false; 366 uint32 curblk; 367 auvia_stream *stream; 368 369 if(auvia_reg_read_32(&card->config, AUVIA_SGD_SHADOW) 370 & card->interrupt_mask) { 371 372 LIST_FOREACH(stream, &card->streams, next) 373 if(auvia_reg_read_8(&card->config, stream->base + AUVIA_RP_STAT) & AUVIA_RPSTAT_INTR) { 374 gotone = true; 375 //TRACE(("interrupt\n")); 376 377 curblk = auvia_stream_curaddr(stream); 378 TRACE(("RPSTAT_INTR at trigblk %lu, stream->trigblk %lu\n", curblk, stream->trigblk)); 379 if (curblk == stream->trigblk) { 380 //TRACE(("AUVIA_RPSTAT_INTR at trigblk %lu\n", curblk)); 381 382 if(stream->inth) 383 stream->inth(stream->inthparam); 384 385 stream->trigblk++; 386 stream->trigblk %= stream->blkmod; 387 } 388 389 auvia_reg_write_8(&card->config, stream->base + AUVIA_RP_STAT, AUVIA_RPSTAT_INTR); 390 } 391 } else { 392 TRACE(("SGD_SHADOW %x %x\n", card->interrupt_mask, auvia_reg_read_32(&card->config, AUVIA_SGD_SHADOW))); 393 } 394 395 if(gotone) 396 return B_INVOKE_SCHEDULER; 397 398 TRACE(("Got unhandled interrupt\n")); 399 return B_UNHANDLED_INTERRUPT; 400 } 401 402 /* Auvia driver functions */ 403 404 /* detect presence of our hardware */ 405 status_t 406 init_hardware(void) 407 { 408 int ix=0; 409 pci_info info; 410 status_t err = ENODEV; 411 412 LOG_CREATE(); 413 414 PRINT(("init_hardware()\n")); 415 416 if (get_module(pci_name, (module_info **)&pci)) 417 return ENOSYS; 418 419 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { 420 if (info.vendor_id == VIATECH_VENDOR_ID && 421 (info.device_id == VIATECH_82C686_AC97_DEVICE_ID 422 || info.device_id == VIATECH_8233_AC97_DEVICE_ID 423 )) { 424 err = B_OK; 425 } 426 ix++; 427 } 428 429 put_module(pci_name); 430 431 return err; 432 } 433 434 static void 435 make_device_names( 436 auvia_dev * card) 437 { 438 sprintf(card->name, "audio/hmulti/auvia/%ld", card-cards+1); 439 names[num_names++] = card->name; 440 441 names[num_names] = NULL; 442 } 443 444 445 static status_t 446 auvia_init(auvia_dev * card) 447 { 448 uint32 pr; 449 450 pr = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, AUVIA_PCICONF_JUNK, 4); 451 PRINT(("AUVIA_PCICONF_JUNK before: %lx\n", pr)); 452 pr &= ~AUVIA_PCICONF_ENABLES; 453 pr |= AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST | AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD; 454 pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB); 455 (*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, AUVIA_PCICONF_JUNK, 4, pr ); 456 snooze(100); 457 pr = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, AUVIA_PCICONF_JUNK, 4); 458 PRINT(("AUVIA_PCICONF_JUNK after: %lx\n", pr)); 459 460 if(IS_8233(&card->config)) { 461 card->interrupt_mask = 462 AUVIA_8233_SGD_STAT_FLAG_EOL | 463 AUVIA_8233_SGD_STAT_FLAG_EOL << 4 | 464 AUVIA_8233_SGD_STAT_FLAG_EOL << 8 | 465 AUVIA_8233_SGD_STAT_FLAG_EOL << 12 | 466 AUVIA_8233_SGD_STAT_FLAG_EOL << 16 | 467 AUVIA_8233_SGD_STAT_FLAG_EOL << 24 | 468 AUVIA_8233_SGD_STAT_FLAG_EOL << 28; 469 } else { 470 card->interrupt_mask = AUVIA_SGD_STAT_ALL | (AUVIA_SGD_STAT_ALL << 4); 471 } 472 473 474 /* Init streams list */ 475 LIST_INIT(&(card->streams)); 476 477 /* Init mems list */ 478 LIST_INIT(&(card->mems)); 479 480 return B_OK; 481 } 482 483 static status_t 484 auvia_setup(auvia_dev * card) 485 { 486 status_t err = B_OK; 487 unsigned char cmd; 488 489 PRINT(("auvia_setup(%p)\n", card)); 490 491 make_device_names(card); 492 493 card->config.nabmbar = card->info.u.h0.base_registers[0]; 494 card->config.irq = card->info.u.h0.interrupt_line; 495 card->config.type = 0; 496 if(card->info.device_id == VIATECH_82C686_AC97_DEVICE_ID) 497 card->config.type |= TYPE_686; 498 if(card->info.device_id == VIATECH_8233_AC97_DEVICE_ID) 499 card->config.type |= TYPE_8233; 500 501 PRINT(("%s deviceid = %#04x chiprev = %x model = %x enhanced at %lx\n", card->name, card->info.device_id, 502 card->info.revision, card->info.u.h0.subsystem_id, card->config.nabmbar)); 503 504 cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2); 505 PRINT(("PCI command before: %x\n", cmd)); 506 (*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2, cmd | PCI_command_io); 507 cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2); 508 PRINT(("PCI command after: %x\n", cmd)); 509 510 /* reset the codec */ 511 PRINT(("codec reset\n")); 512 auvia_codec_write(&card->config, 0x00, 0x0000); 513 snooze(50000); // 50 ms 514 515 ac97_init(&card->config); 516 ac97_amp_enable(&card->config, true); 517 518 PRINT(("codec vendor id = %#08lx\n",ac97_get_vendor_id(&card->config))); 519 PRINT(("codec description = %s\n",ac97_get_vendor_id_description(&card->config))); 520 PRINT(("codec 3d enhancement = %s\n",ac97_get_3d_stereo_enhancement(&card->config))); 521 522 PRINT(("installing interrupt : %lx\n", card->config.irq)); 523 install_io_interrupt_handler(card->config.irq, auvia_int, card, 0); 524 525 /*PRINT(("codec master output = %#04x\n",auvia_codec_read(&card->config, 0x02))); 526 PRINT(("codec aux output = %#04x\n",auvia_codec_read(&card->config, 0x04))); 527 PRINT(("codec mono output = %#04x\n",auvia_codec_read(&card->config, 0x06))); 528 PRINT(("codec pcm output = %#04x\n",auvia_codec_read(&card->config, 0x18))); 529 PRINT(("codec line in = %#04x\n",auvia_codec_read(&card->config, 0x10))); 530 PRINT(("codec record line in= %#04x\n",auvia_codec_read(&card->config, 0x1a))); 531 PRINT(("codec record gain = %#04x\n",auvia_codec_read(&card->config, 0x1c)));*/ 532 533 PRINT(("writing codec registers\n")); 534 // TODO : to move with AC97 535 /* enable master output */ 536 auvia_codec_write(&card->config, AC97_MASTER_VOLUME, 0x0000); 537 /* enable aux output */ 538 auvia_codec_write(&card->config, AC97_AUX_OUT_VOLUME, 0x0000); 539 /* enable mono output */ 540 //auvia_codec_write(&card->config, AC97_MONO_VOLUME, 0x0004); 541 /* enable pcm output */ 542 auvia_codec_write(&card->config, AC97_PCM_OUT_VOLUME, 0x0808); 543 /* enable line in */ 544 //auvia_codec_write(&card->config, AC97_LINE_IN_VOLUME, 0x8808); 545 /* set record line in */ 546 auvia_codec_write(&card->config, AC97_RECORD_SELECT, 0x0404); 547 /* set record gain */ 548 //auvia_codec_write(&card->config, AC97_RECORD_GAIN, 0x0000); 549 550 PRINT(("codec master output = %#04x\n",auvia_codec_read(&card->config, AC97_MASTER_VOLUME))); 551 PRINT(("codec aux output = %#04x\n",auvia_codec_read(&card->config, AC97_AUX_OUT_VOLUME))); 552 PRINT(("codec mono output = %#04x\n",auvia_codec_read(&card->config, AC97_MONO_VOLUME))); 553 PRINT(("codec pcm output = %#04x\n",auvia_codec_read(&card->config, AC97_PCM_OUT_VOLUME))); 554 PRINT(("codec line in = %#04x\n",auvia_codec_read(&card->config, AC97_LINE_IN_VOLUME))); 555 PRINT(("codec record line in= %#04x\n",auvia_codec_read(&card->config, AC97_RECORD_SELECT))); 556 PRINT(("codec record gain = %#04x\n",auvia_codec_read(&card->config, AC97_RECORD_GAIN))); 557 558 if ((err = auvia_init(card))) 559 return (err); 560 561 PRINT(("init_driver done\n")); 562 563 return err; 564 } 565 566 567 status_t 568 init_driver(void) 569 { 570 int ix=0; 571 572 pci_info info; 573 num_cards = 0; 574 575 PRINT(("init_driver()\n")); 576 load_driver_symbols("auvia"); 577 578 if (get_module(pci_name, (module_info **) &pci)) 579 return ENOSYS; 580 581 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { 582 if (info.vendor_id == VIATECH_VENDOR_ID && 583 (info.device_id == VIATECH_82C686_AC97_DEVICE_ID 584 || info.device_id == VIATECH_8233_AC97_DEVICE_ID 585 )) { 586 if (num_cards == NUM_CARDS) { 587 PRINT(("Too many auvia cards installed!\n")); 588 break; 589 } 590 memset(&cards[num_cards], 0, sizeof(auvia_dev)); 591 cards[num_cards].info = info; 592 if (auvia_setup(&cards[num_cards])) { 593 PRINT(("Setup of auvia %ld failed\n", num_cards+1)); 594 } 595 else { 596 num_cards++; 597 } 598 } 599 ix++; 600 } 601 if (!num_cards) { 602 PRINT(("no cards\n")); 603 put_module(pci_name); 604 PRINT(("no suitable cards found\n")); 605 return ENODEV; 606 } 607 608 609 #if DEBUG 610 //add_debugger_command("auvia", auvia_debug, "auvia [card# (1-n)]"); 611 #endif 612 return B_OK; 613 } 614 615 616 static void 617 auvia_shutdown(auvia_dev *card) 618 { 619 PRINT(("shutdown(%p)\n", card)); 620 remove_io_interrupt_handler(card->config.irq, auvia_int, card); 621 } 622 623 624 void 625 uninit_driver(void) 626 { 627 int ix, cnt = num_cards; 628 num_cards = 0; 629 630 PRINT(("uninit_driver()\n")); 631 //remove_debugger_command("auvia", auvia_debug); 632 633 for (ix=0; ix<cnt; ix++) { 634 auvia_shutdown(&cards[ix]); 635 } 636 memset(&cards, 0, sizeof(cards)); 637 put_module(pci_name); 638 } 639 640 641 const char ** 642 publish_devices(void) 643 { 644 int ix = 0; 645 PRINT(("publish_devices()\n")); 646 647 for (ix=0; names[ix]; ix++) { 648 PRINT(("publish %s\n", names[ix])); 649 } 650 return (const char **)names; 651 } 652 653 654 device_hooks * 655 find_device(const char * name) 656 { 657 int ix; 658 659 PRINT(("find_device(%s)\n", name)); 660 661 for (ix=0; ix<num_cards; ix++) { 662 if (!strcmp(cards[ix].name, name)) { 663 return &multi_hooks; 664 } 665 } 666 PRINT(("find_device(%s) failed\n", name)); 667 return NULL; 668 } 669 670 int32 api_version = B_CUR_DRIVER_API_VERSION; 671