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
20Stream::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
43Stream::~Stream()
44{
45	Free();
46}
47
48
49uint32
50Stream::_HWId()
51{
52	return fDevice->HardwareId();
53}
54
55
56status_t
57Stream::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
100void
101Stream::Free()
102{
103	delete_area(fBuffersArea);
104	fStatus = B_NO_INIT;
105}
106
107
108uint32
109Stream::_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
128void
129Stream::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
141status_t
142Stream::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
178void
179Stream::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
216status_t
217Stream::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
311status_t
312Stream::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
338bool
339Stream::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
361void
362Stream::ExchangeBuffers(bigtime_t& RealTime,
363								bigtime_t& FramesCount, int32& BufferCycle)
364{
365	RealTime = fRealTime;
366	FramesCount = fFramesCount;
367	BufferCycle = fBufferCycle;
368}
369
370