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.
6 * Copyright for ali5451 support:
7 * (c) 2009, Krzysztof Ćwiertnia (krzysiek.bmkx_gmail_com).
16 #include "Registers.h"
19 Device::Device(Device::Info
&DeviceInfo
, pci_info
&PCIInfo
)
28 fPlaybackStream(this, false),
29 fRecordStream(this, true)
31 B_INITIALIZE_SPINLOCK(&fHWSpinlock
);
33 fStatus
= _ReserveDeviceOnBus(true);
35 return; // InitCheck will handle the rest
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
);
44 fIOBase
= PCIInfo
.u
.h0
.base_registers
[0];
45 TRACE("fIOBase:%#010x\n", fIOBase
);
54 _ReserveDeviceOnBus(false);
56 if (fBuffersReadySem
> B_OK
) {
57 delete_sem(fBuffersReadySem
);
63 Device::_ResetCard(uint32 resetMask
, uint32 releaseMask
)
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);
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
);
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
);
94 uint32 channelsIndex
= ChIndexMidEna
| ChIndexEndEna
;
96 switch (HardwareId()) {
98 _ResetCard(0x000c0000, 0x00040000);
102 WritePCI32(RegSiSCodecGPIO
, 0x00000000);
103 WritePCI32(RegSiSCodecStatus
, SiSCodecResetOff
);
104 channelsIndex
|= ChIndexSiSEnaB
;
110 _ResetCard(0x000c0000, 0x00040000);
113 WritePCI32(RegALiDigiMixer
, ALiDigiMixerPCMIn
);
114 WritePCI32(RegALiVolumeA
, 0);
119 _ResetCard(0x00010000, 0x00010000);
122 WritePCI32(RegNXCodecStatus
, NXCodecStatusDAC1ON
);
127 _ResetCard(0x00040000, 0x00040000);
130 WritePCI32(RegCodecStatus
, CodecStatusDACON
);
135 // clear channels status
136 WritePCI32(RegStopA
, 0xffffffff);
137 WritePCI32(RegStopB
, 0xffffffff);
139 // disable channels interrupt
140 WritePCI32(RegEnaINTA
, 0x00000000);
141 WritePCI32(RegEnaINTB
, 0x00000000);
143 // enable loop interrupts
144 WritePCI32(RegChIndex
, channelsIndex
);
146 fRecordStream
.Init();
147 fPlaybackStream
.Init();
149 fBuffersReadySem
= create_sem(0, DRIVER_NAME
"_buffers_ready");
158 Device::Open(uint32 flags
)
160 TRACE("flags:%x\n", flags
);
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
);
169 status_t status
= fRecordStream
.Start();
170 if (status
!= B_OK
) {
171 ERROR("Error of starting record stream:%#010x\n", status
);
174 status
= fPlaybackStream
.Start();
175 if (status
!= B_OK
) {
176 ERROR("Error of starting playback stream:%#010x\n", status
);
188 status_t status
= fPlaybackStream
.Stop();
189 if (status
!= B_OK
) {
190 ERROR("Error of stopping playback stream:%#010x\n", status
);
193 status
= fRecordStream
.Stop();
194 if (status
!= B_OK
) {
195 ERROR("Error of stopping record stream:%#010x\n", status
);
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
);
218 Device::Read(uint8
*buffer
, size_t *numBytes
)
226 Device::Write(const uint8
*buffer
, size_t *numBytes
)
234 Device::Control(uint32 op
, void *buffer
, size_t length
)
237 case B_MULTI_GET_DESCRIPTION
:
238 return _MultiGetDescription((multi_description
*)buffer
);
240 case B_MULTI_GET_EVENT_INFO
:
241 TRACE(("B_MULTI_GET_EVENT_INFO\n"));
244 case B_MULTI_SET_EVENT_INFO
:
245 TRACE(("B_MULTI_SET_EVENT_INFO\n"));
248 case B_MULTI_GET_EVENT
:
249 TRACE(("B_MULTI_GET_EVENT\n"));
252 case B_MULTI_GET_ENABLED_CHANNELS
:
253 return _MultiGetEnabledChannels((multi_channel_enable
*)buffer
);
255 case B_MULTI_SET_ENABLED_CHANNELS
:
256 return _MultiSetEnabledChannels((multi_channel_enable
*)buffer
);
258 case B_MULTI_GET_GLOBAL_FORMAT
:
259 return _MultiGetGlobalFormat((multi_format_info
*)buffer
);
261 case B_MULTI_SET_GLOBAL_FORMAT
:
262 return _MultiSetGlobalFormat((multi_format_info
*)buffer
);
264 case B_MULTI_GET_CHANNEL_FORMATS
:
265 TRACE(("B_MULTI_GET_CHANNEL_FORMATS\n"));
268 case B_MULTI_SET_CHANNEL_FORMATS
:
269 TRACE(("B_MULTI_SET_CHANNEL_FORMATS\n"));
272 case B_MULTI_GET_MIX
:
273 return _MultiGetMix((multi_mix_value_info
*)buffer
);
275 case B_MULTI_SET_MIX
:
276 return _MultiSetMix((multi_mix_value_info
*)buffer
);
278 case B_MULTI_LIST_MIX_CHANNELS
:
279 TRACE(("B_MULTI_LIST_MIX_CHANNELS\n"));
282 case B_MULTI_LIST_MIX_CONTROLS
:
283 return _MultiListMixControls((multi_mix_control_info
*)buffer
);
285 case B_MULTI_LIST_MIX_CONNECTIONS
:
286 TRACE(("B_MULTI_LIST_MIX_CONNECTIONS\n"));
289 case B_MULTI_GET_BUFFERS
:
290 return _MultiGetBuffers((multi_buffer_list
*)buffer
);
292 case B_MULTI_SET_BUFFERS
:
293 TRACE(("B_MULTI_SET_BUFFERS\n"));
296 case B_MULTI_SET_START_TIME
:
297 TRACE(("B_MULTI_SET_START_TIME\n"));
300 case B_MULTI_BUFFER_EXCHANGE
:
301 return _MultiBufferExchange((multi_buffer_info
*)buffer
);
303 case B_MULTI_BUFFER_FORCE_STOP
:
304 TRACE(("B_MULTI_BUFFER_FORCE_STOP\n"));
308 ERROR("Unhandled IOCTL catched: %#010x\n", op
);
311 return B_DEV_INVALID_IOCTL
;
316 Device::_MultiGetDescription(multi_description
*multiDescription
)
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
},
333 multi_description Description
;
334 if (user_memcpy(&Description
,
335 multiDescription
, sizeof(multi_description
)) != B_OK
)
336 return B_BAD_ADDRESS
;
338 Description
.interface_version
= B_CURRENT_INTERFACE_VERSION
;
339 Description
.interface_minimum
= B_CURRENT_INTERFACE_VERSION
;
341 strlcpy(Description
.friendly_name
, fInfo
.Name(),
342 sizeof(Description
.friendly_name
));
344 strlcpy(Description
.vendor_info
, "Haiku.Inc.",
345 sizeof(Description
.vendor_info
));
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;
353 Description
.output_rates
= fMixer
.OutputRates();
354 Description
.input_rates
= fMixer
.InputRates();
356 Description
.output_formats
= fMixer
.OutputFormats();
357 Description
.input_formats
= fMixer
.InputFormats();
359 Description
.min_cvsr_rate
= 0;
360 Description
.max_cvsr_rate
= 0;
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;
368 Description
.control_panel
[0] = '\0';
370 if (user_memcpy(multiDescription
,
371 &Description
, sizeof(multi_description
)) != B_OK
)
372 return B_BAD_ADDRESS
;
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
;
386 Device::_MultiGetEnabledChannels(multi_channel_enable
*Enable
)
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
;
398 Device::_MultiSetEnabledChannels(multi_channel_enable
*Enable
)
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");
409 Device::_MultiGetGlobalFormat(multi_format_info
*Format
)
411 fPlaybackStream
.GetFormat(Format
);
412 fRecordStream
.GetFormat(Format
);
419 Device::_MultiSetGlobalFormat(multi_format_info
*Format
)
421 status_t status
= fPlaybackStream
.SetFormat(Format
->output
,
422 fMixer
.OutputFormats(), fMixer
.OutputRates());
426 return fRecordStream
.SetFormat(Format
->input
,
427 fMixer
.InputFormats(), fMixer
.InputRates());
432 Device::_MultiListMixControls(multi_mix_control_info
* Info
)
434 return fMixer
.ListMixControls(Info
);
439 Device::_MultiGetMix(multi_mix_value_info
*Info
)
441 return fMixer
.GetMix(Info
);
446 Device::_MultiSetMix(multi_mix_value_info
*Info
)
448 return fMixer
.SetMix(Info
);
453 Device::_MultiGetBuffers(multi_buffer_list
* List
)
455 fPlaybackStream
.GetBuffers(List
->flags
, List
->return_playback_buffers
,
456 List
->return_playback_channels
, List
->return_playback_buffer_size
,
457 List
->playback_buffers
);
459 fRecordStream
.GetBuffers(List
->flags
, List
->return_record_buffers
,
460 List
->return_record_channels
, List
->return_record_buffer_size
,
461 List
->record_buffers
);
467 Device::_MultiBufferExchange(multi_buffer_info
* bufferInfo
)
469 multi_buffer_info BufferInfo
;
470 if (user_memcpy(&BufferInfo
, bufferInfo
, sizeof(multi_buffer_info
)) != B_OK
) {
471 return B_BAD_ADDRESS
;
474 status_t status
= B_NO_INIT
;
476 if (!fRecordStream
.IsActive()) {
477 status
= fRecordStream
.Start();
478 if (status
!= B_OK
) {
479 ERROR("Error of starting record stream:%#010x\n", status
);
484 if (!fPlaybackStream
.IsActive()) {
485 status
= fPlaybackStream
.Start();
486 if (status
!= B_OK
) {
487 ERROR("Error of starting playback stream:%#010x\n", status
);
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");
498 cpu_status cst
= Lock();
500 fRecordStream
.ExchangeBuffers(BufferInfo
.recorded_real_time
,
501 BufferInfo
.recorded_frames_count
, BufferInfo
.record_buffer_cycle
);
503 fPlaybackStream
.ExchangeBuffers(BufferInfo
.played_real_time
,
504 BufferInfo
.played_frames_count
, BufferInfo
.playback_buffer_cycle
);
508 if (user_memcpy(bufferInfo
, &BufferInfo
, sizeof(multi_buffer_info
)) != B_OK
) {
509 return B_BAD_ADDRESS
;
517 Device::InterruptHandler(void *interruptParam
)
519 Device
*device
= reinterpret_cast<Device
*>(interruptParam
);
521 ERROR("Invalid parameter in the interrupt handler.\n");
522 return B_HANDLED_INTERRUPT
;
525 bool wasHandled
= false;
527 acquire_spinlock(&device
->fHWSpinlock
);
529 uint32 mask
= device
->ReadPCI32(RegMiscINT
);
530 if (mask
& 0x00000020) {
531 wasHandled
= device
->fRecordStream
.InterruptHandler();
532 wasHandled
= device
->fPlaybackStream
.InterruptHandler() || wasHandled
;
535 release_spinlock(&device
->fHWSpinlock
);
537 return wasHandled
? B_INVOKE_SCHEDULER
: B_UNHANDLED_INTERRUPT
;
542 Device::SignalReadyBuffers()
544 release_sem_etc(fBuffersReadySem
, 1, B_DO_NOT_RESCHEDULE
);
549 Device::_ReserveDeviceOnBus(bool reserve
)
551 status_t result
= B_NO_INIT
;
553 result
= gPCI
->reserve_device(fPCIInfo
.bus
, fPCIInfo
.device
,
554 fPCIInfo
.function
, DRIVER_NAME
, this);
556 ERROR("Unable to reserve PCI device %d:%d:%d on bus:%#010x\n",
557 fPCIInfo
.bus
, fPCIInfo
.device
, fPCIInfo
.function
, result
);
559 result
= gPCI
->unreserve_device(fPCIInfo
.bus
, fPCIInfo
.device
,
560 fPCIInfo
.function
, DRIVER_NAME
, this);
568 Device::ReadPCI8(int offset
)
570 return gPCI
->read_io_8(fIOBase
+ offset
);
575 Device::ReadPCI16(int offset
)
577 return gPCI
->read_io_16(fIOBase
+ offset
);
582 Device::ReadPCI32(int offset
)
584 return gPCI
->read_io_32(fIOBase
+ offset
);
589 Device::WritePCI8(int offset
, uint8 value
)
591 gPCI
->write_io_8(fIOBase
+ offset
, value
);
596 Device::WritePCI16(int offset
, uint16 value
)
598 gPCI
->write_io_16(fIOBase
+ offset
, value
);
603 Device::WritePCI32(int offset
, uint32 value
)
605 gPCI
->write_io_32(fIOBase
+ offset
, value
);
612 cpu_status st
= disable_interrupts();
613 acquire_spinlock(&fHWSpinlock
);
619 Device::Unlock(cpu_status st
)
621 release_spinlock(&fHWSpinlock
);
622 restore_interrupts(st
);