1 /* 2 * SiS 7018, Trident 4D Wave DX/NX, Acer Lab M5451 Sound Driver. 3 * Copyright (c) 2002, 2008-2011 S.Zharski <imker@gmx.li> 4 * Distributed under the terms of the MIT license. 5 * 6 * Copyright for ali5451 support: 7 * (c) 2009, Krzysztof Ćwiertnia (krzysiek.bmkx_gmail_com). 8 */ 9 10 11 #include "Device.h" 12 13 #include <string.h> 14 15 #include "Settings.h" 16 #include "Registers.h" 17 18 19 Device::Device(Device::Info &DeviceInfo, pci_info &PCIInfo) 20 : 21 fStatus(B_ERROR), 22 fPCIInfo(PCIInfo), 23 fInfo(DeviceInfo), 24 fIOBase(0), 25 fHWSpinlock(0), 26 fInterruptsNest(0), 27 fBuffersReadySem(-1), 28 fMixer(this), 29 fPlaybackStream(this, false), 30 fRecordStream(this, true) 31 { 32 fStatus = _ReserveDeviceOnBus(true); 33 if (fStatus != B_OK) 34 return; // InitCheck will handle the rest 35 36 uint32 cmdRegister = gPCI->read_pci_config(PCIInfo.bus, 37 PCIInfo.device, PCIInfo.function, PCI_command, 2); 38 TRACE("cmdRegister:%#010x\n", cmdRegister); 39 cmdRegister |= PCI_command_io | PCI_command_memory | PCI_command_master; 40 gPCI->write_pci_config(PCIInfo.bus, PCIInfo.device, 41 PCIInfo.function, PCI_command, 2, cmdRegister); 42 43 fIOBase = PCIInfo.u.h0.base_registers[0]; 44 TRACE("fIOBase:%#010x\n", fIOBase); 45 46 fStatus = B_OK; 47 } 48 49 50 Device::~Device() 51 { 52 fMixer.Free(); 53 _ReserveDeviceOnBus(false); 54 55 if (fBuffersReadySem > B_OK) { 56 delete_sem(fBuffersReadySem); 57 } 58 } 59 60 61 void 62 Device::_ResetCard(uint32 resetMask, uint32 releaseMask) 63 { 64 // disable Legacy Control 65 gPCI->write_pci_config(fPCIInfo.bus, fPCIInfo.device, 66 fPCIInfo.function, 0x40, 4, 0); 67 uint32 cmdReg = gPCI->read_pci_config(fPCIInfo.bus, fPCIInfo.device, 68 fPCIInfo.function, 0x44, 4); 69 gPCI->write_pci_config(fPCIInfo.bus, fPCIInfo.device, 70 fPCIInfo.function, 0x44, 4, cmdReg & 0xffff0000); 71 snooze(100); 72 73 // audio engine reset 74 cmdReg = gPCI->read_pci_config(fPCIInfo.bus, fPCIInfo.device, 75 fPCIInfo.function, 0x44, 4); 76 gPCI->write_pci_config(fPCIInfo.bus, fPCIInfo.device, 77 fPCIInfo.function, 0x44, 4, cmdReg | resetMask); 78 snooze(100); 79 80 // release reset 81 cmdReg = gPCI->read_pci_config(fPCIInfo.bus, fPCIInfo.device, 82 fPCIInfo.function, 0x44, 4); 83 gPCI->write_pci_config(fPCIInfo.bus, fPCIInfo.device, 84 fPCIInfo.function, 0x44, 4, cmdReg & ~releaseMask); 85 snooze(100); 86 } 87 88 89 status_t 90 Device::Setup() 91 { 92 cpu_status cp = 0; 93 uint32 channelsIndex = ChIndexMidEna | ChIndexEndEna; 94 95 switch (HardwareId()) { 96 case SiS7018: 97 _ResetCard(0x000c0000, 0x00040000); 98 99 cp = Lock(); 100 101 WritePCI32(RegSiSCodecGPIO, 0x00000000); 102 WritePCI32(RegSiSCodecStatus, SiSCodecResetOff); 103 channelsIndex |= ChIndexSiSEnaB; 104 105 Unlock(cp); 106 break; 107 108 case ALi5451: 109 _ResetCard(0x000c0000, 0x00040000); 110 111 cp = Lock(); 112 WritePCI32(RegALiDigiMixer, ALiDigiMixerPCMIn); 113 WritePCI32(RegALiVolumeA, 0); 114 Unlock(cp); 115 break; 116 117 case TridentNX: 118 _ResetCard(0x00010000, 0x00010000); 119 120 cp = Lock(); 121 WritePCI32(RegNXCodecStatus, NXCodecStatusDAC1ON); 122 Unlock(cp); 123 break; 124 125 case TridentDX: 126 _ResetCard(0x00040000, 0x00040000); 127 128 cp = Lock(); 129 WritePCI32(RegCodecStatus, CodecStatusDACON); 130 Unlock(cp); 131 break; 132 } 133 134 // clear channels status 135 WritePCI32(RegStopA, 0xffffffff); 136 WritePCI32(RegStopB, 0xffffffff); 137 138 // disable channels interrupt 139 WritePCI32(RegEnaINTA, 0x00000000); 140 WritePCI32(RegEnaINTB, 0x00000000); 141 142 // enable loop interrupts 143 WritePCI32(RegChIndex, channelsIndex); 144 145 fRecordStream.Init(); 146 fPlaybackStream.Init(); 147 148 fBuffersReadySem = create_sem(0, DRIVER_NAME "_buffers_ready"); 149 150 fMixer.Init(); 151 152 return B_OK; 153 } 154 155 156 status_t 157 Device::Open(uint32 flags) 158 { 159 TRACE("flags:%x\n", flags); 160 161 if (atomic_add(&fInterruptsNest, 1) == 0) { 162 install_io_interrupt_handler(fPCIInfo.u.h0.interrupt_line, 163 InterruptHandler, this, 0); 164 TRACE("Interrupt handler installed at line %d.\n", 165 fPCIInfo.u.h0.interrupt_line); 166 } 167 168 status_t status = fRecordStream.Start(); 169 if (status != B_OK) { 170 ERROR("Error of starting record stream:%#010x\n", status); 171 } 172 173 status = fPlaybackStream.Start(); 174 if (status != B_OK) { 175 ERROR("Error of starting playback stream:%#010x\n", status); 176 } 177 178 return B_OK; 179 } 180 181 182 status_t 183 Device::Close() 184 { 185 TRACE("closed!\n"); 186 187 status_t status = fPlaybackStream.Stop(); 188 if (status != B_OK) { 189 ERROR("Error of stopping playback stream:%#010x\n", status); 190 } 191 192 status = fRecordStream.Stop(); 193 if (status != B_OK) { 194 ERROR("Error of stopping record stream:%#010x\n", status); 195 } 196 197 if (atomic_add(&fInterruptsNest, -1) == 1) { 198 remove_io_interrupt_handler(fPCIInfo.u.h0.interrupt_line, 199 InterruptHandler, this); 200 TRACE("Interrupt handler at line %d uninstalled.\n", 201 fPCIInfo.u.h0.interrupt_line); 202 } 203 204 return B_OK; 205 } 206 207 208 status_t 209 Device::Free() 210 { 211 TRACE("freed\n"); 212 return B_OK; 213 } 214 215 216 status_t 217 Device::Read(uint8 *buffer, size_t *numBytes) 218 { 219 *numBytes = 0; 220 return B_IO_ERROR; 221 } 222 223 224 status_t 225 Device::Write(const uint8 *buffer, size_t *numBytes) 226 { 227 *numBytes = 0; 228 return B_IO_ERROR; 229 } 230 231 232 status_t 233 Device::Control(uint32 op, void *buffer, size_t length) 234 { 235 switch (op) { 236 case B_MULTI_GET_DESCRIPTION: 237 return _MultiGetDescription((multi_description*)buffer); 238 239 case B_MULTI_GET_EVENT_INFO: 240 TRACE(("B_MULTI_GET_EVENT_INFO\n")); 241 return B_ERROR; 242 243 case B_MULTI_SET_EVENT_INFO: 244 TRACE(("B_MULTI_SET_EVENT_INFO\n")); 245 return B_ERROR; 246 247 case B_MULTI_GET_EVENT: 248 TRACE(("B_MULTI_GET_EVENT\n")); 249 return B_ERROR; 250 251 case B_MULTI_GET_ENABLED_CHANNELS: 252 return _MultiGetEnabledChannels((multi_channel_enable*)buffer); 253 254 case B_MULTI_SET_ENABLED_CHANNELS: 255 return _MultiSetEnabledChannels((multi_channel_enable*)buffer); 256 257 case B_MULTI_GET_GLOBAL_FORMAT: 258 return _MultiGetGlobalFormat((multi_format_info*)buffer); 259 260 case B_MULTI_SET_GLOBAL_FORMAT: 261 return _MultiSetGlobalFormat((multi_format_info*)buffer); 262 263 case B_MULTI_GET_CHANNEL_FORMATS: 264 TRACE(("B_MULTI_GET_CHANNEL_FORMATS\n")); 265 return B_ERROR; 266 267 case B_MULTI_SET_CHANNEL_FORMATS: 268 TRACE(("B_MULTI_SET_CHANNEL_FORMATS\n")); 269 return B_ERROR; 270 271 case B_MULTI_GET_MIX: 272 return _MultiGetMix((multi_mix_value_info *)buffer); 273 274 case B_MULTI_SET_MIX: 275 return _MultiSetMix((multi_mix_value_info *)buffer); 276 277 case B_MULTI_LIST_MIX_CHANNELS: 278 TRACE(("B_MULTI_LIST_MIX_CHANNELS\n")); 279 return B_ERROR; 280 281 case B_MULTI_LIST_MIX_CONTROLS: 282 return _MultiListMixControls((multi_mix_control_info*)buffer); 283 284 case B_MULTI_LIST_MIX_CONNECTIONS: 285 TRACE(("B_MULTI_LIST_MIX_CONNECTIONS\n")); 286 return B_ERROR; 287 288 case B_MULTI_GET_BUFFERS: 289 return _MultiGetBuffers((multi_buffer_list*)buffer); 290 291 case B_MULTI_SET_BUFFERS: 292 TRACE(("B_MULTI_SET_BUFFERS\n")); 293 return B_ERROR; 294 295 case B_MULTI_SET_START_TIME: 296 TRACE(("B_MULTI_SET_START_TIME\n")); 297 return B_ERROR; 298 299 case B_MULTI_BUFFER_EXCHANGE: 300 return _MultiBufferExchange((multi_buffer_info*)buffer); 301 302 case B_MULTI_BUFFER_FORCE_STOP: 303 TRACE(("B_MULTI_BUFFER_FORCE_STOP\n")); 304 return B_ERROR; 305 306 default: 307 ERROR("Unhandled IOCTL catched: %#010x\n", op); 308 } 309 310 return B_DEV_INVALID_IOCTL; 311 } 312 313 314 status_t 315 Device::_MultiGetDescription(multi_description *multiDescription) 316 { 317 multi_channel_info channel_descriptions[] = { 318 { 0, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, 319 { 1, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, 320 { 2, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 }, 321 { 3, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 }, 322 { 4, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 323 B_CHANNEL_MINI_JACK_STEREO }, 324 { 5, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 325 B_CHANNEL_MINI_JACK_STEREO }, 326 { 6, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 327 B_CHANNEL_MINI_JACK_STEREO }, 328 { 7, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 329 B_CHANNEL_MINI_JACK_STEREO }, 330 }; 331 332 multi_description Description; 333 if (user_memcpy(&Description, 334 multiDescription, sizeof(multi_description)) != B_OK) 335 return B_BAD_ADDRESS; 336 337 Description.interface_version = B_CURRENT_INTERFACE_VERSION; 338 Description.interface_minimum = B_CURRENT_INTERFACE_VERSION; 339 340 strlcpy(Description.friendly_name, fInfo.Name(), 341 sizeof(Description.friendly_name)); 342 343 strlcpy(Description.vendor_info, "Haiku.Inc.", 344 sizeof(Description.vendor_info)); 345 346 Description.output_channel_count = 2; 347 Description.input_channel_count = 2; 348 Description.output_bus_channel_count = 2; 349 Description.input_bus_channel_count = 2; 350 Description.aux_bus_channel_count = 0; 351 352 Description.output_rates = fMixer.OutputRates(); 353 Description.input_rates = fMixer.InputRates(); 354 355 Description.output_formats = fMixer.OutputFormats(); 356 Description.input_formats = fMixer.InputFormats(); 357 358 Description.min_cvsr_rate = 0; 359 Description.max_cvsr_rate = 0; 360 361 Description.lock_sources = B_MULTI_LOCK_INTERNAL; 362 Description.timecode_sources = 0; 363 Description.interface_flags 364 = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD; 365 Description.start_latency = 3000; 366 367 Description.control_panel[0] = '\0'; 368 369 if (user_memcpy(multiDescription, 370 &Description, sizeof(multi_description)) != B_OK) 371 return B_BAD_ADDRESS; 372 373 if (Description.request_channel_count 374 >= (int)(_countof(channel_descriptions))) { 375 if (user_memcpy(multiDescription->channels, 376 &channel_descriptions, sizeof(channel_descriptions)) != B_OK) 377 return B_BAD_ADDRESS; 378 } 379 380 return B_OK; 381 } 382 383 384 status_t 385 Device::_MultiGetEnabledChannels(multi_channel_enable *Enable) 386 { 387 B_SET_CHANNEL(Enable->enable_bits, 0, true); 388 B_SET_CHANNEL(Enable->enable_bits, 1, true); 389 B_SET_CHANNEL(Enable->enable_bits, 2, true); 390 B_SET_CHANNEL(Enable->enable_bits, 3, true); 391 Enable->lock_source = B_MULTI_LOCK_INTERNAL; 392 return B_OK; 393 } 394 395 396 status_t 397 Device::_MultiSetEnabledChannels(multi_channel_enable *Enable) 398 { 399 TRACE("0:%s\n", B_TEST_CHANNEL(Enable->enable_bits, 0) ? "en" : "dis"); 400 TRACE("1:%s\n", B_TEST_CHANNEL(Enable->enable_bits, 1) ? "en" : "dis"); 401 TRACE("2:%s\n", B_TEST_CHANNEL(Enable->enable_bits, 2) ? "en" : "dis"); 402 TRACE("3:%s\n", B_TEST_CHANNEL(Enable->enable_bits, 3) ? "en" : "dis"); 403 return B_OK; 404 } 405 406 407 status_t 408 Device::_MultiGetGlobalFormat(multi_format_info *Format) 409 { 410 fPlaybackStream.GetFormat(Format); 411 fRecordStream.GetFormat(Format); 412 413 return B_OK; 414 } 415 416 417 status_t 418 Device::_MultiSetGlobalFormat(multi_format_info *Format) 419 { 420 status_t status = fPlaybackStream.SetFormat(Format->output, 421 fMixer.OutputFormats(), fMixer.OutputRates()); 422 if (status != B_OK) 423 return status; 424 425 return fRecordStream.SetFormat(Format->input, 426 fMixer.InputFormats(), fMixer.InputRates()); 427 } 428 429 430 status_t 431 Device::_MultiListMixControls(multi_mix_control_info* Info) 432 { 433 return fMixer.ListMixControls(Info); 434 } 435 436 437 status_t 438 Device::_MultiGetMix(multi_mix_value_info *Info) 439 { 440 return fMixer.GetMix(Info); 441 } 442 443 444 status_t 445 Device::_MultiSetMix(multi_mix_value_info *Info) 446 { 447 return fMixer.SetMix(Info); 448 } 449 450 451 status_t 452 Device::_MultiGetBuffers(multi_buffer_list* List) 453 { 454 fPlaybackStream.GetBuffers(List->flags, List->return_playback_buffers, 455 List->return_playback_channels, List->return_playback_buffer_size, 456 List->playback_buffers); 457 458 fRecordStream.GetBuffers(List->flags, List->return_record_buffers, 459 List->return_record_channels, List->return_record_buffer_size, 460 List->record_buffers); 461 return B_OK; 462 } 463 464 465 status_t 466 Device::_MultiBufferExchange(multi_buffer_info* bufferInfo) 467 { 468 multi_buffer_info BufferInfo; 469 if (user_memcpy(&BufferInfo, bufferInfo, sizeof(multi_buffer_info)) != B_OK) { 470 return B_BAD_ADDRESS; 471 } 472 473 status_t status = B_NO_INIT; 474 475 if (!fRecordStream.IsActive()) { 476 status = fRecordStream.Start(); 477 if (status != B_OK) { 478 ERROR("Error of starting record stream:%#010x\n", status); 479 return status; 480 } 481 } 482 483 if (!fPlaybackStream.IsActive()) { 484 status = fPlaybackStream.Start(); 485 if (status != B_OK) { 486 ERROR("Error of starting playback stream:%#010x\n", status); 487 return status; 488 } 489 } 490 491 status = acquire_sem_etc(fBuffersReadySem, 1, 492 B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, 50000); 493 if (status == B_TIMED_OUT) { 494 ERROR("Timeout during buffers exchange.\n"); 495 } 496 497 cpu_status cst = Lock(); 498 499 fRecordStream.ExchangeBuffers(BufferInfo.recorded_real_time, 500 BufferInfo.recorded_frames_count, BufferInfo.record_buffer_cycle); 501 502 fPlaybackStream.ExchangeBuffers(BufferInfo.played_real_time, 503 BufferInfo.played_frames_count, BufferInfo.playback_buffer_cycle); 504 505 Unlock(cst); 506 507 if (user_memcpy(bufferInfo, &BufferInfo, sizeof(multi_buffer_info)) != B_OK) { 508 return B_BAD_ADDRESS; 509 } 510 511 return B_OK; 512 } 513 514 515 int32 516 Device::InterruptHandler(void *interruptParam) 517 { 518 Device *device = reinterpret_cast<Device*>(interruptParam); 519 if (device == 0) { 520 ERROR("Invalid parameter in the interrupt handler.\n"); 521 return B_HANDLED_INTERRUPT; 522 } 523 524 bool wasHandled = false; 525 526 acquire_spinlock(&device->fHWSpinlock); 527 528 uint32 mask = device->ReadPCI32(RegMiscINT); 529 if (mask & 0x00000020) { 530 wasHandled = device->fRecordStream.InterruptHandler(); 531 wasHandled = device->fPlaybackStream.InterruptHandler() || wasHandled; 532 } 533 534 release_spinlock(&device->fHWSpinlock); 535 536 return wasHandled ? B_INVOKE_SCHEDULER : B_UNHANDLED_INTERRUPT; 537 } 538 539 540 void 541 Device::SignalReadyBuffers() 542 { 543 release_sem_etc(fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE); 544 } 545 546 547 status_t 548 Device::_ReserveDeviceOnBus(bool reserve) 549 { 550 status_t result = B_NO_INIT; 551 if (reserve) { 552 result = gPCI->reserve_device(fPCIInfo.bus, fPCIInfo.device, 553 fPCIInfo.function, DRIVER_NAME, this); 554 if (result != B_OK) 555 ERROR("Unable to reserve PCI device %d:%d:%d on bus:%#010x\n", 556 fPCIInfo.bus, fPCIInfo.device, fPCIInfo.function, result); 557 } else { 558 result = gPCI->unreserve_device(fPCIInfo.bus, fPCIInfo.device, 559 fPCIInfo.function, DRIVER_NAME, this); 560 } 561 562 return result; 563 } 564 565 566 uint8 567 Device::ReadPCI8(int offset) 568 { 569 return gPCI->read_io_8(fIOBase + offset); 570 } 571 572 573 uint16 574 Device::ReadPCI16(int offset) 575 { 576 return gPCI->read_io_16(fIOBase + offset); 577 } 578 579 580 uint32 581 Device::ReadPCI32(int offset) 582 { 583 return gPCI->read_io_32(fIOBase + offset); 584 } 585 586 587 void 588 Device::WritePCI8(int offset, uint8 value) 589 { 590 gPCI->write_io_8(fIOBase + offset, value); 591 } 592 593 594 void 595 Device::WritePCI16(int offset, uint16 value) 596 { 597 gPCI->write_io_16(fIOBase + offset, value); 598 } 599 600 601 void 602 Device::WritePCI32(int offset, uint32 value) 603 { 604 gPCI->write_io_32(fIOBase + offset, value); 605 } 606 607 608 cpu_status 609 Device::Lock() 610 { 611 cpu_status st = disable_interrupts(); 612 acquire_spinlock(&fHWSpinlock); 613 return st; 614 } 615 616 617 void 618 Device::Unlock(cpu_status st) 619 { 620 release_spinlock(&fHWSpinlock); 621 restore_interrupts(st); 622 } 623 624 625