[haiku-commits] r40273 - in haiku: branches/developer/siarzhuk trunk/build/jam trunk/src/add-ons/kernel/drivers/audio trunk/src/add-ons/kernel/drivers/audio/ac97 trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018

  • From: zharik@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 23 Jan 2011 19:47:57 +0100 (CET)

Author: siarzhuk
Date: 2011-01-23 19:47:57 +0100 (Sun, 23 Jan 2011)
New Revision: 40273
Changeset: http://dev.haiku-os.org/changeset/40273

Added:
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.cpp
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Driver.cpp
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Driver.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Jamfile
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Mixer.cpp
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Mixer.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Registers.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Settings.cpp
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Settings.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Stream.cpp
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Stream.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/makefile
   
haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/sis7018.settings.sample
Removed:
   haiku/branches/developer/siarzhuk/sis7018/
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/ali5451/
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/AC97.cpp
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/AC97.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.cpp
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Driver.cpp
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Driver.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Jamfile
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Registers.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Settings.cpp
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Settings.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Stream.cpp
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Stream.h
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/makefile
   
haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/sis7018.settings.sample
   haiku/trunk/src/add-ons/kernel/drivers/audio/sis7018/
Modified:
   haiku/trunk/build/jam/HaikuImage
   haiku/trunk/src/add-ons/kernel/drivers/audio/Jamfile
   haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/Jamfile
Log:
Audio driver for SiS 7018, Trident DX/NX and Acer Labs M5451 hardware 
was rewritten to Haiku MultiAudio API.

This changeset replaces both old version of the same driver written for
BeOS R3 Sound API and ali5451 driver that handles the same audio hardware.
The driver was tested with SiS 7018 and ALi M5451 cards. Trident DX/NX
support still should be tested.

Some parts, related to ALi M5451 support were inspired by original ali5451
code so the copyright (c) 2009 by Krzysztof ?\195?\132?\194?\134wiertnia was 
added in the source.



Modified: haiku/trunk/build/jam/HaikuImage
===================================================================
--- haiku/trunk/build/jam/HaikuImage    2011-01-23 16:20:35 UTC (rev 40272)
+++ haiku/trunk/build/jam/HaikuImage    2011-01-23 18:47:57 UTC (rev 40273)
@@ -156,8 +156,8 @@
 ;
 SYSTEM_ADD_ONS_SCREENSAVERS = Butterfly DebugNow Flurry
        $(HAIKU_INCLUDE_TRADEMARKS)Haiku Icons IFS Leaves Message Spider ;
-SYSTEM_ADD_ONS_DRIVERS_AUDIO = auich auvia echo3g emuxki hda ;
-SYSTEM_ADD_ONS_DRIVERS_AUDIO_OLD = ; #cmedia sis7018 usb_audio ;
+SYSTEM_ADD_ONS_DRIVERS_AUDIO = auich auvia echo3g emuxki hda sis7018 ;
+SYSTEM_ADD_ONS_DRIVERS_AUDIO_OLD = ; #cmedia usb_audio ;
 SYSTEM_ADD_ONS_DRIVERS_GRAPHICS = $(X86_ONLY)radeon $(X86_ONLY)nvidia
        $(X86_ONLY)neomagic $(X86_ONLY)matrox $(X86_ONLY)intel_extreme
        $(X86_ONLY)s3 $(X86_ONLY)vesa #$(X86_ONLY)via #$(X86_ONLY)vmware

Modified: haiku/trunk/src/add-ons/kernel/drivers/audio/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/audio/Jamfile        2011-01-23 
16:20:35 UTC (rev 40272)
+++ haiku/trunk/src/add-ons/kernel/drivers/audio/Jamfile        2011-01-23 
18:47:57 UTC (rev 40273)
@@ -9,6 +9,5 @@
 SubInclude HAIKU_TOP src add-ons kernel drivers audio module_driver ;
 SubInclude HAIKU_TOP src add-ons kernel drivers audio null ;
 SubInclude HAIKU_TOP src add-ons kernel drivers audio sb16 ;
-SubInclude HAIKU_TOP src add-ons kernel drivers audio sis7018 ;
 SubInclude HAIKU_TOP src add-ons kernel drivers audio usb_audio ;
 

Modified: haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/Jamfile   2011-01-23 
16:20:35 UTC (rev 40272)
+++ haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/Jamfile   2011-01-23 
18:47:57 UTC (rev 40273)
@@ -1,9 +1,9 @@
 SubDir HAIKU_TOP src add-ons kernel drivers audio ac97 ;
 
-SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 ali5451 ;
 SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 auich ;
 SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 auvia ;
 SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 es1370 ;
 SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 geode ;
 SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 ich ;
 # SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 ichaudio ;
+SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 sis7018 ;

Copied: haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.cpp 
(from rev 40272, haiku/branches/developer/siarzhuk/sis7018/Device.cpp)
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.cpp        
                        (rev 0)
+++ haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.cpp        
2011-01-23 18:47:57 UTC (rev 40273)
@@ -0,0 +1,625 @@
+/*
+ *     SiS 7018, Trident 4D Wave DX/NX, Acer Lab M5451 Sound Driver.
+ *     Copyright (c) 2002, 2008-2011 S.Zharski <imker@xxxxxx>
+ *     Distributed under the terms of the MIT license.
+ *
+ *     Copyright for ali5451 support:
+ *             (c) 2009, Krzysztof Ćwiertnia (krzysiek.bmkx_gmail_com).
+ */
+
+
+#include "Device.h"
+
+#include <string.h>
+
+#include "Settings.h"
+#include "Registers.h"
+
+
+Device::Device(Device::Info &DeviceInfo, pci_info &PCIInfo)
+               :       
+               fStatus(B_ERROR),
+               fPCIInfo(PCIInfo),
+               fInfo(DeviceInfo),
+               fIOBase(0),
+               fHWSpinlock(0),
+               fInterruptsNest(0),
+               fBuffersReadySem(-1),
+               fMixer(this),
+               fPlaybackStream(this, false),
+               fRecordStream(this, true)
+{
+       fStatus = _ReserveDeviceOnBus(true);
+       if (fStatus != B_OK)
+               return; // InitCheck will handle the rest
+
+       uint32 cmdRegister = gPCI->read_pci_config(PCIInfo.bus,
+                                                       PCIInfo.device, 
PCIInfo.function, PCI_command, 2);
+       TRACE("cmdRegister:%#010x\n", cmdRegister);
+       cmdRegister |= PCI_command_io | PCI_command_memory | PCI_command_master;
+       gPCI->write_pci_config(PCIInfo.bus, PCIInfo.device,
+                                                       PCIInfo.function, 
PCI_command, 2, cmdRegister);
+
+       fIOBase = PCIInfo.u.h0.base_registers[0];
+       TRACE("fIOBase:%#010x\n", fIOBase);
+       
+       fStatus = B_OK;
+}
+
+
+Device::~Device()
+{
+       fMixer.Free();
+       _ReserveDeviceOnBus(false);
+
+       if (fBuffersReadySem > B_OK) {
+               delete_sem(fBuffersReadySem);
+       }
+}
+
+
+void
+Device::_ResetCard(uint32 resetMask, uint32 releaseMask)
+{
+       // disable Legacy Control
+       gPCI->write_pci_config(fPCIInfo.bus, fPCIInfo.device,
+                                               fPCIInfo.function, 0x40, 4, 0);
+       uint32 cmdReg = gPCI->read_pci_config(fPCIInfo.bus, fPCIInfo.device,
+                                               fPCIInfo.function, 0x44, 4);
+       gPCI->write_pci_config(fPCIInfo.bus, fPCIInfo.device,
+                                               fPCIInfo.function, 0x44, 4, 
cmdReg & 0xffff0000);
+       snooze(100);
+
+       // audio engine reset
+       cmdReg = gPCI->read_pci_config(fPCIInfo.bus, fPCIInfo.device,
+                                               fPCIInfo.function, 0x44, 4);
+       gPCI->write_pci_config(fPCIInfo.bus, fPCIInfo.device,
+                                               fPCIInfo.function, 0x44, 4, 
cmdReg | resetMask);
+       snooze(100);
+
+       // release reset
+       cmdReg = gPCI->read_pci_config(fPCIInfo.bus, fPCIInfo.device,
+                                               fPCIInfo.function, 0x44, 4);
+       gPCI->write_pci_config(fPCIInfo.bus, fPCIInfo.device,
+                                               fPCIInfo.function, 0x44, 4, 
cmdReg & ~releaseMask);
+       snooze(100);
+}
+
+
+status_t
+Device::Setup()
+{
+       cpu_status cp = 0;
+       uint32 channelsIndex = ChIndexMidEna | ChIndexEndEna;
+
+       switch (HardwareId()) {
+               case SiS7018:
+                       _ResetCard(0x000c0000, 0x00040000);
+
+                       cp = Lock();
+
+                       WritePCI32(RegSiSCodecGPIO, 0x00000000); 
+                       WritePCI32(RegSiSCodecStatus, SiSCodecResetOff);
+                       channelsIndex |= ChIndexSiSEnaB;
+
+                       Unlock(cp);
+                       break;
+
+               case ALi5451:
+                       _ResetCard(0x000c0000, 0x00040000);
+
+                       cp = Lock();
+                       WritePCI32(RegALiDigiMixer, ALiDigiMixerPCMIn); 
+                       WritePCI32(RegALiVolumeA, 0);
+                       Unlock(cp);
+                       break;
+
+               case TridentNX:
+                       _ResetCard(0x00010000, 0x00010000);
+
+                       cp = Lock();
+                       WritePCI32(RegNXCodecStatus, NXCodecStatusDAC1ON); 
+                       Unlock(cp);
+                       break;
+
+               case TridentDX:
+                       _ResetCard(0x00040000, 0x00040000);
+
+                       cp = Lock();
+                       WritePCI32(RegCodecStatus, CodecStatusDACON);
+                       Unlock(cp);
+                       break;
+       }
+
+       // clear channels status
+       WritePCI32(RegStopA, 0xffffffff);
+       WritePCI32(RegStopB, 0xffffffff);
+
+       // disable channels interrupt
+       WritePCI32(RegEnaINTA, 0x00000000);
+       WritePCI32(RegEnaINTB, 0x00000000);
+
+       // enable loop interrupts
+       WritePCI32(RegChIndex, channelsIndex);
+
+       fRecordStream.Init();
+       fPlaybackStream.Init();
+
+       fBuffersReadySem = create_sem(0, DRIVER_NAME "_buffers_ready");
+
+       fMixer.Init();
+       
+       return B_OK;
+}
+
+
+status_t
+Device::Open(uint32 flags)
+{
+       TRACE("flags:%x\n", flags);
+
+       if (atomic_add(&fInterruptsNest, 1) == 0) {
+               install_io_interrupt_handler(fPCIInfo.u.h0.interrupt_line,
+                                                                               
                InterruptHandler, this, 0);
+               TRACE("Interrupt handler installed at line %d.\n",
+                                                                               
                fPCIInfo.u.h0.interrupt_line);
+       }
+
+       status_t status = fRecordStream.Start();
+       if (status != B_OK) {
+               ERROR("Error of starting record stream:%#010x\n", status);
+       }
+
+       status = fPlaybackStream.Start();
+       if (status != B_OK) {
+               ERROR("Error of starting playback stream:%#010x\n", status);
+       }
+
+
+       return B_OK;
+}
+
+
+status_t
+Device::Close()
+{
+       TRACE("closed!\n");
+
+       status_t status = fPlaybackStream.Stop();
+       if (status != B_OK) {
+               ERROR("Error of stopping playback stream:%#010x\n", status);
+       }
+
+       status = fRecordStream.Stop();
+       if (status != B_OK) {
+               ERROR("Error of stopping record stream:%#010x\n", status);
+       }
+
+       if (atomic_add(&fInterruptsNest, -1) == 1) {
+               remove_io_interrupt_handler(fPCIInfo.u.h0.interrupt_line,
+                                                                               
                InterruptHandler, this);
+               TRACE("Interrupt handler at line %d uninstalled.\n",
+                                                                               
                fPCIInfo.u.h0.interrupt_line);
+       }
+
+       return B_OK;
+}
+
+
+status_t
+Device::Free()
+{
+       TRACE("freed\n");
+       return B_OK;
+}
+
+
+status_t
+Device::Read(uint8 *buffer, size_t *numBytes)
+{
+       *numBytes = 0;
+       return B_IO_ERROR;
+}
+
+
+status_t
+Device::Write(const uint8 *buffer, size_t *numBytes)
+{
+       *numBytes = 0;
+       return B_IO_ERROR;
+}
+
+
+status_t
+Device::Control(uint32 op, void *buffer, size_t length)
+{
+       switch (op) {
+               case B_MULTI_GET_DESCRIPTION:
+                       return _MultiGetDescription((multi_description*)buffer);
+
+               case B_MULTI_GET_EVENT_INFO:
+                       TRACE(("B_MULTI_GET_EVENT_INFO\n"));
+                       return B_ERROR;
+
+               case B_MULTI_SET_EVENT_INFO:
+                       TRACE(("B_MULTI_SET_EVENT_INFO\n"));
+                       return B_ERROR;
+
+               case B_MULTI_GET_EVENT:
+                       TRACE(("B_MULTI_GET_EVENT\n"));
+                       return B_ERROR;
+
+               case B_MULTI_GET_ENABLED_CHANNELS:
+                       return 
_MultiGetEnabledChannels((multi_channel_enable*)buffer);
+
+               case B_MULTI_SET_ENABLED_CHANNELS:
+                       return 
_MultiSetEnabledChannels((multi_channel_enable*)buffer);
+
+               case B_MULTI_GET_GLOBAL_FORMAT:
+                       return 
_MultiGetGlobalFormat((multi_format_info*)buffer);
+
+               case B_MULTI_SET_GLOBAL_FORMAT:
+                       return 
_MultiSetGlobalFormat((multi_format_info*)buffer);
+
+               case B_MULTI_GET_CHANNEL_FORMATS:
+                       TRACE(("B_MULTI_GET_CHANNEL_FORMATS\n"));
+                       return B_ERROR;
+
+               case B_MULTI_SET_CHANNEL_FORMATS:
+                       TRACE(("B_MULTI_SET_CHANNEL_FORMATS\n"));
+                       return B_ERROR;
+
+               case B_MULTI_GET_MIX:
+                       return _MultiGetMix((multi_mix_value_info *)buffer);
+
+               case B_MULTI_SET_MIX:
+                       return _MultiSetMix((multi_mix_value_info *)buffer);
+
+               case B_MULTI_LIST_MIX_CHANNELS:
+                       TRACE(("B_MULTI_LIST_MIX_CHANNELS\n"));
+                       return B_ERROR;
+
+               case B_MULTI_LIST_MIX_CONTROLS:
+                       return 
_MultiListMixControls((multi_mix_control_info*)buffer);
+
+               case B_MULTI_LIST_MIX_CONNECTIONS:
+                       TRACE(("B_MULTI_LIST_MIX_CONNECTIONS\n"));
+                       return B_ERROR;
+
+               case B_MULTI_GET_BUFFERS:
+                       return _MultiGetBuffers((multi_buffer_list*)buffer);
+
+               case B_MULTI_SET_BUFFERS:
+                       TRACE(("B_MULTI_SET_BUFFERS\n"));
+                       return B_ERROR;
+
+               case B_MULTI_SET_START_TIME:
+                       TRACE(("B_MULTI_SET_START_TIME\n"));
+                       return B_ERROR;
+
+               case B_MULTI_BUFFER_EXCHANGE:
+                       return _MultiBufferExchange((multi_buffer_info*)buffer);
+
+               case B_MULTI_BUFFER_FORCE_STOP:
+                       TRACE(("B_MULTI_BUFFER_FORCE_STOP\n"));
+                       return B_ERROR;
+
+               default:
+                       ERROR("Unhandled IOCTL catched: %#010x\n", op);
+       }
+
+       return B_DEV_INVALID_IOCTL;
+}
+
+
+status_t
+Device::_MultiGetDescription(multi_description *multiDescription)
+{
+       multi_channel_info channel_descriptions[] = {
+               { 0, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | 
B_CHANNEL_STEREO_BUS,      0 },
+               { 1, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | 
B_CHANNEL_STEREO_BUS, 0 },
+               { 2, B_MULTI_INPUT_CHANNEL,      B_CHANNEL_LEFT | 
B_CHANNEL_STEREO_BUS,  0 },
+               { 3, B_MULTI_INPUT_CHANNEL,      B_CHANNEL_RIGHT | 
B_CHANNEL_STEREO_BUS, 0 },
+               { 4, B_MULTI_OUTPUT_BUS,         B_CHANNEL_LEFT | 
B_CHANNEL_STEREO_BUS,
+                                                                               
B_CHANNEL_MINI_JACK_STEREO },
+               { 5, B_MULTI_OUTPUT_BUS,         B_CHANNEL_RIGHT | 
B_CHANNEL_STEREO_BUS,
+                                                                               
B_CHANNEL_MINI_JACK_STEREO },
+               { 6, B_MULTI_INPUT_BUS,          B_CHANNEL_LEFT | 
B_CHANNEL_STEREO_BUS,
+                                                                               
B_CHANNEL_MINI_JACK_STEREO },
+               { 7, B_MULTI_INPUT_BUS,          B_CHANNEL_RIGHT | 
B_CHANNEL_STEREO_BUS,
+                                                                               
B_CHANNEL_MINI_JACK_STEREO },
+       };
+
+       multi_description Description;
+       if (user_memcpy(&Description,
+                       multiDescription, sizeof(multi_description)) != B_OK)
+               return B_BAD_ADDRESS;
+
+       Description.interface_version = B_CURRENT_INTERFACE_VERSION;
+       Description.interface_minimum = B_CURRENT_INTERFACE_VERSION;
+
+       strncpy(Description.friendly_name, fInfo.Name(),
+                                                                       
sizeof(Description.friendly_name));
+
+       strncpy(Description.vendor_info, "Haiku.Inc.",
+                                                                       
sizeof(Description.vendor_info));
+
+       Description.output_channel_count                = 2;
+       Description.input_channel_count                 = 2;
+       Description.output_bus_channel_count    = 2;
+       Description.input_bus_channel_count             = 2;
+       Description.aux_bus_channel_count               = 0;
+
+       Description.output_rates        = fMixer.OutputRates();
+       Description.input_rates         = fMixer.InputRates();
+
+       Description.output_formats      = fMixer.OutputFormats();
+       Description.input_formats       = fMixer.InputFormats();
+
+       Description.min_cvsr_rate       = 0;
+       Description.max_cvsr_rate       = 0;
+
+       Description.lock_sources = B_MULTI_LOCK_INTERNAL;
+       Description.timecode_sources = 0;
+       Description.interface_flags
+               = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
+       Description.start_latency = 3000;
+
+       Description.control_panel[0] = '\0';
+
+       if (user_memcpy(multiDescription,
+                       &Description, sizeof(multi_description)) != B_OK)
+               return B_BAD_ADDRESS;
+
+       if (Description.request_channel_count
+                       >= (int)(_countof(channel_descriptions))) {
+               if (user_memcpy(multiDescription->channels,
+                                       &channel_descriptions, 
sizeof(channel_descriptions)) != B_OK)
+                       return B_BAD_ADDRESS;
+       }
+
+       return B_OK;
+}
+
+
+status_t
+Device::_MultiGetEnabledChannels(multi_channel_enable *Enable)
+{
+       B_SET_CHANNEL(Enable->enable_bits, 0, true);
+       B_SET_CHANNEL(Enable->enable_bits, 1, true);
+       B_SET_CHANNEL(Enable->enable_bits, 2, true);
+       B_SET_CHANNEL(Enable->enable_bits, 3, true);
+       Enable->lock_source = B_MULTI_LOCK_INTERNAL;
+       return B_OK;
+}
+
+
+status_t
+Device::_MultiSetEnabledChannels(multi_channel_enable *Enable)
+{
+       TRACE("0:%s\n", B_TEST_CHANNEL(Enable->enable_bits, 0) ? "en" : "dis");
+       TRACE("1:%s\n", B_TEST_CHANNEL(Enable->enable_bits, 1) ? "en" : "dis");
+       TRACE("2:%s\n", B_TEST_CHANNEL(Enable->enable_bits, 2) ? "en" : "dis");
+       TRACE("3:%s\n", B_TEST_CHANNEL(Enable->enable_bits, 3) ? "en" : "dis");
+       return B_OK;
+}
+
+
+status_t
+Device::_MultiGetGlobalFormat(multi_format_info *Format)
+{
+       fPlaybackStream.GetFormat(Format);
+       fRecordStream.GetFormat(Format);
+
+       return B_OK;
+}
+
+
+status_t
+Device::_MultiSetGlobalFormat(multi_format_info *Format)
+{
+       status_t status = fPlaybackStream.SetFormat(Format->output, 
+                                                       fMixer.OutputFormats(), 
fMixer.OutputRates());
+       if (status != B_OK)
+               return status;
+
+       return fRecordStream.SetFormat(Format->input,
+                               fMixer.InputFormats(), fMixer.InputRates());
+}
+
+
+status_t
+Device::_MultiListMixControls(multi_mix_control_info* Info)
+{
+       return fMixer.ListMixControls(Info);
+}
+
+
+status_t
+Device::_MultiGetMix(multi_mix_value_info *Info)
+{
+       return fMixer.GetMix(Info);
+}
+
+
+status_t
+Device::_MultiSetMix(multi_mix_value_info *Info)
+{
+       return fMixer.SetMix(Info);
+}
+
+
+status_t
+Device::_MultiGetBuffers(multi_buffer_list* List)
+{
+       fPlaybackStream.GetBuffers(List->flags, List->return_playback_buffers,
+                       List->return_playback_channels, 
List->return_playback_buffer_size,
+                                                                               
                        List->playback_buffers);
+
+       fRecordStream.GetBuffers(List->flags, List->return_record_buffers,
+                       List->return_record_channels, 
List->return_record_buffer_size,
+                                                                               
                        List->record_buffers);
+       return B_OK;
+}
+
+
+status_t
+Device::_MultiBufferExchange(multi_buffer_info* bufferInfo)
+{
+       multi_buffer_info BufferInfo;
+       if (user_memcpy(&BufferInfo, bufferInfo, sizeof(multi_buffer_info)) != 
B_OK) {
+               return B_BAD_ADDRESS;
+       }
+
+       status_t status = B_NO_INIT;
+
+       if (!fRecordStream.IsActive()) {
+               status = fRecordStream.Start();
+               if (status != B_OK) {
+                       ERROR("Error of starting record stream:%#010x\n", 
status);
+                       return status;
+               }
+       }
+
+       if (!fPlaybackStream.IsActive()) {
+               status = fPlaybackStream.Start();
+               if (status != B_OK) {
+                       ERROR("Error of starting playback stream:%#010x\n", 
status);
+                       return status;
+               }
+       }
+
+       status = acquire_sem_etc(fBuffersReadySem, 1,
+                                       B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, 
50000);
+       if (status == B_TIMED_OUT) {
+               ERROR("Timeout during buffers exchange.\n");
+       }
+
+       cpu_status cst = Lock();
+
+       fRecordStream.ExchangeBuffers(BufferInfo.recorded_real_time,
+                       BufferInfo.recorded_frames_count, 
BufferInfo.record_buffer_cycle);
+
+       fPlaybackStream.ExchangeBuffers(BufferInfo.played_real_time,
+                       BufferInfo.played_frames_count, 
BufferInfo.playback_buffer_cycle);
+
+       Unlock(cst);
+
+       if (user_memcpy(bufferInfo, &BufferInfo, sizeof(multi_buffer_info)) != 
B_OK) {
+               return B_BAD_ADDRESS;
+       }
+
+       return B_OK;
+}
+
+
+int32
+Device::InterruptHandler(void *interruptParam)
+{
+       Device *device = reinterpret_cast<Device*>(interruptParam);
+       if (device == 0) {
+               ERROR("Invalid parameter in the interrupt handler.\n");
+               return B_HANDLED_INTERRUPT;
+       }
+
+       bool wasHandled = false;
+
+       acquire_spinlock(&device->fHWSpinlock);
+
+       uint32 mask = device->ReadPCI32(RegMiscINT);
+       if (mask & 0x00000020) {
+               wasHandled = device->fRecordStream.InterruptHandler();
+               wasHandled = device->fPlaybackStream.InterruptHandler() || 
wasHandled;
+       }
+
+       release_spinlock(&device->fHWSpinlock);
+
+       return wasHandled ? B_INVOKE_SCHEDULER : B_UNHANDLED_INTERRUPT;
+}
+
+
+void
+Device::SignalReadyBuffers()
+{
+       release_sem_etc(fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE);
+}
+
+
+status_t
+Device::_ReserveDeviceOnBus(bool reserve)
+{
+       status_t result = B_NO_INIT;
+       if (reserve) {
+               result = gPCI->reserve_device(fPCIInfo.bus, fPCIInfo.device,
+                                                       fPCIInfo.function, 
DRIVER_NAME, this);
+               if (result != B_OK)
+                       ERROR("Unable to reserve PCI device %d:%d:%d on 
bus:%#010x\n",
+                                       fPCIInfo.bus, fPCIInfo.device, 
fPCIInfo.function, result);
+       } else {
+               result = gPCI->unreserve_device(fPCIInfo.bus, fPCIInfo.device,
+                                                       fPCIInfo.function, 
DRIVER_NAME, this);
+       }
+
+       return result;
+}
+
+
+uint8
+Device::ReadPCI8(int offset)
+{
+       return gPCI->read_io_8(fIOBase + offset);
+}
+
+
+uint16
+Device::ReadPCI16(int offset)
+{
+       return gPCI->read_io_16(fIOBase + offset);
+}
+
+
+uint32
+Device::ReadPCI32(int offset)
+{
+       return gPCI->read_io_32(fIOBase + offset);
+}
+
+
+void
+Device::WritePCI8(int offset, uint8 value)
+{
+       gPCI->write_io_8(fIOBase + offset, value);
+}
+
+
+void
+Device::WritePCI16(int offset, uint16 value)
+{
+       gPCI->write_io_16(fIOBase + offset, value);
+}
+
+
+void
+Device::WritePCI32(int offset, uint32 value)
+{
+       gPCI->write_io_32(fIOBase + offset, value);
+}
+
+
+cpu_status
+Device::Lock()
+{
+       cpu_status st = disable_interrupts();
+       acquire_spinlock(&fHWSpinlock);
+       return st;
+}
+
+
+void
+Device::Unlock(cpu_status st)
+{
+       release_spinlock(&fHWSpinlock);
+       restore_interrupts(st);
+}
+
+

Copied: haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.h 
(from rev 40272, haiku/branches/developer/siarzhuk/sis7018/Device.h)
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.h          
                (rev 0)
+++ haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.h  
2011-01-23 18:47:57 UTC (rev 40273)
@@ -0,0 +1,99 @@
+/*
+ *     SiS 7018, Trident 4D Wave DX/NX, Acer Lab M5451 Sound Driver.
+ *     Copyright (c) 2002, 2008-2011 S.Zharski <imker@xxxxxx>
+ *     Distributed under the terms of the MIT license.
+ *
+ */
+#ifndef _SiS7018_DEVICE_H_
+#define _SiS7018_DEVICE_H_
+
+
+#include <KernelExport.h>
+
+#include "Driver.h"
+#include "Mixer.h"
+#include "Registers.h"
+#include "Settings.h"
+#include "Stream.h"
+
+
+// card ids for supported audio hardware
+const uint32 SiS7018   = 0x70181039;
+const uint32 ALi5451   = 0x545110b9;
+const uint32 TridentDX = 0x20001023;
+const uint32 TridentNX = 0x20011023;
+
+
+class Device {
+
+public:
+               class Info {
+               public: 
+                       const uint32            fId;
+                       const char*                     fName;
+                       inline const char*      Name()          { return fName; 
}
+                       inline uint16           DeviceId()      { return (fId 
>> 16) & 0xffff; }
+                       inline uint16           VendorId()      { return (fId) 
& 0xffff; }
+                       inline uint32           Id()            { return fId; }
+               };
+
+               uint32                          HardwareId() { return 
fInfo.Id(); }
+               pci_info&                       PCIInfo() { return fPCIInfo; }
+
+
+                                                       Device(Info 
&DeviceInfo, pci_info &PCIInfo);
+                                                       ~Device();
+
+               status_t                        Setup();
+               status_t                        InitCheck() { return fStatus; };
+
+               status_t                        Open(uint32 flags);
+               status_t                        Read(uint8 *buffer, size_t 
*numBytes);
+               status_t                        Write(const uint8 *buffer, 
size_t *numBytes);
+               status_t                        Control(uint32 op, void 
*buffer, size_t length);
+               status_t                        Close();
+               status_t                        Free();
+
+static int32                           InterruptHandler(void *interruptParam);
+               void                            SignalReadyBuffers();
+
+               cpu_status                      Lock();
+               void                            Unlock(cpu_status st);
+
+               uint8                           ReadPCI8(int offset);
+               uint16                          ReadPCI16(int offset);
+               uint32                          ReadPCI32(int offset);
+               void                            WritePCI8(int offset, uint8 
value);
+               void                            WritePCI16(int offset, uint16 
value);
+               void                            WritePCI32(int offset, uint32 
value);
+
+private:
+               status_t                        _ReserveDeviceOnBus(bool 
reserve);
+               void                            _ResetCard(uint32 resetMask, 
uint32 releaseMask);
+
+               status_t                        
_MultiGetDescription(multi_description *Description);
+               status_t                        
_MultiGetEnabledChannels(multi_channel_enable *Enable);
+               status_t                        
_MultiSetEnabledChannels(multi_channel_enable *Enable);
+               status_t                        
_MultiGetBuffers(multi_buffer_list* List);
+               status_t                        
_MultiGetGlobalFormat(multi_format_info *Format);
+               status_t                        
_MultiSetGlobalFormat(multi_format_info *Format);
+               status_t                        
_MultiGetMix(multi_mix_value_info *Info);
+               status_t                        
_MultiSetMix(multi_mix_value_info *Info);
+               status_t                        
_MultiListMixControls(multi_mix_control_info* Info);
+               status_t                        
_MultiBufferExchange(multi_buffer_info* Info);
+
+               status_t                        fStatus;
+               pci_info                        fPCIInfo;
+               Info&                           fInfo;
+               int                                     fIOBase;
+               int32                           fHWSpinlock;
+               int32                           fInterruptsNest;
+               sem_id                          fBuffersReadySem;
+
+               Mixer                           fMixer;
+               Stream                          fPlaybackStream;
+               Stream                          fRecordStream;
+};
+
+#endif // _SiS7018_DEVICE_H_
+

Copied: haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Driver.cpp 
(from rev 40272, haiku/branches/developer/siarzhuk/sis7018/Driver.cpp)
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Driver.cpp        
                        (rev 0)
+++ haiku/trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018/Driver.cpp        
2011-01-23 18:47:57 UTC (rev 40273)
@@ -0,0 +1,227 @@
+/*
+ *     SiS 7018, Trident 4D Wave DX/NX, Acer Lab M5451 Sound Driver.
+ *     Copyright (c) 2002, 2008-2011 S.Zharski <imker@xxxxxx>
+ *     Distributed under the terms of the MIT license.
+ *
+ */
+
+
+#include "Driver.h"
+
+#include <kernel_cpp.h>
+#include <string.h>
+
+#include "Device.h"
+#include "Settings.h"
+
+
+int32 api_version = B_CUR_DRIVER_API_VERSION;
+
+size_t gNumCards = 0;
+Device *gDevices[MAX_DEVICES] = { 0 };
+char *gDeviceNames[MAX_DEVICES + 1] = { 0 };
+pci_module_info *gPCI = NULL;
+
+
+static Device::Info cardInfos[] = {
+       { SiS7018, "SiS 7018" },
+       { ALi5451, "ALi M5451" },
+       { TridentDX, "Trident DX" },
+       { TridentNX, "Trident NX" }
+};
+
+
+status_t
+init_hardware()
+{
+       dprintf("sis7018:init_hardware:ver:%s\n", kVersion);
+       status_t result = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
+       if (result < B_OK) {
+               return ENOSYS;
+       }
+
+       pci_info info = {0};
+       for (long i = 0; B_OK == (*gPCI->get_nth_pci_info)(i, &info); i++) {
+               for (size_t idx = 0; idx < _countof(cardInfos); idx++) {
+                       if (info.vendor_id == cardInfos[idx].VendorId() &&
+                               info.device_id == cardInfos[idx].DeviceId())
+                       {
+                               put_module(B_PCI_MODULE_NAME);
+                               return B_OK;
+                       }
+               }
+       }
+
+       put_module(B_PCI_MODULE_NAME);
+       return ENODEV;
+}
+
+
+status_t
+init_driver()
+{
+       status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
+       if (status < B_OK) {
+               return ENOSYS;
+       }
+
+       load_settings();
+
+       pci_info info = { 0 };
+       for (long i = 0; B_OK == (*gPCI->get_nth_pci_info)(i, &info); i++) {
+               for (size_t idx = 0; idx < _countof(cardInfos); idx++) {
+                       if (info.vendor_id == cardInfos[idx].VendorId() &&
+                               info.device_id == cardInfos[idx].DeviceId())
+                       {
+                               if (gNumCards == MAX_DEVICES) {
+                                       ERROR("Skipped:%s [%#06x:%#06x]\n", 
cardInfos[idx].Name(),
+                                               cardInfos[idx].VendorId(), 
cardInfos[idx].DeviceId());
+                                       break;
+                               }
+
+                               Device* device = new Device(cardInfos[idx], 
info);
+                               if (device == 0) {
+                                       return ENODEV;
+                               }
+
+                               status_t status = device->InitCheck();
+                               if (status < B_OK) {
+                                       delete device;
+                                       break;
+                               }
+
+                               status = device->Setup();
+                               if (status < B_OK) {
+                                       delete device;
+                                       break;
+                               }
+
+                               char name[32] = {0};
+                               sprintf(name, "audio/hmulti/%s/%ld",
+                                                               
cardInfos[idx].Name(), gNumCards);
+                               gDeviceNames[gNumCards] = strdup(name);
+                               gDevices[gNumCards++] = device;
+
+                               TRACE("Found:%s [%#06x:%#06x]\n", 
cardInfos[idx].Name(),
+                                               cardInfos[idx].VendorId(), 
cardInfos[idx].DeviceId());
+                       }
+               }
+       }
+
+       if (gNumCards == 0) {
+               put_module(B_PCI_MODULE_NAME);
+               return ENODEV;
+       }
+
+       return B_OK;
+}
+
+
+void
+uninit_driver()
+{
+       for (size_t i = 0; i < MAX_DEVICES; i++) {
+               if (gDevices[i]) {
+                       delete gDevices[i];
+                       gDevices[i] = NULL;
+               }
+
+               free(gDeviceNames[i]);
+               gDeviceNames[i] = NULL;
+       }
+
+       put_module(B_PCI_MODULE_NAME);
+
+       release_settings();
+}
+
+
+static status_t
+SiS7018_open(const char *name, uint32 flags, void **cookie)
+{
+       status_t status = ENODEV;
+       *cookie = NULL;
+       for (size_t i = 0; i < MAX_DEVICES; i++) {
+               if (gDeviceNames[i] && !strcmp(gDeviceNames[i], name)) {
+                       status = gDevices[i]->Open(flags);
+                       *cookie = gDevices[i];
+               }
+       }
+
+       return status;
+}
+
+
+static status_t
+SiS7018_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
+{
+       Device *device = (Device *)cookie;
+       return device->Read((uint8 *)buffer, numBytes);
+}
+
+
+static status_t
+SiS7018_write(void *cookie, off_t position,
+                                                       const void *buffer, 
size_t *numBytes)
+{
+       Device *device = (Device *)cookie;
+       return device->Write((const uint8 *)buffer, numBytes);
+}
+
+
+static status_t
+SiS7018_control(void *cookie, uint32 op, void *buffer, size_t length)
+{
+       Device *device = (Device *)cookie;
+       return device->Control(op, buffer, length);
+}
+
+
+static status_t
+SiS7018_close(void *cookie)
+{
+       Device *device = (Device *)cookie;
+       return device->Close();
+}
+
+
+static status_t
+SiS7018_free(void *cookie)
+{
+       Device *device = (Device *)cookie;
+       return device->Free();
+}
+
+
+const char **
+publish_devices()
+{
+       for (size_t i = 0; i < MAX_DEVICES; i++) {
+               if (gDevices[i] == NULL)
+                       continue;
+
+               if (gDeviceNames[i])
+                       TRACE("%s\n", gDeviceNames[i]);
+       }
+
+       return (const char **)&gDeviceNames[0];
+}
+
+
+device_hooks *
+find_device(const char *name)
+{
+       static device_hooks deviceHooks = {
+               SiS7018_open,

[... truncated: 1709 lines follow ...]

Other related posts:

  • » [haiku-commits] r40273 - in haiku: branches/developer/siarzhuk trunk/build/jam trunk/src/add-ons/kernel/drivers/audio trunk/src/add-ons/kernel/drivers/audio/ac97 trunk/src/add-ons/kernel/drivers/audio/ac97/sis7018 - zharik