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 "Stream.h" 12 13 #include <memory.h> 14 15 #include "Device.h" 16 #include "Registers.h" 17 #include "Settings.h" 18 19 20 Stream::Stream(Device *device, bool isInput) 21 : 22 fDevice(device), 23 fStatus(B_NO_INIT), 24 fIsInput(isInput), 25 fIsActive(false), 26 fHWChannel(isInput ? 0 : 1), 27 fBuffersArea(-1), 28 fBuffersAreaSize(0), 29 fBufferSamplesCount(0), 30 fBuffersAddress(0), 31 fBuffersPhysAddress(0), 32 fRealTime(0), 33 fFramesCount(0), 34 fBufferCycle(fIsInput ? 1 :0) 35 { 36 fFormat.format = B_FMT_16BIT; 37 fFormat.rate = B_SR_48000; 38 fFormat.cvsr = _DecodeRate(fFormat.rate); 39 memset(fFormat._reserved_, 0, sizeof(fFormat._reserved_)); 40 } 41 42 43 Stream::~Stream() 44 { 45 Free(); 46 } 47 48 49 uint32 50 Stream::_HWId() 51 { 52 return fDevice->HardwareId(); 53 } 54 55 56 status_t 57 Stream::Init() 58 { 59 if (fStatus == B_OK) 60 Free(); 61 62 fHWChannel = fIsInput ? 0 : 1; 63 64 if (_HWId() == SiS7018) 65 fHWChannel += 0x20; // bank B optimized for PCM 66 else if (_HWId() == ALi5451 && fIsInput) 67 fHWChannel = 31; 68 69 // assume maximal possible buffers size 70 fBuffersAreaSize = 1024; // samples 71 fBuffersAreaSize *= 2 * 2 * 2; // stereo + 16-bit samples + 2 buffers 72 fBuffersAreaSize = (fBuffersAreaSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1); 73 fBuffersArea = create_area( 74 (fIsInput) ? DRIVER_NAME "_record_area" : DRIVER_NAME "_playback_area", 75 &fBuffersAddress, B_ANY_KERNEL_ADDRESS, fBuffersAreaSize, 76 B_32_BIT_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA); 77 if (fBuffersArea < 0) { 78 ERROR("Error of creating %#lx-bytes size buffer area:%#010x\n", 79 fBuffersAreaSize, fBuffersArea); 80 fStatus = fBuffersArea; 81 return fStatus; 82 } 83 84 physical_entry PhysEntry; 85 get_memory_map(fBuffersAddress, fBuffersAreaSize, &PhysEntry, 1); 86 87 fBuffersPhysAddress = PhysEntry.address; 88 89 TRACE("Created area id %d with size: %#x at address %#x[phys:%#lx]\n", 90 fBuffersArea, fBuffersAreaSize, fBuffersAddress, fBuffersPhysAddress); 91 92 // back to samples - half of buffer for 16-bit stereo data 93 fBufferSamplesCount = fBuffersAreaSize / (2 * 2 * 2); 94 95 fStatus = B_OK; 96 return fStatus; 97 } 98 99 100 void 101 Stream::Free() 102 { 103 delete_area(fBuffersArea); 104 fStatus = B_NO_INIT; 105 } 106 107 108 uint32 109 Stream::_DecodeRate(uint32 rate) 110 { 111 switch(rate) { 112 case B_SR_8000: return 8000; 113 case B_SR_11025: return 11025; 114 case B_SR_12000: return 12000; 115 case B_SR_16000: return 16000; 116 case B_SR_22050: return 22050; 117 case B_SR_24000: return 24000; 118 case B_SR_32000: return 32000; 119 case B_SR_44100: return 44100; 120 case B_SR_48000: return 48000; 121 } 122 123 ERROR("Rate:%x is not supported. Fall to default 48000\n", rate); 124 return 48000; 125 } 126 127 128 void 129 Stream::GetFormat(multi_format_info *Format) 130 { 131 if (fIsInput) { 132 Format->input_latency = 0; 133 Format->input = fFormat; 134 } else { 135 Format->output_latency = 0; 136 Format->output = fFormat; 137 } 138 } 139 140 141 status_t 142 Stream::SetFormat(_multi_format& format, uint32 formats, uint32 rates) 143 { 144 if (fFormat.rate == format.rate && fFormat.format == format.format) 145 return B_OK; 146 147 if ((format.rate & rates) == 0 || (format.format & formats) == 0) { 148 ERROR("Unsupported data format:%x or rate:%x. Ignore.\n", 149 format.format, format.rate); 150 return B_ERROR; 151 } 152 153 fFormat = format; 154 fFormat.cvsr = _DecodeRate(fFormat.rate); 155 156 fBufferSamplesCount = fBuffersAreaSize / (2 * 2); 157 switch (fFormat.format) { 158 default: 159 ERROR("Unsupported data format:%x. 16 bit assumed.\n", fFormat.format); 160 case B_FMT_16BIT: 161 fBufferSamplesCount /= 2; 162 break; 163 case B_FMT_8BIT_S: 164 case B_FMT_8BIT_U: 165 break; 166 } 167 168 TRACE("Format:%#x;Rate:%#x;cvsr:%.2f\n", 169 fFormat.format, fFormat.rate, fFormat.cvsr); 170 171 // stop the stream - it will be rewaked during next exchnage buffers call 172 Stop(); 173 174 return B_OK; 175 } 176 177 178 void 179 Stream::GetBuffers(uint32& Flags, int32& BuffersCount, int32& ChannelsCount, 180 uint32& BufferSize, buffer_desc** Buffers) 181 { 182 Flags |= fIsInput ? B_MULTI_BUFFER_RECORD : B_MULTI_BUFFER_PLAYBACK; 183 BuffersCount = 2; 184 ChannelsCount = 2; 185 BufferSize = fBufferSamplesCount; 186 187 uint32 stride = 4; 188 if (fFormat.format == B_FMT_8BIT_S || fFormat.format == B_FMT_8BIT_U) { 189 stride = 2; 190 } 191 // [b][c] init buffers 192 Buffers[0][0].base 193 = Buffers[1][0].base 194 = Buffers[0][1].base 195 = Buffers[1][1].base = (char*)fBuffersAddress; 196 197 Buffers[0][0].stride 198 = Buffers[1][0].stride 199 = Buffers[0][1].stride 200 = Buffers[1][1].stride = stride; 201 202 // shift pair of second part of buffers 203 Buffers[1][0].base += BufferSize * stride; 204 Buffers[1][1].base += BufferSize * stride; 205 206 // shift right channel buffers 207 Buffers[0][1].base += stride / 2; 208 Buffers[1][1].base += stride / 2; 209 210 TRACE("%s buffers:\n", fIsInput ? "input" : "output"); 211 TRACE("1: %#010x %#010x\n", Buffers[0][0].base, Buffers[0][1].base); 212 TRACE("2: %#010x %#010x\n", Buffers[1][0].base, Buffers[1][1].base); 213 } 214 215 216 status_t 217 Stream::Start() 218 { 219 if (!fIsInput) 220 fDevice->Mixer().SetOutputRate(fFormat.cvsr); 221 222 uint32 CSO = 0; 223 uint32 LBA = uint32(fBuffersPhysAddress) & 0x3fffffff; 224 uint32 ESO = ((fBufferSamplesCount * 2) - 1) & 0xffff; 225 uint32 Delta = fIsInput ? ((48000 << 12) / uint32(fFormat.cvsr)) & 0xffff 226 : ((uint32(fFormat.cvsr) << 12) / 48000) & 0xffff; 227 uint32 DeltaESO = (ESO << 16) | Delta; 228 uint32 FMControlEtc = fIsInput ? 0 : (0x03 << 14); 229 uint32 ControlEtc = 1 << 14 | 1 << 12; // stereo data + loop enabled 230 231 switch (fFormat.format) { 232 case B_FMT_16BIT: 233 ControlEtc |= (1 << 15); // 16 bit 234 case B_FMT_8BIT_S: 235 ControlEtc |= (1 << 13); // signed 236 break; 237 } 238 239 switch (_HWId()) { 240 case TridentDX: 241 FMControlEtc |= (0x7f << 7) < 0x7f; 242 break; 243 case TridentNX: 244 CSO = Delta << 24; 245 DeltaESO = ((Delta << 16) & 0xff000000) | (ESO & 0x00ffffff); 246 FMControlEtc |= (0x7f << 7) < 0x7f; 247 break; 248 case SiS7018: 249 FMControlEtc = fIsInput ? (0x8a80 << 16) : FMControlEtc; 250 break; 251 } 252 253 cpu_status cst = fDevice->Lock(); 254 255 // select used channel 256 uint32 ChIntReg = fDevice->ReadPCI32(RegChIndex) & ~0x3f; 257 ChIntReg |= (fHWChannel & 0x3f); 258 fDevice->WritePCI32(RegChIndex, ChIntReg); 259 260 fDevice->WritePCI32(RegCSOAlphaFMS, CSO); 261 fDevice->WritePCI32(RegLBA_PPTR, LBA); 262 fDevice->WritePCI32(RegDeltaESO, DeltaESO); 263 fDevice->WritePCI32(RegRVolCVolFMC, FMControlEtc); 264 fDevice->WritePCI32(RegGVSelVolCtrl, ControlEtc); 265 fDevice->WritePCI32(RegEBuf1, 0); 266 fDevice->WritePCI32(RegEBuf2, 0); 267 268 if (fIsInput) { 269 uint32 reg = 0; 270 switch (_HWId()) { 271 case ALi5451: 272 reg = fDevice->ReadPCI32(RegALiDigiMixer); 273 fDevice->WritePCI32(RegALiDigiMixer, reg | (1 << _HWVoice())); 274 break; 275 case TridentDX: 276 reg = fDevice->ReadPCI8(RegCodecStatus); 277 fDevice->WritePCI8(RegCodecStatus, 278 reg | CodecStatusADCON | CodecStatusSBCtrl); 279 // enable and set record channel 280 fDevice->WritePCI8(RegRecChannel, 0x80 | _HWVoice()); 281 break; 282 case TridentNX: 283 reg = fDevice->ReadPCI16(RegMiscINT); 284 fDevice->WritePCI8(RegMiscINT, reg | 0x1000); 285 // enable and set record channel 286 fDevice->WritePCI8(RegRecChannel, 0x80 | _HWVoice()); 287 break; 288 } 289 } 290 291 // enable INT for current channel 292 uint32 ChIntMask = fDevice->ReadPCI32(_UseBankB() ? RegEnaINTB : RegEnaINTA); 293 ChIntMask |= 1 << _HWVoice(); 294 fDevice->WritePCI32(_UseBankB() ? RegAddrINTB : RegAddrINTA, 1 << _HWVoice()); 295 fDevice->WritePCI32(_UseBankB() ? RegEnaINTB : RegEnaINTA, ChIntMask); 296 297 // start current channel 298 fDevice->WritePCI32(_UseBankB() ? RegStartB : RegStartA, 1 << _HWVoice()); 299 fIsActive = true; 300 301 fDevice->Unlock(cst); 302 303 TRACE("%s:CSO:%#x;LBA:%#x;ESO:%#x;Delta:%#x;FM:%#x:Ctrl:%#x;CIR:%#x\n", 304 fIsInput ? "Rec" : "Play", CSO, LBA, ESO, Delta, FMControlEtc, 305 ControlEtc, ChIntReg); 306 307 return B_OK; 308 } 309 310 311 status_t 312 Stream::Stop() 313 { 314 if (!fIsActive) 315 return B_OK; 316 317 cpu_status cst = fDevice->Lock(); 318 319 // stop current channel 320 fDevice->WritePCI32(_UseBankB() ? RegStopB : RegStopA, 1 << _HWVoice()); 321 fIsActive = false; 322 323 if (_HWId() == ALi5451 && fIsInput) { 324 uint32 reg = fDevice->ReadPCI32(RegALiDigiMixer); 325 fDevice->WritePCI32(RegALiDigiMixer, reg & ~(1 << _HWVoice())); 326 } 327 328 fDevice->Unlock(cst); 329 330 TRACE("%s:OK\n", fIsInput ? "Rec" : "Play"); 331 332 fBufferCycle = fIsInput ? 1 : 0; 333 334 return B_OK; 335 } 336 337 338 bool 339 Stream::InterruptHandler() 340 { 341 uint32 SignaledMask = fDevice->ReadPCI32( 342 _UseBankB() ? RegAddrINTB : RegAddrINTA); 343 uint32 ChannelMask = 1 << _HWVoice(); 344 if ((SignaledMask & ChannelMask) == 0) { 345 return false; 346 } 347 348 // first clear signalled channel bit 349 fDevice->WritePCI32(_UseBankB() ? RegAddrINTB : RegAddrINTA, ChannelMask); 350 351 fRealTime = system_time(); 352 fFramesCount += fBufferSamplesCount; 353 fBufferCycle = (fBufferCycle + 1) % 2; 354 355 fDevice->SignalReadyBuffers(); 356 357 return true; 358 } 359 360 361 void 362 Stream::ExchangeBuffers(bigtime_t& RealTime, 363 bigtime_t& FramesCount, int32& BufferCycle) 364 { 365 RealTime = fRealTime; 366 FramesCount = fFramesCount; 367 BufferCycle = fBufferCycle; 368 } 369 370