BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / audio / ac97 / sis7018 / Stream.cpp
blobcce12579be96979c53a5aa260994f3b9b1f8d307
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.
6 * Copyright for ali5451 support:
7 * (c) 2009, Krzysztof Ćwiertnia (krzysiek.bmkx_gmail_com).
8 */
11 #include "Stream.h"
13 #include <memory.h>
15 #include "Device.h"
16 #include "Registers.h"
17 #include "Settings.h"
20 Stream::Stream(Device *device, bool isInput)
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)
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_));
43 Stream::~Stream()
45 Free();
49 uint32
50 Stream::_HWId()
52 return fDevice->HardwareId();
56 status_t
57 Stream::Init()
59 if (fStatus == B_OK)
60 Free();
62 fHWChannel = fIsInput ? 0 : 1;
64 if (_HWId() == SiS7018)
65 fHWChannel += 0x20; // bank B optimized for PCM
66 else if (_HWId() == ALi5451 && fIsInput)
67 fHWChannel = 31;
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;
84 physical_entry PhysEntry;
85 get_memory_map(fBuffersAddress, fBuffersAreaSize, &PhysEntry, 1);
87 fBuffersPhysAddress = PhysEntry.address;
89 TRACE("Created area id %d with size: %#x at address %#x[phys:%#lx]\n",
90 fBuffersArea, fBuffersAreaSize, fBuffersAddress, fBuffersPhysAddress);
92 // back to samples - half of buffer for 16-bit stereo data
93 fBufferSamplesCount = fBuffersAreaSize / (2 * 2 * 2);
95 fStatus = B_OK;
96 return fStatus;
100 void
101 Stream::Free()
103 delete_area(fBuffersArea);
104 fStatus = B_NO_INIT;
108 uint32
109 Stream::_DecodeRate(uint32 rate)
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;
123 ERROR("Rate:%x is not supported. Fall to default 48000\n", rate);
124 return 48000;
128 void
129 Stream::GetFormat(multi_format_info *Format)
131 if (fIsInput) {
132 Format->input_latency = 0;
133 Format->input = fFormat;
134 } else {
135 Format->output_latency = 0;
136 Format->output = fFormat;
141 status_t
142 Stream::SetFormat(_multi_format& format, uint32 formats, uint32 rates)
144 if (fFormat.rate == format.rate && fFormat.format == format.format)
145 return B_OK;
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;
153 fFormat = format;
154 fFormat.cvsr = _DecodeRate(fFormat.rate);
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;
168 TRACE("Format:%#x;Rate:%#x;cvsr:%.2f\n",
169 fFormat.format, fFormat.rate, fFormat.cvsr);
171 // stop the stream - it will be rewaked during next exchnage buffers call
172 Stop();
174 return B_OK;
178 void
179 Stream::GetBuffers(uint32& Flags, int32& BuffersCount, int32& ChannelsCount,
180 uint32& BufferSize, buffer_desc** Buffers)
182 Flags |= fIsInput ? B_MULTI_BUFFER_RECORD : B_MULTI_BUFFER_PLAYBACK;
183 BuffersCount = 2;
184 ChannelsCount = 2;
185 BufferSize = fBufferSamplesCount;
187 uint32 stride = 4;
188 if (fFormat.format == B_FMT_8BIT_S || fFormat.format == B_FMT_8BIT_U) {
189 stride = 2;
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;
197 Buffers[0][0].stride
198 = Buffers[1][0].stride
199 = Buffers[0][1].stride
200 = Buffers[1][1].stride = stride;
202 // shift pair of second part of buffers
203 Buffers[1][0].base += BufferSize * stride;
204 Buffers[1][1].base += BufferSize * stride;
206 // shift right channel buffers
207 Buffers[0][1].base += stride / 2;
208 Buffers[1][1].base += stride / 2;
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);
216 status_t
217 Stream::Start()
219 if (!fIsInput)
220 fDevice->Mixer().SetOutputRate(fFormat.cvsr);
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
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;
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;
253 cpu_status cst = fDevice->Lock();
255 // select used channel
256 uint32 ChIntReg = fDevice->ReadPCI32(RegChIndex) & ~0x3f;
257 ChIntReg |= (fHWChannel & 0x3f);
258 fDevice->WritePCI32(RegChIndex, ChIntReg);
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);
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;
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);
297 // start current channel
298 fDevice->WritePCI32(_UseBankB() ? RegStartB : RegStartA, 1 << _HWVoice());
299 fIsActive = true;
301 fDevice->Unlock(cst);
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);
307 return B_OK;
311 status_t
312 Stream::Stop()
314 if (!fIsActive)
315 return B_OK;
317 cpu_status cst = fDevice->Lock();
319 // stop current channel
320 fDevice->WritePCI32(_UseBankB() ? RegStopB : RegStopA, 1 << _HWVoice());
321 fIsActive = false;
323 if (_HWId() == ALi5451 && fIsInput) {
324 uint32 reg = fDevice->ReadPCI32(RegALiDigiMixer);
325 fDevice->WritePCI32(RegALiDigiMixer, reg & ~(1 << _HWVoice()));
328 fDevice->Unlock(cst);
330 TRACE("%s:OK\n", fIsInput ? "Rec" : "Play");
332 fBufferCycle = fIsInput ? 1 : 0;
334 return B_OK;
338 bool
339 Stream::InterruptHandler()
341 uint32 SignaledMask = fDevice->ReadPCI32(
342 _UseBankB() ? RegAddrINTB : RegAddrINTA);
343 uint32 ChannelMask = 1 << _HWVoice();
344 if ((SignaledMask & ChannelMask) == 0) {
345 return false;
348 // first clear signalled channel bit
349 fDevice->WritePCI32(_UseBankB() ? RegAddrINTB : RegAddrINTA, ChannelMask);
351 fRealTime = system_time();
352 fFramesCount += fBufferSamplesCount;
353 fBufferCycle = (fBufferCycle + 1) % 2;
355 fDevice->SignalReadyBuffers();
357 return true;
361 void
362 Stream::ExchangeBuffers(bigtime_t& RealTime,
363 bigtime_t& FramesCount, int32& BufferCycle)
365 RealTime = fRealTime;
366 FramesCount = fFramesCount;
367 BufferCycle = fBufferCycle;