Author: siarzhuk Date: 2011-01-23 17:20:35 +0100 (Sun, 23 Jan 2011) New Revision: 40272 Changeset: http://dev.haiku-os.org/changeset/40272 Added: haiku/branches/developer/siarzhuk/sis7018/Mixer.cpp haiku/branches/developer/siarzhuk/sis7018/Mixer.h Removed: haiku/branches/developer/siarzhuk/sis7018/AC97.cpp haiku/branches/developer/siarzhuk/sis7018/AC97.h Modified: haiku/branches/developer/siarzhuk/sis7018/Device.cpp haiku/branches/developer/siarzhuk/sis7018/Device.h haiku/branches/developer/siarzhuk/sis7018/Driver.cpp haiku/branches/developer/siarzhuk/sis7018/Driver.h haiku/branches/developer/siarzhuk/sis7018/Jamfile haiku/branches/developer/siarzhuk/sis7018/Registers.h haiku/branches/developer/siarzhuk/sis7018/Settings.cpp haiku/branches/developer/siarzhuk/sis7018/Settings.h haiku/branches/developer/siarzhuk/sis7018/Stream.cpp haiku/branches/developer/siarzhuk/sis7018/Stream.h haiku/branches/developer/siarzhuk/sis7018/makefile haiku/branches/developer/siarzhuk/sis7018/sis7018.settings.sample Log: Rewriting of SiS7018 Audio driver to Haiku Multi-Audio API finished. It is ready to replace old R?\195?\1303 API one in the Haiku trunk. Modified: haiku/branches/developer/siarzhuk/sis7018/Device.cpp =================================================================== --- haiku/branches/developer/siarzhuk/sis7018/Device.cpp 2011-01-22 22:12:21 UTC (rev 40271) +++ haiku/branches/developer/siarzhuk/sis7018/Device.cpp 2011-01-23 16:20:35 UTC (rev 40272) @@ -1,115 +1,155 @@ /* - * SiS 7018 Audio Driver. - * Copyright (c) 2002, 2008, 2009 S.Zharski <imker@xxxxxx> + * 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 <lock.h> -#include "Driver.h" -#include "Settings.h" + #include "Device.h" -#include "Registers.h" -const uint16 TrCodecTimeout = 0xffff; +#include <string.h> -/*class SmartLock { - mutex &fMutex; -public: - SmartLock(mutex &m):fMutex(m) - { mutex_lock(&fMutex); } - ~SmartLock() { mutex_unlock(&fMutex); } -};*/ +#include "Settings.h" +#include "Registers.h" + Device::Device(Device::Info &DeviceInfo, pci_info &PCIInfo) - : fStatus(B_ERROR), + : + fStatus(B_ERROR), fPCIInfo(PCIInfo), fInfo(DeviceInfo), - fAC97(this), fIOBase(0), fHWSpinlock(0), - fPlaybackStream(this, false, 0), - fRecordStream(this, 10), - fInterruptsNest(0) - /*fOpen(false), - fDevice(device), - fNonBlocking(false), - fNotifyWriteSem(-1), - */ + fInterruptsNest(0), + fBuffersReadySem(-1), + fMixer(this), + fPlaybackStream(this, false), + fRecordStream(this, true) { -// mutex_init(&fInitMutex, "Init_"DRIVER_NAME); - //SmartLock lock(fInitMutex); fStatus = _ReserveDeviceOnBus(true); if (fStatus != B_OK) - return; // InitCheck will handle the rest + return; // InitCheck will handle the rest - uint32 cmdRegister = gPCIModule->read_pci_config(PCIInfo.bus, + uint32 cmdRegister = gPCI->read_pci_config(PCIInfo.bus, PCIInfo.device, PCIInfo.function, PCI_command, 2); - TRACE_ALWAYS("cmdRegister:%#010x\n", cmdRegister); + TRACE("cmdRegister:%#010x\n", cmdRegister); cmdRegister |= PCI_command_io | PCI_command_memory | PCI_command_master; - gPCIModule->write_pci_config(PCIInfo.bus, PCIInfo.device, + gPCI->write_pci_config(PCIInfo.bus, PCIInfo.device, PCIInfo.function, PCI_command, 2, cmdRegister); fIOBase = PCIInfo.u.h0.base_registers[0]; - TRACE_ALWAYS("fIOBase:%#010x\n", fIOBase); + TRACE("fIOBase:%#010x\n", fIOBase); - cpu_status cp = disable_interrupts(); - acquire_spinlock(&fHWSpinlock); - - switch (fInfo.Id()) { - case SiS7018: - WritePCI32(0x4c, 0x00000000); - WritePCI32(SiSCodecStatusReg, 0x000f0000); - break; - case TridentDX: - WritePCI32(TDXCodecStatusReg, 0x2|0x4); // DAC on | ADC on - break; - case TridentNX: - WritePCI32(TNXCodecStatusReg, 0x2|0x8); // DAC on | ADC on - break; - } - - WritePCI32(TrChIndexReg, 0x1000 | 0x2000 | 0x10000); // end | mid INT enable 64-ch mode - - release_spinlock(&fHWSpinlock); - restore_interrupts(cp); - - fPlaybackStream.Init(); - fRecordStream.Init(); - - fBuffersReadySem = create_sem(0, DRIVER_NAME "_buffers_ready"); - - fStatus = fAC97.Init(); + fStatus = B_OK; } Device::~Device() { -// mutex_destroy(&fInitMutex); + 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::_ReserveDeviceOnBus(bool reserve) +Device::Setup() { - status_t result = B_NO_INIT; - if (reserve) { - result = gPCIModule->reserve_device(fPCIInfo.bus, fPCIInfo.device, - fPCIInfo.function, DRIVER_NAME, this); - if (result != B_OK) - TRACE_ALWAYS("Unable to reserve PCI device %d:%d:%d on bus:%#010x\n", - fPCIInfo.bus, fPCIInfo.device, fPCIInfo.function, result); - } else { - result = gPCIModule->unreserve_device(fPCIInfo.bus, fPCIInfo.device, - fPCIInfo.function, DRIVER_NAME, this); + 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; } - return result; + // 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; } @@ -117,30 +157,25 @@ Device::Open(uint32 flags) { TRACE("flags:%x\n", flags); -/* if (fOpen) - return B_BUSY; - - fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK; - fOpen = true; - return result; */ - + if (atomic_add(&fInterruptsNest, 1) == 0) { install_io_interrupt_handler(fPCIInfo.u.h0.interrupt_line, - InterruptHandler, this, 0); + InterruptHandler, this, 0); TRACE("Interrupt handler installed at line %d.\n", - fPCIInfo.u.h0.interrupt_line); + fPCIInfo.u.h0.interrupt_line); } - status_t status = fPlaybackStream.Start(); + status_t status = fRecordStream.Start(); if (status != B_OK) { - TRACE_ALWAYS("Error of starting playback stream:%#010x\n", status); + ERROR("Error of starting record stream:%#010x\n", status); } - status = fRecordStream.Start(); + status = fPlaybackStream.Start(); if (status != B_OK) { - TRACE_ALWAYS("Error of starting record stream:%#010x\n", status); + ERROR("Error of starting playback stream:%#010x\n", status); } + return B_OK; } @@ -149,33 +184,24 @@ Device::Close() { TRACE("closed!\n"); - + status_t status = fPlaybackStream.Stop(); if (status != B_OK) { - TRACE_ALWAYS("Error of stopping playback stream:%#010x\n", status); + ERROR("Error of stopping playback stream:%#010x\n", status); } status = fRecordStream.Stop(); if (status != B_OK) { - TRACE_ALWAYS("Error of stopping record stream:%#010x\n", status); + 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); + InterruptHandler, this); TRACE("Interrupt handler at line %d uninstalled.\n", - fPCIInfo.u.h0.interrupt_line); + fPCIInfo.u.h0.interrupt_line); } -/* if (fRemoved) { - fOpen = false; - return B_OK; - } - - fOpen = false; - - return StopDevice();*/ - return B_OK; } @@ -214,12 +240,15 @@ 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); @@ -235,9 +264,11 @@ case B_MULTI_GET_CHANNEL_FORMATS: TRACE(("B_MULTI_GET_CHANNEL_FORMATS\n")); return B_ERROR; - case B_MULTI_SET_CHANNEL_FORMATS: /* only implemented if possible */ + + 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); @@ -246,30 +277,35 @@ case B_MULTI_LIST_MIX_CHANNELS: TRACE(("B_MULTI_LIST_MIX_CHANNELS\n")); - return B_ERROR;//auich_list_mix_channels(card, (multi_mix_channel_info *)data); + 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;//auich_list_mix_connections(card, (multi_mix_connection_info *)data); - case B_MULTI_GET_BUFFERS: /* Fill out the struct for the first time; doesn't start anything. */ + return B_ERROR; + + case B_MULTI_GET_BUFFERS: return _MultiGetBuffers((multi_buffer_list*)buffer); - case B_MULTI_SET_BUFFERS: /* Set what buffers to use, if the driver supports soft buffers. */ + case B_MULTI_SET_BUFFERS: TRACE(("B_MULTI_SET_BUFFERS\n")); - return B_ERROR; /* we do not support soft buffers */ - case B_MULTI_SET_START_TIME: /* When to actually start */ + return B_ERROR; + + case B_MULTI_SET_START_TIME: TRACE(("B_MULTI_SET_START_TIME\n")); return B_ERROR; - case B_MULTI_BUFFER_EXCHANGE: /* stop and go are derived from this being called */ + + case B_MULTI_BUFFER_EXCHANGE: return _MultiBufferExchange((multi_buffer_info*)buffer); - case B_MULTI_BUFFER_FORCE_STOP: /* force stop of playback, nothing in data */ + case B_MULTI_BUFFER_FORCE_STOP: TRACE(("B_MULTI_BUFFER_FORCE_STOP\n")); - return B_ERROR;//auich_buffer_force_stop(card); + return B_ERROR; + default: - TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op); + ERROR("Unhandled IOCTL catched: %#010x\n", op); } return B_DEV_INVALID_IOCTL; @@ -277,177 +313,6 @@ status_t -Device::SetupDevice() -{ - return B_OK; -} - - -void -Device::TeardownDevice() -{ - -} - - -uint16 -Device::ReadCodec(uint8 cdcReg) -{ - uint8 rdReg = SiSCodecReadReg; - uint32 statusRW = 0x00008000; - switch (fInfo.Id()) { - case SiS7018: - break; - case TridentDX: - rdReg = TDXCodecReadReg; - statusRW = 0x00008000; - break; - case TridentNX: - // TODO !!!! - rdReg = TNXCodecReadReg; - statusRW = 0x00000c00; - break; - case ALi5451: - // TODO !!!! - rdReg = TDXCodecReadReg; - statusRW = 0x00008000; - break; - } - - // TODO for Ali!! - cpu_status cp = disable_interrupts(); - acquire_spinlock(&fHWSpinlock); - - cdcReg &= 0x7f; - - WritePCI32(rdReg, cdcReg | statusRW); - - uint32 status = statusRW; - uint16 TO = TrCodecTimeout; - for (; TO > 0 && (status & statusRW); TO--) { - status = ReadPCI32(rdReg); - } - - release_spinlock(&fHWSpinlock); - restore_interrupts(cp); - - if (TO == 0) { - TRACE_ALWAYS("Timed out reg:%#04x.\n", cdcReg); - } - - return (status >> 16) & 0xffff; -} - - -status_t -Device::WriteCodec(uint8 cdcReg, uint16 value) -{ - uint8 wrReg = SiSCodecWriteReg; - uint32 statusRW = 0x00008000; - switch (fInfo.Id()) { - case SiS7018: - break; - case TridentDX: - wrReg = TDXCodecWriteReg; - statusRW = 0x00008000; - break; - case TridentNX: - // TODO !!!! - wrReg = TNXCodecWriteReg; - statusRW = 0x00000c00; - break; - case ALi5451: - // TODO !!!! - wrReg = TDXCodecWriteReg; - statusRW = 0x00008000; - break; - } - - // TODO for Ali!! - cpu_status cp = disable_interrupts(); - acquire_spinlock(&fHWSpinlock); - - cdcReg &= 0x7f; - uint32 status = statusRW; - - uint16 TO = TrCodecTimeout; - for (; TO > 0 && (status & statusRW); TO--) { - status = ReadPCI32(wrReg); - } - - WritePCI32(wrReg, (value << 16) | cdcReg | statusRW); - - release_spinlock(&fHWSpinlock); - restore_interrupts(cp); - - if (TO == 0) { - TRACE_ALWAYS("Timed out reg:%#04x.\n", cdcReg); - } - - return (TO > 0) ? B_OK : B_TIMED_OUT; -} - - -uint8 -Device::ReadPCI8(int offset) -{ - return gPCIModule->read_io_8(fIOBase + offset); -} - - -uint16 -Device::ReadPCI16(int offset) -{ - return gPCIModule->read_io_16(fIOBase + offset); -} - - -uint32 -Device::ReadPCI32(int offset) -{ - return gPCIModule->read_io_32(fIOBase + offset); -} - - -void -Device::WritePCI8(int offset, uint8 value) -{ - gPCIModule->write_io_8(fIOBase + offset, value); -} - - -void -Device::WritePCI16(int offset, uint16 value) -{ - gPCIModule->write_io_16(fIOBase + offset, value); -} - - -void -Device::WritePCI32(int offset, uint32 value) -{ - gPCIModule->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); -} - - -status_t Device::_MultiGetDescription(multi_description *multiDescription) { multi_channel_info channel_descriptions[] = { @@ -455,39 +320,45 @@ { 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 }, + { 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) + 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, "S.Zharski", + + 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 = B_SR_48000; - Description.input_rates = B_SR_48000; + Description.output_rates = fMixer.OutputRates(); + Description.input_rates = fMixer.InputRates(); - Description.min_cvsr_rate = 0; - Description.max_cvsr_rate = 0; + Description.output_formats = fMixer.OutputFormats(); + Description.input_formats = fMixer.InputFormats(); - Description.output_formats = B_FMT_16BIT; - Description.input_formats = B_FMT_16BIT; + Description.min_cvsr_rate = 0; + Description.max_cvsr_rate = 0; + Description.lock_sources = B_MULTI_LOCK_INTERNAL; Description.timecode_sources = 0; Description.interface_flags @@ -496,12 +367,12 @@ Description.control_panel[0] = '\0'; - if (user_memcpy(multiDescription, &Description, sizeof(multi_description)) != B_OK) + if (user_memcpy(multiDescription, + &Description, sizeof(multi_description)) != B_OK) return B_BAD_ADDRESS; if (Description.request_channel_count - >= (int)(sizeof(channel_descriptions) / sizeof(channel_descriptions[0]))) - { + >= (int)(_countof(channel_descriptions))) { if (user_memcpy(multiDescription->channels, &channel_descriptions, sizeof(channel_descriptions)) != B_OK) return B_BAD_ADDRESS; @@ -510,6 +381,7 @@ return B_OK; } + status_t Device::_MultiGetEnabledChannels(multi_channel_enable *Enable) { @@ -521,6 +393,7 @@ return B_OK; } + status_t Device::_MultiSetEnabledChannels(multi_channel_enable *Enable) { @@ -535,14 +408,9 @@ status_t Device::_MultiGetGlobalFormat(multi_format_info *Format) { - Format->output_latency = 0; - Format->input_latency = 0; - Format->timecode_kind = 0; + fPlaybackStream.GetFormat(Format); + fRecordStream.GetFormat(Format); - Format->output.rate = Format->input.rate = B_SR_48000; - Format->output.cvsr = Format->input.cvsr = 48000; - Format->output.format = Format->input.format = B_FMT_16BIT; - return B_OK; } @@ -550,28 +418,34 @@ status_t Device::_MultiSetGlobalFormat(multi_format_info *Format) { - return B_OK; + 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::_MultiGetMix(multi_mix_value_info *Info) +Device::_MultiListMixControls(multi_mix_control_info* Info) { - return fAC97.GetMix(Info); + return fMixer.ListMixControls(Info); } status_t -Device::_MultiSetMix(multi_mix_value_info *Info) +Device::_MultiGetMix(multi_mix_value_info *Info) { - return fAC97.SetMix(Info); + return fMixer.GetMix(Info); } status_t -Device::_MultiListMixControls(multi_mix_control_info* Info) +Device::_MultiSetMix(multi_mix_value_info *Info) { - return fAC97.ListMixControls(Info); + return fMixer.SetMix(Info); } @@ -592,33 +466,45 @@ status_t Device::_MultiBufferExchange(multi_buffer_info* bufferInfo) { - status_t status = acquire_sem_etc(fBuffersReadySem, 1, - B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, 50000); - if (status == B_TIMED_OUT) { - TRACE_ALWAYS("Timeout during buffers exchange.\n"); - } - 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); + BufferInfo.played_frames_count, BufferInfo.playback_buffer_cycle); - fRecordStream.ExchangeBuffers(BufferInfo.recorded_real_time, - BufferInfo.recorded_frames_count, BufferInfo.record_buffer_cycle); - Unlock(cst); -// TRACE("rt:%lld; fc:%lld; bc:%d; csp:%#010x\n", Info->played_real_time, -// Info->played_frames_count, Info->playback_buffer_cycle, fPlaybackStream.fCSP); - - TRACE("rt:%lld; fc:%lld; bc:%d\n", BufferInfo.recorded_real_time, - BufferInfo.recorded_frames_count, BufferInfo.record_buffer_cycle); - if (user_memcpy(bufferInfo, &BufferInfo, sizeof(multi_buffer_info)) != B_OK) { return B_BAD_ADDRESS; } @@ -626,35 +512,114 @@ return B_OK; } - + int32 -Device::InterruptHandler(void *InterruptParam) +Device::InterruptHandler(void *interruptParam) { - Device *device = (Device*)InterruptParam; + Device *device = reinterpret_cast<Device*>(interruptParam); if (device == 0) { - TRACE_ALWAYS("Invalid parameter in the interrupt handler.\n"); + ERROR("Invalid parameter in the interrupt handler.\n"); return B_HANDLED_INTERRUPT; } - int32 result = B_UNHANDLED_INTERRUPT; + bool wasHandled = false; acquire_spinlock(&device->fHWSpinlock); - uint32 mask = device->ReadPCI32(TrMiscINTReg); + uint32 mask = device->ReadPCI32(RegMiscINT); if (mask & 0x00000020) { - uint32 SignaledChannelsMask = device->ReadPCI32(TrAddressINTBReg); - - result = device->fPlaybackStream.InterruptHandler(SignaledChannelsMask); - - if (result == B_UNHANDLED_INTERRUPT) - result = device->fRecordStream.InterruptHandler(SignaledChannelsMask); - - device->WritePCI32(TrAddressINTBReg, SignaledChannelsMask); - //result = B_HANDLED_INTERRUPT; + 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); +} + + Modified: haiku/branches/developer/siarzhuk/sis7018/Device.h =================================================================== --- haiku/branches/developer/siarzhuk/sis7018/Device.h 2011-01-22 22:12:21 UTC (rev 40271) +++ haiku/branches/developer/siarzhuk/sis7018/Device.h 2011-01-23 16:20:35 UTC (rev 40272) @@ -1,20 +1,21 @@ /* * SiS 7018, Trident 4D Wave DX/NX, Acer Lab M5451 Sound Driver. - * Copyright (c) 2002, 2008 S.Zharski <imker@xxxxxx> + * 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 <lock.h> + +#include <KernelExport.h> + #include "Driver.h" -#include "AC97.h" +#include "Mixer.h" +#include "Registers.h" +#include "Settings.h" #include "Stream.h" -//#include "hmulti_audio.h" -//#include <lock.h> // card ids for supported audio hardware const uint32 SiS7018 = 0x70181039; @@ -23,55 +24,53 @@ const uint32 TridentNX = 0x20011023; -class Device : public Codec { +class Device { + public: class Info { public: const uint32 fId; const char* fName; - // Info(const uint32 Id, const char* Name) - // : fId(Id), fName(Name) { } 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); - virtual ~Device(); + ~Device(); + status_t Setup(); status_t InitCheck() { return fStatus; }; status_t Open(uint32 flags); -// bool IsOpen() { return fOpen; }; - - status_t Close(); - status_t Free(); - 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 SetupDevice(); - void TeardownDevice(); + 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); [... truncated: 2074 lines follow ...]