BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / audio / ac97 / sis7018 / Device.cpp
blob000859a90d96cf0bb3a349df06709271d53ccefa
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.
6 * Copyright for ali5451 support:
7 * (c) 2009, Krzysztof Ćwiertnia (krzysiek.bmkx_gmail_com).
8 */
11 #include "Device.h"
13 #include <string.h>
15 #include "Settings.h"
16 #include "Registers.h"
19 Device::Device(Device::Info &DeviceInfo, pci_info &PCIInfo)
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)
31 B_INITIALIZE_SPINLOCK(&fHWSpinlock);
33 fStatus = _ReserveDeviceOnBus(true);
34 if (fStatus != B_OK)
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);
47 fStatus = B_OK;
51 Device::~Device()
53 fMixer.Free();
54 _ReserveDeviceOnBus(false);
56 if (fBuffersReadySem > B_OK) {
57 delete_sem(fBuffersReadySem);
62 void
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);
72 snooze(100);
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);
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);
90 status_t
91 Device::Setup()
93 cpu_status cp = 0;
94 uint32 channelsIndex = ChIndexMidEna | ChIndexEndEna;
96 switch (HardwareId()) {
97 case SiS7018:
98 _ResetCard(0x000c0000, 0x00040000);
100 cp = Lock();
102 WritePCI32(RegSiSCodecGPIO, 0x00000000);
103 WritePCI32(RegSiSCodecStatus, SiSCodecResetOff);
104 channelsIndex |= ChIndexSiSEnaB;
106 Unlock(cp);
107 break;
109 case ALi5451:
110 _ResetCard(0x000c0000, 0x00040000);
112 cp = Lock();
113 WritePCI32(RegALiDigiMixer, ALiDigiMixerPCMIn);
114 WritePCI32(RegALiVolumeA, 0);
115 Unlock(cp);
116 break;
118 case TridentNX:
119 _ResetCard(0x00010000, 0x00010000);
121 cp = Lock();
122 WritePCI32(RegNXCodecStatus, NXCodecStatusDAC1ON);
123 Unlock(cp);
124 break;
126 case TridentDX:
127 _ResetCard(0x00040000, 0x00040000);
129 cp = Lock();
130 WritePCI32(RegCodecStatus, CodecStatusDACON);
131 Unlock(cp);
132 break;
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");
151 fMixer.Init();
153 return B_OK;
157 status_t
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);
179 return B_OK;
183 status_t
184 Device::Close()
186 TRACE("closed!\n");
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);
205 return B_OK;
209 status_t
210 Device::Free()
212 TRACE("freed\n");
213 return B_OK;
217 status_t
218 Device::Read(uint8 *buffer, size_t *numBytes)
220 *numBytes = 0;
221 return B_IO_ERROR;
225 status_t
226 Device::Write(const uint8 *buffer, size_t *numBytes)
228 *numBytes = 0;
229 return B_IO_ERROR;
233 status_t
234 Device::Control(uint32 op, void *buffer, size_t length)
236 switch (op) {
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"));
242 return B_ERROR;
244 case B_MULTI_SET_EVENT_INFO:
245 TRACE(("B_MULTI_SET_EVENT_INFO\n"));
246 return B_ERROR;
248 case B_MULTI_GET_EVENT:
249 TRACE(("B_MULTI_GET_EVENT\n"));
250 return B_ERROR;
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"));
266 return B_ERROR;
268 case B_MULTI_SET_CHANNEL_FORMATS:
269 TRACE(("B_MULTI_SET_CHANNEL_FORMATS\n"));
270 return B_ERROR;
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"));
280 return B_ERROR;
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"));
287 return B_ERROR;
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"));
294 return B_ERROR;
296 case B_MULTI_SET_START_TIME:
297 TRACE(("B_MULTI_SET_START_TIME\n"));
298 return B_ERROR;
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"));
305 return B_ERROR;
307 default:
308 ERROR("Unhandled IOCTL catched: %#010x\n", op);
311 return B_DEV_INVALID_IOCTL;
315 status_t
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;
381 return B_OK;
385 status_t
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;
393 return B_OK;
397 status_t
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");
404 return B_OK;
408 status_t
409 Device::_MultiGetGlobalFormat(multi_format_info *Format)
411 fPlaybackStream.GetFormat(Format);
412 fRecordStream.GetFormat(Format);
414 return B_OK;
418 status_t
419 Device::_MultiSetGlobalFormat(multi_format_info *Format)
421 status_t status = fPlaybackStream.SetFormat(Format->output,
422 fMixer.OutputFormats(), fMixer.OutputRates());
423 if (status != B_OK)
424 return status;
426 return fRecordStream.SetFormat(Format->input,
427 fMixer.InputFormats(), fMixer.InputRates());
431 status_t
432 Device::_MultiListMixControls(multi_mix_control_info* Info)
434 return fMixer.ListMixControls(Info);
438 status_t
439 Device::_MultiGetMix(multi_mix_value_info *Info)
441 return fMixer.GetMix(Info);
445 status_t
446 Device::_MultiSetMix(multi_mix_value_info *Info)
448 return fMixer.SetMix(Info);
452 status_t
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);
462 return B_OK;
466 status_t
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);
480 return status;
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;
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);
506 Unlock(cst);
508 if (user_memcpy(bufferInfo, &BufferInfo, sizeof(multi_buffer_info)) != B_OK) {
509 return B_BAD_ADDRESS;
512 return B_OK;
516 int32
517 Device::InterruptHandler(void *interruptParam)
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;
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;
541 void
542 Device::SignalReadyBuffers()
544 release_sem_etc(fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE);
548 status_t
549 Device::_ReserveDeviceOnBus(bool reserve)
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);
563 return result;
567 uint8
568 Device::ReadPCI8(int offset)
570 return gPCI->read_io_8(fIOBase + offset);
574 uint16
575 Device::ReadPCI16(int offset)
577 return gPCI->read_io_16(fIOBase + offset);
581 uint32
582 Device::ReadPCI32(int offset)
584 return gPCI->read_io_32(fIOBase + offset);
588 void
589 Device::WritePCI8(int offset, uint8 value)
591 gPCI->write_io_8(fIOBase + offset, value);
595 void
596 Device::WritePCI16(int offset, uint16 value)
598 gPCI->write_io_16(fIOBase + offset, value);
602 void
603 Device::WritePCI32(int offset, uint32 value)
605 gPCI->write_io_32(fIOBase + offset, value);
609 cpu_status
610 Device::Lock()
612 cpu_status st = disable_interrupts();
613 acquire_spinlock(&fHWSpinlock);
614 return st;
618 void
619 Device::Unlock(cpu_status st)
621 release_spinlock(&fHWSpinlock);
622 restore_interrupts(st);