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