summaryrefslogtreecommitdiff
path: root/firmware/target/hosted/ibasso/tinyalsa
diff options
context:
space:
mode:
authorUdo Schläpfer <rockbox-2014.10@desktopwarrior.net>2015-02-02 21:44:29 +0100
committerUdo Schläpfer <rockbox-2014.10@desktopwarrior.net>2015-02-02 21:57:55 +0100
commitdbabd0d9c34a33bc0c51243ec37f230d117db955 (patch)
tree46de348929ce739702a230a2587fdb5539585753 /firmware/target/hosted/ibasso/tinyalsa
parentcef17e3d59ad93f766e8ee23b1610540a33dfe5e (diff)
downloadrockbox-dbabd0d9c34a33bc0c51243ec37f230d117db955.tar.gz
rockbox-dbabd0d9c34a33bc0c51243ec37f230d117db955.zip
iBasso DX50/DX90: Major code cleanup and reorganization.
Reorganization - Separated iBasso devices from PLATFORM_ANDROID. These are now standlone hosted targets. Most device specific code is in the firmware/target/hosted/ibasso directory. - No dependency on Android SDK, only the Android NDK is needed. 32 bit Android NDK and Android API Level 16. - Separate implementation for each device where feasible. Code cleanup - Rewrite of existing code, from simple reformat to complete reimplementation. - New backlight interface, seperating backlight from touchscreen. - Rewrite of device button handler, removing unneeded code and fixing memory leaks. - New Debug messages interface logging to Android adb logcat (DEBUGF, panicf, logf). - Rewrite of lcd device handler, removing unneeded code and fixing memory leaks. - Rewrite of audiohw device handler/pcm interface, removing unneeded code and fixing memory leaks, enabling 44.1/48kHz pthreaded playback. - Rewrite of power and powermng, proper shutdown, using batterylog results (see http://gerrit.rockbox.org/r/#/c/1047/). - Rewrite of configure (Android NDK) and device specific config. - Rewrite of the Android NDK specific Makefile. Misc - All plugins/games/demos activated. - Update tinyalsa to latest from https://github.com/tinyalsa/tinyalsa. Includes - http://gerrit.rockbox.org/r/#/c/993/ - http://gerrit.rockbox.org/r/#/c/1010/ - http://gerrit.rockbox.org/r/#/c/1035/ Does not include http://gerrit.rockbox.org/r/#/c/1007/ due to new backlight interface and new option for hold switch, touchscreen, physical button interaction. Rockbox needs the iBasso DX50/DX90 loader for startup, see http://gerrit.rockbox.org/r/#/c/1099/ The loader expects Rockbox to be installed in /mnt/sdcard/.rockbox/. If /mnt/sdcard/ is accessed as USB mass storage device, Rockbox will exit gracefully and the loader will restart Rockbox on USB disconnect. Tested on iBasso DX50. Compiled (not tested) for iBasso DX90. Compiled (not tested) for PLATFORM_ANDROID. Change-Id: I5f5e22e68f5b4cf29c28e2b40b2c265f2beb7ab7
Diffstat (limited to 'firmware/target/hosted/ibasso/tinyalsa')
-rw-r--r--firmware/target/hosted/ibasso/tinyalsa/include/sound/asound.h820
-rw-r--r--firmware/target/hosted/ibasso/tinyalsa/include/tinyalsa/asoundlib.h260
-rw-r--r--firmware/target/hosted/ibasso/tinyalsa/mixer.c502
-rw-r--r--firmware/target/hosted/ibasso/tinyalsa/pcm.c1049
4 files changed, 2631 insertions, 0 deletions
diff --git a/firmware/target/hosted/ibasso/tinyalsa/include/sound/asound.h b/firmware/target/hosted/ibasso/tinyalsa/include/sound/asound.h
new file mode 100644
index 0000000000..9dd66fe169
--- /dev/null
+++ b/firmware/target/hosted/ibasso/tinyalsa/include/sound/asound.h
@@ -0,0 +1,820 @@
1/****************************************************************************
2 ****************************************************************************
3 ***
4 *** This header was automatically generated from a Linux kernel header
5 *** of the same name, to make information necessary for userspace to
6 *** call into the kernel available to libc. It contains only constants,
7 *** structures, and macros generated from the original header, and thus,
8 *** contains no copyrightable information.
9 ***
10 ****************************************************************************
11 ****************************************************************************/
12#ifndef __SOUND_ASOUND_H
13#define __SOUND_ASOUND_H
14
15#include <linux/types.h>
16
17#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor))
18#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff)
19#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff)
20#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff)
21#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion)))
22
23struct snd_aes_iec958 {
24 unsigned char status[24];
25 unsigned char subcode[147];
26 unsigned char pad;
27 unsigned char dig_subframe[4];
28};
29
30#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1)
31
32enum {
33 SNDRV_HWDEP_IFACE_OPL2 = 0,
34 SNDRV_HWDEP_IFACE_OPL3,
35 SNDRV_HWDEP_IFACE_OPL4,
36 SNDRV_HWDEP_IFACE_SB16CSP,
37 SNDRV_HWDEP_IFACE_EMU10K1,
38 SNDRV_HWDEP_IFACE_YSS225,
39 SNDRV_HWDEP_IFACE_ICS2115,
40 SNDRV_HWDEP_IFACE_SSCAPE,
41 SNDRV_HWDEP_IFACE_VX,
42 SNDRV_HWDEP_IFACE_MIXART,
43 SNDRV_HWDEP_IFACE_USX2Y,
44 SNDRV_HWDEP_IFACE_EMUX_WAVETABLE,
45 SNDRV_HWDEP_IFACE_BLUETOOTH,
46 SNDRV_HWDEP_IFACE_USX2Y_PCM,
47 SNDRV_HWDEP_IFACE_PCXHR,
48 SNDRV_HWDEP_IFACE_SB_RC,
49 SNDRV_HWDEP_IFACE_HDA,
50 SNDRV_HWDEP_IFACE_USB_STREAM,
51
52 SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM
53};
54
55struct snd_hwdep_info {
56 unsigned int device;
57 int card;
58 unsigned char id[64];
59 unsigned char name[80];
60 int iface;
61 unsigned char reserved[64];
62};
63
64struct snd_hwdep_dsp_status {
65 unsigned int version;
66 unsigned char id[32];
67 unsigned int num_dsps;
68 unsigned int dsp_loaded;
69 unsigned int chip_ready;
70 unsigned char reserved[16];
71};
72
73struct snd_hwdep_dsp_image {
74 unsigned int index;
75 unsigned char name[64];
76 unsigned char __user *image;
77 size_t length;
78 unsigned long driver_data;
79};
80
81#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int)
82#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info)
83#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status)
84#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image)
85
86#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10)
87
88typedef unsigned long snd_pcm_uframes_t;
89typedef signed long snd_pcm_sframes_t;
90
91enum {
92 SNDRV_PCM_CLASS_GENERIC = 0,
93 SNDRV_PCM_CLASS_MULTI,
94 SNDRV_PCM_CLASS_MODEM,
95 SNDRV_PCM_CLASS_DIGITIZER,
96
97 SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER,
98};
99
100enum {
101 SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0,
102 SNDRV_PCM_SUBCLASS_MULTI_MIX,
103
104 SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX,
105};
106
107enum {
108 SNDRV_PCM_STREAM_PLAYBACK = 0,
109 SNDRV_PCM_STREAM_CAPTURE,
110 SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE,
111};
112
113typedef int __bitwise snd_pcm_access_t;
114#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0)
115#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1)
116#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2)
117#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3)
118#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4)
119#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED
120
121typedef int __bitwise snd_pcm_format_t;
122#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0)
123#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1)
124#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2)
125#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3)
126#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4)
127#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5)
128#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6)
129#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7)
130#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8)
131#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9)
132#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10)
133#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11)
134#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12)
135#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13)
136#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14)
137#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15)
138#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16)
139#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17)
140#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18)
141#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19)
142#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20)
143#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21)
144#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22)
145#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23)
146#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24)
147#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31)
148#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32)
149#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33)
150#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34)
151#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35)
152#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36)
153#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37)
154#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38)
155#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39)
156#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40)
157#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41)
158#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42)
159#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43)
160#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44)
161#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45)
162#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46)
163#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47)
164#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B
165
166#ifdef SNDRV_LITTLE_ENDIAN
167#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE
168#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE
169#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE
170#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE
171#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE
172#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE
173#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE
174#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE
175#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
176#endif
177#ifdef SNDRV_BIG_ENDIAN
178#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE
179#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE
180#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE
181#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE
182#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE
183#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE
184#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE
185#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE
186#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE
187#endif
188
189typedef int __bitwise snd_pcm_subformat_t;
190#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0)
191#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD
192
193#define SNDRV_PCM_INFO_MMAP 0x00000001
194#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002
195#define SNDRV_PCM_INFO_DOUBLE 0x00000004
196#define SNDRV_PCM_INFO_BATCH 0x00000010
197#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100
198#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200
199#define SNDRV_PCM_INFO_COMPLEX 0x00000400
200#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000
201#define SNDRV_PCM_INFO_OVERRANGE 0x00020000
202#define SNDRV_PCM_INFO_RESUME 0x00040000
203#define SNDRV_PCM_INFO_PAUSE 0x00080000
204#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000
205#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000
206#define SNDRV_PCM_INFO_SYNC_START 0x00400000
207#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000
208#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000
209
210typedef int __bitwise snd_pcm_state_t;
211#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0)
212#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1)
213#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2)
214#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3)
215#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4)
216#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5)
217#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6)
218#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7)
219#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8)
220#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED
221
222enum {
223 SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000,
224 SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000,
225 SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000,
226};
227
228union snd_pcm_sync_id {
229 unsigned char id[16];
230 unsigned short id16[8];
231 unsigned int id32[4];
232};
233
234struct snd_pcm_info {
235 unsigned int device;
236 unsigned int subdevice;
237 int stream;
238 int card;
239 unsigned char id[64];
240 unsigned char name[80];
241 unsigned char subname[32];
242 int dev_class;
243 int dev_subclass;
244 unsigned int subdevices_count;
245 unsigned int subdevices_avail;
246 union snd_pcm_sync_id sync;
247 unsigned char reserved[64];
248};
249
250typedef int snd_pcm_hw_param_t;
251#define SNDRV_PCM_HW_PARAM_ACCESS 0
252#define SNDRV_PCM_HW_PARAM_FORMAT 1
253#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2
254#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS
255#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT
256
257#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8
258#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9
259#define SNDRV_PCM_HW_PARAM_CHANNELS 10
260#define SNDRV_PCM_HW_PARAM_RATE 11
261#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12
262#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13
263#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14
264#define SNDRV_PCM_HW_PARAM_PERIODS 15
265#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16
266#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17
267#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18
268#define SNDRV_PCM_HW_PARAM_TICK_TIME 19
269#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS
270#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME
271
272#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0)
273#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1)
274#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2)
275
276struct snd_interval {
277 unsigned int min, max;
278 unsigned int openmin:1,
279 openmax:1,
280 integer:1,
281 empty:1;
282};
283
284#define SNDRV_MASK_MAX 256
285
286struct snd_mask {
287 __u32 bits[(SNDRV_MASK_MAX+31)/32];
288};
289
290struct snd_pcm_hw_params {
291 unsigned int flags;
292 struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK -
293 SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
294 struct snd_mask mres[5];
295 struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
296 SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
297 struct snd_interval ires[9];
298 unsigned int rmask;
299 unsigned int cmask;
300 unsigned int info;
301 unsigned int msbits;
302 unsigned int rate_num;
303 unsigned int rate_den;
304 snd_pcm_uframes_t fifo_size;
305 unsigned char reserved[64];
306};
307
308enum {
309 SNDRV_PCM_TSTAMP_NONE = 0,
310 SNDRV_PCM_TSTAMP_ENABLE,
311 SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE,
312};
313
314struct snd_pcm_sw_params {
315 int tstamp_mode;
316 unsigned int period_step;
317 unsigned int sleep_min;
318 snd_pcm_uframes_t avail_min;
319 snd_pcm_uframes_t xfer_align;
320 snd_pcm_uframes_t start_threshold;
321 snd_pcm_uframes_t stop_threshold;
322 snd_pcm_uframes_t silence_threshold;
323 snd_pcm_uframes_t silence_size;
324 snd_pcm_uframes_t boundary;
325 unsigned char reserved[64];
326};
327
328struct snd_pcm_channel_info {
329 unsigned int channel;
330 __kernel_off_t offset;
331 unsigned int first;
332 unsigned int step;
333};
334
335struct snd_pcm_status {
336 snd_pcm_state_t state;
337 struct timespec trigger_tstamp;
338 struct timespec tstamp;
339 snd_pcm_uframes_t appl_ptr;
340 snd_pcm_uframes_t hw_ptr;
341 snd_pcm_sframes_t delay;
342 snd_pcm_uframes_t avail;
343 snd_pcm_uframes_t avail_max;
344 snd_pcm_uframes_t overrange;
345 snd_pcm_state_t suspended_state;
346 unsigned char reserved[60];
347};
348
349struct snd_pcm_mmap_status {
350 snd_pcm_state_t state;
351 int pad1;
352 snd_pcm_uframes_t hw_ptr;
353 struct timespec tstamp;
354 snd_pcm_state_t suspended_state;
355};
356
357struct snd_pcm_mmap_control {
358 snd_pcm_uframes_t appl_ptr;
359 snd_pcm_uframes_t avail_min;
360};
361
362#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0)
363#define SNDRV_PCM_SYNC_PTR_APPL (1<<1)
364#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2)
365
366struct snd_pcm_sync_ptr {
367 unsigned int flags;
368 union {
369 struct snd_pcm_mmap_status status;
370 unsigned char reserved[64];
371 } s;
372 union {
373 struct snd_pcm_mmap_control control;
374 unsigned char reserved[64];
375 } c;
376};
377
378struct snd_xferi {
379 snd_pcm_sframes_t result;
380 void __user *buf;
381 snd_pcm_uframes_t frames;
382};
383
384struct snd_xfern {
385 snd_pcm_sframes_t result;
386 void __user * __user *bufs;
387 snd_pcm_uframes_t frames;
388};
389
390enum {
391 SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0,
392 SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
393 SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
394};
395
396#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int)
397#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info)
398#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int)
399#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int)
400#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params)
401#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params)
402#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12)
403#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params)
404#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status)
405#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t)
406#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22)
407#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
408#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info)
409#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40)
410#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41)
411#define SNDRV_PCM_IOCTL_START _IO('A', 0x42)
412#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43)
413#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44)
414#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int)
415#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t)
416#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47)
417#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48)
418#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t)
419#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi)
420#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi)
421#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern)
422#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern)
423#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int)
424#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61)
425
426#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0)
427
428enum {
429 SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
430 SNDRV_RAWMIDI_STREAM_INPUT,
431 SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT,
432};
433
434#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001
435#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002
436#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004
437
438struct snd_rawmidi_info {
439 unsigned int device;
440 unsigned int subdevice;
441 int stream;
442 int card;
443 unsigned int flags;
444 unsigned char id[64];
445 unsigned char name[80];
446 unsigned char subname[32];
447 unsigned int subdevices_count;
448 unsigned int subdevices_avail;
449 unsigned char reserved[64];
450};
451
452struct snd_rawmidi_params {
453 int stream;
454 size_t buffer_size;
455 size_t avail_min;
456 unsigned int no_active_sensing: 1;
457 unsigned char reserved[16];
458};
459
460struct snd_rawmidi_status {
461 int stream;
462 struct timespec tstamp;
463 size_t avail;
464 size_t xruns;
465 unsigned char reserved[16];
466};
467
468#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int)
469#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info)
470#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params)
471#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status)
472#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int)
473#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int)
474
475#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
476
477enum {
478 SNDRV_TIMER_CLASS_NONE = -1,
479 SNDRV_TIMER_CLASS_SLAVE = 0,
480 SNDRV_TIMER_CLASS_GLOBAL,
481 SNDRV_TIMER_CLASS_CARD,
482 SNDRV_TIMER_CLASS_PCM,
483 SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM,
484};
485
486enum {
487 SNDRV_TIMER_SCLASS_NONE = 0,
488 SNDRV_TIMER_SCLASS_APPLICATION,
489 SNDRV_TIMER_SCLASS_SEQUENCER,
490 SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
491 SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
492};
493
494#define SNDRV_TIMER_GLOBAL_SYSTEM 0
495#define SNDRV_TIMER_GLOBAL_RTC 1
496#define SNDRV_TIMER_GLOBAL_HPET 2
497#define SNDRV_TIMER_GLOBAL_HRTIMER 3
498
499#define SNDRV_TIMER_FLG_SLAVE (1<<0)
500
501struct snd_timer_id {
502 int dev_class;
503 int dev_sclass;
504 int card;
505 int device;
506 int subdevice;
507};
508
509struct snd_timer_ginfo {
510 struct snd_timer_id tid;
511 unsigned int flags;
512 int card;
513 unsigned char id[64];
514 unsigned char name[80];
515 unsigned long reserved0;
516 unsigned long resolution;
517 unsigned long resolution_min;
518 unsigned long resolution_max;
519 unsigned int clients;
520 unsigned char reserved[32];
521};
522
523struct snd_timer_gparams {
524 struct snd_timer_id tid;
525 unsigned long period_num;
526 unsigned long period_den;
527 unsigned char reserved[32];
528};
529
530struct snd_timer_gstatus {
531 struct snd_timer_id tid;
532 unsigned long resolution;
533 unsigned long resolution_num;
534 unsigned long resolution_den;
535 unsigned char reserved[32];
536};
537
538struct snd_timer_select {
539 struct snd_timer_id id;
540 unsigned char reserved[32];
541};
542
543struct snd_timer_info {
544 unsigned int flags;
545 int card;
546 unsigned char id[64];
547 unsigned char name[80];
548 unsigned long reserved0;
549 unsigned long resolution;
550 unsigned char reserved[64];
551};
552
553#define SNDRV_TIMER_PSFLG_AUTO (1<<0)
554#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1)
555#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2)
556
557struct snd_timer_params {
558 unsigned int flags;
559 unsigned int ticks;
560 unsigned int queue_size;
561 unsigned int reserved0;
562 unsigned int filter;
563 unsigned char reserved[60];
564};
565
566struct snd_timer_status {
567 struct timespec tstamp;
568 unsigned int resolution;
569 unsigned int lost;
570 unsigned int overrun;
571 unsigned int queue;
572 unsigned char reserved[64];
573};
574
575#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
576#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
577#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int)
578#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo)
579#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams)
580#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus)
581#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select)
582#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info)
583#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params)
584#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status)
585
586#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0)
587#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1)
588#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
589#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
590
591struct snd_timer_read {
592 unsigned int resolution;
593 unsigned int ticks;
594};
595
596enum {
597 SNDRV_TIMER_EVENT_RESOLUTION = 0,
598 SNDRV_TIMER_EVENT_TICK,
599 SNDRV_TIMER_EVENT_START,
600 SNDRV_TIMER_EVENT_STOP,
601 SNDRV_TIMER_EVENT_CONTINUE,
602 SNDRV_TIMER_EVENT_PAUSE,
603 SNDRV_TIMER_EVENT_EARLY,
604 SNDRV_TIMER_EVENT_SUSPEND,
605 SNDRV_TIMER_EVENT_RESUME,
606
607 SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
608 SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
609 SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10,
610 SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10,
611 SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10,
612 SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
613};
614
615struct snd_timer_tread {
616 int event;
617 struct timespec tstamp;
618 unsigned int val;
619};
620
621#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
622
623struct snd_ctl_card_info {
624 int card;
625 int pad;
626 unsigned char id[16];
627 unsigned char driver[16];
628 unsigned char name[32];
629 unsigned char longname[80];
630 unsigned char reserved_[16];
631 unsigned char mixername[80];
632 unsigned char components[128];
633};
634
635typedef int __bitwise snd_ctl_elem_type_t;
636#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0)
637#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1)
638#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2)
639#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3)
640#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4)
641#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5)
642#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6)
643#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64
644
645typedef int __bitwise snd_ctl_elem_iface_t;
646#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0)
647#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1)
648#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2)
649#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3)
650#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4)
651#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5)
652#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6)
653#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER
654
655#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0)
656#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
657#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
658#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2)
659#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3)
660#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4)
661#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5)
662#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
663#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6)
664#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8)
665#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9)
666#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10)
667#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28)
668#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29)
669
670#define SNDRV_CTL_POWER_D0 0x0000
671#define SNDRV_CTL_POWER_D1 0x0100
672#define SNDRV_CTL_POWER_D2 0x0200
673#define SNDRV_CTL_POWER_D3 0x0300
674#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000)
675#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001)
676
677struct snd_ctl_elem_id {
678 unsigned int numid;
679 snd_ctl_elem_iface_t iface;
680 unsigned int device;
681 unsigned int subdevice;
682 unsigned char name[44];
683 unsigned int index;
684};
685
686struct snd_ctl_elem_list {
687 unsigned int offset;
688 unsigned int space;
689 unsigned int used;
690 unsigned int count;
691 struct snd_ctl_elem_id __user *pids;
692 unsigned char reserved[50];
693};
694
695struct snd_ctl_elem_info {
696 struct snd_ctl_elem_id id;
697 snd_ctl_elem_type_t type;
698 unsigned int access;
699 unsigned int count;
700 __kernel_pid_t owner;
701 union {
702 struct {
703 long min;
704 long max;
705 long step;
706 } integer;
707 struct {
708 long long min;
709 long long max;
710 long long step;
711 } integer64;
712 struct {
713 unsigned int items;
714 unsigned int item;
715 char name[64];
716 } enumerated;
717 unsigned char reserved[128];
718 } value;
719 union {
720 unsigned short d[4];
721 unsigned short *d_ptr;
722 } dimen;
723 unsigned char reserved[64-4*sizeof(unsigned short)];
724};
725
726struct snd_ctl_elem_value {
727 struct snd_ctl_elem_id id;
728 unsigned int indirect: 1;
729 union {
730 union {
731 long value[128];
732 long *value_ptr;
733 } integer;
734 union {
735 long long value[64];
736 long long *value_ptr;
737 } integer64;
738 union {
739 unsigned int item[128];
740 unsigned int *item_ptr;
741 } enumerated;
742 union {
743 unsigned char data[512];
744 unsigned char *data_ptr;
745 } bytes;
746 struct snd_aes_iec958 iec958;
747 } value;
748 struct timespec tstamp;
749 unsigned char reserved[128-sizeof(struct timespec)];
750};
751
752struct snd_ctl_tlv {
753 unsigned int numid;
754 unsigned int length;
755 unsigned int tlv[0];
756};
757
758#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
759#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
760#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
761#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
762#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)
763#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value)
764#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id)
765#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id)
766#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int)
767#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info)
768#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info)
769#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id)
770#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv)
771#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv)
772#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv)
773#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int)
774#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info)
775#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int)
776#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info)
777#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int)
778#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int)
779#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info)
780#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int)
781#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int)
782#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int)
783
784enum sndrv_ctl_event_type {
785 SNDRV_CTL_EVENT_ELEM = 0,
786 SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM,
787};
788
789#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0)
790#define SNDRV_CTL_EVENT_MASK_INFO (1<<1)
791#define SNDRV_CTL_EVENT_MASK_ADD (1<<2)
792#define SNDRV_CTL_EVENT_MASK_TLV (1<<3)
793#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U)
794
795struct snd_ctl_event {
796 int type;
797 union {
798 struct {
799 unsigned int mask;
800 struct snd_ctl_elem_id id;
801 } elem;
802 unsigned char data8[60];
803 } data;
804};
805
806#define SNDRV_CTL_NAME_NONE ""
807#define SNDRV_CTL_NAME_PLAYBACK "Playback "
808#define SNDRV_CTL_NAME_CAPTURE "Capture "
809
810#define SNDRV_CTL_NAME_IEC958_NONE ""
811#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch"
812#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume"
813#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default"
814#define SNDRV_CTL_NAME_IEC958_MASK "Mask"
815#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask"
816#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask"
817#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream"
818#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what
819
820#endif
diff --git a/firmware/target/hosted/ibasso/tinyalsa/include/tinyalsa/asoundlib.h b/firmware/target/hosted/ibasso/tinyalsa/include/tinyalsa/asoundlib.h
new file mode 100644
index 0000000000..ba58bdcdfc
--- /dev/null
+++ b/firmware/target/hosted/ibasso/tinyalsa/include/tinyalsa/asoundlib.h
@@ -0,0 +1,260 @@
1/* asoundlib.h
2**
3** Copyright 2011, The Android Open Source Project
4**
5** Redistribution and use in source and binary forms, with or without
6** modification, are permitted provided that the following conditions are met:
7** * Redistributions of source code must retain the above copyright
8** notice, this list of conditions and the following disclaimer.
9** * Redistributions in binary form must reproduce the above copyright
10** notice, this list of conditions and the following disclaimer in the
11** documentation and/or other materials provided with the distribution.
12** * Neither the name of The Android Open Source Project nor the names of
13** its contributors may be used to endorse or promote products derived
14** from this software without specific prior written permission.
15**
16** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
17** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
20** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26** DAMAGE.
27*/
28
29#ifndef ASOUNDLIB_H
30#define ASOUNDLIB_H
31
32#include <sys/time.h>
33#include <stddef.h>
34
35#if defined(__cplusplus)
36extern "C" {
37#endif
38
39/*
40 * PCM API
41 */
42
43struct pcm;
44
45#define PCM_OUT 0x00000000
46#define PCM_IN 0x10000000
47#define PCM_MMAP 0x00000001
48#define PCM_NOIRQ 0x00000002
49#define PCM_NORESTART 0x00000004 /* PCM_NORESTART - when set, calls to
50 * pcm_write for a playback stream will not
51 * attempt to restart the stream in the case
52 * of an underflow, but will return -EPIPE
53 * instead. After the first -EPIPE error, the
54 * stream is considered to be stopped, and a
55 * second call to pcm_write will attempt to
56 * restart the stream.
57 */
58#define PCM_MONOTONIC 0x00000008 /* see pcm_get_htimestamp */
59
60/* PCM runtime states */
61#define PCM_STATE_RUNNING 3
62#define PCM_STATE_XRUN 4
63#define PCM_STATE_DRAINING 5
64#define PCM_STATE_SUSPENDED 7
65#define PCM_STATE_DISCONNECTED 8
66
67/* Bit formats */
68enum pcm_format {
69 PCM_FORMAT_S16_LE = 0,
70 PCM_FORMAT_S32_LE,
71 PCM_FORMAT_S8,
72 PCM_FORMAT_S24_LE,
73
74 PCM_FORMAT_MAX,
75};
76
77/* Bitmask has 256 bits (32 bytes) in asound.h */
78struct pcm_mask {
79 unsigned int bits[32 / sizeof(unsigned int)];
80};
81
82/* Configuration for a stream */
83struct pcm_config {
84 unsigned int channels;
85 unsigned int rate;
86 unsigned int period_size;
87 unsigned int period_count;
88 enum pcm_format format;
89
90 /* Values to use for the ALSA start, stop and silence thresholds. Setting
91 * any one of these values to 0 will cause the default tinyalsa values to be
92 * used instead. Tinyalsa defaults are as follows.
93 *
94 * start_threshold : period_count * period_size
95 * stop_threshold : period_count * period_size
96 * silence_threshold : 0
97 */
98 unsigned int start_threshold;
99 unsigned int stop_threshold;
100 unsigned int silence_threshold;
101};
102
103/* PCM parameters */
104enum pcm_param
105{
106 /* mask parameters */
107 PCM_PARAM_ACCESS,
108 PCM_PARAM_FORMAT,
109 PCM_PARAM_SUBFORMAT,
110 /* interval parameters */
111 PCM_PARAM_SAMPLE_BITS,
112 PCM_PARAM_FRAME_BITS,
113 PCM_PARAM_CHANNELS,
114 PCM_PARAM_RATE,
115 PCM_PARAM_PERIOD_TIME,
116 PCM_PARAM_PERIOD_SIZE,
117 PCM_PARAM_PERIOD_BYTES,
118 PCM_PARAM_PERIODS,
119 PCM_PARAM_BUFFER_TIME,
120 PCM_PARAM_BUFFER_SIZE,
121 PCM_PARAM_BUFFER_BYTES,
122 PCM_PARAM_TICK_TIME,
123};
124
125/* Mixer control types */
126enum mixer_ctl_type {
127 MIXER_CTL_TYPE_BOOL,
128 MIXER_CTL_TYPE_INT,
129 MIXER_CTL_TYPE_ENUM,
130 MIXER_CTL_TYPE_BYTE,
131 MIXER_CTL_TYPE_IEC958,
132 MIXER_CTL_TYPE_INT64,
133 MIXER_CTL_TYPE_UNKNOWN,
134
135 MIXER_CTL_TYPE_MAX,
136};
137
138/* Open and close a stream */
139struct pcm *pcm_open(unsigned int card, unsigned int device,
140 unsigned int flags, struct pcm_config *config);
141int pcm_close(struct pcm *pcm);
142int pcm_is_ready(struct pcm *pcm);
143
144/* Obtain the parameters for a PCM */
145struct pcm_params *pcm_params_get(unsigned int card, unsigned int device,
146 unsigned int flags);
147void pcm_params_free(struct pcm_params *pcm_params);
148
149struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params,
150 enum pcm_param param);
151unsigned int pcm_params_get_min(struct pcm_params *pcm_params,
152 enum pcm_param param);
153unsigned int pcm_params_get_max(struct pcm_params *pcm_params,
154 enum pcm_param param);
155
156/* Returns a human readable reason for the last error */
157const char *pcm_get_error(struct pcm *pcm);
158
159/* Returns the sample size in bits for a PCM format.
160 * As with ALSA formats, this is the storage size for the format, whereas the
161 * format represents the number of significant bits. For example,
162 * PCM_FORMAT_S24_LE uses 32 bits of storage.
163 */
164unsigned int pcm_format_to_bits(enum pcm_format format);
165
166/* Returns the buffer size (int frames) that should be used for pcm_write. */
167unsigned int pcm_get_buffer_size(struct pcm *pcm);
168unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames);
169unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes);
170
171/* Returns available frames in pcm buffer and corresponding time stamp.
172 * The clock is CLOCK_MONOTONIC if flag PCM_MONOTONIC was specified in pcm_open,
173 * otherwise the clock is CLOCK_REALTIME.
174 * For an input stream, frames available are frames ready for the
175 * application to read.
176 * For an output stream, frames available are the number of empty frames available
177 * for the application to write.
178 */
179int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
180 struct timespec *tstamp);
181
182/* Write data to the fifo.
183 * Will start playback on the first write or on a write that
184 * occurs after a fifo underrun.
185 */
186int pcm_write(struct pcm *pcm, const void *data, unsigned int count);
187int pcm_read(struct pcm *pcm, void *data, unsigned int count);
188
189/*
190 * mmap() support.
191 */
192int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count);
193int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count);
194int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset,
195 unsigned int *frames);
196int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames);
197
198/* Prepare the PCM substream to be triggerable */
199int pcm_prepare(struct pcm *pcm);
200/* Start and stop a PCM channel that doesn't transfer data */
201int pcm_start(struct pcm *pcm);
202int pcm_stop(struct pcm *pcm);
203
204/* Interrupt driven API */
205int pcm_wait(struct pcm *pcm, int timeout);
206
207
208/*
209 * MIXER API
210 */
211
212struct mixer;
213struct mixer_ctl;
214
215/* Open and close a mixer */
216struct mixer *mixer_open(unsigned int card);
217void mixer_close(struct mixer *mixer);
218
219/* Get info about a mixer */
220const char *mixer_get_name(struct mixer *mixer);
221
222/* Obtain mixer controls */
223unsigned int mixer_get_num_ctls(struct mixer *mixer);
224struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id);
225struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name);
226
227/* Get info about mixer controls */
228const char *mixer_ctl_get_name(struct mixer_ctl *ctl);
229enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl);
230const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl);
231unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl);
232unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl);
233const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
234 unsigned int enum_id);
235
236/* Some sound cards update their controls due to external events,
237 * such as HDMI EDID byte data changing when an HDMI cable is
238 * connected. This API allows the count of elements to be updated.
239 */
240void mixer_ctl_update(struct mixer_ctl *ctl);
241
242/* Set and get mixer controls */
243int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id);
244int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent);
245
246int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id);
247int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count);
248int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value);
249int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count);
250int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string);
251
252/* Determe range of integer mixer controls */
253int mixer_ctl_get_range_min(struct mixer_ctl *ctl);
254int mixer_ctl_get_range_max(struct mixer_ctl *ctl);
255
256#if defined(__cplusplus)
257} /* extern "C" */
258#endif
259
260#endif
diff --git a/firmware/target/hosted/ibasso/tinyalsa/mixer.c b/firmware/target/hosted/ibasso/tinyalsa/mixer.c
new file mode 100644
index 0000000000..24e94f4f1d
--- /dev/null
+++ b/firmware/target/hosted/ibasso/tinyalsa/mixer.c
@@ -0,0 +1,502 @@
1/* mixer.c
2**
3** Copyright 2011, The Android Open Source Project
4**
5** Redistribution and use in source and binary forms, with or without
6** modification, are permitted provided that the following conditions are met:
7** * Redistributions of source code must retain the above copyright
8** notice, this list of conditions and the following disclaimer.
9** * Redistributions in binary form must reproduce the above copyright
10** notice, this list of conditions and the following disclaimer in the
11** documentation and/or other materials provided with the distribution.
12** * Neither the name of The Android Open Source Project nor the names of
13** its contributors may be used to endorse or promote products derived
14** from this software without specific prior written permission.
15**
16** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
17** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
20** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26** DAMAGE.
27*/
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33#include <fcntl.h>
34#include <errno.h>
35#include <ctype.h>
36
37#include <sys/ioctl.h>
38
39#include <linux/ioctl.h>
40#define __force
41#define __bitwise
42#define __user
43#include <sound/asound.h>
44
45#include <tinyalsa/asoundlib.h>
46
47struct mixer_ctl {
48 struct mixer *mixer;
49 struct snd_ctl_elem_info *info;
50 char **ename;
51};
52
53struct mixer {
54 int fd;
55 struct snd_ctl_card_info card_info;
56 struct snd_ctl_elem_info *elem_info;
57 struct mixer_ctl *ctl;
58 unsigned int count;
59};
60
61void mixer_close(struct mixer *mixer)
62{
63 unsigned int n,m;
64
65 if (!mixer)
66 return;
67
68 if (mixer->fd >= 0)
69 close(mixer->fd);
70
71 if (mixer->ctl) {
72 for (n = 0; n < mixer->count; n++) {
73 if (mixer->ctl[n].ename) {
74 unsigned int max = mixer->ctl[n].info->value.enumerated.items;
75 for (m = 0; m < max; m++)
76 free(mixer->ctl[n].ename[m]);
77 free(mixer->ctl[n].ename);
78 }
79 }
80 free(mixer->ctl);
81 }
82
83 if (mixer->elem_info)
84 free(mixer->elem_info);
85
86 free(mixer);
87
88 /* TODO: verify frees */
89}
90
91struct mixer *mixer_open(unsigned int card)
92{
93 struct snd_ctl_elem_list elist;
94 struct snd_ctl_elem_info tmp;
95 struct snd_ctl_elem_id *eid = NULL;
96 struct mixer *mixer = NULL;
97 unsigned int n, m;
98 int fd;
99 char fn[256];
100
101 snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
102 fd = open(fn, O_RDWR);
103 if (fd < 0)
104 return 0;
105
106 memset(&elist, 0, sizeof(elist));
107 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
108 goto fail;
109
110 mixer = calloc(1, sizeof(*mixer));
111 if (!mixer)
112 goto fail;
113
114 mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl));
115 mixer->elem_info = calloc(elist.count, sizeof(struct snd_ctl_elem_info));
116 if (!mixer->ctl || !mixer->elem_info)
117 goto fail;
118
119 if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)
120 goto fail;
121
122 eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id));
123 if (!eid)
124 goto fail;
125
126 mixer->count = elist.count;
127 mixer->fd = fd;
128 elist.space = mixer->count;
129 elist.pids = eid;
130 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
131 goto fail;
132
133 for (n = 0; n < mixer->count; n++) {
134 struct snd_ctl_elem_info *ei = mixer->elem_info + n;
135 ei->id.numid = eid[n].numid;
136 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
137 goto fail;
138 mixer->ctl[n].info = ei;
139 mixer->ctl[n].mixer = mixer;
140 if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
141 char **enames = calloc(ei->value.enumerated.items, sizeof(char*));
142 if (!enames)
143 goto fail;
144 mixer->ctl[n].ename = enames;
145 for (m = 0; m < ei->value.enumerated.items; m++) {
146 memset(&tmp, 0, sizeof(tmp));
147 tmp.id.numid = ei->id.numid;
148 tmp.value.enumerated.item = m;
149 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
150 goto fail;
151 enames[m] = strdup(tmp.value.enumerated.name);
152 if (!enames[m])
153 goto fail;
154 }
155 }
156 }
157
158 free(eid);
159 return mixer;
160
161fail:
162 /* TODO: verify frees in failure case */
163 if (eid)
164 free(eid);
165 if (mixer)
166 mixer_close(mixer);
167 else if (fd >= 0)
168 close(fd);
169 return 0;
170}
171
172const char *mixer_get_name(struct mixer *mixer)
173{
174 return (const char *)mixer->card_info.name;
175}
176
177unsigned int mixer_get_num_ctls(struct mixer *mixer)
178{
179 if (!mixer)
180 return 0;
181
182 return mixer->count;
183}
184
185struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id)
186{
187 if (mixer && (id < mixer->count))
188 return mixer->ctl + id;
189
190 return NULL;
191}
192
193struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
194{
195 unsigned int n;
196
197 if (!mixer)
198 return NULL;
199
200 for (n = 0; n < mixer->count; n++)
201 if (!strcmp(name, (char*) mixer->elem_info[n].id.name))
202 return mixer->ctl + n;
203
204 return NULL;
205}
206
207void mixer_ctl_update(struct mixer_ctl *ctl)
208{
209 ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info);
210}
211
212const char *mixer_ctl_get_name(struct mixer_ctl *ctl)
213{
214 if (!ctl)
215 return NULL;
216
217 return (const char *)ctl->info->id.name;
218}
219
220enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl)
221{
222 if (!ctl)
223 return MIXER_CTL_TYPE_UNKNOWN;
224
225 switch (ctl->info->type) {
226 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL;
227 case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT;
228 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM;
229 case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE;
230 case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958;
231 case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64;
232 default: return MIXER_CTL_TYPE_UNKNOWN;
233 };
234}
235
236const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl)
237{
238 if (!ctl)
239 return "";
240
241 switch (ctl->info->type) {
242 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
243 case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT";
244 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
245 case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE";
246 case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
247 case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
248 default: return "Unknown";
249 };
250}
251
252unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl)
253{
254 if (!ctl)
255 return 0;
256
257 return ctl->info->count;
258}
259
260static int percent_to_int(struct snd_ctl_elem_info *ei, int percent)
261{
262 if ((percent > 100) || (percent < 0)) {
263 return -EINVAL;
264 }
265
266 int range = (ei->value.integer.max - ei->value.integer.min);
267
268 return ei->value.integer.min + (range * percent) / 100;
269}
270
271static int int_to_percent(struct snd_ctl_elem_info *ei, int value)
272{
273 int range = (ei->value.integer.max - ei->value.integer.min);
274
275 if (range == 0)
276 return 0;
277
278 return ((value - ei->value.integer.min) / range) * 100;
279}
280
281int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id)
282{
283 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
284 return -EINVAL;
285
286 return int_to_percent(ctl->info, mixer_ctl_get_value(ctl, id));
287}
288
289int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent)
290{
291 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
292 return -EINVAL;
293
294 return mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent));
295}
296
297int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id)
298{
299 struct snd_ctl_elem_value ev;
300 int ret;
301
302 if (!ctl || (id >= ctl->info->count))
303 return -EINVAL;
304
305 memset(&ev, 0, sizeof(ev));
306 ev.id.numid = ctl->info->id.numid;
307 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
308 if (ret < 0)
309 return ret;
310
311 switch (ctl->info->type) {
312 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
313 return !!ev.value.integer.value[id];
314
315 case SNDRV_CTL_ELEM_TYPE_INTEGER:
316 return ev.value.integer.value[id];
317
318 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
319 return ev.value.enumerated.item[id];
320
321 case SNDRV_CTL_ELEM_TYPE_BYTES:
322 return ev.value.bytes.data[id];
323
324 default:
325 return -EINVAL;
326 }
327
328 return 0;
329}
330
331int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count)
332{
333 struct snd_ctl_elem_value ev;
334 int ret;
335 size_t size;
336 void *source;
337
338 if (!ctl || (count > ctl->info->count) || !count || !array)
339 return -EINVAL;
340
341 memset(&ev, 0, sizeof(ev));
342 ev.id.numid = ctl->info->id.numid;
343
344 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
345 if (ret < 0)
346 return ret;
347
348 switch (ctl->info->type) {
349 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
350 case SNDRV_CTL_ELEM_TYPE_INTEGER:
351 size = sizeof(ev.value.integer.value[0]);
352 source = ev.value.integer.value;
353 break;
354
355 case SNDRV_CTL_ELEM_TYPE_BYTES:
356 size = sizeof(ev.value.bytes.data[0]);
357 source = ev.value.bytes.data;
358 break;
359
360 default:
361 return -EINVAL;
362 }
363
364 memcpy(array, source, size * count);
365
366 return 0;
367}
368
369int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
370{
371 struct snd_ctl_elem_value ev;
372 int ret;
373
374 if (!ctl || (id >= ctl->info->count))
375 return -EINVAL;
376
377 memset(&ev, 0, sizeof(ev));
378 ev.id.numid = ctl->info->id.numid;
379 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
380 if (ret < 0)
381 return ret;
382
383 switch (ctl->info->type) {
384 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
385 ev.value.integer.value[id] = !!value;
386 break;
387
388 case SNDRV_CTL_ELEM_TYPE_INTEGER:
389 if ((value < mixer_ctl_get_range_min(ctl)) ||
390 (value > mixer_ctl_get_range_max(ctl))) {
391 return -EINVAL;
392 }
393
394 ev.value.integer.value[id] = value;
395 break;
396
397 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
398 ev.value.enumerated.item[id] = value;
399 break;
400
401 case SNDRV_CTL_ELEM_TYPE_BYTES:
402 ev.value.bytes.data[id] = value;
403 break;
404
405 default:
406 return -EINVAL;
407 }
408
409 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
410}
411
412int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count)
413{
414 struct snd_ctl_elem_value ev;
415 size_t size;
416 void *dest;
417
418 if (!ctl || (count > ctl->info->count) || !count || !array)
419 return -EINVAL;
420
421 memset(&ev, 0, sizeof(ev));
422 ev.id.numid = ctl->info->id.numid;
423
424 switch (ctl->info->type) {
425 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
426 case SNDRV_CTL_ELEM_TYPE_INTEGER:
427 size = sizeof(ev.value.integer.value[0]);
428 dest = ev.value.integer.value;
429 break;
430
431 case SNDRV_CTL_ELEM_TYPE_BYTES:
432 size = sizeof(ev.value.bytes.data[0]);
433 dest = ev.value.bytes.data;
434 break;
435
436 default:
437 return -EINVAL;
438 }
439
440 memcpy(dest, array, size * count);
441
442 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
443}
444
445int mixer_ctl_get_range_min(struct mixer_ctl *ctl)
446{
447 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
448 return -EINVAL;
449
450 return ctl->info->value.integer.min;
451}
452
453int mixer_ctl_get_range_max(struct mixer_ctl *ctl)
454{
455 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
456 return -EINVAL;
457
458 return ctl->info->value.integer.max;
459}
460
461unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl)
462{
463 if (!ctl)
464 return 0;
465
466 return ctl->info->value.enumerated.items;
467}
468
469const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
470 unsigned int enum_id)
471{
472 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
473 (enum_id >= ctl->info->value.enumerated.items))
474 return NULL;
475
476 return (const char *)ctl->ename[enum_id];
477}
478
479int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string)
480{
481 unsigned int i, num_enums;
482 struct snd_ctl_elem_value ev;
483 int ret;
484
485 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED))
486 return -EINVAL;
487
488 num_enums = ctl->info->value.enumerated.items;
489 for (i = 0; i < num_enums; i++) {
490 if (!strcmp(string, ctl->ename[i])) {
491 memset(&ev, 0, sizeof(ev));
492 ev.value.enumerated.item[0] = i;
493 ev.id.numid = ctl->info->id.numid;
494 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
495 if (ret < 0)
496 return ret;
497 return 0;
498 }
499 }
500
501 return -EINVAL;
502}
diff --git a/firmware/target/hosted/ibasso/tinyalsa/pcm.c b/firmware/target/hosted/ibasso/tinyalsa/pcm.c
new file mode 100644
index 0000000000..0d2f0adf08
--- /dev/null
+++ b/firmware/target/hosted/ibasso/tinyalsa/pcm.c
@@ -0,0 +1,1049 @@
1/* pcm.c
2**
3** Copyright 2011, The Android Open Source Project
4**
5** Redistribution and use in source and binary forms, with or without
6** modification, are permitted provided that the following conditions are met:
7** * Redistributions of source code must retain the above copyright
8** notice, this list of conditions and the following disclaimer.
9** * Redistributions in binary form must reproduce the above copyright
10** notice, this list of conditions and the following disclaimer in the
11** documentation and/or other materials provided with the distribution.
12** * Neither the name of The Android Open Source Project nor the names of
13** its contributors may be used to endorse or promote products derived
14** from this software without specific prior written permission.
15**
16** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
17** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
20** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26** DAMAGE.
27*/
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <fcntl.h>
32#include <stdarg.h>
33#include <string.h>
34#include <errno.h>
35#include <unistd.h>
36#include <poll.h>
37
38#include <sys/ioctl.h>
39#include <sys/mman.h>
40#include <sys/time.h>
41#include <limits.h>
42
43#include <linux/ioctl.h>
44#define __force
45#define __bitwise
46#define __user
47#include <sound/asound.h>
48
49#include <tinyalsa/asoundlib.h>
50
51#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL
52#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2)
53
54static inline int param_is_mask(int p)
55{
56 return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
57 (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
58}
59
60static inline int param_is_interval(int p)
61{
62 return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
63 (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
64}
65
66static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
67{
68 return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
69}
70
71static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
72{
73 return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
74}
75
76static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
77{
78 if (bit >= SNDRV_MASK_MAX)
79 return;
80 if (param_is_mask(n)) {
81 struct snd_mask *m = param_to_mask(p, n);
82 m->bits[0] = 0;
83 m->bits[1] = 0;
84 m->bits[bit >> 5] |= (1 << (bit & 31));
85 }
86}
87
88static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned int val)
89{
90 if (param_is_interval(n)) {
91 struct snd_interval *i = param_to_interval(p, n);
92 i->min = val;
93 }
94}
95
96static unsigned int param_get_min(struct snd_pcm_hw_params *p, int n)
97{
98 if (param_is_interval(n)) {
99 struct snd_interval *i = param_to_interval(p, n);
100 return i->min;
101 }
102 return 0;
103}
104
105static unsigned int param_get_max(struct snd_pcm_hw_params *p, int n)
106{
107 if (param_is_interval(n)) {
108 struct snd_interval *i = param_to_interval(p, n);
109 return i->max;
110 }
111 return 0;
112}
113
114static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned int val)
115{
116 if (param_is_interval(n)) {
117 struct snd_interval *i = param_to_interval(p, n);
118 i->min = val;
119 i->max = val;
120 i->integer = 1;
121 }
122}
123
124static unsigned int param_get_int(struct snd_pcm_hw_params *p, int n)
125{
126 if (param_is_interval(n)) {
127 struct snd_interval *i = param_to_interval(p, n);
128 if (i->integer)
129 return i->max;
130 }
131 return 0;
132}
133
134static void param_init(struct snd_pcm_hw_params *p)
135{
136 int n;
137
138 memset(p, 0, sizeof(*p));
139 for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
140 n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
141 struct snd_mask *m = param_to_mask(p, n);
142 m->bits[0] = ~0;
143 m->bits[1] = ~0;
144 }
145 for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
146 n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
147 struct snd_interval *i = param_to_interval(p, n);
148 i->min = 0;
149 i->max = ~0;
150 }
151 p->rmask = ~0U;
152 p->cmask = 0;
153 p->info = ~0U;
154}
155
156#define PCM_ERROR_MAX 128
157
158struct pcm {
159 int fd;
160 unsigned int flags;
161 int running:1;
162 int prepared:1;
163 int underruns;
164 unsigned int buffer_size;
165 unsigned int boundary;
166 char error[PCM_ERROR_MAX];
167 struct pcm_config config;
168 struct snd_pcm_mmap_status *mmap_status;
169 struct snd_pcm_mmap_control *mmap_control;
170 struct snd_pcm_sync_ptr *sync_ptr;
171 void *mmap_buffer;
172 unsigned int noirq_frames_per_msec;
173};
174
175unsigned int pcm_get_buffer_size(struct pcm *pcm)
176{
177 return pcm->buffer_size;
178}
179
180const char* pcm_get_error(struct pcm *pcm)
181{
182 return pcm->error;
183}
184
185static int oops(struct pcm *pcm, int e, const char *fmt, ...)
186{
187 va_list ap;
188 int sz;
189
190 va_start(ap, fmt);
191 vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap);
192 va_end(ap);
193 sz = strlen(pcm->error);
194
195 if (errno)
196 snprintf(pcm->error + sz, PCM_ERROR_MAX - sz,
197 ": %s", strerror(e));
198 return -1;
199}
200
201static unsigned int pcm_format_to_alsa(enum pcm_format format)
202{
203 switch (format) {
204 case PCM_FORMAT_S32_LE:
205 return SNDRV_PCM_FORMAT_S32_LE;
206 case PCM_FORMAT_S8:
207 return SNDRV_PCM_FORMAT_S8;
208 case PCM_FORMAT_S24_LE:
209 return SNDRV_PCM_FORMAT_S24_LE;
210 default:
211 case PCM_FORMAT_S16_LE:
212 return SNDRV_PCM_FORMAT_S16_LE;
213 };
214}
215
216unsigned int pcm_format_to_bits(enum pcm_format format)
217{
218 switch (format) {
219 case PCM_FORMAT_S32_LE:
220 case PCM_FORMAT_S24_LE:
221 return 32;
222 default:
223 case PCM_FORMAT_S16_LE:
224 return 16;
225 };
226}
227
228unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes)
229{
230 return bytes / (pcm->config.channels *
231 (pcm_format_to_bits(pcm->config.format) >> 3));
232}
233
234unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames)
235{
236 return frames * pcm->config.channels *
237 (pcm_format_to_bits(pcm->config.format) >> 3);
238}
239
240static int pcm_sync_ptr(struct pcm *pcm, int flags) {
241 if (pcm->sync_ptr) {
242 pcm->sync_ptr->flags = flags;
243 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr) < 0)
244 return -1;
245 }
246 return 0;
247}
248
249static int pcm_hw_mmap_status(struct pcm *pcm) {
250
251 if (pcm->sync_ptr)
252 return 0;
253
254 int page_size = sysconf(_SC_PAGE_SIZE);
255 pcm->mmap_status = mmap(NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED,
256 pcm->fd, SNDRV_PCM_MMAP_OFFSET_STATUS);
257 if (pcm->mmap_status == MAP_FAILED)
258 pcm->mmap_status = NULL;
259 if (!pcm->mmap_status)
260 goto mmap_error;
261
262 pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
263 MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
264 if (pcm->mmap_control == MAP_FAILED)
265 pcm->mmap_control = NULL;
266 if (!pcm->mmap_control) {
267 munmap(pcm->mmap_status, page_size);
268 pcm->mmap_status = NULL;
269 goto mmap_error;
270 }
271 pcm->mmap_control->avail_min = 1;
272
273 return 0;
274
275mmap_error:
276
277 pcm->sync_ptr = calloc(1, sizeof(*pcm->sync_ptr));
278 if (!pcm->sync_ptr)
279 return -ENOMEM;
280 pcm->mmap_status = &pcm->sync_ptr->s.status;
281 pcm->mmap_control = &pcm->sync_ptr->c.control;
282 pcm->mmap_control->avail_min = 1;
283 pcm_sync_ptr(pcm, 0);
284
285 return 0;
286}
287
288static void pcm_hw_munmap_status(struct pcm *pcm) {
289 if (pcm->sync_ptr) {
290 free(pcm->sync_ptr);
291 pcm->sync_ptr = NULL;
292 } else {
293 int page_size = sysconf(_SC_PAGE_SIZE);
294 if (pcm->mmap_status)
295 munmap(pcm->mmap_status, page_size);
296 if (pcm->mmap_control)
297 munmap(pcm->mmap_control, page_size);
298 }
299 pcm->mmap_status = NULL;
300 pcm->mmap_control = NULL;
301}
302
303static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset,
304 char *buf, unsigned int src_offset,
305 unsigned int frames)
306{
307 int size_bytes = pcm_frames_to_bytes(pcm, frames);
308 int pcm_offset_bytes = pcm_frames_to_bytes(pcm, pcm_offset);
309 int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset);
310
311 /* interleaved only atm */
312 if (pcm->flags & PCM_IN)
313 memcpy(buf + src_offset_bytes,
314 (char*)pcm->mmap_buffer + pcm_offset_bytes,
315 size_bytes);
316 else
317 memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes,
318 buf + src_offset_bytes,
319 size_bytes);
320 return 0;
321}
322
323static int pcm_mmap_transfer_areas(struct pcm *pcm, char *buf,
324 unsigned int offset, unsigned int size)
325{
326 void *pcm_areas;
327 int commit;
328 unsigned int pcm_offset, frames, count = 0;
329
330 while (size > 0) {
331 frames = size;
332 pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames);
333 pcm_areas_copy(pcm, pcm_offset, buf, offset, frames);
334 commit = pcm_mmap_commit(pcm, pcm_offset, frames);
335 if (commit < 0) {
336 oops(pcm, commit, "failed to commit %d frames\n", frames);
337 return commit;
338 }
339
340 offset += commit;
341 count += commit;
342 size -= commit;
343 }
344 return count;
345}
346
347int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
348 struct timespec *tstamp)
349{
350 int frames;
351 int rc;
352 snd_pcm_uframes_t hw_ptr;
353
354 if (!pcm_is_ready(pcm))
355 return -1;
356
357 rc = pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_APPL|SNDRV_PCM_SYNC_PTR_HWSYNC);
358 if (rc < 0)
359 return -1;
360
361 if ((pcm->mmap_status->state != PCM_STATE_RUNNING) &&
362 (pcm->mmap_status->state != PCM_STATE_DRAINING))
363 return -1;
364
365 *tstamp = pcm->mmap_status->tstamp;
366 if (tstamp->tv_sec == 0 && tstamp->tv_nsec == 0)
367 return -1;
368
369 hw_ptr = pcm->mmap_status->hw_ptr;
370 if (pcm->flags & PCM_IN)
371 frames = hw_ptr - pcm->mmap_control->appl_ptr;
372 else
373 frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr;
374
375 if (frames < 0)
376 return -1;
377
378 *avail = (unsigned int)frames;
379
380 return 0;
381}
382
383int pcm_write(struct pcm *pcm, const void *data, unsigned int count)
384{
385 struct snd_xferi x;
386
387 if (pcm->flags & PCM_IN)
388 return -EINVAL;
389
390 x.buf = (void*)data;
391 x.frames = count / (pcm->config.channels *
392 pcm_format_to_bits(pcm->config.format) / 8);
393
394 for (;;) {
395 if (!pcm->running) {
396 int prepare_error = pcm_prepare(pcm);
397 if (prepare_error)
398 return prepare_error;
399 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))
400 return oops(pcm, errno, "cannot write initial data");
401 pcm->running = 1;
402 return 0;
403 }
404 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
405 pcm->prepared = 0;
406 pcm->running = 0;
407 if (errno == EPIPE) {
408 /* we failed to make our window -- try to restart if we are
409 * allowed to do so. Otherwise, simply allow the EPIPE error to
410 * propagate up to the app level */
411 pcm->underruns++;
412 if (pcm->flags & PCM_NORESTART)
413 return -EPIPE;
414 continue;
415 }
416 return oops(pcm, errno, "cannot write stream data");
417 }
418 return 0;
419 }
420}
421
422int pcm_read(struct pcm *pcm, void *data, unsigned int count)
423{
424 struct snd_xferi x;
425
426 if (!(pcm->flags & PCM_IN))
427 return -EINVAL;
428
429 x.buf = data;
430 x.frames = count / (pcm->config.channels *
431 pcm_format_to_bits(pcm->config.format) / 8);
432
433 for (;;) {
434 if (!pcm->running) {
435 if (pcm_start(pcm) < 0) {
436 fprintf(stderr, "start error");
437 return -errno;
438 }
439 }
440 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {
441 pcm->prepared = 0;
442 pcm->running = 0;
443 if (errno == EPIPE) {
444 /* we failed to make our window -- try to restart */
445 pcm->underruns++;
446 continue;
447 }
448 return oops(pcm, errno, "cannot read stream data");
449 }
450 return 0;
451 }
452}
453
454static struct pcm bad_pcm = {
455 .fd = -1,
456};
457
458struct pcm_params *pcm_params_get(unsigned int card, unsigned int device,
459 unsigned int flags)
460{
461 struct snd_pcm_hw_params *params;
462 char fn[256];
463 int fd;
464
465 snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device,
466 flags & PCM_IN ? 'c' : 'p');
467
468 fd = open(fn, O_RDWR);
469 if (fd < 0) {
470 fprintf(stderr, "cannot open device '%s'\n", fn);
471 goto err_open;
472 }
473
474 params = calloc(1, sizeof(struct snd_pcm_hw_params));
475 if (!params)
476 goto err_calloc;
477
478 param_init(params);
479 if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params)) {
480 fprintf(stderr, "SNDRV_PCM_IOCTL_HW_REFINE error (%d)\n", errno);
481 goto err_hw_refine;
482 }
483
484 close(fd);
485
486 return (struct pcm_params *)params;
487
488err_hw_refine:
489 free(params);
490err_calloc:
491 close(fd);
492err_open:
493 return NULL;
494}
495
496void pcm_params_free(struct pcm_params *pcm_params)
497{
498 struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
499
500 if (params)
501 free(params);
502}
503
504static int pcm_param_to_alsa(enum pcm_param param)
505{
506 switch (param) {
507 case PCM_PARAM_ACCESS:
508 return SNDRV_PCM_HW_PARAM_ACCESS;
509 case PCM_PARAM_FORMAT:
510 return SNDRV_PCM_HW_PARAM_FORMAT;
511 case PCM_PARAM_SUBFORMAT:
512 return SNDRV_PCM_HW_PARAM_SUBFORMAT;
513 case PCM_PARAM_SAMPLE_BITS:
514 return SNDRV_PCM_HW_PARAM_SAMPLE_BITS;
515 break;
516 case PCM_PARAM_FRAME_BITS:
517 return SNDRV_PCM_HW_PARAM_FRAME_BITS;
518 break;
519 case PCM_PARAM_CHANNELS:
520 return SNDRV_PCM_HW_PARAM_CHANNELS;
521 break;
522 case PCM_PARAM_RATE:
523 return SNDRV_PCM_HW_PARAM_RATE;
524 break;
525 case PCM_PARAM_PERIOD_TIME:
526 return SNDRV_PCM_HW_PARAM_PERIOD_TIME;
527 break;
528 case PCM_PARAM_PERIOD_SIZE:
529 return SNDRV_PCM_HW_PARAM_PERIOD_SIZE;
530 break;
531 case PCM_PARAM_PERIOD_BYTES:
532 return SNDRV_PCM_HW_PARAM_PERIOD_BYTES;
533 break;
534 case PCM_PARAM_PERIODS:
535 return SNDRV_PCM_HW_PARAM_PERIODS;
536 break;
537 case PCM_PARAM_BUFFER_TIME:
538 return SNDRV_PCM_HW_PARAM_BUFFER_TIME;
539 break;
540 case PCM_PARAM_BUFFER_SIZE:
541 return SNDRV_PCM_HW_PARAM_BUFFER_SIZE;
542 break;
543 case PCM_PARAM_BUFFER_BYTES:
544 return SNDRV_PCM_HW_PARAM_BUFFER_BYTES;
545 break;
546 case PCM_PARAM_TICK_TIME:
547 return SNDRV_PCM_HW_PARAM_TICK_TIME;
548 break;
549
550 default:
551 return -1;
552 }
553}
554
555struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params,
556 enum pcm_param param)
557{
558 int p;
559 struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
560 if (params == NULL) {
561 return NULL;
562 }
563
564 p = pcm_param_to_alsa(param);
565 if (p < 0 || !param_is_mask(p)) {
566 return NULL;
567 }
568
569 return (struct pcm_mask *)param_to_mask(params, p);
570}
571
572unsigned int pcm_params_get_min(struct pcm_params *pcm_params,
573 enum pcm_param param)
574{
575 struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
576 int p;
577
578 if (!params)
579 return 0;
580
581 p = pcm_param_to_alsa(param);
582 if (p < 0)
583 return 0;
584
585 return param_get_min(params, p);
586}
587
588unsigned int pcm_params_get_max(struct pcm_params *pcm_params,
589 enum pcm_param param)
590{
591 struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
592 int p;
593
594 if (!params)
595 return 0;
596
597 p = pcm_param_to_alsa(param);
598 if (p < 0)
599 return 0;
600
601 return param_get_max(params, p);
602}
603
604int pcm_close(struct pcm *pcm)
605{
606 if (pcm == &bad_pcm)
607 return 0;
608
609 pcm_hw_munmap_status(pcm);
610
611 if (pcm->flags & PCM_MMAP) {
612 pcm_stop(pcm);
613 munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size));
614 }
615
616 if (pcm->fd >= 0)
617 close(pcm->fd);
618 pcm->prepared = 0;
619 pcm->running = 0;
620 pcm->buffer_size = 0;
621 pcm->fd = -1;
622 free(pcm);
623 return 0;
624}
625
626struct pcm *pcm_open(unsigned int card, unsigned int device,
627 unsigned int flags, struct pcm_config *config)
628{
629 struct pcm *pcm;
630 struct snd_pcm_info info;
631 struct snd_pcm_hw_params params;
632 struct snd_pcm_sw_params sparams;
633 char fn[256];
634 int rc;
635
636 pcm = calloc(1, sizeof(struct pcm));
637 if (!pcm || !config)
638 return &bad_pcm; /* TODO: could support default config here */
639
640 pcm->config = *config;
641
642 snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device,
643 flags & PCM_IN ? 'c' : 'p');
644
645 pcm->flags = flags;
646 pcm->fd = open(fn, O_RDWR);
647 if (pcm->fd < 0) {
648 oops(pcm, errno, "cannot open device '%s'", fn);
649 return pcm;
650 }
651
652 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) {
653 oops(pcm, errno, "cannot get info");
654 goto fail_close;
655 }
656
657 param_init(&params);
658 param_set_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT,
659 pcm_format_to_alsa(config->format));
660 param_set_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
661 SNDRV_PCM_SUBFORMAT_STD);
662 param_set_min(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size);
663 param_set_int(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
664 pcm_format_to_bits(config->format));
665 param_set_int(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
666 pcm_format_to_bits(config->format) * config->channels);
667 param_set_int(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
668 config->channels);
669 param_set_int(&params, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count);
670 param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, config->rate);
671
672 if (flags & PCM_NOIRQ) {
673
674 if (!(flags & PCM_MMAP)) {
675 oops(pcm, -EINVAL, "noirq only currently supported with mmap().");
676 goto fail;
677 }
678
679 params.flags |= SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP;
680 pcm->noirq_frames_per_msec = config->rate / 1000;
681 }
682
683 if (flags & PCM_MMAP)
684 param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
685 SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
686 else
687 param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
688 SNDRV_PCM_ACCESS_RW_INTERLEAVED);
689
690 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) {
691 oops(pcm, errno, "cannot set hw params");
692 goto fail_close;
693 }
694
695 /* get our refined hw_params */
696 config->period_size = param_get_int(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
697 config->period_count = param_get_int(&params, SNDRV_PCM_HW_PARAM_PERIODS);
698 pcm->buffer_size = config->period_count * config->period_size;
699
700 if (flags & PCM_MMAP) {
701 pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size),
702 PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0);
703 if (pcm->mmap_buffer == MAP_FAILED) {
704 oops(pcm, -errno, "failed to mmap buffer %d bytes\n",
705 pcm_frames_to_bytes(pcm, pcm->buffer_size));
706 goto fail_close;
707 }
708 }
709
710
711 memset(&sparams, 0, sizeof(sparams));
712 sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE;
713 sparams.period_step = 1;
714 sparams.avail_min = 1;
715
716 if (!config->start_threshold) {
717 if (pcm->flags & PCM_IN)
718 pcm->config.start_threshold = sparams.start_threshold = 1;
719 else
720 pcm->config.start_threshold = sparams.start_threshold =
721 config->period_count * config->period_size / 2;
722 } else
723 sparams.start_threshold = config->start_threshold;
724
725 /* pick a high stop threshold - todo: does this need further tuning */
726 if (!config->stop_threshold) {
727 if (pcm->flags & PCM_IN)
728 pcm->config.stop_threshold = sparams.stop_threshold =
729 config->period_count * config->period_size * 10;
730 else
731 pcm->config.stop_threshold = sparams.stop_threshold =
732 config->period_count * config->period_size;
733 }
734 else
735 sparams.stop_threshold = config->stop_threshold;
736
737 sparams.xfer_align = config->period_size / 2; /* needed for old kernels */
738 sparams.silence_size = 0;
739 sparams.silence_threshold = config->silence_threshold;
740 pcm->boundary = sparams.boundary = pcm->buffer_size;
741
742 while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size)
743 pcm->boundary *= 2;
744
745 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) {
746 oops(pcm, errno, "cannot set sw params");
747 goto fail;
748 }
749
750 rc = pcm_hw_mmap_status(pcm);
751 if (rc < 0) {
752 oops(pcm, rc, "mmap status failed");
753 goto fail;
754 }
755
756#ifdef SNDRV_PCM_IOCTL_TTSTAMP
757 if (pcm->flags & PCM_MONOTONIC) {
758 int arg = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
759 rc = ioctl(pcm->fd, SNDRV_PCM_IOCTL_TTSTAMP, &arg);
760 if (rc < 0) {
761 oops(pcm, rc, "cannot set timestamp type");
762 goto fail;
763 }
764 }
765#endif
766
767 pcm->underruns = 0;
768 return pcm;
769
770fail:
771 if (flags & PCM_MMAP)
772 munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size));
773fail_close:
774 close(pcm->fd);
775 pcm->fd = -1;
776 return pcm;
777}
778
779int pcm_is_ready(struct pcm *pcm)
780{
781 return pcm->fd >= 0;
782}
783
784int pcm_prepare(struct pcm *pcm)
785{
786 if (pcm->prepared)
787 return 0;
788
789 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0)
790 return oops(pcm, errno, "cannot prepare channel");
791
792 pcm->prepared = 1;
793 return 0;
794}
795
796int pcm_start(struct pcm *pcm)
797{
798 int prepare_error = pcm_prepare(pcm);
799 if (prepare_error)
800 return prepare_error;
801
802 if (pcm->flags & PCM_MMAP)
803 pcm_sync_ptr(pcm, 0);
804
805 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0)
806 return oops(pcm, errno, "cannot start channel");
807
808 pcm->running = 1;
809 return 0;
810}
811
812int pcm_stop(struct pcm *pcm)
813{
814 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0)
815 return oops(pcm, errno, "cannot stop channel");
816
817 pcm->prepared = 0;
818 pcm->running = 0;
819 return 0;
820}
821
822static inline int pcm_mmap_playback_avail(struct pcm *pcm)
823{
824 int avail;
825
826 avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr;
827
828 if (avail < 0)
829 avail += pcm->boundary;
830 else if (avail > (int)pcm->boundary)
831 avail -= pcm->boundary;
832
833 return avail;
834}
835
836static inline int pcm_mmap_capture_avail(struct pcm *pcm)
837{
838 int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
839 if (avail < 0)
840 avail += pcm->boundary;
841 return avail;
842}
843
844static inline int pcm_mmap_avail(struct pcm *pcm)
845{
846 pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_HWSYNC);
847 if (pcm->flags & PCM_IN)
848 return pcm_mmap_capture_avail(pcm);
849 else
850 return pcm_mmap_playback_avail(pcm);
851}
852
853static void pcm_mmap_appl_forward(struct pcm *pcm, int frames)
854{
855 unsigned int appl_ptr = pcm->mmap_control->appl_ptr;
856 appl_ptr += frames;
857
858 /* check for boundary wrap */
859 if (appl_ptr > pcm->boundary)
860 appl_ptr -= pcm->boundary;
861 pcm->mmap_control->appl_ptr = appl_ptr;
862}
863
864int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset,
865 unsigned int *frames)
866{
867 unsigned int continuous, copy_frames, avail;
868
869 /* return the mmap buffer */
870 *areas = pcm->mmap_buffer;
871
872 /* and the application offset in frames */
873 *offset = pcm->mmap_control->appl_ptr % pcm->buffer_size;
874
875 avail = pcm_mmap_avail(pcm);
876 if (avail > pcm->buffer_size)
877 avail = pcm->buffer_size;
878 continuous = pcm->buffer_size - *offset;
879
880 /* we can only copy frames if the are availabale and continuos */
881 copy_frames = *frames;
882 if (copy_frames > avail)
883 copy_frames = avail;
884 if (copy_frames > continuous)
885 copy_frames = continuous;
886 *frames = copy_frames;
887
888 return 0;
889}
890
891int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames)
892{
893 (void) offset;
894 /* update the application pointer in userspace and kernel */
895 pcm_mmap_appl_forward(pcm, frames);
896 pcm_sync_ptr(pcm, 0);
897
898 return frames;
899}
900
901int pcm_avail_update(struct pcm *pcm)
902{
903 pcm_sync_ptr(pcm, 0);
904 return pcm_mmap_avail(pcm);
905}
906
907int pcm_state(struct pcm *pcm)
908{
909 int err = pcm_sync_ptr(pcm, 0);
910 if (err < 0)
911 return err;
912
913 return pcm->mmap_status->state;
914}
915
916int pcm_wait(struct pcm *pcm, int timeout)
917{
918 struct pollfd pfd;
919 int err;
920
921 pfd.fd = pcm->fd;
922 pfd.events = POLLOUT | POLLERR | POLLNVAL;
923
924 do {
925 /* let's wait for avail or timeout */
926 err = poll(&pfd, 1, timeout);
927 if (err < 0)
928 return -errno;
929
930 /* timeout ? */
931 if (err == 0)
932 return 0;
933
934 /* have we been interrupted ? */
935 if (errno == -EINTR)
936 continue;
937
938 /* check for any errors */
939 if (pfd.revents & (POLLERR | POLLNVAL)) {
940 switch (pcm_state(pcm)) {
941 case PCM_STATE_XRUN:
942 return -EPIPE;
943 case PCM_STATE_SUSPENDED:
944 return -ESTRPIPE;
945 case PCM_STATE_DISCONNECTED:
946 return -ENODEV;
947 default:
948 return -EIO;
949 }
950 }
951 /* poll again if fd not ready for IO */
952 } while (!(pfd.revents & (POLLIN | POLLOUT)));
953
954 return 1;
955}
956
957int pcm_mmap_transfer(struct pcm *pcm, const void *buffer, unsigned int bytes)
958{
959 int err = 0, frames, avail;
960 unsigned int offset = 0, count;
961
962 if (bytes == 0)
963 return 0;
964
965 count = pcm_bytes_to_frames(pcm, bytes);
966
967 while (count > 0) {
968
969 /* get the available space for writing new frames */
970 avail = pcm_avail_update(pcm);
971 if (avail < 0) {
972 fprintf(stderr, "cannot determine available mmap frames");
973 return err;
974 }
975
976 /* start the audio if we reach the threshold */
977 if (!pcm->running &&
978 (pcm->buffer_size - avail) >= pcm->config.start_threshold) {
979 if (pcm_start(pcm) < 0) {
980 fprintf(stderr, "start error: hw 0x%x app 0x%x avail 0x%x\n",
981 (unsigned int)pcm->mmap_status->hw_ptr,
982 (unsigned int)pcm->mmap_control->appl_ptr,
983 avail);
984 return -errno;
985 }
986 }
987
988 /* sleep until we have space to write new frames */
989 if (pcm->running &&
990 (unsigned int)avail < pcm->mmap_control->avail_min) {
991 int time = -1;
992
993 if (pcm->flags & PCM_NOIRQ)
994 time = (pcm->buffer_size - avail - pcm->mmap_control->avail_min)
995 / pcm->noirq_frames_per_msec;
996
997 err = pcm_wait(pcm, time);
998 if (err < 0) {
999 pcm->prepared = 0;
1000 pcm->running = 0;
1001 fprintf(stderr, "wait error: hw 0x%x app 0x%x avail 0x%x\n",
1002 (unsigned int)pcm->mmap_status->hw_ptr,
1003 (unsigned int)pcm->mmap_control->appl_ptr,
1004 avail);
1005 pcm->mmap_control->appl_ptr = 0;
1006 return err;
1007 }
1008 continue;
1009 }
1010
1011 frames = count;
1012 if (frames > avail)
1013 frames = avail;
1014
1015 if (!frames)
1016 break;
1017
1018 /* copy frames from buffer */
1019 frames = pcm_mmap_transfer_areas(pcm, (void *)buffer, offset, frames);
1020 if (frames < 0) {
1021 fprintf(stderr, "write error: hw 0x%x app 0x%x avail 0x%x\n",
1022 (unsigned int)pcm->mmap_status->hw_ptr,
1023 (unsigned int)pcm->mmap_control->appl_ptr,
1024 avail);
1025 return frames;
1026 }
1027
1028 offset += frames;
1029 count -= frames;
1030 }
1031
1032 return 0;
1033}
1034
1035int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count)
1036{
1037 if ((~pcm->flags) & (PCM_OUT | PCM_MMAP))
1038 return -ENOSYS;
1039
1040 return pcm_mmap_transfer(pcm, (void *)data, count);
1041}
1042
1043int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count)
1044{
1045 if ((~pcm->flags) & (PCM_IN | PCM_MMAP))
1046 return -ENOSYS;
1047
1048 return pcm_mmap_transfer(pcm, data, count);
1049}