diff options
Diffstat (limited to 'firmware/target/hosted/android')
-rw-r--r-- | firmware/target/hosted/android/dx50/adc-target.h | 0 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/backlight-dx50.c | 76 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/backlight-target.h | 31 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/button-dx50.c | 314 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/button-target.h | 72 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/lcd-dx50.c | 120 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/lcd-target.h | 29 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/pcm-dx50.c | 364 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/powermgmt-dx50.c | 72 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/tinyalsa/asound.h | 821 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/tinyalsa/asoundlib.h | 257 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/tinyalsa/mixer.c | 497 | ||||
-rw-r--r-- | firmware/target/hosted/android/dx50/tinyalsa/pcm.c | 973 | ||||
-rw-r--r-- | firmware/target/hosted/android/system-android.c | 54 |
14 files changed, 3678 insertions, 2 deletions
diff --git a/firmware/target/hosted/android/dx50/adc-target.h b/firmware/target/hosted/android/dx50/adc-target.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/firmware/target/hosted/android/dx50/adc-target.h | |||
diff --git a/firmware/target/hosted/android/dx50/backlight-dx50.c b/firmware/target/hosted/android/dx50/backlight-dx50.c new file mode 100644 index 0000000000..98dbcb8abe --- /dev/null +++ b/firmware/target/hosted/android/dx50/backlight-dx50.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2011 by Lorenzo Miori | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | #include "config.h" | ||
21 | #include "system.h" | ||
22 | #include "backlight.h" | ||
23 | #include "backlight-target.h" | ||
24 | #include "lcd.h" | ||
25 | #include "lcd-target.h" | ||
26 | #include <fcntl.h> | ||
27 | #include <stdio.h> | ||
28 | #include "unistd.h" | ||
29 | |||
30 | bool _backlight_init(void) | ||
31 | { | ||
32 | /* We have nothing to do */ | ||
33 | return true; | ||
34 | } | ||
35 | |||
36 | void _backlight_on(void) | ||
37 | { | ||
38 | FILE *f = fopen("/sys/power/state", "w"); | ||
39 | fputs("on", f); | ||
40 | fclose(f); | ||
41 | lcd_enable(true); | ||
42 | } | ||
43 | |||
44 | void _backlight_off(void) | ||
45 | { | ||
46 | FILE * f; | ||
47 | |||
48 | /* deny the player to sleep deep */ | ||
49 | f = fopen("/sys/power/wake_lock", "w"); | ||
50 | fputs("player", f); | ||
51 | fclose(f); | ||
52 | |||
53 | /* deny the player to mute */ | ||
54 | f = fopen("/sys/class/codec/wm8740_mute", "w"); | ||
55 | fputc(0, f); | ||
56 | fclose(f); | ||
57 | |||
58 | /* turn off backlight */ | ||
59 | f = fopen("/sys/power/state", "w"); | ||
60 | fputs("mem", f); | ||
61 | fclose(f); | ||
62 | |||
63 | } | ||
64 | |||
65 | void _backlight_set_brightness(int brightness) | ||
66 | { | ||
67 | /* Just another check... */ | ||
68 | if (brightness > MAX_BRIGHTNESS_SETTING) | ||
69 | brightness = MAX_BRIGHTNESS_SETTING; | ||
70 | if (brightness < MIN_BRIGHTNESS_SETTING) | ||
71 | brightness = MIN_BRIGHTNESS_SETTING; | ||
72 | |||
73 | FILE *f = fopen("/sys/devices/platform/rk29_backlight/backlight/rk28_bl/brightness", "w"); | ||
74 | fprintf(f, "%d", brightness); | ||
75 | fclose(f); | ||
76 | } | ||
diff --git a/firmware/target/hosted/android/dx50/backlight-target.h b/firmware/target/hosted/android/dx50/backlight-target.h new file mode 100644 index 0000000000..67836aa790 --- /dev/null +++ b/firmware/target/hosted/android/dx50/backlight-target.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2008 by Maurus Cuelenaere | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef BACKLIGHT_TARGET_H | ||
22 | #define BACKLIGHT_TARGET_H | ||
23 | |||
24 | #include <stdbool.h> | ||
25 | |||
26 | bool _backlight_init(void); | ||
27 | void _backlight_on(void); | ||
28 | void _backlight_off(void); | ||
29 | void _backlight_set_brightness(int brightness); | ||
30 | |||
31 | #endif /* BACKLIGHT_TARGET_H */ | ||
diff --git a/firmware/target/hosted/android/dx50/button-dx50.c b/firmware/target/hosted/android/dx50/button-dx50.c new file mode 100644 index 0000000000..5ab58ce420 --- /dev/null +++ b/firmware/target/hosted/android/dx50/button-dx50.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (c) 2010 Thomas Martitz | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | |||
23 | #include <stdbool.h> | ||
24 | #include "button.h" | ||
25 | #include "buttonmap.h" | ||
26 | #include "config.h" | ||
27 | #include "kernel.h" | ||
28 | #include "system.h" | ||
29 | #include "touchscreen.h" | ||
30 | #include "powermgmt.h" | ||
31 | #include "backlight.h" | ||
32 | |||
33 | #include <linux/input.h> | ||
34 | #include <stdio.h> | ||
35 | #include <stdlib.h> | ||
36 | #include <string.h> | ||
37 | #include <stdint.h> | ||
38 | #include <dirent.h> | ||
39 | #include <fcntl.h> | ||
40 | #include <sys/ioctl.h> | ||
41 | #include <sys/inotify.h> | ||
42 | #include <sys/limits.h> | ||
43 | #include <sys/poll.h> | ||
44 | #include <errno.h> | ||
45 | |||
46 | |||
47 | static struct pollfd *ufds; | ||
48 | static char **device_names; | ||
49 | static int nfds; | ||
50 | |||
51 | enum { | ||
52 | PRINT_DEVICE_ERRORS = 1U << 0, | ||
53 | PRINT_DEVICE = 1U << 1, | ||
54 | PRINT_DEVICE_NAME = 1U << 2, | ||
55 | PRINT_DEVICE_INFO = 1U << 3, | ||
56 | PRINT_VERSION = 1U << 4, | ||
57 | PRINT_POSSIBLE_EVENTS = 1U << 5, | ||
58 | PRINT_INPUT_PROPS = 1U << 6, | ||
59 | PRINT_HID_DESCRIPTOR = 1U << 7, | ||
60 | |||
61 | PRINT_ALL_INFO = (1U << 8) - 1, | ||
62 | |||
63 | PRINT_LABELS = 1U << 16, | ||
64 | }; | ||
65 | |||
66 | static int last_y, last_x; | ||
67 | static int last_btns; | ||
68 | |||
69 | static enum { | ||
70 | STATE_UNKNOWN, | ||
71 | STATE_UP, | ||
72 | STATE_DOWN | ||
73 | } last_touch_state = STATE_UNKNOWN; | ||
74 | |||
75 | |||
76 | static int open_device(const char *device, int print_flags) | ||
77 | { | ||
78 | int fd; | ||
79 | struct pollfd *new_ufds; | ||
80 | char **new_device_names; | ||
81 | |||
82 | fd = open(device, O_RDWR); | ||
83 | if(fd < 0) { | ||
84 | if(print_flags & PRINT_DEVICE_ERRORS) | ||
85 | fprintf(stderr, "could not open %s, %s\n", device, strerror(errno)); | ||
86 | return -1; | ||
87 | } | ||
88 | |||
89 | new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1)); | ||
90 | if(new_ufds == NULL) { | ||
91 | fprintf(stderr, "out of memory\n"); | ||
92 | return -1; | ||
93 | } | ||
94 | ufds = new_ufds; | ||
95 | new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1)); | ||
96 | if(new_device_names == NULL) { | ||
97 | fprintf(stderr, "out of memory\n"); | ||
98 | return -1; | ||
99 | } | ||
100 | device_names = new_device_names; | ||
101 | |||
102 | ufds[nfds].fd = fd; | ||
103 | ufds[nfds].events = POLLIN; | ||
104 | device_names[nfds] = strdup(device); | ||
105 | nfds++; | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | |||
111 | |||
112 | static int scan_dir(const char *dirname, int print_flags) | ||
113 | { | ||
114 | char devname[PATH_MAX]; | ||
115 | char *filename; | ||
116 | DIR *dir; | ||
117 | struct dirent *de; | ||
118 | dir = opendir(dirname); | ||
119 | if(dir == NULL) | ||
120 | return -1; | ||
121 | strcpy(devname, dirname); | ||
122 | filename = devname + strlen(devname); | ||
123 | *filename++ = '/'; | ||
124 | while((de = readdir(dir))) { | ||
125 | if(de->d_name[0] == '.' && | ||
126 | (de->d_name[1] == '\0' || | ||
127 | (de->d_name[1] == '.' && de->d_name[2] == '\0'))) | ||
128 | continue; | ||
129 | strcpy(filename, de->d_name); | ||
130 | open_device(devname, print_flags); | ||
131 | } | ||
132 | closedir(dir); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | bool _hold; | ||
137 | |||
138 | bool button_hold() | ||
139 | { | ||
140 | FILE *f = fopen("/sys/class/axppower/holdkey", "r"); | ||
141 | char x; | ||
142 | fscanf(f, "%c", &x); | ||
143 | fclose(f); | ||
144 | _hold = !(x&STATE_UNLOCKED); | ||
145 | return _hold; | ||
146 | } | ||
147 | |||
148 | |||
149 | void button_init_device(void) | ||
150 | { | ||
151 | int res; | ||
152 | int print_flags = 0; | ||
153 | const char *device = NULL; | ||
154 | const char *device_path = "/dev/input"; | ||
155 | |||
156 | nfds = 1; | ||
157 | ufds = calloc(1, sizeof(ufds[0])); | ||
158 | ufds[0].fd = inotify_init(); | ||
159 | ufds[0].events = POLLIN; | ||
160 | if(device) { | ||
161 | res = open_device(device, print_flags); | ||
162 | if(res < 0) { | ||
163 | // return 1; | ||
164 | } | ||
165 | } else { | ||
166 | res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE); | ||
167 | if(res < 0) { | ||
168 | fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno)); | ||
169 | // return 1; | ||
170 | } | ||
171 | res = scan_dir(device_path, print_flags); | ||
172 | if(res < 0) { | ||
173 | fprintf(stderr, "scan dir failed for %s\n", device_path); | ||
174 | // return 1; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | button_hold(); //store state | ||
179 | |||
180 | set_rockbox_ready(); | ||
181 | } | ||
182 | |||
183 | void touchscreen_enable_device(bool en) | ||
184 | { | ||
185 | (void)en; /* FIXME: do something smart */ | ||
186 | } | ||
187 | |||
188 | |||
189 | int keycode_to_button(int keyboard_key) | ||
190 | { | ||
191 | switch(keyboard_key){ | ||
192 | case KEYCODE_PWR: | ||
193 | return BUTTON_POWER; | ||
194 | |||
195 | case KEYCODE_PWR_LONG: | ||
196 | return BUTTON_POWER_LONG; | ||
197 | |||
198 | case KEYCODE_VOLPLUS: | ||
199 | return BUTTON_VOL_UP; | ||
200 | |||
201 | case KEYCODE_VOLMINUS: | ||
202 | return BUTTON_VOL_DOWN; | ||
203 | |||
204 | case KEYCODE_PREV: | ||
205 | return BUTTON_LEFT; | ||
206 | |||
207 | case KEYCODE_NEXT: | ||
208 | return BUTTON_RIGHT; | ||
209 | |||
210 | case KEYCODE_PLAY: | ||
211 | return BUTTON_PLAY; | ||
212 | |||
213 | case KEYCODE_HOLD: | ||
214 | button_hold(); /* store state */ | ||
215 | backlight_hold_changed(_hold); | ||
216 | return BUTTON_NONE; | ||
217 | |||
218 | default: | ||
219 | return BUTTON_NONE; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | |||
224 | int button_read_device(int *data) | ||
225 | { | ||
226 | int i; | ||
227 | int res; | ||
228 | struct input_event event; | ||
229 | int read_more; | ||
230 | unsigned button = 0; | ||
231 | |||
232 | if(last_btns & BUTTON_POWER_LONG) | ||
233 | { | ||
234 | return last_btns; /* simulate repeat */ | ||
235 | } | ||
236 | |||
237 | do { | ||
238 | read_more = 0; | ||
239 | poll(ufds, nfds, 10); | ||
240 | for(i = 1; i < nfds; i++) { | ||
241 | if(ufds[i].revents & POLLIN) { | ||
242 | res = read(ufds[i].fd, &event, sizeof(event)); | ||
243 | if(res < (int)sizeof(event)) { | ||
244 | fprintf(stderr, "could not get event\n"); | ||
245 | } | ||
246 | |||
247 | switch(event.type) | ||
248 | { | ||
249 | case 1: /* HW-Button */ | ||
250 | button = keycode_to_button(event.code); | ||
251 | if (_hold) /* we have to wait for keycode_to_button() first to maybe clear hold state */ | ||
252 | break; | ||
253 | if (button == BUTTON_NONE) | ||
254 | { | ||
255 | last_btns = button; | ||
256 | break; | ||
257 | } | ||
258 | /* workaround for a wrong feedback, only present with DX90 */ | ||
259 | #if defined(DX90) | ||
260 | if (button == BUTTON_RIGHT && (last_btns & BUTTON_LEFT == BUTTON_LEFT) && !event.value) | ||
261 | { | ||
262 | button = BUTTON_LEFT; | ||
263 | } | ||
264 | #endif | ||
265 | if (event.value) | ||
266 | last_btns |= button; | ||
267 | else | ||
268 | last_btns &= (~button); | ||
269 | |||
270 | break; | ||
271 | |||
272 | case 3: /* Touchscreen */ | ||
273 | if(_hold) | ||
274 | break; | ||
275 | |||
276 | switch(event.code) | ||
277 | { | ||
278 | case 53: /* x -> next will be y */ | ||
279 | last_x = event.value; | ||
280 | read_more = 1; | ||
281 | break; | ||
282 | case 54: /* y */ | ||
283 | last_y = event.value; | ||
284 | break; | ||
285 | case 57: /* press -> next will be x */ | ||
286 | if(event.value==1) | ||
287 | { | ||
288 | last_touch_state = STATE_DOWN; | ||
289 | read_more = 1; | ||
290 | } | ||
291 | else | ||
292 | last_touch_state = STATE_UP; | ||
293 | break; | ||
294 | } | ||
295 | break; | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | } while(read_more); | ||
300 | |||
301 | |||
302 | /* Get grid button/coordinates based on the current touchscreen mode | ||
303 | * | ||
304 | * Caveat: the caller seemingly depends on *data always being filled with | ||
305 | * the last known touchscreen position, so always call | ||
306 | * touchscreen_to_pixels() */ | ||
307 | int touch = touchscreen_to_pixels(last_x, last_y, data); | ||
308 | |||
309 | if (last_touch_state == STATE_DOWN) | ||
310 | return last_btns | touch; | ||
311 | |||
312 | return last_btns; | ||
313 | } | ||
314 | |||
diff --git a/firmware/target/hosted/android/dx50/button-target.h b/firmware/target/hosted/android/dx50/button-target.h new file mode 100644 index 0000000000..adc9cf6bfd --- /dev/null +++ b/firmware/target/hosted/android/dx50/button-target.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Rob Purchase | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version.r | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef _BUTTON_TARGET_H_ | ||
23 | #define _BUTTON_TARGET_H_ | ||
24 | |||
25 | #include <stdbool.h> | ||
26 | |||
27 | #define HAS_BUTTON_HOLD | ||
28 | |||
29 | /* Main unit's 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\ | ||
39 | |BUTTON_RIGHT|BUTTON_PLAY|BUTTON_POWER|BUTTON_POWER_LONG) | ||
40 | |||
41 | #define KEYCODE_LINEOUT 113 | ||
42 | #define KEYCODE_SPDIF 114 | ||
43 | #define KEYCODE_HOLD 115 | ||
44 | #define KEYCODE_PWR 116 | ||
45 | #define KEYCODE_PWR_LONG 117 | ||
46 | #define KEYCODE_SD 143 | ||
47 | #define KEYCODE_VOLPLUS 158 | ||
48 | #define KEYCODE_VOLMINUS 159 | ||
49 | #define KEYCODE_PREV 160 | ||
50 | #define KEYCODE_NEXT 162 | ||
51 | #define KEYCODE_PLAY 161 | ||
52 | #define STATE_UNLOCKED 16 | ||
53 | #define STATE_SPDIF_UNPLUGGED 32 | ||
54 | #define STATE_LINEOUT_UNPLUGGED 64 | ||
55 | |||
56 | /* Touch Screen Area Buttons */ | ||
57 | #define BUTTON_TOPLEFT 0x00001000 | ||
58 | #define BUTTON_TOPMIDDLE 0x00002000 | ||
59 | #define BUTTON_TOPRIGHT 0x00004000 | ||
60 | #define BUTTON_MIDLEFT 0x00008000 | ||
61 | #define BUTTON_CENTER 0x00010000 | ||
62 | #define BUTTON_MIDRIGHT 0x00020000 | ||
63 | #define BUTTON_BOTTOMLEFT 0x00040000 | ||
64 | #define BUTTON_BOTTOMMIDDLE 0x00080000 | ||
65 | #define BUTTON_BOTTOMRIGHT 0x00100000 | ||
66 | |||
67 | |||
68 | /* Software power-off */ | ||
69 | #define POWEROFF_BUTTON BUTTON_POWER_LONG | ||
70 | #define POWEROFF_COUNT 0 | ||
71 | |||
72 | #endif /* _BUTTON_TARGET_H_ */ | ||
diff --git a/firmware/target/hosted/android/dx50/lcd-dx50.c b/firmware/target/hosted/android/dx50/lcd-dx50.c new file mode 100644 index 0000000000..4d78baaf00 --- /dev/null +++ b/firmware/target/hosted/android/dx50/lcd-dx50.c | |||
@@ -0,0 +1,120 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: lcd-bitmap.c 29248 2011-02-08 20:05:25Z thomasjfox $ | ||
9 | * | ||
10 | * Copyright (C) 2011 Lorenzo Miori, Thomas Martitz | ||
11 | * Copyright (C) 2013 Lorenzo Miori | ||
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 | |||
23 | #include <stdlib.h> | ||
24 | #include <unistd.h> | ||
25 | #include <stdio.h> | ||
26 | #include <linux/fb.h> | ||
27 | #include <sys/mman.h> | ||
28 | #include <sys/ioctl.h> | ||
29 | #include "config.h" | ||
30 | #include "file.h" | ||
31 | #include "debug.h" | ||
32 | #include "system.h" | ||
33 | #include "screendump.h" | ||
34 | #include "lcd.h" | ||
35 | #include "lcd-target.h" | ||
36 | |||
37 | static int dev_fd = 0; | ||
38 | fb_data *dev_fb = 0; | ||
39 | |||
40 | #ifdef HAVE_LCD_SHUTDOWN | ||
41 | void lcd_shutdown(void) | ||
42 | { | ||
43 | printf("FB closed."); | ||
44 | munmap(dev_fb, FRAMEBUFFER_SIZE); | ||
45 | close(dev_fd); | ||
46 | } | ||
47 | #endif | ||
48 | |||
49 | void lcd_init_device(void) | ||
50 | { | ||
51 | size_t screensize; | ||
52 | struct fb_var_screeninfo vinfo; | ||
53 | struct fb_fix_screeninfo finfo; | ||
54 | |||
55 | /* Open the framebuffer device */ | ||
56 | dev_fd = open("/dev/graphics/fb0", O_RDWR); | ||
57 | if (dev_fd == -1) { | ||
58 | perror("Error: cannot open framebuffer device"); | ||
59 | exit(1); | ||
60 | } | ||
61 | |||
62 | /* Get the fixed properties */ | ||
63 | if (ioctl(dev_fd, FBIOGET_FSCREENINFO, &finfo) == -1) { | ||
64 | perror("Error reading fixed information"); | ||
65 | exit(2); | ||
66 | } | ||
67 | |||
68 | |||
69 | /* Now we get the settable settings, and we set 16 bit bpp */ | ||
70 | if (ioctl(dev_fd, FBIOGET_VSCREENINFO, &vinfo) == -1) { | ||
71 | perror("Error reading variable information"); | ||
72 | exit(3); | ||
73 | } | ||
74 | /* framebuffer does not fit the screen, a bug of iBassos Firmware, not rockbox. | ||
75 | cannot be solved with parameters */ | ||
76 | vinfo.bits_per_pixel = LCD_DEPTH; | ||
77 | vinfo.xres = vinfo.xres_virtual = vinfo.width = LCD_WIDTH; | ||
78 | vinfo.yres = vinfo.yres_virtual = vinfo.height = LCD_HEIGHT; | ||
79 | |||
80 | if (ioctl(dev_fd, FBIOPUT_VSCREENINFO, &vinfo)) { | ||
81 | perror("fbset(ioctl)"); | ||
82 | exit(4); | ||
83 | } | ||
84 | |||
85 | /* Figure out the size of the screen in bytes */ | ||
86 | screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; | ||
87 | if (screensize != FRAMEBUFFER_SIZE) { | ||
88 | exit(4); | ||
89 | perror("Display and framebuffer mismatch!\n"); | ||
90 | } | ||
91 | |||
92 | /* Map the device to memory */ | ||
93 | dev_fb = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0); | ||
94 | if ((int)dev_fb == -1) { | ||
95 | perror("Error: failed to map framebuffer device to memory"); | ||
96 | exit(4); | ||
97 | } | ||
98 | |||
99 | /* Be sure to turn on display at startup */ | ||
100 | ioctl(dev_fd, FBIOBLANK, VESA_NO_BLANKING); | ||
101 | #ifdef HAVE_LCD_ENABLE | ||
102 | lcd_set_active(true); | ||
103 | #endif | ||
104 | } | ||
105 | |||
106 | #ifdef HAVE_LCD_ENABLE | ||
107 | void lcd_enable(bool enable) | ||
108 | { | ||
109 | if (lcd_active() == enable) | ||
110 | return; | ||
111 | |||
112 | lcd_set_active(enable); | ||
113 | |||
114 | /* Turn on or off the display using Linux interface */ | ||
115 | ioctl(dev_fd, FBIOBLANK, enable ? VESA_NO_BLANKING : VESA_POWERDOWN); | ||
116 | |||
117 | if (enable) | ||
118 | send_event(LCD_EVENT_ACTIVATION, NULL); | ||
119 | } | ||
120 | #endif | ||
diff --git a/firmware/target/hosted/android/dx50/lcd-target.h b/firmware/target/hosted/android/dx50/lcd-target.h new file mode 100644 index 0000000000..900350eca2 --- /dev/null +++ b/firmware/target/hosted/android/dx50/lcd-target.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version 2 | ||
13 | * of the License, or (at your option) any later version. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef __LCD_TARGET_H__ | ||
21 | #define __LCD_TARGET_H__ | ||
22 | |||
23 | extern fb_data *dev_fb; | ||
24 | #define LCD_FRAMEBUF_ADDR(col, row) (dev_fb + row*LCD_WIDTH + col) | ||
25 | #ifdef HAVE_LCD_ENABLE | ||
26 | extern void lcd_set_active(bool active); | ||
27 | extern void lcd_enable(bool enable); | ||
28 | #endif | ||
29 | #endif | ||
diff --git a/firmware/target/hosted/android/dx50/pcm-dx50.c b/firmware/target/hosted/android/dx50/pcm-dx50.c new file mode 100644 index 0000000000..e7695873a0 --- /dev/null +++ b/firmware/target/hosted/android/dx50/pcm-dx50.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Thomas Martitz | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | |||
23 | /* | ||
24 | * Based, but heavily modified, on the example given at | ||
25 | * http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html | ||
26 | * | ||
27 | * This driver uses the so-called unsafe async callback method and hardcoded device | ||
28 | * names. It fails when the audio device is busy by other apps. | ||
29 | * | ||
30 | * To make the async callback safer, an alternative stack is installed, since | ||
31 | * it's run from a signal hanlder (which otherwise uses the user stack). If | ||
32 | * tick tasks are run from a signal handler too, please install | ||
33 | * an alternative stack for it too. | ||
34 | * | ||
35 | * TODO: Rewrite this to do it properly with multithreading | ||
36 | * | ||
37 | * Alternatively, a version using polling in a tick task is provided. While | ||
38 | * supposedly safer, it appears to use more CPU (however I didn't measure it | ||
39 | * accurately, only looked at htop). At least, in this mode the "default" | ||
40 | * device works which doesnt break with other apps running. | ||
41 | */ | ||
42 | |||
43 | |||
44 | #include "autoconf.h" | ||
45 | |||
46 | #include <stdlib.h> | ||
47 | #include <stdbool.h> | ||
48 | #include <stdio.h> | ||
49 | #include <errno.h> | ||
50 | #include "tinyalsa/asoundlib.h" | ||
51 | #include "tinyalsa/asound.h" | ||
52 | #include "system.h" | ||
53 | #include "debug.h" | ||
54 | #include "kernel.h" | ||
55 | |||
56 | #include "pcm.h" | ||
57 | #include "pcm-internal.h" | ||
58 | #include "pcm_mixer.h" | ||
59 | #include "pcm_sampr.h" | ||
60 | #include "audiohw.h" | ||
61 | |||
62 | #include <pthread.h> | ||
63 | #include <signal.h> | ||
64 | |||
65 | static const snd_pcm_format_t format = PCM_FORMAT_S16_LE; /* sample format */ | ||
66 | static const int channels = 2; /* count of channels */ | ||
67 | static unsigned int rate = 44100; /* stream rate */ | ||
68 | |||
69 | typedef struct pcm snd_pcm_t; | ||
70 | static snd_pcm_t *handle; | ||
71 | struct pcm_config config; | ||
72 | |||
73 | static snd_pcm_sframes_t period_size = 512; /* if set to >= 1024, all timers become even slower */ | ||
74 | static char *frames; | ||
75 | |||
76 | static const void *pcm_data = 0; | ||
77 | static size_t pcm_size = 0; | ||
78 | |||
79 | static int recursion; | ||
80 | |||
81 | static int set_hwparams(snd_pcm_t *handle) | ||
82 | { | ||
83 | int err; | ||
84 | if (!frames) | ||
85 | frames = malloc(pcm_frames_to_bytes(handle, pcm_get_buffer_size(handle))); | ||
86 | err = 0; /* success */ | ||
87 | return err; | ||
88 | } | ||
89 | |||
90 | |||
91 | /* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */ | ||
92 | static bool fill_frames(void) | ||
93 | { | ||
94 | size_t copy_n, frames_left = period_size; | ||
95 | bool new_buffer = false; | ||
96 | |||
97 | while (frames_left > 0) | ||
98 | { | ||
99 | if (!pcm_size) | ||
100 | { | ||
101 | new_buffer = true; | ||
102 | if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &pcm_data, | ||
103 | &pcm_size)) | ||
104 | { | ||
105 | return false; | ||
106 | } | ||
107 | } | ||
108 | copy_n = MIN((size_t)pcm_size, pcm_frames_to_bytes(handle, frames_left)); | ||
109 | memcpy(&frames[pcm_frames_to_bytes(handle, period_size-frames_left)], pcm_data, copy_n); | ||
110 | |||
111 | pcm_data += copy_n; | ||
112 | pcm_size -= copy_n; | ||
113 | frames_left -= pcm_bytes_to_frames(handle, copy_n); | ||
114 | |||
115 | if (new_buffer) | ||
116 | { | ||
117 | new_buffer = false; | ||
118 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); | ||
119 | } | ||
120 | } | ||
121 | return true; | ||
122 | } | ||
123 | |||
124 | |||
125 | static void pcm_tick(void) | ||
126 | { | ||
127 | if (fill_frames()) | ||
128 | { | ||
129 | if (pcm_write(handle, frames, pcm_frames_to_bytes(handle, period_size))) { | ||
130 | printf("Error playing sample\n"); | ||
131 | return;//break; | ||
132 | } | ||
133 | |||
134 | } | ||
135 | else | ||
136 | { | ||
137 | DEBUGF("%s: No Data.\n", __func__); | ||
138 | return;//break; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static int async_rw(snd_pcm_t *handle) | ||
143 | { | ||
144 | int err; | ||
145 | snd_pcm_sframes_t sample_size; | ||
146 | char *samples; | ||
147 | |||
148 | /* fill buffer with silence to initiate playback without noisy click */ | ||
149 | sample_size = pcm_frames_to_bytes(handle, pcm_get_buffer_size(handle)); | ||
150 | samples = malloc(sample_size); | ||
151 | |||
152 | memset(samples, 0, sample_size); | ||
153 | |||
154 | err = pcm_write(handle, samples, sample_size); | ||
155 | free(samples); | ||
156 | |||
157 | if (err != 0) | ||
158 | { | ||
159 | DEBUGF("Initial write error: %d\n", err); | ||
160 | return err; | ||
161 | } | ||
162 | if (pcm_state(handle) == PCM_STATE_PREPARED) | ||
163 | { | ||
164 | err = pcm_start(handle); | ||
165 | if (err < 0) | ||
166 | { | ||
167 | DEBUGF("Start error: %d\n", err); | ||
168 | return err; | ||
169 | } | ||
170 | } | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | void cleanup(void) | ||
175 | { | ||
176 | free(frames); | ||
177 | frames = NULL; | ||
178 | pcm_close(handle); | ||
179 | } | ||
180 | |||
181 | void pcm_play_dma_init(void) | ||
182 | { | ||
183 | config.channels = channels; | ||
184 | config.rate = rate; | ||
185 | config.period_size = period_size; | ||
186 | config.period_count = 4; | ||
187 | config.format = format; | ||
188 | config.start_threshold = 0; | ||
189 | config.stop_threshold = 0; | ||
190 | config.silence_threshold = 0; | ||
191 | |||
192 | |||
193 | handle = pcm_open(0, 0, PCM_OUT, &config); | ||
194 | if (!handle || !pcm_is_ready(handle)) { | ||
195 | printf("Unable to open PCM device: %s\n", pcm_get_error(handle)); | ||
196 | return; | ||
197 | } | ||
198 | |||
199 | pcm_dma_apply_settings(); | ||
200 | |||
201 | tick_add_task(pcm_tick); | ||
202 | |||
203 | atexit(cleanup); | ||
204 | return; | ||
205 | } | ||
206 | |||
207 | |||
208 | void pcm_play_lock(void) | ||
209 | { | ||
210 | if (recursion++ == 0) | ||
211 | tick_remove_task(pcm_tick); | ||
212 | } | ||
213 | |||
214 | void pcm_play_unlock(void) | ||
215 | { | ||
216 | if (--recursion == 0) | ||
217 | tick_add_task(pcm_tick); | ||
218 | } | ||
219 | |||
220 | static void pcm_dma_apply_settings_nolock(void) | ||
221 | { | ||
222 | set_hwparams(handle); | ||
223 | } | ||
224 | |||
225 | void pcm_dma_apply_settings(void) | ||
226 | { | ||
227 | pcm_play_lock(); | ||
228 | pcm_dma_apply_settings_nolock(); | ||
229 | pcm_play_unlock(); | ||
230 | } | ||
231 | |||
232 | |||
233 | void pcm_play_dma_pause(bool pause) | ||
234 | { | ||
235 | (void)pause; | ||
236 | } | ||
237 | |||
238 | |||
239 | void pcm_play_dma_stop(void) | ||
240 | { | ||
241 | pcm_stop(handle); | ||
242 | } | ||
243 | |||
244 | void pcm_play_dma_start(const void *addr, size_t size) | ||
245 | { | ||
246 | #if defined(DX50) || defined(DX90) | ||
247 | /* headphone output relay: if this is done at startup already, a loud click is audible on headphones. Here, some time later, | ||
248 | the output caps are charged a bit and the click is much softer */ | ||
249 | system("/system/bin/muteopen"); | ||
250 | #endif | ||
251 | pcm_dma_apply_settings_nolock(); | ||
252 | |||
253 | pcm_data = addr; | ||
254 | pcm_size = size; | ||
255 | |||
256 | while (1) | ||
257 | { | ||
258 | snd_pcm_state_t state = pcm_state(handle); | ||
259 | switch (state) | ||
260 | { | ||
261 | case PCM_STATE_RUNNING: | ||
262 | return; | ||
263 | case PCM_STATE_XRUN: | ||
264 | { | ||
265 | printf("No handler for STATE_XRUN!\n"); | ||
266 | continue; | ||
267 | } | ||
268 | case PCM_STATE_PREPARED: | ||
269 | { /* prepared state, we need to fill the buffer with silence before | ||
270 | * starting */ | ||
271 | int err = async_rw(handle); | ||
272 | if (err < 0) | ||
273 | printf("Start error: %d\n", err); | ||
274 | return; | ||
275 | } | ||
276 | case PCM_STATE_PAUSED: | ||
277 | { /* paused, simply resume */ | ||
278 | pcm_play_dma_pause(0); | ||
279 | return; | ||
280 | } | ||
281 | case PCM_STATE_DRAINING: | ||
282 | /* run until drained */ | ||
283 | continue; | ||
284 | default: | ||
285 | DEBUGF("Unhandled state: %d\n", state); | ||
286 | return; | ||
287 | } | ||
288 | } | ||
289 | } | ||
290 | |||
291 | size_t pcm_get_bytes_waiting(void) | ||
292 | { | ||
293 | return pcm_size; | ||
294 | } | ||
295 | |||
296 | const void * pcm_play_dma_get_peak_buffer(int *count) | ||
297 | { | ||
298 | uintptr_t addr = (uintptr_t)pcm_data; | ||
299 | *count = pcm_size / 4; | ||
300 | return (void *)((addr + 3) & ~3); | ||
301 | } | ||
302 | |||
303 | void pcm_play_dma_postinit(void) | ||
304 | { | ||
305 | return; | ||
306 | } | ||
307 | |||
308 | void pcm_set_mixer_volume(int volume) | ||
309 | { | ||
310 | #if defined(DX50) || defined(DX90) | ||
311 | /* -990 to 0 -> 0 to 255 */ | ||
312 | int val = (volume+990)*255/990; | ||
313 | #if defined(DX50) | ||
314 | FILE *f = fopen("/dev/codec_volume", "w"); | ||
315 | #else /* DX90 */ | ||
316 | FILE *f = fopen("/sys/class/codec/es9018_volume", "w"); | ||
317 | #endif /* DX50 */ | ||
318 | fprintf(f, "%d", val); | ||
319 | fclose(f); | ||
320 | #else | ||
321 | (void)volume; | ||
322 | #endif /* DX50 || DX90 */ | ||
323 | } | ||
324 | |||
325 | #ifdef HAVE_RECORDING | ||
326 | void pcm_rec_lock(void) | ||
327 | { | ||
328 | } | ||
329 | |||
330 | void pcm_rec_unlock(void) | ||
331 | { | ||
332 | } | ||
333 | |||
334 | void pcm_rec_dma_init(void) | ||
335 | { | ||
336 | } | ||
337 | |||
338 | void pcm_rec_dma_close(void) | ||
339 | { | ||
340 | } | ||
341 | |||
342 | void pcm_rec_dma_start(void *start, size_t size) | ||
343 | { | ||
344 | (void)start; | ||
345 | (void)size; | ||
346 | } | ||
347 | |||
348 | void pcm_rec_dma_stop(void) | ||
349 | { | ||
350 | } | ||
351 | |||
352 | const void * pcm_rec_dma_get_peak_buffer(void) | ||
353 | { | ||
354 | return NULL; | ||
355 | } | ||
356 | |||
357 | void audiohw_set_recvol(int left, int right, int type) | ||
358 | { | ||
359 | (void)left; | ||
360 | (void)right; | ||
361 | (void)type; | ||
362 | } | ||
363 | |||
364 | #endif /* HAVE_RECORDING */ | ||
diff --git a/firmware/target/hosted/android/dx50/powermgmt-dx50.c b/firmware/target/hosted/android/dx50/powermgmt-dx50.c new file mode 100644 index 0000000000..45756cb8e8 --- /dev/null +++ b/firmware/target/hosted/android/dx50/powermgmt-dx50.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 by Thomas Martitz | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include <stdbool.h> | ||
23 | #include <stdio.h> | ||
24 | #include "config.h" | ||
25 | #include "power.h" | ||
26 | #include "powermgmt.h" | ||
27 | |||
28 | unsigned int power_input_status(void) | ||
29 | { | ||
30 | int val; | ||
31 | FILE *f = fopen("/sys/class/power_supply/ac/present", "r"); | ||
32 | fscanf(f, "%d", &val); | ||
33 | fclose(f); | ||
34 | return val?POWER_INPUT_MAIN_CHARGER:POWER_INPUT_NONE; | ||
35 | } | ||
36 | |||
37 | /* Values for stock PISEN battery. TODO: Needs optimization */ | ||
38 | |||
39 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = | ||
40 | { | ||
41 | 3380 | ||
42 | }; | ||
43 | |||
44 | const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = | ||
45 | { | ||
46 | 3100 | ||
47 | }; | ||
48 | |||
49 | /* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ | ||
50 | const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = | ||
51 | { | ||
52 | { 3370, 3650, 3700, 3740, 3780, 3820, 3870, 3930, 4000, 4090, 4190 } | ||
53 | }; | ||
54 | |||
55 | /* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ | ||
56 | const unsigned short percent_to_volt_charge[11] = | ||
57 | { | ||
58 | 3540, 3860, 3930, 3980, 4000, 4020, 4040, 4080, 4130, 4180, 4220 /* LiPo */ | ||
59 | }; | ||
60 | |||
61 | |||
62 | /* Returns battery voltage from android measurement [millivolts] */ | ||
63 | int _battery_voltage(void) | ||
64 | { | ||
65 | int val; | ||
66 | FILE *f = fopen("/sys/class/power_supply/battery/voltage_now", "r"); | ||
67 | fscanf(f, "%d", &val); | ||
68 | fclose(f); | ||
69 | return (val/1000); | ||
70 | } | ||
71 | |||
72 | |||
diff --git a/firmware/target/hosted/android/dx50/tinyalsa/asound.h b/firmware/target/hosted/android/dx50/tinyalsa/asound.h new file mode 100644 index 0000000000..fc1e4f6d67 --- /dev/null +++ b/firmware/target/hosted/android/dx50/tinyalsa/asound.h | |||
@@ -0,0 +1,821 @@ | |||
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 | |||
23 | struct 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 | |||
32 | enum { | ||
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 | |||
55 | struct 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 | |||
64 | struct 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 | |||
73 | struct 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 | |||
88 | typedef unsigned long snd_pcm_uframes_t; | ||
89 | typedef signed long snd_pcm_sframes_t; | ||
90 | |||
91 | enum { | ||
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 | |||
100 | enum { | ||
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 | |||
107 | enum { | ||
108 | SNDRV_PCM_STREAM_PLAYBACK = 0, | ||
109 | SNDRV_PCM_STREAM_CAPTURE, | ||
110 | SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE, | ||
111 | }; | ||
112 | |||
113 | typedef 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 | |||
121 | typedef 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 | |||
189 | typedef 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 | |||
210 | typedef 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 | |||
222 | enum { | ||
223 | SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, | ||
224 | SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000, | ||
225 | SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000, | ||
226 | }; | ||
227 | |||
228 | union snd_pcm_sync_id { | ||
229 | unsigned char id[16]; | ||
230 | unsigned short id16[8]; | ||
231 | unsigned int id32[4]; | ||
232 | }; | ||
233 | |||
234 | struct 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 | |||
250 | typedef 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 | |||
276 | struct 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 | |||
286 | struct snd_mask { | ||
287 | __u32 bits[(SNDRV_MASK_MAX+31)/32]; | ||
288 | }; | ||
289 | |||
290 | struct 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 | |||
308 | enum { | ||
309 | SNDRV_PCM_TSTAMP_NONE = 0, | ||
310 | SNDRV_PCM_TSTAMP_ENABLE, | ||
311 | SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE, | ||
312 | }; | ||
313 | |||
314 | struct 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 | |||
328 | struct snd_pcm_channel_info { | ||
329 | unsigned int channel; | ||
330 | __kernel_off_t offset; | ||
331 | unsigned int first; | ||
332 | unsigned int step; | ||
333 | }; | ||
334 | |||
335 | struct 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 | |||
349 | struct 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 | |||
357 | struct 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 | |||
366 | struct 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 | |||
378 | struct snd_xferi { | ||
379 | snd_pcm_sframes_t result; | ||
380 | void __user *buf; | ||
381 | snd_pcm_uframes_t frames; | ||
382 | }; | ||
383 | |||
384 | struct snd_xfern { | ||
385 | snd_pcm_sframes_t result; | ||
386 | void __user * __user *bufs; | ||
387 | snd_pcm_uframes_t frames; | ||
388 | }; | ||
389 | |||
390 | enum { | ||
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 | |||
428 | enum { | ||
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 | |||
438 | struct 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 | |||
452 | struct 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 | |||
460 | struct 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 | |||
477 | enum { | ||
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 | |||
486 | enum { | ||
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 | |||
501 | struct snd_timer_id { | ||
502 | int dev_class; | ||
503 | int dev_sclass; | ||
504 | int card; | ||
505 | int device; | ||
506 | int subdevice; | ||
507 | }; | ||
508 | |||
509 | struct 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 | |||
523 | struct 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 | |||
530 | struct 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 | |||
538 | struct snd_timer_select { | ||
539 | struct snd_timer_id id; | ||
540 | unsigned char reserved[32]; | ||
541 | }; | ||
542 | |||
543 | struct 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 | |||
557 | struct 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 | |||
566 | struct 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 | |||
591 | struct snd_timer_read { | ||
592 | unsigned int resolution; | ||
593 | unsigned int ticks; | ||
594 | }; | ||
595 | |||
596 | enum { | ||
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 | |||
615 | struct 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 | |||
623 | struct 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 | |||
635 | typedef 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 | |||
645 | typedef 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 | |||
677 | struct 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 | |||
686 | struct 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 | |||
695 | struct 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 | |||
726 | struct 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 | |||
752 | struct 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 | |||
784 | enum 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 | |||
795 | struct 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 | ||
821 | |||
diff --git a/firmware/target/hosted/android/dx50/tinyalsa/asoundlib.h b/firmware/target/hosted/android/dx50/tinyalsa/asoundlib.h new file mode 100644 index 0000000000..6aacae46d6 --- /dev/null +++ b/firmware/target/hosted/android/dx50/tinyalsa/asoundlib.h | |||
@@ -0,0 +1,257 @@ | |||
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) | ||
36 | extern "C" { | ||
37 | #endif | ||
38 | |||
39 | /* | ||
40 | * PCM API | ||
41 | */ | ||
42 | |||
43 | struct 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 | |||
59 | /* PCM runtime states */ | ||
60 | #define PCM_STATE_OPEN 0 | ||
61 | #define PCM_STATE_SETUP 1 | ||
62 | #define PCM_STATE_PREPARED 2 | ||
63 | #define PCM_STATE_RUNNING 3 | ||
64 | #define PCM_STATE_XRUN 4 | ||
65 | #define PCM_STATE_DRAINING 5 | ||
66 | #define PCM_STATE_PAUSED 6 | ||
67 | #define PCM_STATE_SUSPENDED 7 | ||
68 | #define PCM_STATE_DISCONNECTED 8 | ||
69 | |||
70 | /* Bit formats */ | ||
71 | enum pcm_format { | ||
72 | PCM_FORMAT_S16_LE = 0, | ||
73 | PCM_FORMAT_S32_LE, | ||
74 | PCM_FORMAT_S8, | ||
75 | PCM_FORMAT_S24_LE, | ||
76 | |||
77 | PCM_FORMAT_MAX, | ||
78 | }; | ||
79 | |||
80 | /* Configuration for a stream */ | ||
81 | struct pcm_config { | ||
82 | unsigned int channels; | ||
83 | unsigned int rate; | ||
84 | unsigned int period_size; | ||
85 | unsigned int period_count; | ||
86 | enum pcm_format format; | ||
87 | |||
88 | /* Values to use for the ALSA start, stop and silence thresholds. Setting | ||
89 | * any one of these values to 0 will cause the default tinyalsa values to be | ||
90 | * used instead. Tinyalsa defaults are as follows. | ||
91 | * | ||
92 | * start_threshold : period_count * period_size | ||
93 | * stop_threshold : period_count * period_size | ||
94 | * silence_threshold : 0 | ||
95 | */ | ||
96 | unsigned int start_threshold; | ||
97 | unsigned int stop_threshold; | ||
98 | unsigned int silence_threshold; | ||
99 | }; | ||
100 | |||
101 | /* PCM parameters */ | ||
102 | enum pcm_param | ||
103 | { | ||
104 | PCM_PARAM_SAMPLE_BITS, | ||
105 | PCM_PARAM_FRAME_BITS, | ||
106 | PCM_PARAM_CHANNELS, | ||
107 | PCM_PARAM_RATE, | ||
108 | PCM_PARAM_PERIOD_TIME, | ||
109 | PCM_PARAM_PERIOD_SIZE, | ||
110 | PCM_PARAM_PERIOD_BYTES, | ||
111 | PCM_PARAM_PERIODS, | ||
112 | PCM_PARAM_BUFFER_TIME, | ||
113 | PCM_PARAM_BUFFER_SIZE, | ||
114 | PCM_PARAM_BUFFER_BYTES, | ||
115 | PCM_PARAM_TICK_TIME, | ||
116 | }; | ||
117 | |||
118 | /* Mixer control types */ | ||
119 | enum mixer_ctl_type { | ||
120 | MIXER_CTL_TYPE_BOOL, | ||
121 | MIXER_CTL_TYPE_INT, | ||
122 | MIXER_CTL_TYPE_ENUM, | ||
123 | MIXER_CTL_TYPE_BYTE, | ||
124 | MIXER_CTL_TYPE_IEC958, | ||
125 | MIXER_CTL_TYPE_INT64, | ||
126 | MIXER_CTL_TYPE_UNKNOWN, | ||
127 | |||
128 | MIXER_CTL_TYPE_MAX, | ||
129 | }; | ||
130 | |||
131 | /* Open and close a stream */ | ||
132 | struct pcm *pcm_open(unsigned int card, unsigned int device, | ||
133 | unsigned int flags, struct pcm_config *config); | ||
134 | int pcm_close(struct pcm *pcm); | ||
135 | int pcm_is_ready(struct pcm *pcm); | ||
136 | |||
137 | /* Obtain the parameters for a PCM */ | ||
138 | struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, | ||
139 | unsigned int flags); | ||
140 | void pcm_params_free(struct pcm_params *pcm_params); | ||
141 | unsigned int pcm_params_get_min(struct pcm_params *pcm_params, | ||
142 | enum pcm_param param); | ||
143 | unsigned int pcm_params_get_max(struct pcm_params *pcm_params, | ||
144 | enum pcm_param param); | ||
145 | |||
146 | /* Set and get config */ | ||
147 | int pcm_get_config(struct pcm *pcm, struct pcm_config *config); | ||
148 | int pcm_set_config(struct pcm *pcm, struct pcm_config *config); | ||
149 | |||
150 | /* Returns a human readable reason for the last error */ | ||
151 | const char *pcm_get_error(struct pcm *pcm); | ||
152 | |||
153 | /* Returns the sample size in bits for a PCM format. | ||
154 | * As with ALSA formats, this is the storage size for the format, whereas the | ||
155 | * format represents the number of significant bits. For example, | ||
156 | * PCM_FORMAT_S24_LE uses 32 bits of storage. | ||
157 | */ | ||
158 | unsigned int pcm_format_to_bits(enum pcm_format format); | ||
159 | |||
160 | /* Returns the buffer size (int frames) that should be used for pcm_write. */ | ||
161 | unsigned int pcm_get_buffer_size(struct pcm *pcm); | ||
162 | unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames); | ||
163 | unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes); | ||
164 | |||
165 | /* Returns the pcm latency in ms */ | ||
166 | unsigned int pcm_get_latency(struct pcm *pcm); | ||
167 | |||
168 | /* Returns available frames in pcm buffer and corresponding time stamp. | ||
169 | * For an input stream, frames available are frames ready for the | ||
170 | * application to read. | ||
171 | * For an output stream, frames available are the number of empty frames available | ||
172 | * for the application to write. | ||
173 | */ | ||
174 | int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail, | ||
175 | struct timespec *tstamp); | ||
176 | |||
177 | /* Write data to the fifo. | ||
178 | * Will start playback on the first write or on a write that | ||
179 | * occurs after a fifo underrun. | ||
180 | */ | ||
181 | int pcm_write(struct pcm *pcm, const void *data, unsigned int count); | ||
182 | int pcm_read(struct pcm *pcm, void *data, unsigned int count); | ||
183 | |||
184 | /* | ||
185 | * mmap() support. | ||
186 | */ | ||
187 | int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count); | ||
188 | int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, | ||
189 | unsigned int *frames); | ||
190 | int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames); | ||
191 | |||
192 | |||
193 | /* Start and stop a PCM channel that doesn't transfer data */ | ||
194 | int pcm_start(struct pcm *pcm); | ||
195 | int pcm_stop(struct pcm *pcm); | ||
196 | |||
197 | /* Interrupt driven API */ | ||
198 | int pcm_wait(struct pcm *pcm, int timeout); | ||
199 | |||
200 | int pcm_avail_update(struct pcm *pcm); | ||
201 | |||
202 | int pcm_state(struct pcm *pcm); | ||
203 | |||
204 | |||
205 | /* | ||
206 | * MIXER API | ||
207 | */ | ||
208 | |||
209 | struct mixer; | ||
210 | struct mixer_ctl; | ||
211 | |||
212 | /* Open and close a mixer */ | ||
213 | struct mixer *mixer_open(unsigned int card); | ||
214 | void mixer_close(struct mixer *mixer); | ||
215 | |||
216 | /* Get info about a mixer */ | ||
217 | const char *mixer_get_name(struct mixer *mixer); | ||
218 | |||
219 | /* Obtain mixer controls */ | ||
220 | unsigned int mixer_get_num_ctls(struct mixer *mixer); | ||
221 | struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id); | ||
222 | struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name); | ||
223 | |||
224 | /* Get info about mixer controls */ | ||
225 | const char *mixer_ctl_get_name(struct mixer_ctl *ctl); | ||
226 | enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl); | ||
227 | const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl); | ||
228 | unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl); | ||
229 | unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl); | ||
230 | const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl, | ||
231 | unsigned int enum_id); | ||
232 | |||
233 | /* Some sound cards update their controls due to external events, | ||
234 | * such as HDMI EDID byte data changing when an HDMI cable is | ||
235 | * connected. This API allows the count of elements to be updated. | ||
236 | */ | ||
237 | void mixer_ctl_update(struct mixer_ctl *ctl); | ||
238 | |||
239 | /* Set and get mixer controls */ | ||
240 | int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id); | ||
241 | int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent); | ||
242 | |||
243 | int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id); | ||
244 | int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count); | ||
245 | int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value); | ||
246 | int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count); | ||
247 | int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string); | ||
248 | |||
249 | /* Determe range of integer mixer controls */ | ||
250 | int mixer_ctl_get_range_min(struct mixer_ctl *ctl); | ||
251 | int mixer_ctl_get_range_max(struct mixer_ctl *ctl); | ||
252 | |||
253 | #if defined(__cplusplus) | ||
254 | } /* extern "C" */ | ||
255 | #endif | ||
256 | |||
257 | #endif | ||
diff --git a/firmware/target/hosted/android/dx50/tinyalsa/mixer.c b/firmware/target/hosted/android/dx50/tinyalsa/mixer.c new file mode 100644 index 0000000000..f75dec488a --- /dev/null +++ b/firmware/target/hosted/android/dx50/tinyalsa/mixer.c | |||
@@ -0,0 +1,497 @@ | |||
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 <tinyalsa/asound.h> | ||
44 | |||
45 | #include <tinyalsa/asoundlib.h> | ||
46 | |||
47 | struct mixer_ctl { | ||
48 | struct mixer *mixer; | ||
49 | struct snd_ctl_elem_info *info; | ||
50 | char **ename; | ||
51 | }; | ||
52 | |||
53 | struct 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 | |||
61 | void 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 | |||
91 | struct 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 | |||
161 | fail: | ||
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 | |||
172 | const char *mixer_get_name(struct mixer *mixer) | ||
173 | { | ||
174 | return (const char *)mixer->card_info.name; | ||
175 | } | ||
176 | |||
177 | unsigned int mixer_get_num_ctls(struct mixer *mixer) | ||
178 | { | ||
179 | if (!mixer) | ||
180 | return 0; | ||
181 | |||
182 | return mixer->count; | ||
183 | } | ||
184 | |||
185 | struct 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 | |||
193 | struct 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 | |||
207 | void mixer_ctl_update(struct mixer_ctl *ctl) | ||
208 | { | ||
209 | ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info); | ||
210 | } | ||
211 | |||
212 | const 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 | |||
220 | enum 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 | |||
236 | const 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 | |||
252 | unsigned 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 | |||
260 | static int percent_to_int(struct snd_ctl_elem_info *ei, int percent) | ||
261 | { | ||
262 | int range; | ||
263 | |||
264 | if (percent > 100) | ||
265 | percent = 100; | ||
266 | else if (percent < 0) | ||
267 | percent = 0; | ||
268 | |||
269 | range = (ei->value.integer.max - ei->value.integer.min); | ||
270 | |||
271 | return ei->value.integer.min + (range * percent) / 100; | ||
272 | } | ||
273 | |||
274 | static int int_to_percent(struct snd_ctl_elem_info *ei, int value) | ||
275 | { | ||
276 | int range = (ei->value.integer.max - ei->value.integer.min); | ||
277 | |||
278 | if (range == 0) | ||
279 | return 0; | ||
280 | |||
281 | return ((value - ei->value.integer.min) / range) * 100; | ||
282 | } | ||
283 | |||
284 | int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id) | ||
285 | { | ||
286 | if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) | ||
287 | return -EINVAL; | ||
288 | |||
289 | return int_to_percent(ctl->info, mixer_ctl_get_value(ctl, id)); | ||
290 | } | ||
291 | |||
292 | int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent) | ||
293 | { | ||
294 | if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) | ||
295 | return -EINVAL; | ||
296 | |||
297 | return mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent)); | ||
298 | } | ||
299 | |||
300 | int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id) | ||
301 | { | ||
302 | struct snd_ctl_elem_value ev; | ||
303 | int ret; | ||
304 | |||
305 | if (!ctl || (id >= ctl->info->count)) | ||
306 | return -EINVAL; | ||
307 | |||
308 | memset(&ev, 0, sizeof(ev)); | ||
309 | ev.id.numid = ctl->info->id.numid; | ||
310 | ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); | ||
311 | if (ret < 0) | ||
312 | return ret; | ||
313 | |||
314 | switch (ctl->info->type) { | ||
315 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: | ||
316 | return !!ev.value.integer.value[id]; | ||
317 | |||
318 | case SNDRV_CTL_ELEM_TYPE_INTEGER: | ||
319 | return ev.value.integer.value[id]; | ||
320 | |||
321 | case SNDRV_CTL_ELEM_TYPE_ENUMERATED: | ||
322 | return ev.value.enumerated.item[id]; | ||
323 | |||
324 | case SNDRV_CTL_ELEM_TYPE_BYTES: | ||
325 | return ev.value.bytes.data[id]; | ||
326 | |||
327 | default: | ||
328 | return -EINVAL; | ||
329 | } | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count) | ||
335 | { | ||
336 | struct snd_ctl_elem_value ev; | ||
337 | int ret; | ||
338 | size_t size; | ||
339 | void *source; | ||
340 | |||
341 | if (!ctl || (count > ctl->info->count) || !count || !array) | ||
342 | return -EINVAL; | ||
343 | |||
344 | memset(&ev, 0, sizeof(ev)); | ||
345 | ev.id.numid = ctl->info->id.numid; | ||
346 | |||
347 | ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); | ||
348 | if (ret < 0) | ||
349 | return ret; | ||
350 | |||
351 | switch (ctl->info->type) { | ||
352 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: | ||
353 | case SNDRV_CTL_ELEM_TYPE_INTEGER: | ||
354 | size = sizeof(ev.value.integer.value[0]); | ||
355 | source = ev.value.integer.value; | ||
356 | break; | ||
357 | |||
358 | case SNDRV_CTL_ELEM_TYPE_BYTES: | ||
359 | size = sizeof(ev.value.bytes.data[0]); | ||
360 | source = ev.value.bytes.data; | ||
361 | break; | ||
362 | |||
363 | default: | ||
364 | return -EINVAL; | ||
365 | } | ||
366 | |||
367 | memcpy(array, source, size * count); | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value) | ||
373 | { | ||
374 | struct snd_ctl_elem_value ev; | ||
375 | int ret; | ||
376 | |||
377 | if (!ctl || (id >= ctl->info->count)) | ||
378 | return -EINVAL; | ||
379 | |||
380 | memset(&ev, 0, sizeof(ev)); | ||
381 | ev.id.numid = ctl->info->id.numid; | ||
382 | ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); | ||
383 | if (ret < 0) | ||
384 | return ret; | ||
385 | |||
386 | switch (ctl->info->type) { | ||
387 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: | ||
388 | ev.value.integer.value[id] = !!value; | ||
389 | break; | ||
390 | |||
391 | case SNDRV_CTL_ELEM_TYPE_INTEGER: | ||
392 | ev.value.integer.value[id] = value; | ||
393 | break; | ||
394 | |||
395 | case SNDRV_CTL_ELEM_TYPE_ENUMERATED: | ||
396 | ev.value.enumerated.item[id] = value; | ||
397 | break; | ||
398 | |||
399 | default: | ||
400 | return -EINVAL; | ||
401 | } | ||
402 | |||
403 | return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); | ||
404 | } | ||
405 | |||
406 | int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count) | ||
407 | { | ||
408 | struct snd_ctl_elem_value ev; | ||
409 | size_t size; | ||
410 | void *dest; | ||
411 | |||
412 | if (!ctl || (count > ctl->info->count) || !count || !array) | ||
413 | return -EINVAL; | ||
414 | |||
415 | memset(&ev, 0, sizeof(ev)); | ||
416 | ev.id.numid = ctl->info->id.numid; | ||
417 | |||
418 | switch (ctl->info->type) { | ||
419 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: | ||
420 | case SNDRV_CTL_ELEM_TYPE_INTEGER: | ||
421 | size = sizeof(ev.value.integer.value[0]); | ||
422 | dest = ev.value.integer.value; | ||
423 | break; | ||
424 | |||
425 | case SNDRV_CTL_ELEM_TYPE_BYTES: | ||
426 | size = sizeof(ev.value.bytes.data[0]); | ||
427 | dest = ev.value.bytes.data; | ||
428 | break; | ||
429 | |||
430 | default: | ||
431 | return -EINVAL; | ||
432 | } | ||
433 | |||
434 | memcpy(dest, array, size * count); | ||
435 | |||
436 | return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); | ||
437 | } | ||
438 | |||
439 | int mixer_ctl_get_range_min(struct mixer_ctl *ctl) | ||
440 | { | ||
441 | if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) | ||
442 | return -EINVAL; | ||
443 | |||
444 | return ctl->info->value.integer.min; | ||
445 | } | ||
446 | |||
447 | int mixer_ctl_get_range_max(struct mixer_ctl *ctl) | ||
448 | { | ||
449 | if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) | ||
450 | return -EINVAL; | ||
451 | |||
452 | return ctl->info->value.integer.max; | ||
453 | } | ||
454 | |||
455 | unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl) | ||
456 | { | ||
457 | if (!ctl) | ||
458 | return 0; | ||
459 | |||
460 | return ctl->info->value.enumerated.items; | ||
461 | } | ||
462 | |||
463 | const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl, | ||
464 | unsigned int enum_id) | ||
465 | { | ||
466 | if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) || | ||
467 | (enum_id >= ctl->info->value.enumerated.items)) | ||
468 | return NULL; | ||
469 | |||
470 | return (const char *)ctl->ename[enum_id]; | ||
471 | } | ||
472 | |||
473 | int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string) | ||
474 | { | ||
475 | unsigned int i, num_enums; | ||
476 | struct snd_ctl_elem_value ev; | ||
477 | int ret; | ||
478 | |||
479 | if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED)) | ||
480 | return -EINVAL; | ||
481 | |||
482 | num_enums = ctl->info->value.enumerated.items; | ||
483 | for (i = 0; i < num_enums; i++) { | ||
484 | if (!strcmp(string, ctl->ename[i])) { | ||
485 | memset(&ev, 0, sizeof(ev)); | ||
486 | ev.value.enumerated.item[0] = i; | ||
487 | ev.id.numid = ctl->info->id.numid; | ||
488 | ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); | ||
489 | if (ret < 0) | ||
490 | return ret; | ||
491 | return 0; | ||
492 | } | ||
493 | } | ||
494 | |||
495 | return -EINVAL; | ||
496 | } | ||
497 | |||
diff --git a/firmware/target/hosted/android/dx50/tinyalsa/pcm.c b/firmware/target/hosted/android/dx50/tinyalsa/pcm.c new file mode 100644 index 0000000000..bd44dce52f --- /dev/null +++ b/firmware/target/hosted/android/dx50/tinyalsa/pcm.c | |||
@@ -0,0 +1,973 @@ | |||
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 <tinyalsa/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 | |||
54 | static 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 | |||
60 | static 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 | |||
66 | static 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 | |||
71 | static 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 | |||
76 | static 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 | |||
88 | static 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 | |||
96 | static 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 | |||
105 | static 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 | |||
114 | static 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 | |||
124 | static 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 | |||
134 | static 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 | |||
158 | struct pcm { | ||
159 | int fd; | ||
160 | unsigned int flags; | ||
161 | int running:1; | ||
162 | int underruns; | ||
163 | unsigned int buffer_size; | ||
164 | unsigned int boundary; | ||
165 | char error[PCM_ERROR_MAX]; | ||
166 | struct pcm_config config; | ||
167 | struct snd_pcm_mmap_status *mmap_status; | ||
168 | struct snd_pcm_mmap_control *mmap_control; | ||
169 | struct snd_pcm_sync_ptr *sync_ptr; | ||
170 | void *mmap_buffer; | ||
171 | unsigned int noirq_frames_per_msec; | ||
172 | }; | ||
173 | |||
174 | unsigned int pcm_get_buffer_size(struct pcm *pcm) | ||
175 | { | ||
176 | return pcm->buffer_size; | ||
177 | } | ||
178 | |||
179 | const char* pcm_get_error(struct pcm *pcm) | ||
180 | { | ||
181 | return pcm->error; | ||
182 | } | ||
183 | |||
184 | static int oops(struct pcm *pcm, int e, const char *fmt, ...) | ||
185 | { | ||
186 | va_list ap; | ||
187 | int sz; | ||
188 | |||
189 | va_start(ap, fmt); | ||
190 | vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap); | ||
191 | va_end(ap); | ||
192 | sz = strlen(pcm->error); | ||
193 | |||
194 | if (errno) | ||
195 | snprintf(pcm->error + sz, PCM_ERROR_MAX - sz, | ||
196 | ": %s", strerror(e)); | ||
197 | return -1; | ||
198 | } | ||
199 | |||
200 | static unsigned int pcm_format_to_alsa(enum pcm_format format) | ||
201 | { | ||
202 | switch (format) { | ||
203 | case PCM_FORMAT_S32_LE: | ||
204 | return SNDRV_PCM_FORMAT_S32_LE; | ||
205 | case PCM_FORMAT_S8: | ||
206 | return SNDRV_PCM_FORMAT_S8; | ||
207 | case PCM_FORMAT_S24_LE: | ||
208 | return SNDRV_PCM_FORMAT_S24_LE; | ||
209 | default: | ||
210 | case PCM_FORMAT_S16_LE: | ||
211 | return SNDRV_PCM_FORMAT_S16_LE; | ||
212 | }; | ||
213 | } | ||
214 | |||
215 | unsigned int pcm_format_to_bits(enum pcm_format format) | ||
216 | { | ||
217 | switch (format) { | ||
218 | case PCM_FORMAT_S32_LE: | ||
219 | case PCM_FORMAT_S24_LE: | ||
220 | return 32; | ||
221 | default: | ||
222 | case PCM_FORMAT_S16_LE: | ||
223 | return 16; | ||
224 | }; | ||
225 | } | ||
226 | |||
227 | unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes) | ||
228 | { | ||
229 | return bytes / (pcm->config.channels * | ||
230 | (pcm_format_to_bits(pcm->config.format) >> 3)); | ||
231 | } | ||
232 | |||
233 | unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames) | ||
234 | { | ||
235 | return frames * pcm->config.channels * | ||
236 | (pcm_format_to_bits(pcm->config.format) >> 3); | ||
237 | } | ||
238 | |||
239 | static int pcm_sync_ptr(struct pcm *pcm, int flags) { | ||
240 | if (pcm->sync_ptr) { | ||
241 | pcm->sync_ptr->flags = flags; | ||
242 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr) < 0) | ||
243 | return -1; | ||
244 | } | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int pcm_hw_mmap_status(struct pcm *pcm) { | ||
249 | |||
250 | if (pcm->sync_ptr) | ||
251 | return 0; | ||
252 | |||
253 | int page_size = sysconf(_SC_PAGE_SIZE); | ||
254 | pcm->mmap_status = mmap(NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED, | ||
255 | pcm->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); | ||
256 | if (pcm->mmap_status == MAP_FAILED) | ||
257 | pcm->mmap_status = NULL; | ||
258 | if (!pcm->mmap_status) | ||
259 | goto mmap_error; | ||
260 | |||
261 | pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE, | ||
262 | MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); | ||
263 | if (pcm->mmap_control == MAP_FAILED) | ||
264 | pcm->mmap_control = NULL; | ||
265 | if (!pcm->mmap_control) { | ||
266 | munmap(pcm->mmap_status, page_size); | ||
267 | pcm->mmap_status = NULL; | ||
268 | goto mmap_error; | ||
269 | } | ||
270 | pcm->mmap_control->avail_min = 1; | ||
271 | |||
272 | return 0; | ||
273 | |||
274 | mmap_error: | ||
275 | |||
276 | pcm->sync_ptr = calloc(1, sizeof(*pcm->sync_ptr)); | ||
277 | if (!pcm->sync_ptr) | ||
278 | return -ENOMEM; | ||
279 | pcm->mmap_status = &pcm->sync_ptr->s.status; | ||
280 | pcm->mmap_control = &pcm->sync_ptr->c.control; | ||
281 | pcm->mmap_control->avail_min = 1; | ||
282 | pcm_sync_ptr(pcm, 0); | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static void pcm_hw_munmap_status(struct pcm *pcm) { | ||
288 | if (pcm->sync_ptr) { | ||
289 | free(pcm->sync_ptr); | ||
290 | pcm->sync_ptr = NULL; | ||
291 | } else { | ||
292 | int page_size = sysconf(_SC_PAGE_SIZE); | ||
293 | if (pcm->mmap_status) | ||
294 | munmap(pcm->mmap_status, page_size); | ||
295 | if (pcm->mmap_control) | ||
296 | munmap(pcm->mmap_control, page_size); | ||
297 | } | ||
298 | pcm->mmap_status = NULL; | ||
299 | pcm->mmap_control = NULL; | ||
300 | } | ||
301 | |||
302 | static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset, | ||
303 | const char *src, unsigned int src_offset, | ||
304 | unsigned int frames) | ||
305 | { | ||
306 | int size_bytes = pcm_frames_to_bytes(pcm, frames); | ||
307 | int pcm_offset_bytes = pcm_frames_to_bytes(pcm, pcm_offset); | ||
308 | int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset); | ||
309 | |||
310 | /* interleaved only atm */ | ||
311 | memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes, | ||
312 | src + src_offset_bytes, size_bytes); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int pcm_mmap_write_areas(struct pcm *pcm, const char *src, | ||
317 | unsigned int offset, unsigned int size) | ||
318 | { | ||
319 | void *pcm_areas; | ||
320 | int commit; | ||
321 | unsigned int pcm_offset, frames, count = 0; | ||
322 | |||
323 | while (size > 0) { | ||
324 | frames = size; | ||
325 | pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); | ||
326 | pcm_areas_copy(pcm, pcm_offset, src, offset, frames); | ||
327 | commit = pcm_mmap_commit(pcm, pcm_offset, frames); | ||
328 | if (commit < 0) { | ||
329 | oops(pcm, commit, "failed to commit %d frames\n", frames); | ||
330 | return commit; | ||
331 | } | ||
332 | |||
333 | offset += commit; | ||
334 | count += commit; | ||
335 | size -= commit; | ||
336 | } | ||
337 | return count; | ||
338 | } | ||
339 | |||
340 | int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail, | ||
341 | struct timespec *tstamp) | ||
342 | { | ||
343 | int frames; | ||
344 | int rc; | ||
345 | snd_pcm_uframes_t hw_ptr; | ||
346 | |||
347 | if (!pcm_is_ready(pcm)) | ||
348 | return -1; | ||
349 | |||
350 | rc = pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_APPL|SNDRV_PCM_SYNC_PTR_HWSYNC); | ||
351 | if (rc < 0) | ||
352 | return -1; | ||
353 | |||
354 | if ((pcm->mmap_status->state != PCM_STATE_RUNNING) && | ||
355 | (pcm->mmap_status->state != PCM_STATE_DRAINING)) | ||
356 | return -1; | ||
357 | |||
358 | *tstamp = pcm->mmap_status->tstamp; | ||
359 | if (tstamp->tv_sec == 0 && tstamp->tv_nsec == 0) | ||
360 | return -1; | ||
361 | |||
362 | hw_ptr = pcm->mmap_status->hw_ptr; | ||
363 | if (pcm->flags & PCM_IN) | ||
364 | frames = hw_ptr - pcm->mmap_control->appl_ptr; | ||
365 | else | ||
366 | frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; | ||
367 | |||
368 | if (frames < 0) | ||
369 | return -1; | ||
370 | |||
371 | *avail = (unsigned int)frames; | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | int pcm_write(struct pcm *pcm, const void *data, unsigned int count) | ||
377 | { | ||
378 | struct snd_xferi x; | ||
379 | |||
380 | if (pcm->flags & PCM_IN) | ||
381 | return -EINVAL; | ||
382 | |||
383 | x.buf = (void*)data; | ||
384 | x.frames = count / (pcm->config.channels * | ||
385 | pcm_format_to_bits(pcm->config.format) / 8); | ||
386 | |||
387 | for (;;) { | ||
388 | if (!pcm->running) { | ||
389 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) | ||
390 | return oops(pcm, errno, "cannot prepare channel"); | ||
391 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) | ||
392 | return oops(pcm, errno, "cannot write initial data"); | ||
393 | pcm->running = 1; | ||
394 | return 0; | ||
395 | } | ||
396 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { | ||
397 | pcm->running = 0; | ||
398 | if (errno == EPIPE) { | ||
399 | /* we failed to make our window -- try to restart if we are | ||
400 | * allowed to do so. Otherwise, simply allow the EPIPE error to | ||
401 | * propagate up to the app level */ | ||
402 | pcm->underruns++; | ||
403 | if (pcm->flags & PCM_NORESTART) | ||
404 | return -EPIPE; | ||
405 | continue; | ||
406 | } | ||
407 | return oops(pcm, errno, "cannot write stream data"); | ||
408 | } | ||
409 | return 0; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | int pcm_read(struct pcm *pcm, void *data, unsigned int count) | ||
414 | { | ||
415 | struct snd_xferi x; | ||
416 | |||
417 | if (!(pcm->flags & PCM_IN)) | ||
418 | return -EINVAL; | ||
419 | |||
420 | x.buf = data; | ||
421 | x.frames = count / (pcm->config.channels * | ||
422 | pcm_format_to_bits(pcm->config.format) / 8); | ||
423 | |||
424 | for (;;) { | ||
425 | if (!pcm->running) { | ||
426 | if (pcm_start(pcm) < 0) { | ||
427 | fprintf(stderr, "start error"); | ||
428 | return -errno; | ||
429 | } | ||
430 | } | ||
431 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { | ||
432 | pcm->running = 0; | ||
433 | if (errno == EPIPE) { | ||
434 | /* we failed to make our window -- try to restart */ | ||
435 | pcm->underruns++; | ||
436 | continue; | ||
437 | } | ||
438 | return oops(pcm, errno, "cannot read stream data"); | ||
439 | } | ||
440 | return 0; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | static struct pcm bad_pcm = { | ||
445 | .fd = -1, | ||
446 | }; | ||
447 | |||
448 | struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, | ||
449 | unsigned int flags) | ||
450 | { | ||
451 | struct snd_pcm_hw_params *params; | ||
452 | char fn[256]; | ||
453 | int fd; | ||
454 | |||
455 | snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, | ||
456 | flags & PCM_IN ? 'c' : 'p'); | ||
457 | |||
458 | fd = open(fn, O_RDWR); | ||
459 | if (fd < 0) { | ||
460 | fprintf(stderr, "cannot open device '%s'\n", fn); | ||
461 | goto err_open; | ||
462 | } | ||
463 | |||
464 | params = calloc(1, sizeof(struct snd_pcm_hw_params)); | ||
465 | if (!params) | ||
466 | goto err_calloc; | ||
467 | |||
468 | param_init(params); | ||
469 | if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params)) { | ||
470 | fprintf(stderr, "SNDRV_PCM_IOCTL_HW_REFINE error (%d)\n", errno); | ||
471 | goto err_hw_refine; | ||
472 | } | ||
473 | |||
474 | close(fd); | ||
475 | |||
476 | return (struct pcm_params *)params; | ||
477 | |||
478 | err_hw_refine: | ||
479 | free(params); | ||
480 | err_calloc: | ||
481 | close(fd); | ||
482 | err_open: | ||
483 | return NULL; | ||
484 | } | ||
485 | |||
486 | void pcm_params_free(struct pcm_params *pcm_params) | ||
487 | { | ||
488 | struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; | ||
489 | |||
490 | if (params) | ||
491 | free(params); | ||
492 | } | ||
493 | |||
494 | static int pcm_param_to_alsa(enum pcm_param param) | ||
495 | { | ||
496 | switch (param) { | ||
497 | case PCM_PARAM_SAMPLE_BITS: | ||
498 | return SNDRV_PCM_HW_PARAM_SAMPLE_BITS; | ||
499 | break; | ||
500 | case PCM_PARAM_FRAME_BITS: | ||
501 | return SNDRV_PCM_HW_PARAM_FRAME_BITS; | ||
502 | break; | ||
503 | case PCM_PARAM_CHANNELS: | ||
504 | return SNDRV_PCM_HW_PARAM_CHANNELS; | ||
505 | break; | ||
506 | case PCM_PARAM_RATE: | ||
507 | return SNDRV_PCM_HW_PARAM_RATE; | ||
508 | break; | ||
509 | case PCM_PARAM_PERIOD_TIME: | ||
510 | return SNDRV_PCM_HW_PARAM_PERIOD_TIME; | ||
511 | break; | ||
512 | case PCM_PARAM_PERIOD_SIZE: | ||
513 | return SNDRV_PCM_HW_PARAM_PERIOD_SIZE; | ||
514 | break; | ||
515 | case PCM_PARAM_PERIOD_BYTES: | ||
516 | return SNDRV_PCM_HW_PARAM_PERIOD_BYTES; | ||
517 | break; | ||
518 | case PCM_PARAM_PERIODS: | ||
519 | return SNDRV_PCM_HW_PARAM_PERIODS; | ||
520 | break; | ||
521 | case PCM_PARAM_BUFFER_TIME: | ||
522 | return SNDRV_PCM_HW_PARAM_BUFFER_TIME; | ||
523 | break; | ||
524 | case PCM_PARAM_BUFFER_SIZE: | ||
525 | return SNDRV_PCM_HW_PARAM_BUFFER_SIZE; | ||
526 | break; | ||
527 | case PCM_PARAM_BUFFER_BYTES: | ||
528 | return SNDRV_PCM_HW_PARAM_BUFFER_BYTES; | ||
529 | break; | ||
530 | case PCM_PARAM_TICK_TIME: | ||
531 | return SNDRV_PCM_HW_PARAM_TICK_TIME; | ||
532 | break; | ||
533 | |||
534 | default: | ||
535 | return -1; | ||
536 | } | ||
537 | } | ||
538 | |||
539 | unsigned int pcm_params_get_min(struct pcm_params *pcm_params, | ||
540 | enum pcm_param param) | ||
541 | { | ||
542 | struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; | ||
543 | int p; | ||
544 | |||
545 | if (!params) | ||
546 | return 0; | ||
547 | |||
548 | p = pcm_param_to_alsa(param); | ||
549 | if (p < 0) | ||
550 | return 0; | ||
551 | |||
552 | return param_get_min(params, p); | ||
553 | } | ||
554 | |||
555 | unsigned int pcm_params_get_max(struct pcm_params *pcm_params, | ||
556 | enum pcm_param param) | ||
557 | { | ||
558 | struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; | ||
559 | int p; | ||
560 | |||
561 | if (!params) | ||
562 | return 0; | ||
563 | |||
564 | p = pcm_param_to_alsa(param); | ||
565 | if (p < 0) | ||
566 | return 0; | ||
567 | |||
568 | return param_get_max(params, p); | ||
569 | } | ||
570 | |||
571 | int pcm_close(struct pcm *pcm) | ||
572 | { | ||
573 | if (pcm == &bad_pcm) | ||
574 | return 0; | ||
575 | |||
576 | pcm_hw_munmap_status(pcm); | ||
577 | |||
578 | if (pcm->flags & PCM_MMAP) { | ||
579 | pcm_stop(pcm); | ||
580 | munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); | ||
581 | } | ||
582 | |||
583 | if (pcm->fd >= 0) | ||
584 | close(pcm->fd); | ||
585 | pcm->running = 0; | ||
586 | pcm->buffer_size = 0; | ||
587 | pcm->fd = -1; | ||
588 | free(pcm); | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | struct pcm *pcm_open(unsigned int card, unsigned int device, | ||
593 | unsigned int flags, struct pcm_config *config) | ||
594 | { | ||
595 | struct pcm *pcm; | ||
596 | struct snd_pcm_info info; | ||
597 | struct snd_pcm_hw_params params; | ||
598 | struct snd_pcm_sw_params sparams; | ||
599 | char fn[256]; | ||
600 | int rc; | ||
601 | |||
602 | pcm = calloc(1, sizeof(struct pcm)); | ||
603 | if (!pcm || !config) | ||
604 | return &bad_pcm; /* TODO: could support default config here */ | ||
605 | |||
606 | pcm->config = *config; | ||
607 | |||
608 | snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, | ||
609 | flags & PCM_IN ? 'c' : 'p'); | ||
610 | |||
611 | pcm->flags = flags; | ||
612 | pcm->fd = open(fn, O_RDWR); | ||
613 | if (pcm->fd < 0) { | ||
614 | oops(pcm, errno, "cannot open device '%s'", fn); | ||
615 | return pcm; | ||
616 | } | ||
617 | |||
618 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { | ||
619 | oops(pcm, errno, "cannot get info"); | ||
620 | goto fail_close; | ||
621 | } | ||
622 | |||
623 | param_init(¶ms); | ||
624 | param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, | ||
625 | pcm_format_to_alsa(config->format)); | ||
626 | param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT, | ||
627 | SNDRV_PCM_SUBFORMAT_STD); | ||
628 | param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size); | ||
629 | param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
630 | pcm_format_to_bits(config->format)); | ||
631 | param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS, | ||
632 | pcm_format_to_bits(config->format) * config->channels); | ||
633 | param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
634 | config->channels); | ||
635 | param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count); | ||
636 | param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, config->rate); | ||
637 | |||
638 | if (flags & PCM_NOIRQ) { | ||
639 | |||
640 | if (!(flags & PCM_MMAP)) { | ||
641 | oops(pcm, -EINVAL, "noirq only currently supported with mmap()."); | ||
642 | goto fail; | ||
643 | } | ||
644 | |||
645 | params.flags |= SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP; | ||
646 | pcm->noirq_frames_per_msec = config->rate / 1000; | ||
647 | } | ||
648 | |||
649 | if (flags & PCM_MMAP) | ||
650 | param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, | ||
651 | SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); | ||
652 | else | ||
653 | param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, | ||
654 | SNDRV_PCM_ACCESS_RW_INTERLEAVED); | ||
655 | |||
656 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { | ||
657 | oops(pcm, errno, "cannot set hw params"); | ||
658 | goto fail_close; | ||
659 | } | ||
660 | |||
661 | /* get our refined hw_params */ | ||
662 | config->period_size = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); | ||
663 | config->period_count = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS); | ||
664 | pcm->buffer_size = config->period_count * config->period_size; | ||
665 | |||
666 | if (flags & PCM_MMAP) { | ||
667 | pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size), | ||
668 | PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0); | ||
669 | if (pcm->mmap_buffer == MAP_FAILED) { | ||
670 | oops(pcm, -errno, "failed to mmap buffer %d bytes\n", | ||
671 | pcm_frames_to_bytes(pcm, pcm->buffer_size)); | ||
672 | goto fail_close; | ||
673 | } | ||
674 | } | ||
675 | |||
676 | |||
677 | memset(&sparams, 0, sizeof(sparams)); | ||
678 | sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; | ||
679 | sparams.period_step = 1; | ||
680 | sparams.avail_min = 1; | ||
681 | |||
682 | if (!config->start_threshold) { | ||
683 | if (pcm->flags & PCM_IN) | ||
684 | pcm->config.start_threshold = sparams.start_threshold = 1; | ||
685 | else | ||
686 | pcm->config.start_threshold = sparams.start_threshold = | ||
687 | config->period_count * config->period_size / 2; | ||
688 | } else | ||
689 | sparams.start_threshold = config->start_threshold; | ||
690 | |||
691 | /* pick a high stop threshold - todo: does this need further tuning */ | ||
692 | if (!config->stop_threshold) { | ||
693 | if (pcm->flags & PCM_IN) | ||
694 | pcm->config.stop_threshold = sparams.stop_threshold = | ||
695 | config->period_count * config->period_size * 10; | ||
696 | else | ||
697 | pcm->config.stop_threshold = sparams.stop_threshold = | ||
698 | config->period_count * config->period_size; | ||
699 | } | ||
700 | else | ||
701 | sparams.stop_threshold = config->stop_threshold; | ||
702 | |||
703 | sparams.xfer_align = config->period_size / 2; /* needed for old kernels */ | ||
704 | sparams.silence_size = 0; | ||
705 | sparams.silence_threshold = config->silence_threshold; | ||
706 | pcm->boundary = sparams.boundary = pcm->buffer_size; | ||
707 | |||
708 | while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) | ||
709 | pcm->boundary *= 2; | ||
710 | |||
711 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { | ||
712 | oops(pcm, errno, "cannot set sw params"); | ||
713 | goto fail; | ||
714 | } | ||
715 | |||
716 | rc = pcm_hw_mmap_status(pcm); | ||
717 | if (rc < 0) { | ||
718 | oops(pcm, rc, "mmap status failed"); | ||
719 | goto fail; | ||
720 | } | ||
721 | |||
722 | pcm->underruns = 0; | ||
723 | return pcm; | ||
724 | |||
725 | fail: | ||
726 | if (flags & PCM_MMAP) | ||
727 | munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); | ||
728 | fail_close: | ||
729 | close(pcm->fd); | ||
730 | pcm->fd = -1; | ||
731 | return pcm; | ||
732 | } | ||
733 | |||
734 | int pcm_is_ready(struct pcm *pcm) | ||
735 | { | ||
736 | return pcm->fd >= 0; | ||
737 | } | ||
738 | |||
739 | int pcm_start(struct pcm *pcm) | ||
740 | { | ||
741 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) | ||
742 | return oops(pcm, errno, "cannot prepare channel"); | ||
743 | |||
744 | if (pcm->flags & PCM_MMAP) | ||
745 | pcm_sync_ptr(pcm, 0); | ||
746 | |||
747 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0) | ||
748 | return oops(pcm, errno, "cannot start channel"); | ||
749 | |||
750 | pcm->running = 1; | ||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | int pcm_stop(struct pcm *pcm) | ||
755 | { | ||
756 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) | ||
757 | return oops(pcm, errno, "cannot stop channel"); | ||
758 | |||
759 | pcm->running = 0; | ||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | static inline int pcm_mmap_playback_avail(struct pcm *pcm) | ||
764 | { | ||
765 | int avail; | ||
766 | |||
767 | avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; | ||
768 | |||
769 | if (avail < 0) | ||
770 | avail += pcm->boundary; | ||
771 | else if (avail > (int)pcm->boundary) | ||
772 | avail -= pcm->boundary; | ||
773 | |||
774 | return avail; | ||
775 | } | ||
776 | |||
777 | static inline int pcm_mmap_capture_avail(struct pcm *pcm) | ||
778 | { | ||
779 | int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr; | ||
780 | if (avail < 0) | ||
781 | avail += pcm->boundary; | ||
782 | return avail; | ||
783 | } | ||
784 | |||
785 | static inline int pcm_mmap_avail(struct pcm *pcm) | ||
786 | { | ||
787 | pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_HWSYNC); | ||
788 | if (pcm->flags & PCM_IN) | ||
789 | return pcm_mmap_capture_avail(pcm); | ||
790 | else | ||
791 | return pcm_mmap_playback_avail(pcm); | ||
792 | } | ||
793 | |||
794 | static void pcm_mmap_appl_forward(struct pcm *pcm, int frames) | ||
795 | { | ||
796 | unsigned int appl_ptr = pcm->mmap_control->appl_ptr; | ||
797 | appl_ptr += frames; | ||
798 | |||
799 | /* check for boundary wrap */ | ||
800 | if (appl_ptr > pcm->boundary) | ||
801 | appl_ptr -= pcm->boundary; | ||
802 | pcm->mmap_control->appl_ptr = appl_ptr; | ||
803 | } | ||
804 | |||
805 | int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, | ||
806 | unsigned int *frames) | ||
807 | { | ||
808 | unsigned int continuous, copy_frames, avail; | ||
809 | |||
810 | /* return the mmap buffer */ | ||
811 | *areas = pcm->mmap_buffer; | ||
812 | |||
813 | /* and the application offset in frames */ | ||
814 | *offset = pcm->mmap_control->appl_ptr % pcm->buffer_size; | ||
815 | |||
816 | avail = pcm_mmap_avail(pcm); | ||
817 | if (avail > pcm->buffer_size) | ||
818 | avail = pcm->buffer_size; | ||
819 | continuous = pcm->buffer_size - *offset; | ||
820 | |||
821 | /* we can only copy frames if the are availabale and continuos */ | ||
822 | copy_frames = *frames; | ||
823 | if (copy_frames > avail) | ||
824 | copy_frames = avail; | ||
825 | if (copy_frames > continuous) | ||
826 | copy_frames = continuous; | ||
827 | *frames = copy_frames; | ||
828 | |||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames) | ||
833 | { | ||
834 | (void)offset; | ||
835 | /* update the application pointer in userspace and kernel */ | ||
836 | pcm_mmap_appl_forward(pcm, frames); | ||
837 | pcm_sync_ptr(pcm, 0); | ||
838 | |||
839 | return frames; | ||
840 | } | ||
841 | |||
842 | int pcm_avail_update(struct pcm *pcm) | ||
843 | { | ||
844 | pcm_sync_ptr(pcm, 0); | ||
845 | return pcm_mmap_avail(pcm); | ||
846 | } | ||
847 | |||
848 | int pcm_state(struct pcm *pcm) | ||
849 | { | ||
850 | int err = pcm_sync_ptr(pcm, 0); | ||
851 | if (err < 0) | ||
852 | return err; | ||
853 | |||
854 | return pcm->mmap_status->state; | ||
855 | } | ||
856 | |||
857 | int pcm_wait(struct pcm *pcm, int timeout) | ||
858 | { | ||
859 | struct pollfd pfd; | ||
860 | int err; | ||
861 | |||
862 | pfd.fd = pcm->fd; | ||
863 | pfd.events = POLLOUT | POLLERR | POLLNVAL; | ||
864 | |||
865 | do { | ||
866 | /* let's wait for avail or timeout */ | ||
867 | err = poll(&pfd, 1, timeout); | ||
868 | if (err < 0) | ||
869 | return -errno; | ||
870 | |||
871 | /* timeout ? */ | ||
872 | if (err == 0) | ||
873 | return 0; | ||
874 | |||
875 | /* have we been interrupted ? */ | ||
876 | if (errno == -EINTR) | ||
877 | continue; | ||
878 | |||
879 | /* check for any errors */ | ||
880 | if (pfd.revents & (POLLERR | POLLNVAL)) { | ||
881 | switch (pcm_state(pcm)) { | ||
882 | case PCM_STATE_XRUN: | ||
883 | return -EPIPE; | ||
884 | case PCM_STATE_SUSPENDED: | ||
885 | return -ESTRPIPE; | ||
886 | case PCM_STATE_DISCONNECTED: | ||
887 | return -ENODEV; | ||
888 | default: | ||
889 | return -EIO; | ||
890 | } | ||
891 | } | ||
892 | /* poll again if fd not ready for IO */ | ||
893 | } while (!(pfd.revents & (POLLIN | POLLOUT))); | ||
894 | |||
895 | return 1; | ||
896 | } | ||
897 | |||
898 | int pcm_mmap_write(struct pcm *pcm, const void *buffer, unsigned int bytes) | ||
899 | { | ||
900 | int err = 0, frames, avail; | ||
901 | unsigned int offset = 0, count; | ||
902 | |||
903 | if (bytes == 0) | ||
904 | return 0; | ||
905 | |||
906 | count = pcm_bytes_to_frames(pcm, bytes); | ||
907 | |||
908 | while (count > 0) { | ||
909 | |||
910 | /* get the available space for writing new frames */ | ||
911 | avail = pcm_avail_update(pcm); | ||
912 | if (avail < 0) { | ||
913 | fprintf(stderr, "cannot determine available mmap frames"); | ||
914 | return err; | ||
915 | } | ||
916 | |||
917 | /* start the audio if we reach the threshold */ | ||
918 | if (!pcm->running && | ||
919 | (pcm->buffer_size - avail) >= pcm->config.start_threshold) { | ||
920 | if (pcm_start(pcm) < 0) { | ||
921 | fprintf(stderr, "start error: hw 0x%x app 0x%x avail 0x%x\n", | ||
922 | (unsigned int)pcm->mmap_status->hw_ptr, | ||
923 | (unsigned int)pcm->mmap_control->appl_ptr, | ||
924 | avail); | ||
925 | return -errno; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | /* sleep until we have space to write new frames */ | ||
930 | if (pcm->running && | ||
931 | (unsigned int)avail < pcm->mmap_control->avail_min) { | ||
932 | int time = -1; | ||
933 | |||
934 | if (pcm->flags & PCM_NOIRQ) | ||
935 | time = (pcm->buffer_size - avail - pcm->mmap_control->avail_min) | ||
936 | / pcm->noirq_frames_per_msec; | ||
937 | |||
938 | err = pcm_wait(pcm, time); | ||
939 | if (err < 0) { | ||
940 | pcm->running = 0; | ||
941 | fprintf(stderr, "wait error: hw 0x%x app 0x%x avail 0x%x\n", | ||
942 | (unsigned int)pcm->mmap_status->hw_ptr, | ||
943 | (unsigned int)pcm->mmap_control->appl_ptr, | ||
944 | avail); | ||
945 | pcm->mmap_control->appl_ptr = 0; | ||
946 | return err; | ||
947 | } | ||
948 | continue; | ||
949 | } | ||
950 | |||
951 | frames = count; | ||
952 | if (frames > avail) | ||
953 | frames = avail; | ||
954 | |||
955 | if (!frames) | ||
956 | break; | ||
957 | |||
958 | /* copy frames from buffer */ | ||
959 | frames = pcm_mmap_write_areas(pcm, buffer, offset, frames); | ||
960 | if (frames < 0) { | ||
961 | fprintf(stderr, "write error: hw 0x%x app 0x%x avail 0x%x\n", | ||
962 | (unsigned int)pcm->mmap_status->hw_ptr, | ||
963 | (unsigned int)pcm->mmap_control->appl_ptr, | ||
964 | avail); | ||
965 | return frames; | ||
966 | } | ||
967 | |||
968 | offset += frames; | ||
969 | count -= frames; | ||
970 | } | ||
971 | |||
972 | return 0; | ||
973 | } | ||
diff --git a/firmware/target/hosted/android/system-android.c b/firmware/target/hosted/android/system-android.c index d13b8d6462..6279504e48 100644 --- a/firmware/target/hosted/android/system-android.c +++ b/firmware/target/hosted/android/system-android.c | |||
@@ -23,6 +23,12 @@ | |||
23 | #include <setjmp.h> | 23 | #include <setjmp.h> |
24 | #include <jni.h> | 24 | #include <jni.h> |
25 | #include <pthread.h> | 25 | #include <pthread.h> |
26 | #if defined(DX50) || defined(DX90) | ||
27 | #include <stdlib.h> | ||
28 | #include <sys/reboot.h> | ||
29 | #include <sys/stat.h> | ||
30 | #include <stdio.h> | ||
31 | #endif /* DX50 || DX90 */ | ||
26 | #include <unistd.h> | 32 | #include <unistd.h> |
27 | #include "config.h" | 33 | #include "config.h" |
28 | #include "system.h" | 34 | #include "system.h" |
@@ -31,40 +37,83 @@ | |||
31 | 37 | ||
32 | 38 | ||
33 | 39 | ||
40 | #if !defined(DX50) && !defined(DX90) | ||
34 | /* global fields for use with various JNI calls */ | 41 | /* global fields for use with various JNI calls */ |
35 | static JavaVM *vm_ptr; | 42 | static JavaVM *vm_ptr; |
36 | JNIEnv *env_ptr; | 43 | JNIEnv *env_ptr; |
37 | jobject RockboxService_instance; | 44 | jobject RockboxService_instance; |
38 | jclass RockboxService_class; | 45 | jclass RockboxService_class; |
46 | #endif /* !DX50 && !DX90 */ | ||
39 | 47 | ||
40 | uintptr_t *stackbegin; | 48 | uintptr_t *stackbegin; |
41 | uintptr_t *stackend; | 49 | uintptr_t *stackend; |
42 | 50 | ||
43 | extern int main(void); | 51 | extern int main(void); |
52 | #if !defined(DX50) && !defined(DX90) | ||
44 | extern void telephony_init_device(void); | 53 | extern void telephony_init_device(void); |
45 | 54 | #endif | |
46 | void system_exception_wait(void) | 55 | void system_exception_wait(void) |
47 | { | 56 | { |
57 | #if defined(DX50) || defined(DX90) | ||
58 | while(1); | ||
59 | #else | ||
48 | intptr_t dummy = 0; | 60 | intptr_t dummy = 0; |
49 | while(button_read_device(&dummy) != BUTTON_BACK); | 61 | while(button_read_device(&dummy) != BUTTON_BACK); |
62 | #endif /* DX50 || DX90 */ | ||
50 | } | 63 | } |
51 | 64 | ||
52 | void system_reboot(void) | 65 | void system_reboot(void) |
53 | { | 66 | { |
67 | #if defined(DX50) || defined(DX90) | ||
68 | reboot(RB_AUTOBOOT); | ||
69 | #else | ||
54 | power_off(); | 70 | power_off(); |
71 | #endif /* DX50 || DX90 */ | ||
55 | } | 72 | } |
56 | 73 | ||
74 | #if !defined(DX50) && !defined(DX90) | ||
57 | /* this is used to return from the entry point of the native library. */ | 75 | /* this is used to return from the entry point of the native library. */ |
58 | static jmp_buf poweroff_buf; | 76 | static jmp_buf poweroff_buf; |
77 | #endif | ||
78 | |||
59 | void power_off(void) | 79 | void power_off(void) |
60 | { | 80 | { |
81 | #if defined(DX50) || defined(DX90) | ||
82 | reboot(RB_POWER_OFF); | ||
83 | #else | ||
61 | longjmp(poweroff_buf, 1); | 84 | longjmp(poweroff_buf, 1); |
85 | #endif /* DX50 || DX90 */ | ||
62 | } | 86 | } |
63 | 87 | ||
64 | void system_init(void) | 88 | void system_init(void) |
65 | { | 89 | { |
90 | #if defined(DX50) || defined(DX90) | ||
91 | volatile uintptr_t stack = 0; | ||
92 | stackbegin = stackend = (uintptr_t*) &stack; | ||
93 | |||
94 | struct stat m1, m2; | ||
95 | stat("/mnt/", &m1); | ||
96 | do | ||
97 | { | ||
98 | /* waiting for storage to get mounted */ | ||
99 | stat("/sdcard/", &m2); | ||
100 | usleep(100000); | ||
101 | } | ||
102 | while(m1.st_dev == m2.st_dev); | ||
103 | /* here would be the correct place for 'system("/system/bin/muteopen");' (headphone-out relay) but in pcm-dx50.c, pcm_play_dma_start() | ||
104 | the output capacitors are charged already a bit and the click of the headphone-connection-relay is softer */ | ||
105 | |||
106 | #if defined(DX90) | ||
107 | /* DAC needs to be unmuted on DX90 */ | ||
108 | FILE * f = fopen("/sys/class/codec/wm8740_mute", "w"); | ||
109 | fputc(0, f); | ||
110 | fclose(f); | ||
111 | #endif /* DX90 */ | ||
112 | |||
113 | #else | ||
66 | /* no better place yet */ | 114 | /* no better place yet */ |
67 | telephony_init_device(); | 115 | telephony_init_device(); |
116 | #endif /* DX50 || DX90 */ | ||
68 | } | 117 | } |
69 | 118 | ||
70 | int hostfs_init(void) | 119 | int hostfs_init(void) |
@@ -79,6 +128,7 @@ int hostfs_flush(void) | |||
79 | return 0; | 128 | return 0; |
80 | } | 129 | } |
81 | 130 | ||
131 | #if !defined(DX50) && !defined(DX90) | ||
82 | JNIEXPORT jint JNICALL | 132 | JNIEXPORT jint JNICALL |
83 | JNI_OnLoad(JavaVM *vm, void* reserved) | 133 | JNI_OnLoad(JavaVM *vm, void* reserved) |
84 | { | 134 | { |
@@ -119,7 +169,7 @@ Java_org_rockbox_RockboxService_main(JNIEnv *env, jobject this) | |||
119 | /* simply return here. this will allow the VM to clean up objects and do | 169 | /* simply return here. this will allow the VM to clean up objects and do |
120 | * garbage collection */ | 170 | * garbage collection */ |
121 | } | 171 | } |
122 | 172 | #endif /* !DX50 && !DX90 */ | |
123 | 173 | ||
124 | /* below is the facility for external (from other java threads) to safely call | 174 | /* below is the facility for external (from other java threads) to safely call |
125 | * into our snative code. When extracting rockbox.zip the main function is | 175 | * into our snative code. When extracting rockbox.zip the main function is |