summaryrefslogtreecommitdiff
path: root/firmware/target/hosted/ibasso
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
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')
-rw-r--r--firmware/target/hosted/ibasso/android_ndk.make49
-rw-r--r--firmware/target/hosted/ibasso/audiohw-ibasso.c81
-rw-r--r--firmware/target/hosted/ibasso/backlight-ibasso.c132
-rw-r--r--firmware/target/hosted/ibasso/backlight-target.h39
-rw-r--r--firmware/target/hosted/ibasso/button-ibasso.c420
-rw-r--r--firmware/target/hosted/ibasso/button-ibasso.h61
-rw-r--r--firmware/target/hosted/ibasso/button-target.h63
-rw-r--r--firmware/target/hosted/ibasso/debug-ibasso.c70
-rw-r--r--firmware/target/hosted/ibasso/debug-ibasso.h38
-rw-r--r--firmware/target/hosted/ibasso/dx50/audiohw-dx50.c68
-rw-r--r--firmware/target/hosted/ibasso/dx50/button-dx50.c96
-rw-r--r--firmware/target/hosted/ibasso/dx50/codec-dx50.h51
-rw-r--r--firmware/target/hosted/ibasso/dx90/audiohw-dx90.c63
-rw-r--r--firmware/target/hosted/ibasso/dx90/button-dx90.c104
-rw-r--r--firmware/target/hosted/ibasso/dx90/codec-dx90.h35
-rw-r--r--firmware/target/hosted/ibasso/hostfs-ibasso.c47
-rw-r--r--firmware/target/hosted/ibasso/lcd-ibasso.c195
-rw-r--r--firmware/target/hosted/ibasso/lcd-target.h44
-rw-r--r--firmware/target/hosted/ibasso/pcm-ibasso.c488
-rw-r--r--firmware/target/hosted/ibasso/pcm-ibasso.h33
-rw-r--r--firmware/target/hosted/ibasso/power-ibasso.c97
-rw-r--r--firmware/target/hosted/ibasso/powermgmt-ibasso.c122
-rw-r--r--firmware/target/hosted/ibasso/sysfs-ibasso.c404
-rw-r--r--firmware/target/hosted/ibasso/sysfs-ibasso.h111
-rw-r--r--firmware/target/hosted/ibasso/system-ibasso.c101
-rw-r--r--firmware/target/hosted/ibasso/system-target.h33
-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
-rw-r--r--firmware/target/hosted/ibasso/usb-ibasso.c92
-rw-r--r--firmware/target/hosted/ibasso/usb-ibasso.h54
-rw-r--r--firmware/target/hosted/ibasso/vold-ibasso.c203
-rw-r--r--firmware/target/hosted/ibasso/vold-ibasso.h42
34 files changed, 6067 insertions, 0 deletions
diff --git a/firmware/target/hosted/ibasso/android_ndk.make b/firmware/target/hosted/ibasso/android_ndk.make
new file mode 100644
index 0000000000..e2f5c93db8
--- /dev/null
+++ b/firmware/target/hosted/ibasso/android_ndk.make
@@ -0,0 +1,49 @@
1# __________ __ ___
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7#
8# Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
9# Copyright (C) 2014 by Mario Basister: iBasso DX90 port
10# Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
11# Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
12#
13# This program is free software; you can redistribute it and/or
14# modify it under the terms of the GNU General Public License
15# as published by the Free Software Foundation; either version 2
16# of the License, or (at your option) any later version.
17#
18# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19# KIND, either express or implied.
20
21
22# This is a glibc compatibility hack to provide a get_nprocs() replacement.
23# The NDK ships cpu-features.c which has a compatible function android_getCpuCount()
24CPUFEAT = $(ANDROID_NDK_PATH)/sources/android/cpufeatures
25CPUFEAT_BUILD = $(BUILDDIR)/android-ndk/sources/android/cpufeatures
26INCLUDES += -I$(CPUFEAT)
27OTHER_SRC += $(CPUFEAT)/cpu-features.c
28CLEANOBJS += $(CPUFEAT_BUILD)/cpu-features.o
29$(CPUFEAT_BUILD)/cpu-features.o: $(CPUFEAT)/cpu-features.c
30 $(SILENT)mkdir -p $(dir $@)
31 $(call PRINTS,CC $(subst $(CPUFEAT)/,,$<))$(CC) -o $@ -c $(CPUFEAT)/cpu-features.c $(GCCOPTS) -Wno-unused
32
33.SECONDEXPANSION:
34.PHONY: clean dirs
35
36DIRS += $(CPUFEAT_BUILD)
37
38.PHONY:
39$(BUILDDIR)/$(BINARY): $$(OBJ) $(FIRMLIB) $(VOICESPEEXLIB) $(CORE_LIBS) $(CPUFEAT_BUILD)/cpu-features.o
40 $(call PRINTS,LD $(BINARY))$(CC) -o $@ $^ $(LDOPTS) $(GLOBAL_LDOPTS) -Wl,-Map,$(BUILDDIR)/rockbox.map
41 $(call PRINTS,OC $(@F))$(call objcopy,$@,$@)
42
43$(DIRS):
44 $(SILENT)mkdir -p $@
45
46dirs: $(DIRS)
47
48clean::
49 $(SILENT)rm -rf $(BUILDDIR)/android-ndk
diff --git a/firmware/target/hosted/ibasso/audiohw-ibasso.c b/firmware/target/hosted/ibasso/audiohw-ibasso.c
new file mode 100644
index 0000000000..447e133eba
--- /dev/null
+++ b/firmware/target/hosted/ibasso/audiohw-ibasso.c
@@ -0,0 +1,81 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include "config.h"
26#include "debug.h"
27#include "pcm_sw_volume.h"
28#include "settings.h"
29
30#include "debug-ibasso.h"
31#include "pcm-ibasso.h"
32
33
34void audiohw_close(void)
35{
36 TRACE;
37
38 pcm_close_device();
39}
40
41
42void set_software_volume(void)
43{
44 /* -73dB (?) minimum software volume in decibels. See pcm-internal.h. */
45 static const int SW_VOLUME_MIN = 730;
46
47 int sw_volume_l = 0;
48 int sw_volume_r = 0;
49
50 if(global_settings.balance > 0)
51 {
52 if(global_settings.balance == 100)
53 {
54 sw_volume_l = PCM_MUTE_LEVEL;
55 }
56 else
57 {
58 sw_volume_l -= SW_VOLUME_MIN * global_settings.balance / 100;
59 }
60 }
61 else if(global_settings.balance < 0)
62 {
63 if(global_settings.balance == -100)
64 {
65 sw_volume_r = PCM_MUTE_LEVEL;
66 }
67 else
68 {
69 sw_volume_r = SW_VOLUME_MIN * global_settings.balance / 100;
70 }
71 }
72
73 DEBUGF("DEBUG %s: global_settings.balance: %d, sw_volume_l: %d, sw_volume_r: %d.",
74 __func__,
75 global_settings.balance,
76 sw_volume_l,
77 sw_volume_r);
78
79 /* Emulate balance with software volume. */
80 pcm_set_master_volume(sw_volume_l, sw_volume_r);
81}
diff --git a/firmware/target/hosted/ibasso/backlight-ibasso.c b/firmware/target/hosted/ibasso/backlight-ibasso.c
new file mode 100644
index 0000000000..907980e01a
--- /dev/null
+++ b/firmware/target/hosted/ibasso/backlight-ibasso.c
@@ -0,0 +1,132 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <stdbool.h>
26
27#include "config.h"
28#include "debug.h"
29#include "lcd.h"
30#include "panic.h"
31
32#include "debug-ibasso.h"
33#include "sysfs-ibasso.h"
34
35
36/*
37 Prevent excessive backlight_hw_on usage.
38 Required for proper seeking.
39*/
40static bool _backlight_enabled = false;
41
42
43bool backlight_hw_init(void)
44{
45 TRACE;
46
47 /*
48 /sys/devices/platform/rk29_backlight/backlight/rk28_bl/bl_power
49 0: backlight on
50 */
51 if(! sysfs_set_int(SYSFS_BACKLIGHT_POWER, 0))
52 {
53 DEBUGF("ERROR %s: Can not enable backlight.", __func__);
54 panicf("ERROR %s: Can not enable backlight.", __func__);
55 return false;
56 }
57
58 _backlight_enabled = true;
59
60 return true;
61}
62
63
64void backlight_hw_on(void)
65{
66 if(! _backlight_enabled)
67 {
68 backlight_hw_init();
69 lcd_enable(true);
70 }
71}
72
73
74void backlight_hw_off(void)
75{
76 TRACE;
77
78 /*
79 /sys/devices/platform/rk29_backlight/backlight/rk28_bl/bl_power
80 1: backlight off
81 */
82 if(! sysfs_set_int(SYSFS_BACKLIGHT_POWER, 1))
83 {
84 DEBUGF("ERROR %s: Can not disable backlight.", __func__);
85 return;
86 }
87
88 lcd_enable(false);
89
90 _backlight_enabled = false;
91}
92
93
94/*
95 Prevent excessive backlight_hw_brightness usage.
96 Required for proper seeking.
97*/
98static int _current_brightness = -1;
99
100
101void backlight_hw_brightness(int brightness)
102{
103 if(brightness > MAX_BRIGHTNESS_SETTING)
104 {
105 DEBUGF("DEBUG %s: Adjusting brightness from %d to MAX.", __func__, brightness);
106 brightness = MAX_BRIGHTNESS_SETTING;
107 }
108 if(brightness < MIN_BRIGHTNESS_SETTING)
109 {
110 DEBUGF("DEBUG %s: Adjusting brightness from %d to MIN.", __func__, brightness);
111 brightness = MIN_BRIGHTNESS_SETTING;
112 }
113
114 if(_current_brightness == brightness)
115 {
116 return;
117 }
118
119 TRACE;
120
121 _current_brightness = brightness;
122
123 /*
124 /sys/devices/platform/rk29_backlight/backlight/rk28_bl/max_brightness
125 0 ... 255
126 */
127 if(! sysfs_set_int(SYSFS_BACKLIGHT_BRIGHTNESS, _current_brightness))
128 {
129 DEBUGF("ERROR %s: Can not set brightness.", __func__);
130 return;
131 }
132}
diff --git a/firmware/target/hosted/ibasso/backlight-target.h b/firmware/target/hosted/ibasso/backlight-target.h
new file mode 100644
index 0000000000..aa8fafab04
--- /dev/null
+++ b/firmware/target/hosted/ibasso/backlight-target.h
@@ -0,0 +1,39 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef _BACKLIGHT_TARGET_H_
26#define _BACKLIGHT_TARGET_H_
27
28
29#include <stdbool.h>
30
31
32/* See backlight.c */
33bool backlight_hw_init(void);
34void backlight_hw_on(void);
35void backlight_hw_off(void);
36void backlight_hw_brightness(int brightness);
37
38
39#endif
diff --git a/firmware/target/hosted/ibasso/button-ibasso.c b/firmware/target/hosted/ibasso/button-ibasso.c
new file mode 100644
index 0000000000..1694992ea4
--- /dev/null
+++ b/firmware/target/hosted/ibasso/button-ibasso.c
@@ -0,0 +1,420 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <dirent.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <stdbool.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32#include <linux/input.h>
33#include <sys/inotify.h>
34#include <sys/limits.h>
35#include <sys/poll.h>
36
37#include "config.h"
38#include "backlight.h"
39#include "button.h"
40#include "debug.h"
41#include "panic.h"
42#include "settings.h"
43#include "touchscreen.h"
44
45#include "button-ibasso.h"
46#include "button-target.h"
47#include "debug-ibasso.h"
48#include "sysfs-ibasso.h"
49
50
51#define EVENT_TYPE_BUTTON 1
52
53/* /dev/input/event0 */
54#define EVENT_CODE_BUTTON_LINEOUT 113
55#define EVENT_CODE_BUTTON_SPDIF 114
56#define EVENT_CODE_BUTTON_HOLD 115
57
58/* /dev/input/event1 */
59#define EVENT_CODE_BUTTON_SDCARD 143
60
61
62#define EVENT_TYPE_TOUCHSCREEN 3
63
64/* /dev/input/event2 */
65#define EVENT_CODE_TOUCHSCREEN_X 53
66#define EVENT_CODE_TOUCHSCREEN_Y 54
67#define EVENT_CODE_TOUCHSCREEN 57
68
69#define EVENT_VALUE_TOUCHSCREEN_PRESS 1
70#define EVENT_VALUE_TOUCHSCREEN_RELEASE -1
71
72
73/*
74 Changing bit, when hold switch is toggled.
75 Bit is off when hold switch is engaged.
76*/
77#define HOLD_SWITCH_BIT 16
78
79/*
80 Changing bit, when coaxial out is plugged.
81 Bit is off when coaxial out is plugged in.
82*/
83#define COAX_BIT 32
84
85/*
86 Changing bit, when line out is plugged.
87 Bit is off when line out is plugged in.
88*/
89#define SPDIF_BIT 64
90
91
92/* State of the hold switch; true: hold switch engaged. */
93static bool _hold = false;
94
95
96/* See button.h. */
97bool button_hold(void)
98{
99 char hold_state;
100 if(! sysfs_get_char(SYSFS_HOLDKEY, &hold_state))
101 {
102 DEBUGF("ERROR %s: Can not get hold switch state.", __func__);
103 hold_state = HOLD_SWITCH_BIT;
104 }
105
106 /*DEBUGF("%s: hold_state: %d, %c.", __func__, hold_state, hold_state);*/
107
108 /*bool coax_connected = ! (hold_state & COAX_BIT);
109 bool spdif_connected = ! (hold_state & SPDIF_BIT);*/
110
111 _hold = ! (hold_state & HOLD_SWITCH_BIT);
112
113 /*DEBUGF("%s: _hold: %d, coax_connected: %d, spdif_connected: %d.", __func__, _hold, coax_connected, spdif_connected);*/
114
115 return _hold;
116}
117
118
119/* Input devices monitored with poll API. */
120static struct pollfd* _fds = NULL;
121
122
123/* Number of input devices monitored with poll API. */
124static nfds_t _nfds = 0;
125
126
127/* The names of the devices in _fds. */
128static char** _device_names = NULL;
129
130
131/* Open device device_name and add it to the list of polled devices. */
132static bool open_device(const char* device_name)
133{
134 int fd = open(device_name, O_RDONLY);
135 if(fd == -1)
136 {
137 DEBUGF("ERROR %s: open failed on %s.", __func__, device_name);
138 return false;
139 }
140
141 struct pollfd* new_fds = realloc(_fds, sizeof(struct pollfd) * (_nfds + 1));
142 if(new_fds == NULL)
143 {
144 DEBUGF("ERROR %s: realloc for _fds failed.", __func__);
145 panicf("ERROR %s: realloc for _fds failed.", __func__);
146 return false;
147 }
148
149 _fds = new_fds;
150 _fds[_nfds].fd = fd;
151 _fds[_nfds].events = POLLIN;
152
153 char** new_device_names = realloc(_device_names, sizeof(char*) * (_nfds + 1));
154 if(new_device_names == NULL)
155 {
156 DEBUGF("ERROR %s: realloc for _device_names failed.", __func__);
157 panicf("ERROR %s: realloc for _device_names failed.", __func__);
158 return false;
159 }
160
161 _device_names = new_device_names;
162 _device_names[_nfds] = strdup(device_name);
163 if(_device_names[_nfds] == NULL)
164 {
165 DEBUGF("ERROR %s: strdup failed.", __func__);
166 panicf("ERROR %s: strdup failed.", __func__);
167 return false;
168 }
169
170 ++_nfds;
171
172 DEBUGF("DEBUG %s: Opened device %s.", __func__, device_name);
173
174 return true;
175}
176
177
178/* See button.h. */
179void button_init_device(void)
180{
181 TRACE;
182
183 if((_fds != NULL) || (_nfds != 0) || (_device_names != NULL))
184 {
185 DEBUGF("ERROR %s: Allready initialized.", __func__);
186 panicf("ERROR %s: Allready initialized.", __func__);
187 return;
188 }
189
190 /* The input device directory. */
191 static const char device_path[] = "/dev/input";
192
193 /* Path delimeter. */
194 static const char delimeter[] = "/";
195
196 /* Open all devices in device_path. */
197 DIR* dir = opendir(device_path);
198 if(dir == NULL)
199 {
200 DEBUGF("ERROR %s: opendir failed: errno: %d.", __func__, errno);
201 panicf("ERROR %s: opendir failed: errno: %d.", __func__, errno);
202 return;
203 }
204
205 char device_name[PATH_MAX];
206 strcpy(device_name, device_path);
207 strcat(device_name, delimeter);
208 char* device_name_idx = device_name + strlen(device_name);
209
210 struct dirent* dir_entry;
211 while((dir_entry = readdir(dir)))
212 {
213 if( ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '\0'))
214 || ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '.') && (dir_entry->d_name[2] == '\0')))
215 {
216 continue;
217 }
218
219 strcpy(device_name_idx, dir_entry->d_name);
220
221 /* Open and add device to _fds. */
222 open_device(device_name);
223 }
224
225 closedir(dir);
226
227 /* Sanity check. */
228 if(_nfds < 2)
229 {
230 DEBUGF("ERROR %s: No input devices.", __func__);
231 panicf("ERROR %s: No input devices.", __func__);
232 return;
233 }
234
235 /*
236 Hold switch has a separate interface for its state.
237 Input events just report that it has been toggled, but not the state.
238 */
239 button_hold();
240}
241
242
243/* Last known touchscreen coordinates. */
244static int _last_x = 0;
245static int _last_y = 0;
246
247
248/* Last known touchscreen state. */
249static enum
250{
251 TOUCHSCREEN_STATE_UNKNOWN = 0,
252 TOUCHSCREEN_STATE_UP,
253 TOUCHSCREEN_STATE_DOWN
254} _last_touch_state = TOUCHSCREEN_STATE_UNKNOWN;
255
256
257static bool handle_touchscreen_event(__u16 code, __s32 value)
258{
259 bool read_more = false;
260
261 switch(code)
262 {
263 case EVENT_CODE_TOUCHSCREEN_X:
264 {
265 _last_x = value;
266
267 /* x -> next will be y. */
268 read_more = true;
269
270 break;
271 }
272
273 case EVENT_CODE_TOUCHSCREEN_Y:
274 {
275 _last_y = value;
276 break;
277 }
278
279 case EVENT_CODE_TOUCHSCREEN:
280 {
281 if(value == EVENT_VALUE_TOUCHSCREEN_PRESS)
282 {
283 _last_touch_state = TOUCHSCREEN_STATE_DOWN;
284
285 /* Press -> next will be x. */
286 read_more = true;
287 }
288 else
289 {
290 _last_touch_state = TOUCHSCREEN_STATE_UP;
291 }
292 break;
293 }
294 }
295
296 return read_more;
297}
298
299
300/* Last known hardware buttons pressed. */
301static int _last_btns = BUTTON_NONE;
302
303
304/* See button.h. */
305int button_read_device(int *data)
306{
307 bool read_more = true;
308 while(read_more)
309 {
310 read_more = false;
311
312 /* Poll all input devices. */
313 poll(_fds, _nfds, 0);
314
315 for(nfds_t fds_idx = 0; fds_idx < _nfds; ++fds_idx)
316 {
317 if(! (_fds[fds_idx].revents & POLLIN))
318 {
319 continue;
320 }
321
322 struct input_event event;
323 if(read(_fds[fds_idx].fd, &event, sizeof(event)) < (int) sizeof(event))
324 {
325 DEBUGF("ERROR %s: Read of input devices failed.", __func__);
326 continue;
327 }
328
329 /*DEBUGF("DEBUG %s: device: %s, event.type: %d, event.code: %d, event.value: %d", __func__, _device_names[fds_idx], event.type, event.code, event.value);*/
330
331 switch(event.type)
332 {
333 case EVENT_TYPE_BUTTON:
334 {
335 if(event.code == EVENT_CODE_BUTTON_HOLD)
336 {
337 /* Hold switch toggled, update hold switch state. */
338 button_hold();
339 backlight_hold_changed(_hold);
340
341 _last_btns = BUTTON_NONE;
342 break;
343 }
344
345 _last_btns = handle_button_event(event.code, event.value, _last_btns);
346
347 if(_hold)
348 {
349 /* Hold switch engaged. Ignore all button events. */
350 _last_btns = BUTTON_NONE;
351 }
352
353 /*DEBUGF("DEBUG %s: _last_btns: %#8.8x", __func__, _last_btns);*/
354 break;
355 }
356
357 case EVENT_TYPE_TOUCHSCREEN:
358 {
359 if(_hold)
360 {
361 /* Hold switch engaged, ignore all touchscreen events. */
362 _last_touch_state = TOUCHSCREEN_STATE_UNKNOWN;
363 _last_btns = BUTTON_NONE;
364 }
365 else
366 {
367 read_more = handle_touchscreen_event(event.code, event.value);
368 /*DEBUGF("DEBUG %s: _last_touch_state: %d, _last_x: %d, _last_y: %d, read_more: %s", __func__, _last_touch_state, _last_x, _last_y, read_more ? "true" : "false");*/
369 }
370 break;
371 }
372 }
373 }
374 }
375
376 /*
377 Get grid button/coordinates based on the current touchscreen mode
378 Caveat: The caller seemingly depends on *data always being filled with
379 the last known touchscreen position, so always call
380 touchscreen_to_pixels().
381 */
382 int touch = touchscreen_to_pixels(_last_x, _last_y, data);
383
384 if(_last_touch_state == TOUCHSCREEN_STATE_DOWN)
385 {
386 return _last_btns | touch;
387 }
388
389 /*DEBUGF("DEBUG %s: _last_btns: %#8.8x.", __func__, _last_btns);*/
390
391 return _last_btns;
392}
393
394
395void button_close_device(void)
396{
397 TRACE;
398
399 if(_fds)
400 {
401 for(nfds_t fds_idx = 0; fds_idx < _nfds; ++fds_idx)
402 {
403 close(_fds[fds_idx].fd);
404 }
405 free(_fds);
406 _fds = NULL;
407 }
408
409 if(_device_names)
410 {
411 for(nfds_t fds_idx = 0; fds_idx < _nfds; ++fds_idx)
412 {
413 free(_device_names[fds_idx]);
414 }
415 free(_device_names);
416 _device_names = NULL;
417 }
418
419 _nfds = 0;
420}
diff --git a/firmware/target/hosted/ibasso/button-ibasso.h b/firmware/target/hosted/ibasso/button-ibasso.h
new file mode 100644
index 0000000000..09c09e7c83
--- /dev/null
+++ b/firmware/target/hosted/ibasso/button-ibasso.h
@@ -0,0 +1,61 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef _BUTTON_IBASSO_H_
26#define _BUTTON_IBASSO_H_
27
28
29#include <sys/types.h>
30
31
32/* /dev/input/event0 */
33#define EVENT_CODE_BUTTON_PWR 116
34#define EVENT_CODE_BUTTON_PWR_LONG 117
35
36/* /dev/input/event1 */
37#define EVENT_CODE_BUTTON_VOLPLUS 158
38#define EVENT_CODE_BUTTON_VOLMINUS 159
39#define EVENT_CODE_BUTTON_REV 160
40#define EVENT_CODE_BUTTON_PLAY 161
41#define EVENT_CODE_BUTTON_NEXT 162
42
43#define EVENT_VALUE_BUTTON_PRESS 1
44#define EVENT_VALUE_BUTTON_RELEASE 0
45
46
47/*
48 Handle hardware button events.
49 code: Input event code.
50 value: Input event value.
51 last_btns: Last known pressed buttons.
52 Returns: Currently pressed buttons as bitmask (BUTTON_ values in button-target.h).
53*/
54int handle_button_event(__u16 code, __s32 value, int last_btns);
55
56
57/* Clean up the button device handler. */
58void button_close_device(void);
59
60
61#endif
diff --git a/firmware/target/hosted/ibasso/button-target.h b/firmware/target/hosted/ibasso/button-target.h
new file mode 100644
index 0000000000..d1b3c8a8de
--- /dev/null
+++ b/firmware/target/hosted/ibasso/button-target.h
@@ -0,0 +1,63 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef _BUTTON_TARGET_H_
26#define _BUTTON_TARGET_H_
27
28
29/* Hardware buttons. */
30#define BUTTON_LEFT 0x00000001
31#define BUTTON_RIGHT 0x00000002
32#define BUTTON_PLAY 0x00000004
33#define BUTTON_POWER 0x00000008
34#define BUTTON_VOL_UP 0x00000010
35#define BUTTON_VOL_DOWN 0x00000020
36#define BUTTON_POWER_LONG 0x00000040
37
38#define BUTTON_MAIN ( BUTTON_LEFT | BUTTON_VOL_UP | BUTTON_VOL_DOWN | BUTTON_RIGHT \
39 | BUTTON_PLAY | BUTTON_POWER | BUTTON_POWER_LONG)
40
41
42#define STATE_SPDIF_UNPLUGGED 32
43#define STATE_LINEOUT_UNPLUGGED 64
44
45
46/* Touchscreen area buttons 3x3 grid. */
47#define BUTTON_TOPLEFT 0x00001000
48#define BUTTON_TOPMIDDLE 0x00002000
49#define BUTTON_TOPRIGHT 0x00004000
50#define BUTTON_MIDLEFT 0x00008000
51#define BUTTON_CENTER 0x00010000
52#define BUTTON_MIDRIGHT 0x00020000
53#define BUTTON_BOTTOMLEFT 0x00040000
54#define BUTTON_BOTTOMMIDDLE 0x00080000
55#define BUTTON_BOTTOMRIGHT 0x00100000
56
57
58/* Power-off */
59#define POWEROFF_BUTTON BUTTON_POWER_LONG
60#define POWEROFF_COUNT 0
61
62
63#endif
diff --git a/firmware/target/hosted/ibasso/debug-ibasso.c b/firmware/target/hosted/ibasso/debug-ibasso.c
new file mode 100644
index 0000000000..6295de1f6c
--- /dev/null
+++ b/firmware/target/hosted/ibasso/debug-ibasso.c
@@ -0,0 +1,70 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <stdarg.h>
26#include <stdio.h>
27#include <string.h>
28#include <android/log.h>
29
30#include "config.h"
31#include "debug.h"
32
33#include "debug-ibasso.h"
34
35
36static const char log_tag[] = "Rockbox";
37
38
39void debug_init(void)
40{}
41
42
43void debugf(const char *fmt, ...)
44{
45 va_list ap;
46 va_start(ap, fmt);
47 __android_log_vprint(ANDROID_LOG_DEBUG, log_tag, fmt, ap);
48 va_end(ap);
49}
50
51
52void ldebugf(const char* file, int line, const char *fmt, ...)
53{
54 va_list ap;
55 /* 13: 5 literal chars and 8 chars for the line number. */
56 char buf[strlen(file) + strlen(fmt) + 13];
57 snprintf(buf, sizeof(buf), "%s (%d): %s", file, line, fmt);
58 va_start(ap, fmt);
59 __android_log_vprint(ANDROID_LOG_DEBUG, log_tag, buf, ap);
60 va_end(ap);
61}
62
63
64void debug_trace(const char* function)
65{
66 static const char trace_tag[] = "TRACE: ";
67 char msg[strlen(trace_tag) + strlen(function) + 1];
68 snprintf(msg, sizeof(msg), "%s%s", trace_tag, function);
69 __android_log_write(ANDROID_LOG_DEBUG, log_tag, msg);
70}
diff --git a/firmware/target/hosted/ibasso/debug-ibasso.h b/firmware/target/hosted/ibasso/debug-ibasso.h
new file mode 100644
index 0000000000..456f189a5a
--- /dev/null
+++ b/firmware/target/hosted/ibasso/debug-ibasso.h
@@ -0,0 +1,38 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef _DEBUG_IBASSO_H_
26#define _DEBUG_IBASSO_H_
27
28
29void debug_trace(const char* function);
30
31
32#ifdef DEBUG
33#define TRACE debug_trace(__func__)
34#else
35#define TRACE
36#endif
37
38#endif \ No newline at end of file
diff --git a/firmware/target/hosted/ibasso/dx50/audiohw-dx50.c b/firmware/target/hosted/ibasso/dx50/audiohw-dx50.c
new file mode 100644
index 0000000000..5e61348c8d
--- /dev/null
+++ b/firmware/target/hosted/ibasso/dx50/audiohw-dx50.c
@@ -0,0 +1,68 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include "config.h"
26#include "debug.h"
27
28#include "debug-ibasso.h"
29#include "sysfs-ibasso.h"
30
31
32extern void set_software_volume(void);
33
34
35void audiohw_set_volume(int volume)
36{
37 set_software_volume();
38
39 /*
40 See codec-dx50.h.
41 -128db -> -1 (adjusted to 0, mute)
42 -127dB to 0dB -> 1 to 255 in steps of 2
43 volume is in centibels (tenth-decibels).
44 */
45 int volume_adjusted = (volume / 10) * 2 + 255;
46
47 DEBUGF("DEBUG %s: volume: %d, volume_adjusted: %d.", __func__, volume, volume_adjusted);
48
49 if(volume_adjusted > 255)
50 {
51 DEBUGF("DEBUG %s: Adjusting volume from %d to 255.", __func__, volume);
52 volume_adjusted = 255;
53 }
54 if(volume_adjusted < 0)
55 {
56 DEBUGF("DEBUG %s: Adjusting volume from %d to 0.", __func__, volume);
57 volume_adjusted = 0;
58 }
59
60 /*
61 /dev/codec_volume
62 0 ... 255
63 */
64 if(! sysfs_set_int(SYSFS_DX50_CODEC_VOLUME, volume_adjusted))
65 {
66 DEBUGF("ERROR %s: Can not set volume.", __func__);
67 }
68}
diff --git a/firmware/target/hosted/ibasso/dx50/button-dx50.c b/firmware/target/hosted/ibasso/dx50/button-dx50.c
new file mode 100644
index 0000000000..b4f6952d44
--- /dev/null
+++ b/firmware/target/hosted/ibasso/dx50/button-dx50.c
@@ -0,0 +1,96 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include "config.h"
26#include "button.h"
27
28#include "button-ibasso.h"
29
30
31int handle_button_event(__u16 code, __s32 value, int last_btns)
32{
33 int button = BUTTON_NONE;
34
35 switch(code)
36 {
37 case EVENT_CODE_BUTTON_PWR:
38 {
39 button = BUTTON_POWER;
40 break;
41 }
42
43 case EVENT_CODE_BUTTON_PWR_LONG:
44 {
45 button = BUTTON_POWER_LONG;
46 break;
47 }
48
49 case EVENT_CODE_BUTTON_VOLPLUS:
50 {
51 button = BUTTON_VOL_UP;
52 break;
53 }
54
55 case EVENT_CODE_BUTTON_VOLMINUS:
56 {
57 button = BUTTON_VOL_DOWN;
58 break;
59 }
60
61 case EVENT_CODE_BUTTON_REV:
62 {
63 button = BUTTON_LEFT;
64 break;
65 }
66
67 case EVENT_CODE_BUTTON_PLAY:
68 {
69 button = BUTTON_PLAY;
70 break;
71 }
72
73 case EVENT_CODE_BUTTON_NEXT:
74 {
75 button = BUTTON_RIGHT;
76 break;
77 }
78
79 default:
80 {
81 return BUTTON_NONE;
82 }
83 }
84
85 int buttons = last_btns;
86 if(value == EVENT_VALUE_BUTTON_PRESS)
87 {
88 buttons = (last_btns | button);
89 }
90 else
91 {
92 buttons = (last_btns & (~ button));
93 }
94
95 return buttons;
96}
diff --git a/firmware/target/hosted/ibasso/dx50/codec-dx50.h b/firmware/target/hosted/ibasso/dx50/codec-dx50.h
new file mode 100644
index 0000000000..89a1a3f1c4
--- /dev/null
+++ b/firmware/target/hosted/ibasso/dx50/codec-dx50.h
@@ -0,0 +1,51 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef _CODEC_DX50_H_
26#define _CODEC_DX50_H_
27
28
29#define AUDIOHW_CAPS MONO_VOL_CAP
30
31
32/*
33 http://www.wolfsonmicro.com/media/76425/WM8740.pdf
34
35 0.5 * ( x - 255 ) = ydB 1 <= x <= 255
36 mute x = 0
37
38 x = 255 -> 0dB
39 .
40 .
41 .
42 x = 2 -> -126.5dB
43 x = 1 -> -127dB
44 x = 0 -> -128dB
45
46 See audiohw.h, sound.c.
47*/
48AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -128, 0, -30)
49
50
51#endif
diff --git a/firmware/target/hosted/ibasso/dx90/audiohw-dx90.c b/firmware/target/hosted/ibasso/dx90/audiohw-dx90.c
new file mode 100644
index 0000000000..ef18aae4bd
--- /dev/null
+++ b/firmware/target/hosted/ibasso/dx90/audiohw-dx90.c
@@ -0,0 +1,63 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include "config.h"
26#include "debug.h"
27
28#include "debug-ibasso.h"
29#include "sysfs-ibasso.h"
30
31
32extern void set_software_volume(void);
33
34
35void audiohw_set_volume(int volume)
36{
37 set_software_volume();
38
39 /* See codec-dx90.h. -2550 to 0 -> 0 to 255 */
40 int volume_adjusted = ((volume + 2550) / 10);
41
42 DEBUGF("DEBUG %s: volume: %d, volume_adjusted: %d.", __func__, volume, volume_adjusted);
43
44 if(volume_adjusted > 255)
45 {
46 DEBUGF("DEBUG %s: Adjusting volume from %d to 255.", __func__, volume);
47 volume_adjusted = 255;
48 }
49 if(volume_adjusted < 0)
50 {
51 DEBUGF("DEBUG %s: Adjusting volume from %d to 0.", __func__, volume);
52 volume_adjusted = 0;
53 }
54
55 /*
56 /sys/class/codec/es9018_volume
57 0 ... 255
58 */
59 if(! sysfs_set_int(SYSFS_DX90_ES9018_VOLUME, volume_adjusted))
60 {
61 DEBUGF("ERROR %s: Can not set volume.", __func__);
62 }
63}
diff --git a/firmware/target/hosted/ibasso/dx90/button-dx90.c b/firmware/target/hosted/ibasso/dx90/button-dx90.c
new file mode 100644
index 0000000000..27e4be0c1e
--- /dev/null
+++ b/firmware/target/hosted/ibasso/dx90/button-dx90.c
@@ -0,0 +1,104 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include "config.h"
26#include "button.h"
27
28#include "button-ibasso.h"
29
30
31int handle_button_event(__u16 code, __s32 value, int last_btns)
32{
33 int button = BUTTON_NONE;
34
35 switch(code)
36 {
37 case EVENT_CODE_BUTTON_PWR:
38 {
39 button = BUTTON_POWER;
40 break;
41 }
42
43 case EVENT_CODE_BUTTON_PWR_LONG:
44 {
45 button = BUTTON_POWER_LONG;
46 break;
47 }
48
49 case EVENT_CODE_BUTTON_VOLPLUS:
50 {
51 button = BUTTON_VOL_UP;
52 break;
53 }
54
55 case EVENT_CODE_BUTTON_VOLMINUS:
56 {
57 button = BUTTON_VOL_DOWN;
58 break;
59 }
60
61 case EVENT_CODE_BUTTON_REV:
62 {
63 button = BUTTON_LEFT;
64 break;
65 }
66
67 case EVENT_CODE_BUTTON_PLAY:
68 {
69 button = BUTTON_PLAY;
70 break;
71 }
72
73 case EVENT_CODE_BUTTON_NEXT:
74 {
75 button = BUTTON_RIGHT;
76 break;
77 }
78
79 default:
80 {
81 return BUTTON_NONE;
82 }
83 }
84
85 if( (button == BUTTON_RIGHT)
86 && ((last_btns & BUTTON_LEFT) == BUTTON_LEFT)
87 && (value == EVENT_VALUE_BUTTON_RELEASE))
88 {
89 /* Workaround for a wrong feedback, only present with DX90. */
90 button = BUTTON_LEFT;
91 }
92
93 int buttons = last_btns;
94 if(value == EVENT_VALUE_BUTTON_PRESS)
95 {
96 buttons = (last_btns | button);
97 }
98 else
99 {
100 buttons = (last_btns & (~button));
101 }
102
103 return buttons;
104}
diff --git a/firmware/target/hosted/ibasso/dx90/codec-dx90.h b/firmware/target/hosted/ibasso/dx90/codec-dx90.h
new file mode 100644
index 0000000000..b96377dfec
--- /dev/null
+++ b/firmware/target/hosted/ibasso/dx90/codec-dx90.h
@@ -0,0 +1,35 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef _CODEC_DX90_H_
26#define _CODEC_DX90_H_
27
28
29#define AUDIOHW_CAPS MONO_VOL_CAP
30
31
32AUDIOHW_SETTING(VOLUME, "", 0, 1, -255, 0, -128)
33
34
35#endif
diff --git a/firmware/target/hosted/ibasso/hostfs-ibasso.c b/firmware/target/hosted/ibasso/hostfs-ibasso.c
new file mode 100644
index 0000000000..3970d06987
--- /dev/null
+++ b/firmware/target/hosted/ibasso/hostfs-ibasso.c
@@ -0,0 +1,47 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <unistd.h>
26
27#include "debug-ibasso.h"
28
29
30/* See hostfs.h. */
31
32
33int hostfs_init(void)
34{
35 TRACE;
36
37 return 0;
38}
39
40
41int hostfs_flush(void)
42{
43 TRACE;
44
45 sync();
46 return 0;
47}
diff --git a/firmware/target/hosted/ibasso/lcd-ibasso.c b/firmware/target/hosted/ibasso/lcd-ibasso.c
new file mode 100644
index 0000000000..4e03ba7e50
--- /dev/null
+++ b/firmware/target/hosted/ibasso/lcd-ibasso.c
@@ -0,0 +1,195 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <errno.h>
26#include <fcntl.h>
27#include <stdbool.h>
28#include <stdlib.h>
29#include <linux/fb.h>
30#include <sys/ioctl.h>
31#include <sys/mman.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34
35#include "config.h"
36#include "debug.h"
37#include "events.h"
38#include "panic.h"
39
40#include "debug-ibasso.h"
41#include "lcd-target.h"
42#include "sysfs-ibasso.h"
43
44
45fb_data *dev_fb = 0;
46
47
48/* Framebuffer device handle. */
49static int dev_fd = 0;
50
51
52void lcd_init_device(void)
53{
54 TRACE;
55
56 dev_fd = open("/dev/graphics/fb0", O_RDWR);
57 if(dev_fd == -1)
58 {
59 DEBUGF("ERROR %s: open failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
60 exit(errno);
61 }
62
63 /* Get the changeable information. */
64 struct fb_var_screeninfo vinfo;
65 if(ioctl(dev_fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
66 {
67 DEBUGF("ERROR %s: ioctl FBIOGET_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
68 exit(errno);
69 }
70
71 DEBUGF("DEBUG %s: bits_per_pixel: %u, width: %u, height: %u.", __func__, vinfo.bits_per_pixel, vinfo.width, vinfo.height);
72
73 /*
74 Framebuffer does not fit the screen, a bug of iBassos Firmware, not Rockbox.
75 Cannot be solved with parameters.
76 */
77 /*vinfo.bits_per_pixel = LCD_DEPTH;
78 vinfo.xres = LCD_WIDTH;
79 vinfo.xres_virtual = LCD_WIDTH;
80 vinfo.width = LCD_WIDTH;
81 vinfo.yres = LCD_HEIGHT;
82 vinfo.yres_virtual = LCD_HEIGHT;
83 vinfo.height = LCD_HEIGHT;
84 vinfo.activate = FB_ACTIVATE_NOW;
85 if(ioctl(dev_fd, FBIOPUT_VSCREENINFO, &vinfo) == -1)
86 {
87 DEBUGF("ERROR %s: ioctl FBIOPUT_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
88 exit(EXIT_FAILURE);
89 }*/
90
91
92 /* Sanity check: Does framebuffer config match Rockbox config? */
93 size_t screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
94 if(screensize != FRAMEBUFFER_SIZE)
95 {
96 DEBUGF("ERROR %s: Screen size does not match config: %d != %d.", __func__, screensize, FRAMEBUFFER_SIZE);
97 exit(EXIT_FAILURE);
98 }
99
100 /* Map the device to memory. */
101 dev_fb = mmap(0, FRAMEBUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
102 if(dev_fb == MAP_FAILED)
103 {
104 DEBUGF("ERROR %s: mmap failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
105 exit(errno);
106 }
107
108 /* Activate Rockbox LCD. */
109 lcd_enable(true);
110}
111
112
113void lcd_shutdown(void)
114{
115 TRACE;
116
117 lcd_set_active(false);
118 munmap(dev_fb, FRAMEBUFFER_SIZE);
119 close(dev_fd) ;
120}
121
122
123/*
124 Left as reference. Unblanking does not work as expected, will not enable LCD after a few
125 seconds of power down.
126 Instead the backlight power is toggled.
127*/
128/*void lcd_power_on(void)
129{
130 TRACE;
131
132 if(ioctl(dev_fd, FBIOBLANK, VESA_NO_BLANKING) == -1)
133 {
134 DEBUGF("ERROR %s: ioctl FBIOBLANK failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
135 panicf("ERROR %s: ioctl FBIOBLANK failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
136 return;
137 }
138
139 lcd_set_active(true);
140 send_event(LCD_EVENT_ACTIVATION, NULL);
141}
142
143
144void lcd_power_off(void)
145{
146 TRACE;
147
148 lcd_set_active(false);
149
150 if(ioctl(dev_fd, FBIOBLANK, VESA_POWERDOWN) == -1)
151 {
152 DEBUGF("ERROR %s: ioctl FBIOBLANK failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
153 panicf("ERROR %s: ioctl FBIOBLANK failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
154 return;
155 }
156}*/
157
158
159void lcd_enable(bool on)
160{
161 TRACE;
162
163 lcd_set_active(on);
164
165 if(on)
166 {
167 /*
168 /sys/power/state
169 on: Cancel suspend.
170 */
171 if(! sysfs_set_string(SYSFS_POWER_STATE, "on"))
172 {
173 DEBUGF("ERROR %s: Can not set power state.", __func__);
174 }
175
176 send_event(LCD_EVENT_ACTIVATION, NULL);
177 }
178}
179
180
181void lcd_sleep(void)
182{
183 TRACE;
184
185 /*
186 See system_init(). Without suspend blocker und mute prevention this will interrupt playback.
187 Essentially, we are turning off the touch screen.
188 /sys/power/state
189 mem: Suspend to RAM.
190 */
191 if(! sysfs_set_string(SYSFS_POWER_STATE, "mem"))
192 {
193 DEBUGF("ERROR %s: Can not set power state.", __func__);
194 }
195}
diff --git a/firmware/target/hosted/ibasso/lcd-target.h b/firmware/target/hosted/ibasso/lcd-target.h
new file mode 100644
index 0000000000..50cc92599d
--- /dev/null
+++ b/firmware/target/hosted/ibasso/lcd-target.h
@@ -0,0 +1,44 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef __LCD_TARGET_H__
26#define __LCD_TARGET_H__
27
28
29#include "lcd.h"
30
31
32/*
33 Framebuffer device and framebuffer access.
34 See lcd-memframe.c
35*/
36extern fb_data *dev_fb;
37#define LCD_FRAMEBUF_ADDR(col, row) (dev_fb + row * LCD_WIDTH + col)
38
39
40/* See lcd-memframe.c */
41extern void lcd_set_active(bool active);
42
43
44#endif
diff --git a/firmware/target/hosted/ibasso/pcm-ibasso.c b/firmware/target/hosted/ibasso/pcm-ibasso.c
new file mode 100644
index 0000000000..14ef298af0
--- /dev/null
+++ b/firmware/target/hosted/ibasso/pcm-ibasso.c
@@ -0,0 +1,488 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <pthread.h>
26#include <stdbool.h>
27#include <unistd.h>
28
29#include "config.h"
30#include "debug.h"
31#include "panic.h"
32#include "pcm.h"
33#include "pcm-internal.h"
34
35#include "sound/asound.h"
36#include "tinyalsa/asoundlib.h"
37
38#include "debug-ibasso.h"
39#include "sysfs-ibasso.h"
40
41
42/* Tiny alsa handle. */
43static struct pcm* _alsa_handle = NULL;
44
45
46/* Bytes left in the Rockbox PCM frame buffer. */
47static size_t _pcm_buffer_size = 0;
48
49
50/* Rockbox PCM frame buffer. */
51static const void *_pcm_buffer = NULL;
52
53
54/*
55 1: PCM thread suspended.
56 0: PCM thread running.
57 These are used by pcm_play_[lock|unlock] or pcm_play_dma_[start|stop|pause]. These need to be
58 separated because of nested calls for locking and stopping.
59*/
60static volatile sig_atomic_t _dma_stopped = 1;
61static volatile sig_atomic_t _dma_locked = 1;
62
63
64/* Mutex for PCM thread suspend/unsuspend. */
65static pthread_mutex_t _dma_suspended_mtx = PTHREAD_MUTEX_INITIALIZER;
66
67
68/* Signal condition for PCM thread suspend/unsuspend. */
69static pthread_cond_t _dma_suspended_cond = PTHREAD_COND_INITIALIZER;
70
71
72static void* pcm_thread_run(void* nothing)
73{
74 (void) nothing;
75
76 DEBUGF("DEBUG %s: Thread start.", __func__);
77
78 while(true)
79 {
80 pthread_mutex_lock(&_dma_suspended_mtx);
81 while((_dma_stopped == 1) || (_dma_locked == 1))
82 {
83 DEBUGF("DEBUG %s: Playback suspended.", __func__);
84 pthread_cond_wait(&_dma_suspended_cond, &_dma_suspended_mtx);
85 DEBUGF("DEBUG %s: Playback resumed.", __func__);
86 }
87 pthread_mutex_unlock(&_dma_suspended_mtx);
88
89 if(_pcm_buffer_size == 0)
90 {
91 /* Retrive a new PCM buffer from Rockbox. */
92 if(! pcm_play_dma_complete_callback(PCM_DMAST_OK, &_pcm_buffer, &_pcm_buffer_size))
93 {
94 DEBUGF("DEBUG %s: No new buffer.", __func__);
95
96 usleep( 10000 );
97 continue;
98 }
99 }
100 pcm_play_dma_status_callback(PCM_DMAST_STARTED);
101
102 /* This relies on Rockbox PCM frame buffer size == ALSA PCM frame buffer size. */
103 if(pcm_write(_alsa_handle, _pcm_buffer, _pcm_buffer_size) != 0)
104 {
105 DEBUGF("ERROR %s: pcm_write failed: %s.", __func__, pcm_get_error(_alsa_handle));
106
107 usleep( 10000 );
108 continue;
109 }
110
111 _pcm_buffer_size = 0;
112
113 /*DEBUGF("DEBUG %s: Thread running.", __func__);*/
114 }
115
116 DEBUGF("DEBUG %s: Thread end.", __func__);
117
118 return 0;
119}
120
121
122#ifdef DEBUG
123
124/* https://github.com/tinyalsa/tinyalsa/blob/master/tinypcminfo.c */
125
126static const char* format_lookup[] =
127{
128 /*[0] =*/ "S8",
129 "U8",
130 "S16_LE",
131 "S16_BE",
132 "U16_LE",
133 "U16_BE",
134 "S24_LE",
135 "S24_BE",
136 "U24_LE",
137 "U24_BE",
138 "S32_LE",
139 "S32_BE",
140 "U32_LE",
141 "U32_BE",
142 "FLOAT_LE",
143 "FLOAT_BE",
144 "FLOAT64_LE",
145 "FLOAT64_BE",
146 "IEC958_SUBFRAME_LE",
147 "IEC958_SUBFRAME_BE",
148 "MU_LAW",
149 "A_LAW",
150 "IMA_ADPCM",
151 "MPEG",
152 /*[24] =*/ "GSM",
153 [31] = "SPECIAL",
154 "S24_3LE",
155 "S24_3BE",
156 "U24_3LE",
157 "U24_3BE",
158 "S20_3LE",
159 "S20_3BE",
160 "U20_3LE",
161 "U20_3BE",
162 "S18_3LE",
163 "S18_3BE",
164 "U18_3LE",
165 /*[43] =*/ "U18_3BE"
166};
167
168
169static const char* pcm_get_format_name(unsigned int bit_index)
170{
171 return(bit_index < 43 ? format_lookup[bit_index] : NULL);
172}
173
174#endif
175
176
177/* Thread that copies the Rockbox PCM buffer to ALSA. */
178static pthread_t _pcm_thread;
179
180
181/* ALSA card and device. */
182static const unsigned int CARD = 0;
183static const unsigned int DEVICE = 0;
184
185
186/* ALSA config. */
187static struct pcm_config _config;
188
189
190void pcm_play_dma_init(void)
191{
192 TRACE;
193
194#ifdef DEBUG
195
196 /*
197 DEBUG pcm_play_dma_init: Access: 0x000009
198 DEBUG pcm_play_dma_init: Format[0]: 0x000044
199 DEBUG pcm_play_dma_init: Format[1]: 0x000010
200 DEBUG pcm_play_dma_init: Format: S16_LE
201 DEBUG pcm_play_dma_init: Format: S24_LE
202 DEBUG pcm_play_dma_init: Format: S20_3LE
203 DEBUG pcm_play_dma_init: Subformat: 0x000001
204 DEBUG pcm_play_dma_init: Rate: min = 8000Hz, max = 192000Hz
205 DEBUG pcm_play_dma_init: Channels: min = 2, max = 2
206 DEBUG pcm_play_dma_init: Sample bits: min=16, max=32
207 DEBUG pcm_play_dma_init: Period size: min=8, max=10922
208 DEBUG pcm_play_dma_init: Period count: min=3, max=128
209 DEBUG pcm_play_dma_init: 0 mixer controls.
210 */
211
212 struct pcm_params* params = pcm_params_get(CARD, DEVICE, PCM_OUT);
213 if(params == NULL)
214 {
215 DEBUGF("ERROR %s: Card/device does not exist.", __func__);
216 panicf("ERROR %s: Card/device does not exist.", __func__);
217 return;
218 }
219
220 struct pcm_mask* m = pcm_params_get_mask(params, PCM_PARAM_ACCESS);
221 if(m)
222 {
223 DEBUGF("DEBUG %s: Access: %#08x", __func__, m->bits[0]);
224 }
225
226 m = pcm_params_get_mask(params, PCM_PARAM_FORMAT);
227 if(m)
228 {
229 DEBUGF("DEBUG %s: Format[0]: %#08x", __func__, m->bits[0]);
230 DEBUGF("DEBUG %s: Format[1]: %#08x", __func__, m->bits[1]);
231
232 unsigned int j;
233 unsigned int k;
234 const unsigned int bitcount = sizeof(m->bits[0]) * 8;
235 for(k = 0; k < 2; ++k)
236 {
237 for(j = 0; j < bitcount; ++j)
238 {
239 const char* name;
240 if(m->bits[k] & (1 << j))
241 {
242 name = pcm_get_format_name(j + (k * bitcount));
243 if(name)
244 {
245 DEBUGF("DEBUG %s: Format: %s", __func__, name);
246 }
247 }
248 }
249 }
250 }
251
252 m = pcm_params_get_mask(params, PCM_PARAM_SUBFORMAT);
253 if(m)
254 {
255 DEBUGF("DEBUG %s: Subformat: %#08x", __func__, m->bits[0]);
256 }
257
258 unsigned int min = pcm_params_get_min(params, PCM_PARAM_RATE);
259 unsigned int max = pcm_params_get_max(params, PCM_PARAM_RATE) ;
260 DEBUGF("DEBUG %s: Rate: min = %uHz, max = %uHz", __func__, min, max);
261
262 min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
263 max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
264 DEBUGF("DEBUG %s: Channels: min = %u, max = %u", __func__, min, max);
265
266 min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
267 max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
268 DEBUGF("DEBUG %s: Sample bits: min=%u, max=%u", __func__, min, max);
269
270 min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
271 max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
272 DEBUGF("DEBUG %s: Period size: min=%u, max=%u", __func__, min, max);
273
274 min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
275 max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
276 DEBUGF("DEBUG %s: Period count: min=%u, max=%u", __func__, min, max);
277
278 pcm_params_free(params);
279
280 struct mixer* mixer = mixer_open(CARD);
281 if(! mixer)
282 {
283 DEBUGF("ERROR %s: Failed to open mixer.", __func__);
284 }
285 else
286 {
287 int num_ctls = mixer_get_num_ctls(mixer);
288
289 DEBUGF("DEBUG %s: %d mixer controls.", __func__, num_ctls);
290
291 mixer_close(mixer);
292 }
293
294#endif
295
296 if(_alsa_handle != NULL)
297 {
298 DEBUGF("ERROR %s: Allready initialized.", __func__);
299 panicf("ERROR %s: Allready initialized.", __func__);
300 return;
301 }
302
303 /*
304 Rockbox outputs 16 Bit/44.1kHz stereo by default.
305
306 ALSA frame buffer size = config.period_count * config.period_size * config.channels * (16 \ 8)
307 = 4 * 256 * 2 * 2
308 = 4096
309 = Rockbox PCM buffer size
310 pcm_thread_run relies on this size match. See pcm_mixer.h.
311 */
312 _config.channels = 2;
313 _config.rate = 44100;
314 _config.period_size = 256;
315 _config.period_count = 4;
316 _config.format = PCM_FORMAT_S16_LE;
317 _config.start_threshold = 0;
318 _config.stop_threshold = 0;
319 _config.silence_threshold = 0;
320
321 _alsa_handle = pcm_open(CARD, DEVICE, PCM_OUT, &_config);
322 if(! pcm_is_ready(_alsa_handle))
323 {
324 DEBUGF("ERROR %s: pcm_open failed: %s.", __func__, pcm_get_error(_alsa_handle));
325 panicf("ERROR %s: pcm_open failed: %s.", __func__, pcm_get_error(_alsa_handle));
326 return;
327 }
328
329 DEBUGF("DEBUG %s: ALSA PCM frame buffer size: %d.", __func__, pcm_frames_to_bytes(_alsa_handle, pcm_get_buffer_size(_alsa_handle)));
330
331 /* Create pcm thread in the suspended state. */
332 pthread_mutex_lock(&_dma_suspended_mtx);
333 _dma_stopped = 1;
334 _dma_locked = 1;
335 pthread_create(&_pcm_thread, NULL, pcm_thread_run, NULL);
336 pthread_mutex_unlock(&_dma_suspended_mtx);
337}
338
339
340void pcm_play_dma_start(const void *addr, size_t size)
341{
342 TRACE;
343
344 /*
345 DX50
346 /sys/class/codec/mute
347 Mute: echo 'A' > /sys/class/codec/mute
348 Unmute: echo 'B' > /sys/class/codec/mute
349
350 DX90?
351 */
352 if(! sysfs_set_char(SYSFS_MUTE, 'B'))
353 {
354 DEBUGF("ERROR %s: Could not unmute.", __func__);
355 panicf("ERROR %s: Could not unmute.", __func__);
356 }
357
358 _pcm_buffer = addr;
359 _pcm_buffer_size = size;
360
361 pthread_mutex_lock(&_dma_suspended_mtx);
362 _dma_stopped = 0;
363 pthread_cond_signal(&_dma_suspended_cond);
364 pthread_mutex_unlock(&_dma_suspended_mtx);
365}
366
367
368/* TODO: Why is this in the API if it gets never called? */
369void pcm_play_dma_pause(bool pause)
370{
371 TRACE;
372
373 pthread_mutex_lock(&_dma_suspended_mtx);
374 _dma_stopped = pause ? 1 : 0;
375 if(_dma_stopped == 0)
376 {
377 pthread_cond_signal(&_dma_suspended_cond);
378 }
379 pthread_mutex_unlock(&_dma_suspended_mtx);
380}
381
382
383void pcm_play_dma_stop(void)
384{
385 TRACE;
386
387 pthread_mutex_lock(&_dma_suspended_mtx);
388 _dma_stopped = 1;
389 pcm_stop(_alsa_handle);
390 pthread_mutex_unlock(&_dma_suspended_mtx);
391}
392
393
394/* Unessecary play locks before pcm_play_dma_postinit. */
395static int _play_lock_recursion_count = -10000;
396
397
398void pcm_play_dma_postinit(void)
399{
400 TRACE;
401
402 _play_lock_recursion_count = 0;
403}
404
405
406void pcm_play_lock(void)
407{
408 TRACE;
409
410 ++_play_lock_recursion_count;
411
412 if(_play_lock_recursion_count == 1)
413 {
414 pthread_mutex_lock(&_dma_suspended_mtx);
415 _dma_locked = 1;
416 pthread_mutex_unlock(&_dma_suspended_mtx);
417 }
418}
419
420
421void pcm_play_unlock(void)
422{
423 TRACE;
424
425 --_play_lock_recursion_count;
426
427 if(_play_lock_recursion_count == 0)
428 {
429 pthread_mutex_lock(&_dma_suspended_mtx);
430 _dma_locked = 0;
431 pthread_cond_signal(&_dma_suspended_cond);
432 pthread_mutex_unlock(&_dma_suspended_mtx);
433 }
434}
435
436
437void pcm_dma_apply_settings(void)
438{
439 unsigned int rate = pcm_get_frequency();
440
441 DEBUGF("DEBUG %s: Current sample rate: %u, next sampe rate: %u.", __func__, _config.rate, rate);
442
443 if(( _config.rate != rate) && (rate >= 8000) && (rate <= 192000))
444 {
445 _config.rate = rate;
446
447 pcm_close(_alsa_handle);
448 _alsa_handle = pcm_open(CARD, DEVICE, PCM_OUT, &_config);
449
450 if(! pcm_is_ready(_alsa_handle))
451 {
452 DEBUGF("ERROR %s: pcm_open failed: %s.", __func__, pcm_get_error(_alsa_handle));
453 panicf("ERROR %s: pcm_open failed: %s.", __func__, pcm_get_error(_alsa_handle));
454 }
455 }
456}
457
458
459size_t pcm_get_bytes_waiting(void)
460{
461 TRACE;
462
463 return _pcm_buffer_size;
464}
465
466
467/* TODO: WTF */
468const void* pcm_play_dma_get_peak_buffer(int* count)
469{
470 TRACE;
471
472 uintptr_t addr = (uintptr_t) _pcm_buffer;
473 *count = _pcm_buffer_size / 4;
474 return (void*) ((addr + 3) & ~3);
475}
476
477
478void pcm_close_device(void)
479{
480 TRACE;
481
482 pthread_mutex_lock(&_dma_suspended_mtx);
483 _dma_stopped = 1;
484 pthread_mutex_unlock(&_dma_suspended_mtx);
485
486 pcm_close(_alsa_handle);
487 _alsa_handle = NULL;
488}
diff --git a/firmware/target/hosted/ibasso/pcm-ibasso.h b/firmware/target/hosted/ibasso/pcm-ibasso.h
new file mode 100644
index 0000000000..588c4dfb9b
--- /dev/null
+++ b/firmware/target/hosted/ibasso/pcm-ibasso.h
@@ -0,0 +1,33 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef __PCM_IBASSO_H__
26#define __PCM_IBASSO_H__
27
28
29/* Clean up the audio device handler. */
30void pcm_close_device(void);
31
32
33#endif
diff --git a/firmware/target/hosted/ibasso/power-ibasso.c b/firmware/target/hosted/ibasso/power-ibasso.c
new file mode 100644
index 0000000000..8257de5f33
--- /dev/null
+++ b/firmware/target/hosted/ibasso/power-ibasso.c
@@ -0,0 +1,97 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <stdbool.h>
26#include <stdlib.h>
27#include <sys/reboot.h>
28
29#include "config.h"
30#include "debug.h"
31#include "power.h"
32
33#include "button-ibasso.h"
34#include "debug-ibasso.h"
35#include "pcm-ibasso.h"
36#include "sysfs-ibasso.h"
37#include "vold-ibasso.h"
38
39
40unsigned int power_input_status(void)
41{
42 /*TRACE;*/
43
44 /*
45 /sys/class/power_supply/usb/present
46 0: No external power supply connected.
47 1: External power supply connected.
48 */
49 int val = 0;
50 if(! sysfs_get_int(SYSFS_USB_POWER_PRESENT, &val))
51 {
52 DEBUGF("ERROR %s: Can not get power supply status.", __func__);
53 return POWER_INPUT_NONE;
54 }
55
56 return val ? POWER_INPUT_USB_CHARGER : POWER_INPUT_NONE;
57}
58
59
60void power_off(void)
61{
62 TRACE;
63
64 button_close_device();
65
66 if(vold_monitor_forced_close_imminent())
67 {
68 /*
69 We are here, because Android Vold is going to kill Rockbox. Instead of powering off,
70 we exit into the loader.
71 */
72 DEBUGF("DEBUG %s: Exit Rockbox.", __func__);
73 exit(42);
74 }
75
76 reboot(RB_POWER_OFF);
77}
78
79
80/* Returns true, if battery is charging, false else. */
81bool charging_state(void)
82{
83 /*TRACE;*/
84
85 /*
86 /sys/class/power_supply/battery/status
87 "Full", "Charging", "Discharging"
88 */
89 char state[9];
90 if(! sysfs_get_string(SYSFS_BATTERY_STATUS, state, 9))
91 {
92 DEBUGF("ERROR %s: Can not get battery charging state.", __func__);
93 return false;
94 }
95
96 return(strcmp(state, "Charging") == 0);;
97}
diff --git a/firmware/target/hosted/ibasso/powermgmt-ibasso.c b/firmware/target/hosted/ibasso/powermgmt-ibasso.c
new file mode 100644
index 0000000000..7df0064097
--- /dev/null
+++ b/firmware/target/hosted/ibasso/powermgmt-ibasso.c
@@ -0,0 +1,122 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <stdio.h>
26
27#include "config.h"
28#include "debug.h"
29#include "panic.h"
30
31#include "debug-ibasso.h"
32#include "sysfs-ibasso.h"
33
34
35/* Based on batterymonitor with PISEN and Samsung SIII battery. */
36
37
38const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
39{
40 3600
41};
42
43
44const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
45{
46 3500
47};
48
49
50/*
51 Averages at percent of running time from five measuremnts with PISEN and Samsung SIII battery
52 during normal usage.
53
54 Mongo default values (?)
55 < 3660 (0%), < 3730 (1% - 10%), < 3780 (11% - 20%), < 3830 (21% - 40%), < 3950 (41% - 60%),
56 < 4080 (61% - 80%), > 4081 (81% - 100%)
57*/
58const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
59{
60 { 3522, 3660, 3720, 3752, 3784, 3827, 3896, 3978, 4072, 4168, 4255 }
61};
62
63
64/* Copied from percent_to_volt_discharge. */
65const unsigned short percent_to_volt_charge[11] =
66{
67 3500, 3544, 3578, 3623, 3660, 3773, 3782, 3853, 3980, 4130, 4360
68};
69
70
71static int _battery_present = -1;
72
73
74int _battery_voltage(void)
75{
76 /*TRACE;*/
77
78 if( (_battery_present == -1)
79 && (! sysfs_get_int(SYSFS_BATTERY_PRESENT, &_battery_present)))
80 {
81 /* This check is only done once at startup. */
82
83 DEBUGF("ERROR %s: Can not get current battery availabilty.", __func__);
84 _battery_present = 1;
85 }
86
87 int val;
88
89 if(_battery_present == 1)
90 {
91 /* Battery is present. */
92
93 /*
94 /sys/class/power_supply/battery/voltage_now
95 Voltage in microvolt.
96 */
97 if(! sysfs_get_int(SYSFS_BATTERY_VOLTAGE_NOW, &val))
98 {
99 DEBUGF("ERROR %s: Can not get current battery voltage.", __func__);
100 return 0;
101 }
102 }
103 else
104 {
105 /*
106 No battery, so we have to be running solely from USB power.
107 This will prevent Rockbox from forcing shutdown due to low power.
108 */
109
110 /*
111 /sys/class/power_supply/usb/voltage_now
112 Voltage in microvolt.
113 */
114 if(! sysfs_get_int(SYSFS_USB_POWER_VOLTAGE_NOW, &val))
115 {
116 DEBUGF("ERROR %s: Can not get current USB voltage.", __func__);
117 return 0;
118 }
119 }
120
121 return(val / 1000);
122}
diff --git a/firmware/target/hosted/ibasso/sysfs-ibasso.c b/firmware/target/hosted/ibasso/sysfs-ibasso.c
new file mode 100644
index 0000000000..8ca3edf387
--- /dev/null
+++ b/firmware/target/hosted/ibasso/sysfs-ibasso.c
@@ -0,0 +1,404 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <stdio.h>
26#include <string.h>
27
28#include "config.h"
29#include "debug.h"
30
31#include "debug-ibasso.h"
32#include "sysfs-ibasso.h"
33
34
35static const char* SYSFS_PATHS[] =
36{
37 /* SYSFS_DX50_CODEC_VOLUME */
38 "/dev/codec_volume",
39
40 /* SYSFS_HOLDKEY */
41 "/sys/class/axppower/holdkey",
42
43 /* SYSFS_DX90_ES9018_VOLUME */
44 "/sys/class/codec/es9018_volume",
45
46 /* SYSFS_MUTE */
47 "/sys/class/codec/mute",
48
49 /* SYSFS_WM8740_MUTE */
50 "/sys/class/codec/wm8740_mute",
51
52 /* SYSFS_BATTERY_CAPACITY */
53 "/sys/class/power_supply/battery/capacity",
54
55 /* SYSFS_BATTERY_CURRENT_NOW */
56 "/sys/class/power_supply/battery/current_now",
57
58 /* SYSFS_BATTERY_ENERGY_FULL_DESIGN */
59 "/sys/class/power_supply/battery/energy_full_design",
60
61 /* SYSFS_BATTERY_HEALTH */
62 "/sys/class/power_supply/battery/health",
63
64 /* SYSFS_BATTERY_MODEL_NAME */
65 "/sys/class/power_supply/battery/model_name",
66
67 /* SYSFS_BATTERY_ONLINE */
68 "/sys/class/power_supply/battery/online",
69
70 /* SYSFS_BATTERY_PRESENT */
71 "/sys/class/power_supply/battery/present",
72
73 /* SYSFS_BATTERY_STATUS */
74 "/sys/class/power_supply/battery/status",
75
76 /* SYSFS_BATTERY_TECHNOLOGY */
77 "/sys/class/power_supply/battery/technology",
78
79 /* SYSFS_BATTERY_TEMP */
80 "/sys/class/power_supply/battery/temp",
81
82 /* SYSFS_BATTERY_TYPE */
83 "/sys/class/power_supply/battery/type",
84
85 /* SYSFS_BATTERY_VOLTAGE_MAX_DESIGN */
86 "/sys/class/power_supply/battery/voltage_max_design",
87
88 /* SYSFS_BATTERY_VOLTAGE_MIN_DESIGN */
89 "/sys/class/power_supply/battery/voltage_min_design",
90
91 /* SYSFS_BATTERY_VOLTAGE_NOW */
92 "/sys/class/power_supply/battery/voltage_now",
93
94 /* SYSFS_USB_POWER_CURRENT_NOW */
95 "/sys/class/power_supply/usb/current_now",
96
97 /* SYSFS_USB_POWER_ONLINE */
98 "/sys/class/power_supply/usb/online",
99
100 /* SYSFS_USB_POWER_PRESENT */
101 "/sys/class/power_supply/usb/present",
102
103 /* SYSFS_USB_POWER_VOLTAGE_NOW */
104 "/sys/class/power_supply/usb/voltage_now",
105
106 /* SYSFS_BACKLIGHT_POWER */
107 "/sys/devices/platform/rk29_backlight/backlight/rk28_bl/bl_power",
108
109 /* SYSFS_BACKLIGHT_BRIGHTNESS */
110 "/sys/devices/platform/rk29_backlight/backlight/rk28_bl/brightness",
111
112 /* SYSFS_POWER_STATE */
113 "/sys/power/state",
114
115 /* SYSFS_POWER_WAKE_LOCK */
116 "/sys/power/wake_lock"
117};
118
119
120static FILE* open_read(const char* file_name)
121{
122 FILE *f = fopen(file_name, "r");
123 if(f == NULL)
124 {
125 DEBUGF("ERROR %s: Can not open %s for reading.", __func__, file_name);
126 }
127
128 return f;
129}
130
131
132static FILE* open_write(const char* file_name)
133{
134 FILE *f = fopen(file_name, "w");
135 if(f == NULL)
136 {
137 DEBUGF("ERROR %s: Can not open %s for writing.", __func__, file_name);
138 }
139
140 return f;
141}
142
143
144bool sysfs_get_int(enum sys_fs_interface_id id, int* value)
145{
146 *value = -1;
147
148 switch(id)
149 {
150 case SYSFS_BATTERY_CAPACITY:
151 case SYSFS_BATTERY_CURRENT_NOW:
152 case SYSFS_BATTERY_ENERGY_FULL_DESIGN:
153 case SYSFS_BATTERY_ONLINE:
154 case SYSFS_BATTERY_PRESENT:
155 case SYSFS_BATTERY_TEMP:
156 case SYSFS_BATTERY_VOLTAGE_MAX_DESIGN:
157 case SYSFS_BATTERY_VOLTAGE_MIN_DESIGN:
158 case SYSFS_BATTERY_VOLTAGE_NOW:
159 case SYSFS_USB_POWER_CURRENT_NOW:
160 case SYSFS_USB_POWER_VOLTAGE_NOW:
161 case SYSFS_USB_POWER_ONLINE:
162 case SYSFS_USB_POWER_PRESENT:
163 {
164 break;
165 }
166
167 default:
168 {
169 DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id);
170 return false;
171 }
172 }
173
174 const char* interface = SYSFS_PATHS[id];
175
176 /*DEBUGF("%s: interface: %s.", __func__, interface);*/
177
178 FILE *f = open_read(interface);
179 if(f == NULL)
180 {
181 return false;
182 }
183
184 bool success = true;
185 if(fscanf(f, "%d", value) == EOF)
186 {
187 DEBUGF("ERROR %s: Read failed for %s.", __func__, interface);
188 success = false;
189 }
190
191 fclose(f);
192 return success;
193}
194
195
196bool sysfs_set_int(enum sys_fs_interface_id id, int value)
197{
198 switch(id)
199 {
200 case SYSFS_BACKLIGHT_POWER:
201 case SYSFS_BACKLIGHT_BRIGHTNESS:
202 case SYSFS_DX50_CODEC_VOLUME:
203 case SYSFS_DX90_ES9018_VOLUME:
204 {
205 break;
206 }
207
208 default:
209 {
210 DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id);
211 return false;
212 }
213 }
214
215 const char* interface = SYSFS_PATHS[id];
216
217 /*DEBUGF("%s: interface: %s, value: %d.", __func__, interface, value);*/
218
219 FILE *f = open_write(interface);
220 if(f == NULL)
221 {
222 return false;
223 }
224
225 bool success = true;
226 if(fprintf(f, "%d", value) < 1)
227 {
228 DEBUGF("ERROR %s: Write failed for %s.", __func__, interface);
229 success = false;
230 }
231
232 fclose(f);
233 return success;
234}
235
236
237bool sysfs_get_char(enum sys_fs_interface_id id, char* value)
238{
239 *value = '\0';
240
241 switch(id)
242 {
243 case SYSFS_HOLDKEY:
244 {
245 break;
246 }
247
248 default:
249 {
250 DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id);
251 return false;
252 }
253 }
254
255 const char* interface = SYSFS_PATHS[id];
256
257 /*DEBUGF("%s: interface: %s.", __func__, interface);*/
258
259 FILE *f = open_read(interface);
260 if(f == NULL)
261 {
262 return false;
263 }
264
265 bool success = true;
266 if(fscanf(f, "%c", value) == EOF)
267 {
268 DEBUGF("ERROR %s: Read failed for %s.", __func__, interface);
269 success = false;
270 }
271
272 fclose(f);
273 return success;
274}
275
276
277bool sysfs_set_char(enum sys_fs_interface_id id, char value)
278{
279 switch(id)
280 {
281 case SYSFS_MUTE:
282 case SYSFS_WM8740_MUTE:
283 {
284 break;
285 }
286
287 default:
288 {
289 DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id);
290 return false;
291 }
292 }
293
294 const char* interface = SYSFS_PATHS[id];
295
296 /*DEBUGF("%s: interface: %s, value: %c.", __func__, interface, value);*/
297
298 FILE *f = open_write(interface);
299 if(f == NULL)
300 {
301 return false;
302 }
303
304 bool success = true;
305 if(fprintf(f, "%c", value) < 1)
306 {
307 DEBUGF("ERROR %s: Write failed for %s.", __func__, interface);
308 success = false;
309 }
310
311 fclose(f);
312 return success;
313}
314
315
316bool sysfs_get_string(enum sys_fs_interface_id id, char* value, int size)
317{
318 value[0] = '\0';
319
320 switch(id)
321 {
322 case SYSFS_BATTERY_STATUS:
323 case SYSFS_BATTERY_HEALTH:
324 case SYSFS_BATTERY_MODEL_NAME:
325 case SYSFS_BATTERY_TECHNOLOGY:
326 case SYSFS_BATTERY_TYPE:
327 {
328 break;
329 }
330
331 default:
332 {
333 DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id);
334 return false;
335 }
336 }
337
338 const char* interface = SYSFS_PATHS[id];
339
340 /*DEBUGF("%s: interface: %s, size: %d.", __func__, interface, size);*/
341
342 FILE *f = open_read(interface);
343 if(f == NULL)
344 {
345 return false;
346 }
347
348 bool success = true;
349 if(fgets(value, size, f) == NULL)
350 {
351 DEBUGF("ERROR %s: Read failed for %s.", __func__, interface);
352 success = false;
353 }
354 else
355 {
356 size_t length = strlen(value);
357 if((length > 0) && value[length - 1] == '\n')
358 {
359 value[length - 1] = '\0';
360 }
361 }
362
363 fclose(f);
364 return success;
365}
366
367
368bool sysfs_set_string(enum sys_fs_interface_id id, char* value)
369{
370 switch(id)
371 {
372 case SYSFS_POWER_STATE:
373 case SYSFS_POWER_WAKE_LOCK:
374 {
375 break;
376 }
377
378 default:
379 {
380 DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id);
381 return false;
382 }
383 }
384
385 const char* interface = SYSFS_PATHS[id];
386
387 /*DEBUGF("%s: interface: %s, value: %s.", __func__, interface, value);*/
388
389 FILE *f = open_write(interface);
390 if(f == NULL)
391 {
392 return false;
393 }
394
395 bool success = true;
396 if(fprintf(f, "%s", value) < 1)
397 {
398 DEBUGF("ERROR %s: Write failed for %s.", __func__, interface);
399 success = false;
400 }
401
402 fclose(f);
403 return success;
404}
diff --git a/firmware/target/hosted/ibasso/sysfs-ibasso.h b/firmware/target/hosted/ibasso/sysfs-ibasso.h
new file mode 100644
index 0000000000..fec8a082f9
--- /dev/null
+++ b/firmware/target/hosted/ibasso/sysfs-ibasso.h
@@ -0,0 +1,111 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef _SYSFS_IBASSO_H_
26#define _SYSFS_IBASSO_H_
27
28
29#include <stdbool.h>
30
31
32/*
33 Sys FS path identifiers.
34 See SYSFS_PATHS in sysfs-ibasso.c.
35*/
36enum sys_fs_interface_id
37{
38 SYSFS_DX50_CODEC_VOLUME = 0,
39 SYSFS_HOLDKEY,
40 SYSFS_DX90_ES9018_VOLUME,
41 SYSFS_MUTE,
42 SYSFS_WM8740_MUTE,
43 SYSFS_BATTERY_CAPACITY,
44 SYSFS_BATTERY_CURRENT_NOW,
45 SYSFS_BATTERY_ENERGY_FULL_DESIGN,
46 SYSFS_BATTERY_HEALTH,
47 SYSFS_BATTERY_MODEL_NAME,
48 SYSFS_BATTERY_ONLINE,
49 SYSFS_BATTERY_PRESENT,
50 SYSFS_BATTERY_STATUS,
51 SYSFS_BATTERY_TECHNOLOGY,
52 SYSFS_BATTERY_TEMP,
53 SYSFS_BATTERY_TYPE,
54 SYSFS_BATTERY_VOLTAGE_MAX_DESIGN,
55 SYSFS_BATTERY_VOLTAGE_MIN_DESIGN,
56 SYSFS_BATTERY_VOLTAGE_NOW,
57 SYSFS_USB_POWER_CURRENT_NOW,
58 SYSFS_USB_POWER_ONLINE,
59 SYSFS_USB_POWER_PRESENT,
60 SYSFS_USB_POWER_VOLTAGE_NOW,
61 SYSFS_BACKLIGHT_POWER,
62 SYSFS_BACKLIGHT_BRIGHTNESS,
63 SYSFS_POWER_STATE,
64 SYSFS_POWER_WAKE_LOCK
65};
66
67
68/*
69 Read a integer value from the sys fs interface given by id.
70 Returns true on success, false else.
71*/
72bool sysfs_get_int(enum sys_fs_interface_id id, int* value);
73
74
75/*
76 Write a integer value to the sys fs interface given by id.
77 Returns true on success, false else.
78*/
79bool sysfs_set_int(enum sys_fs_interface_id id, int value);
80
81
82/*
83 Read a char value from the sys fs interface given by id.
84 Returns true on success, false else.
85*/
86bool sysfs_get_char(enum sys_fs_interface_id id, char* value);
87
88
89/*
90 Write a char value to the sys fs interface given by id.
91 Returns true on success, false else.
92*/
93bool sysfs_set_char(enum sys_fs_interface_id id, char value);
94
95/*
96 Read a single line of text from the sys fs interface given by id.
97 A newline will be discarded.
98 size: The size of value.
99 Returns true on success, false else.
100*/
101bool sysfs_get_string(enum sys_fs_interface_id id, char* value, int size);
102
103
104/*
105 Write text to the sys fs interface given by id.
106 Returns true on success, false else.
107*/
108bool sysfs_set_string(enum sys_fs_interface_id id, char* value);
109
110
111#endif
diff --git a/firmware/target/hosted/ibasso/system-ibasso.c b/firmware/target/hosted/ibasso/system-ibasso.c
new file mode 100644
index 0000000000..00f8669ae0
--- /dev/null
+++ b/firmware/target/hosted/ibasso/system-ibasso.c
@@ -0,0 +1,101 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <stdint.h>
26#include <stdlib.h>
27#include <sys/reboot.h>
28
29#include "config.h"
30#include "cpufreq-linux.h"
31#include "debug.h"
32
33#include "button-ibasso.h"
34#include "debug-ibasso.h"
35#include "sysfs-ibasso.h"
36#include "usb-ibasso.h"
37#include "vold-ibasso.h"
38
39
40/* Fake stack. */
41uintptr_t* stackbegin;
42uintptr_t* stackend;
43
44
45void system_init(void)
46{
47 TRACE;
48
49 /* Fake stack. */
50 volatile uintptr_t stack = 0;
51 stackbegin = stackend = (uintptr_t*) &stack;
52
53 cpufreq_set_governor("powersave", CPUFREQ_ALL_CPUS);
54 vold_monitor_start();
55 ibasso_set_usb_mode(USB_MODE_MASS_STORAGE);
56
57 /*
58 Prevent device from deep sleeping, which will interrupt playback.
59 /sys/power/wake_lock
60 */
61 if(! sysfs_set_string(SYSFS_POWER_WAKE_LOCK, "rockbox"))
62 {
63 DEBUGF("ERROR %s: Can not set suspend blocker.", __func__);
64 }
65
66 /*
67 Prevent device to mute, which will cause tinyalsa pcm_writes to fail.
68 /sys/class/codec/wm8740_mute
69 */
70 if(! sysfs_set_char(SYSFS_WM8740_MUTE, '0'))
71 {
72 DEBUGF("ERROR %s: Can not set WM8740 lock.", __func__);
73 }
74}
75
76
77void system_reboot(void)
78{
79 TRACE;
80
81 button_close_device();
82
83 if(vold_monitor_forced_close_imminent())
84 {
85 /*
86 We are here, because Android Vold is going to kill Rockbox. Instead of powering off,
87 we exit into the loader.
88 */
89 exit(42);
90 }
91
92 reboot(RB_AUTOBOOT);
93}
94
95
96void system_exception_wait(void)
97{
98 TRACE;
99
100 while(1) {};
101}
diff --git a/firmware/target/hosted/ibasso/system-target.h b/firmware/target/hosted/ibasso/system-target.h
new file mode 100644
index 0000000000..17b1238380
--- /dev/null
+++ b/firmware/target/hosted/ibasso/system-target.h
@@ -0,0 +1,33 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef __SYSTEM_TARGET_H__
26#define __SYSTEM_TARGET_H__
27
28
29#include "kernel-unix.h"
30#include "system-hosted.h"
31
32
33#endif
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}
diff --git a/firmware/target/hosted/ibasso/usb-ibasso.c b/firmware/target/hosted/ibasso/usb-ibasso.c
new file mode 100644
index 0000000000..e1b134e545
--- /dev/null
+++ b/firmware/target/hosted/ibasso/usb-ibasso.c
@@ -0,0 +1,92 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <stdlib.h>
26
27#include "config.h"
28#include "debug.h"
29
30#include "debug-ibasso.h"
31#include "usb-ibasso.h"
32
33
34static void usb_enable_adb(void)
35{
36 TRACE;
37
38 if(system(NULL))
39 {
40 system("setprop persist.sys.usb.config adb");
41 system("setprop persist.usb.debug 1");
42 return;
43 }
44
45 DEBUGF("ERROR %s: No command processor available.", __func__);
46}
47
48
49static void usb_enable_mass_storage(void)
50{
51 TRACE;
52
53 if(system(NULL))
54 {
55 system("setprop persist.sys.usb.config mass_storage");
56 system("setprop persist.usb.debug 0");
57 return;
58 }
59
60 DEBUGF("ERROR %s: No command processor available.", __func__);
61}
62
63
64/* Default at boot not known. */
65static int _last_usb_mode = -1;
66
67
68void ibasso_set_usb_mode(int mode)
69{
70 DEBUGF("DEBUG %s: _last_usb_mode: %d, mode: %d.", __func__, _last_usb_mode, mode);
71
72 if(_last_usb_mode != mode)
73 {
74 switch(mode)
75 {
76 case USB_MODE_MASS_STORAGE:
77 {
78 _last_usb_mode = mode;
79 usb_enable_mass_storage();
80 break;
81 }
82
83 case USB_MODE_CHARGE: /* Work around. */
84 case USB_MODE_ADB:
85 {
86 _last_usb_mode = mode;
87 usb_enable_adb();
88 break;
89 }
90 }
91 }
92}
diff --git a/firmware/target/hosted/ibasso/usb-ibasso.h b/firmware/target/hosted/ibasso/usb-ibasso.h
new file mode 100644
index 0000000000..f509d43038
--- /dev/null
+++ b/firmware/target/hosted/ibasso/usb-ibasso.h
@@ -0,0 +1,54 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef _USB_DX50_H_
26#define _USB_DX50_H_
27
28
29/* Supported usb modes. */
30enum ibasso_usb_mode
31{
32 /*
33 USB mass storage mode. On USB connection, Rockbox will terminate and the internel and
34 external storage gets exported to the connected client.
35 */
36 USB_MODE_MASS_STORAGE = 0,
37
38 /*
39 Actually the same, since we to not have proper USB detection.
40 Starts the adb server and enables adb connection over USB. Rockbox will continue to run.
41 */
42 USB_MODE_CHARGE,
43 USB_MODE_ADB
44};
45
46
47/*
48 Set the usb mode.
49 mode: ibasso_usb_mode
50*/
51void ibasso_set_usb_mode(int mode);
52
53
54#endif
diff --git a/firmware/target/hosted/ibasso/vold-ibasso.c b/firmware/target/hosted/ibasso/vold-ibasso.c
new file mode 100644
index 0000000000..c92b86d364
--- /dev/null
+++ b/firmware/target/hosted/ibasso/vold-ibasso.c
@@ -0,0 +1,203 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <pthread.h>
26#include <stdbool.h>
27#include <string.h>
28#include <unistd.h>
29#include <sys/poll.h>
30#include <sys/socket.h>
31#include <sys/types.h>
32#include <sys/un.h>
33
34#include "config.h"
35#include "debug.h"
36#include "powermgmt.h"
37
38#include "debug-ibasso.h"
39
40
41/*
42 Without this socket iBasso Vold will not start.
43 iBasso Vold uses this to send status messages about storage devices.
44*/
45static const char VOLD_MONITOR_SOCKET_NAME[] = "UNIX_domain";
46static int _vold_monitor_socket_fd = -1;
47
48
49static void vold_monitor_open_socket(void)
50{
51 TRACE;
52
53 unlink(VOLD_MONITOR_SOCKET_NAME);
54
55 _vold_monitor_socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
56
57 if(_vold_monitor_socket_fd < 0)
58 {
59 _vold_monitor_socket_fd = -1;
60 return;
61 }
62
63 struct sockaddr_un addr;
64 memset(&addr, 0, sizeof(addr));
65 addr.sun_family = AF_UNIX;
66 strncpy(addr.sun_path, VOLD_MONITOR_SOCKET_NAME, sizeof(addr.sun_path) -1);
67
68 if(bind(_vold_monitor_socket_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
69 {
70 close(_vold_monitor_socket_fd);
71 unlink(VOLD_MONITOR_SOCKET_NAME);
72 _vold_monitor_socket_fd = -1;
73 return;
74 }
75
76 if(listen(_vold_monitor_socket_fd, 1) < 0)
77 {
78 close(_vold_monitor_socket_fd);
79 unlink(VOLD_MONITOR_SOCKET_NAME);
80 _vold_monitor_socket_fd = -1;
81 return;
82 }
83}
84
85
86/*
87 bionic does not have pthread_cancel.
88 0: Vold monitor thread stopped/ending.
89 1: Vold monitor thread started/running.
90*/
91static volatile sig_atomic_t _vold_monitor_active = 0;
92
93
94/*
95 1: /mnt/sdcard is unmounting
96 0: else
97*/
98static volatile sig_atomic_t _vold_monitor_forced_close_imminent = 0;
99
100
101static void* vold_monitor_run(void* nothing)
102{
103 _vold_monitor_active = 1;
104
105 (void) nothing;
106
107 DEBUGF("DEBUG %s: Thread start.", __func__);
108
109 vold_monitor_open_socket();
110 if(_vold_monitor_socket_fd < 0)
111 {
112 DEBUGF("ERROR %s: Thread end: No socket.", __func__);
113
114 _vold_monitor_active = 0;
115 return 0;
116 }
117
118 struct pollfd fds[1];
119 fds[0].fd = _vold_monitor_socket_fd;
120 fds[0].events = POLLIN;
121
122 while(_vold_monitor_active == 1)
123 {
124 poll(fds, 1, 10);
125 if(! (fds[0].revents & POLLIN))
126 {
127 continue;
128 }
129
130 int socket_fd = accept(_vold_monitor_socket_fd, NULL, NULL);
131
132 if(socket_fd < 0)
133 {
134 DEBUGF("ERROR %s: accept failed.", __func__);
135
136 continue;
137 }
138
139 while(true)
140 {
141 char msg[1024];
142 memset(msg, 0, sizeof(msg));
143 int length = read(socket_fd, msg, sizeof(msg));
144
145 if(length <= 0)
146 {
147 close(socket_fd);
148 break;
149 }
150
151 DEBUGF("%s: msg: %s", __func__, msg);
152
153 if(strcmp(msg, "Volume flash /mnt/sdcard state changed from 4 (Mounted) to 5 (Unmounting)") == 0)
154 {
155 /* We are losing /mnt/sdcard, shutdown Rockbox before it is forced closed. */
156
157 _vold_monitor_forced_close_imminent = 1;
158 sys_poweroff();
159 _vold_monitor_active = 0;
160 }
161 else if(strcmp(msg, "Volume sdcard /mnt/external_sd state changed from 4 (Mounted) to 5 (Unmounting)") == 0)
162 {
163 /* We are loosing the external sdcard, inform Rockbox. */
164 }
165 else if(strcmp(msg, "Volume sdcard /mnt/external_sd state changed from 3 (Checking) to 4 (Mounted)") == 0)
166 {
167 /* The external sdcard is back, inform Rockbox. */
168 }
169 }
170 }
171
172 close(_vold_monitor_socket_fd);
173 unlink(VOLD_MONITOR_SOCKET_NAME);
174 _vold_monitor_socket_fd = -1;
175
176 DEBUGF("%s: Thread end.", __func__);
177
178 _vold_monitor_active = 0;
179 return 0;
180}
181
182
183/* Vold monitor thread. */
184static pthread_t _vold_monitor_thread;
185
186
187void vold_monitor_start(void)
188{
189 TRACE;
190
191 if(_vold_monitor_active == 0)
192 {
193 pthread_create(&_vold_monitor_thread, NULL, vold_monitor_run, NULL);
194 }
195}
196
197
198bool vold_monitor_forced_close_imminent(void)
199{
200 TRACE;
201
202 return(_vold_monitor_forced_close_imminent == 1);
203}
diff --git a/firmware/target/hosted/ibasso/vold-ibasso.h b/firmware/target/hosted/ibasso/vold-ibasso.h
new file mode 100644
index 0000000000..18012b7e16
--- /dev/null
+++ b/firmware/target/hosted/ibasso/vold-ibasso.h
@@ -0,0 +1,42 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#ifndef __VOLD_IBASSO_H__
26#define __VOLD_IBASSO_H__
27
28
29/* Start the vold monitor thread. */
30void vold_monitor_start(void);
31
32
33/*
34 Used to change Rockbox shutdown from reboot/power off to program exit.
35 true: vold monitor has detected, that vold is remounting /mnt/sdcard for USB mass storage
36 access.
37 false: else.
38*/
39bool vold_monitor_forced_close_imminent(void);
40
41
42#endif