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
Device(Device::Info & DeviceInfo,pci_info & PCIInfo)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
~Device()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
_ResetCard(uint32 resetMask,uint32 releaseMask)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
Setup()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
Open(uint32 flags)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
Close()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
Free()210 Device::Free()
211 {
212 TRACE("freed\n");
213 return B_OK;
214 }
215
216
217 status_t
Read(uint8 * buffer,size_t * numBytes)218 Device::Read(uint8 *buffer, size_t *numBytes)
219 {
220 *numBytes = 0;
221 return B_IO_ERROR;
222 }
223
224
225 status_t
Write(const uint8 * buffer,size_t * numBytes)226 Device::Write(const uint8 *buffer, size_t *numBytes)
227 {
228 *numBytes = 0;
229 return B_IO_ERROR;
230 }
231
232
233 status_t
Control(uint32 op,void * buffer,size_t length)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
_MultiGetDescription(multi_description * multiDescription)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
_MultiGetEnabledChannels(multi_channel_enable * Enable)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
_MultiSetEnabledChannels(multi_channel_enable * Enable)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
_MultiGetGlobalFormat(multi_format_info * Format)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
_MultiSetGlobalFormat(multi_format_info * Format)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
_MultiListMixControls(multi_mix_control_info * Info)432 Device::_MultiListMixControls(multi_mix_control_info* Info)
433 {
434 return fMixer.ListMixControls(Info);
435 }
436
437
438 status_t
_MultiGetMix(multi_mix_value_info * Info)439 Device::_MultiGetMix(multi_mix_value_info *Info)
440 {
441 return fMixer.GetMix(Info);
442 }
443
444
445 status_t
_MultiSetMix(multi_mix_value_info * Info)446 Device::_MultiSetMix(multi_mix_value_info *Info)
447 {
448 return fMixer.SetMix(Info);
449 }
450
451
452 status_t
_MultiGetBuffers(multi_buffer_list * List)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
_MultiBufferExchange(multi_buffer_info * bufferInfo)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
InterruptHandler(void * interruptParam)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
SignalReadyBuffers()542 Device::SignalReadyBuffers()
543 {
544 release_sem_etc(fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE);
545 }
546
547
548 status_t
_ReserveDeviceOnBus(bool reserve)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
ReadPCI8(int offset)568 Device::ReadPCI8(int offset)
569 {
570 return gPCI->read_io_8(fIOBase + offset);
571 }
572
573
574 uint16
ReadPCI16(int offset)575 Device::ReadPCI16(int offset)
576 {
577 return gPCI->read_io_16(fIOBase + offset);
578 }
579
580
581 uint32
ReadPCI32(int offset)582 Device::ReadPCI32(int offset)
583 {
584 return gPCI->read_io_32(fIOBase + offset);
585 }
586
587
588 void
WritePCI8(int offset,uint8 value)589 Device::WritePCI8(int offset, uint8 value)
590 {
591 gPCI->write_io_8(fIOBase + offset, value);
592 }
593
594
595 void
WritePCI16(int offset,uint16 value)596 Device::WritePCI16(int offset, uint16 value)
597 {
598 gPCI->write_io_16(fIOBase + offset, value);
599 }
600
601
602 void
WritePCI32(int offset,uint32 value)603 Device::WritePCI32(int offset, uint32 value)
604 {
605 gPCI->write_io_32(fIOBase + offset, value);
606 }
607
608
609 cpu_status
Lock()610 Device::Lock()
611 {
612 cpu_status st = disable_interrupts();
613 acquire_spinlock(&fHWSpinlock);
614 return st;
615 }
616
617
618 void
Unlock(cpu_status st)619 Device::Unlock(cpu_status st)
620 {
621 release_spinlock(&fHWSpinlock);
622 restore_interrupts(st);
623 }
624
625
626