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