xref: /haiku/src/add-ons/kernel/drivers/audio/ac97/sis7018/Stream.cpp (revision 25a7b01d15612846f332751841da3579db313082)
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 
Stream(Device * device,bool isInput)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 
~Stream()43 Stream::~Stream()
44 {
45 	Free();
46 }
47 
48 
49 uint32
_HWId()50 Stream::_HWId()
51 {
52 	return fDevice->HardwareId();
53 }
54 
55 
56 status_t
Init()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
Free()101 Stream::Free()
102 {
103 	delete_area(fBuffersArea);
104 	fStatus = B_NO_INIT;
105 }
106 
107 
108 uint32
_DecodeRate(uint32 rate)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
GetFormat(multi_format_info * Format)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
SetFormat(_multi_format & format,uint32 formats,uint32 rates)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
GetBuffers(uint32 & Flags,int32 & BuffersCount,int32 & ChannelsCount,uint32 & BufferSize,buffer_desc ** Buffers)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
Start()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
Stop()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
InterruptHandler()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
ExchangeBuffers(bigtime_t & RealTime,bigtime_t & FramesCount,int32 & BufferCycle)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