diff options
Diffstat (limited to 'firmware/target')
42 files changed, 3480 insertions, 1116 deletions
diff --git a/firmware/target/hosted/android/dx50/adc-target.h b/firmware/target/hosted/android/dx50/adc-target.h deleted file mode 100644 index e69de29bb2..0000000000 --- a/firmware/target/hosted/android/dx50/adc-target.h +++ /dev/null | |||
diff --git a/firmware/target/hosted/android/dx50/backlight-dx50.c b/firmware/target/hosted/android/dx50/backlight-dx50.c deleted file mode 100644 index 8eb4c58191..0000000000 --- a/firmware/target/hosted/android/dx50/backlight-dx50.c +++ /dev/null | |||
@@ -1,76 +0,0 @@ | |||
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_hw_init(void) | ||
31 | { | ||
32 | /* We have nothing to do */ | ||
33 | return true; | ||
34 | } | ||
35 | |||
36 | void backlight_hw_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_hw_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_hw_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/button-dx50.c b/firmware/target/hosted/android/dx50/button-dx50.c deleted file mode 100644 index 250b448491..0000000000 --- a/firmware/target/hosted/android/dx50/button-dx50.c +++ /dev/null | |||
@@ -1,316 +0,0 @@ | |||
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 | close(fd); | ||
93 | return -1; | ||
94 | } | ||
95 | ufds = new_ufds; | ||
96 | new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1)); | ||
97 | if(new_device_names == NULL) { | ||
98 | fprintf(stderr, "out of memory\n"); | ||
99 | close(fd); | ||
100 | return -1; | ||
101 | } | ||
102 | device_names = new_device_names; | ||
103 | |||
104 | ufds[nfds].fd = fd; | ||
105 | ufds[nfds].events = POLLIN; | ||
106 | device_names[nfds] = strdup(device); | ||
107 | nfds++; | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | |||
113 | |||
114 | static int scan_dir(const char *dirname, int print_flags) | ||
115 | { | ||
116 | char devname[PATH_MAX]; | ||
117 | char *filename; | ||
118 | DIR *dir; | ||
119 | struct dirent *de; | ||
120 | dir = opendir(dirname); | ||
121 | if(dir == NULL) | ||
122 | return -1; | ||
123 | strcpy(devname, dirname); | ||
124 | filename = devname + strlen(devname); | ||
125 | *filename++ = '/'; | ||
126 | while((de = readdir(dir))) { | ||
127 | if(de->d_name[0] == '.' && | ||
128 | (de->d_name[1] == '\0' || | ||
129 | (de->d_name[1] == '.' && de->d_name[2] == '\0'))) | ||
130 | continue; | ||
131 | strcpy(filename, de->d_name); | ||
132 | open_device(devname, print_flags); | ||
133 | } | ||
134 | closedir(dir); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | bool _hold; | ||
139 | |||
140 | bool button_hold() | ||
141 | { | ||
142 | FILE *f = fopen("/sys/class/axppower/holdkey", "r"); | ||
143 | char x; | ||
144 | fscanf(f, "%c", &x); | ||
145 | fclose(f); | ||
146 | _hold = !(x&STATE_UNLOCKED); | ||
147 | return _hold; | ||
148 | } | ||
149 | |||
150 | |||
151 | void button_init_device(void) | ||
152 | { | ||
153 | int res; | ||
154 | int print_flags = 0; | ||
155 | const char *device = NULL; | ||
156 | const char *device_path = "/dev/input"; | ||
157 | |||
158 | nfds = 1; | ||
159 | ufds = calloc(1, sizeof(ufds[0])); | ||
160 | ufds[0].fd = inotify_init(); | ||
161 | ufds[0].events = POLLIN; | ||
162 | if(device) { | ||
163 | res = open_device(device, print_flags); | ||
164 | if(res < 0) { | ||
165 | // return 1; | ||
166 | } | ||
167 | } else { | ||
168 | res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE); | ||
169 | if(res < 0) { | ||
170 | fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno)); | ||
171 | // return 1; | ||
172 | } | ||
173 | res = scan_dir(device_path, print_flags); | ||
174 | if(res < 0) { | ||
175 | fprintf(stderr, "scan dir failed for %s\n", device_path); | ||
176 | // return 1; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | button_hold(); //store state | ||
181 | |||
182 | set_rockbox_ready(); | ||
183 | } | ||
184 | |||
185 | void touchscreen_enable_device(bool en) | ||
186 | { | ||
187 | (void)en; /* FIXME: do something smart */ | ||
188 | } | ||
189 | |||
190 | |||
191 | int keycode_to_button(int keyboard_key) | ||
192 | { | ||
193 | switch(keyboard_key){ | ||
194 | case KEYCODE_PWR: | ||
195 | return BUTTON_POWER; | ||
196 | |||
197 | case KEYCODE_PWR_LONG: | ||
198 | return BUTTON_POWER_LONG; | ||
199 | |||
200 | case KEYCODE_VOLPLUS: | ||
201 | return BUTTON_VOL_UP; | ||
202 | |||
203 | case KEYCODE_VOLMINUS: | ||
204 | return BUTTON_VOL_DOWN; | ||
205 | |||
206 | case KEYCODE_PREV: | ||
207 | return BUTTON_LEFT; | ||
208 | |||
209 | case KEYCODE_NEXT: | ||
210 | return BUTTON_RIGHT; | ||
211 | |||
212 | case KEYCODE_PLAY: | ||
213 | return BUTTON_PLAY; | ||
214 | |||
215 | case KEYCODE_HOLD: | ||
216 | button_hold(); /* store state */ | ||
217 | backlight_hold_changed(_hold); | ||
218 | return BUTTON_NONE; | ||
219 | |||
220 | default: | ||
221 | return BUTTON_NONE; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | |||
226 | int button_read_device(int *data) | ||
227 | { | ||
228 | int i; | ||
229 | int res; | ||
230 | struct input_event event; | ||
231 | int read_more; | ||
232 | unsigned button = 0; | ||
233 | |||
234 | if(last_btns & BUTTON_POWER_LONG) | ||
235 | { | ||
236 | return last_btns; /* simulate repeat */ | ||
237 | } | ||
238 | |||
239 | do { | ||
240 | read_more = 0; | ||
241 | poll(ufds, nfds, 10); | ||
242 | for(i = 1; i < nfds; i++) { | ||
243 | if(ufds[i].revents & POLLIN) { | ||
244 | res = read(ufds[i].fd, &event, sizeof(event)); | ||
245 | if(res < (int)sizeof(event)) { | ||
246 | fprintf(stderr, "could not get event\n"); | ||
247 | } | ||
248 | |||
249 | switch(event.type) | ||
250 | { | ||
251 | case 1: /* HW-Button */ | ||
252 | button = keycode_to_button(event.code); | ||
253 | if (_hold) /* we have to wait for keycode_to_button() first to maybe clear hold state */ | ||
254 | break; | ||
255 | if (button == BUTTON_NONE) | ||
256 | { | ||
257 | last_btns = button; | ||
258 | break; | ||
259 | } | ||
260 | /* workaround for a wrong feedback, only present with DX90 */ | ||
261 | #if defined(DX90) | ||
262 | if (button == BUTTON_RIGHT && (last_btns & BUTTON_LEFT == BUTTON_LEFT) && !event.value) | ||
263 | { | ||
264 | button = BUTTON_LEFT; | ||
265 | } | ||
266 | #endif | ||
267 | if (event.value) | ||
268 | last_btns |= button; | ||
269 | else | ||
270 | last_btns &= (~button); | ||
271 | |||
272 | break; | ||
273 | |||
274 | case 3: /* Touchscreen */ | ||
275 | if(_hold) | ||
276 | break; | ||
277 | |||
278 | switch(event.code) | ||
279 | { | ||
280 | case 53: /* x -> next will be y */ | ||
281 | last_x = event.value; | ||
282 | read_more = 1; | ||
283 | break; | ||
284 | case 54: /* y */ | ||
285 | last_y = event.value; | ||
286 | break; | ||
287 | case 57: /* press -> next will be x */ | ||
288 | if(event.value==1) | ||
289 | { | ||
290 | last_touch_state = STATE_DOWN; | ||
291 | read_more = 1; | ||
292 | } | ||
293 | else | ||
294 | last_touch_state = STATE_UP; | ||
295 | break; | ||
296 | } | ||
297 | break; | ||
298 | } | ||
299 | } | ||
300 | } | ||
301 | } while(read_more); | ||
302 | |||
303 | |||
304 | /* Get grid button/coordinates based on the current touchscreen mode | ||
305 | * | ||
306 | * Caveat: the caller seemingly depends on *data always being filled with | ||
307 | * the last known touchscreen position, so always call | ||
308 | * touchscreen_to_pixels() */ | ||
309 | int touch = touchscreen_to_pixels(last_x, last_y, data); | ||
310 | |||
311 | if (last_touch_state == STATE_DOWN) | ||
312 | return last_btns | touch; | ||
313 | |||
314 | return last_btns; | ||
315 | } | ||
316 | |||
diff --git a/firmware/target/hosted/android/dx50/lcd-dx50.c b/firmware/target/hosted/android/dx50/lcd-dx50.c deleted file mode 100644 index 4d78baaf00..0000000000 --- a/firmware/target/hosted/android/dx50/lcd-dx50.c +++ /dev/null | |||
@@ -1,120 +0,0 @@ | |||
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/pcm-dx50.c b/firmware/target/hosted/android/dx50/pcm-dx50.c deleted file mode 100644 index e7695873a0..0000000000 --- a/firmware/target/hosted/android/dx50/pcm-dx50.c +++ /dev/null | |||
@@ -1,364 +0,0 @@ | |||
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 deleted file mode 100644 index 713e8a977e..0000000000 --- a/firmware/target/hosted/android/dx50/powermgmt-dx50.c +++ /dev/null | |||
@@ -1,97 +0,0 @@ | |||
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 <stdlib.h> | ||
25 | #include "config.h" | ||
26 | #include "power.h" | ||
27 | #include "powermgmt.h" | ||
28 | |||
29 | |||
30 | unsigned int power_input_status(void) | ||
31 | { | ||
32 | int val; | ||
33 | FILE *f = fopen("/sys/class/power_supply/ac/present", "r"); | ||
34 | fscanf(f, "%d", &val); | ||
35 | fclose(f); | ||
36 | return val?POWER_INPUT_MAIN_CHARGER:POWER_INPUT_NONE; | ||
37 | } | ||
38 | |||
39 | |||
40 | /* Returns true, if battery is charging, false else. */ | ||
41 | bool charging_state( void ) | ||
42 | { | ||
43 | /* Full, Charging, Discharging */ | ||
44 | char state[9]; | ||
45 | |||
46 | /* true if charging. */ | ||
47 | bool charging = false; | ||
48 | |||
49 | FILE *f = fopen( "/sys/class/power_supply/battery/status", "r" ); | ||
50 | if( f != NULL ) | ||
51 | { | ||
52 | if( fgets( state, 9, f ) != NULL ) | ||
53 | { | ||
54 | charging = ( strcmp( state, "Charging" ) == 0 ); | ||
55 | } | ||
56 | } | ||
57 | fclose( f ); | ||
58 | |||
59 | return charging; | ||
60 | } | ||
61 | |||
62 | |||
63 | /* Values for stock PISEN battery. TODO: Needs optimization */ | ||
64 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = | ||
65 | { | ||
66 | 3380 | ||
67 | }; | ||
68 | |||
69 | const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = | ||
70 | { | ||
71 | 3100 | ||
72 | }; | ||
73 | |||
74 | /* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ | ||
75 | const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = | ||
76 | { | ||
77 | { 3370, 3650, 3700, 3740, 3780, 3820, 3870, 3930, 4000, 4090, 4190 } | ||
78 | }; | ||
79 | |||
80 | /* Voltages (millivolt) of 0%, 10%, ... 100% when charging is enabled. */ | ||
81 | const unsigned short percent_to_volt_charge[11] = | ||
82 | { | ||
83 | 3370, 3650, 3700, 3740, 3780, 3820, 3870, 3930, 4000, 4090, 4190 | ||
84 | }; | ||
85 | |||
86 | |||
87 | /* Returns battery voltage from android measurement [millivolts] */ | ||
88 | int _battery_voltage(void) | ||
89 | { | ||
90 | int val; | ||
91 | FILE *f = fopen("/sys/class/power_supply/battery/voltage_now", "r"); | ||
92 | fscanf(f, "%d", &val); | ||
93 | fclose(f); | ||
94 | return (val/1000); | ||
95 | } | ||
96 | |||
97 | |||
diff --git a/firmware/target/hosted/android/system-android.c b/firmware/target/hosted/android/system-android.c index 6279504e48..d13b8d6462 100644 --- a/firmware/target/hosted/android/system-android.c +++ b/firmware/target/hosted/android/system-android.c | |||
@@ -23,12 +23,6 @@ | |||
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 */ | ||
32 | #include <unistd.h> | 26 | #include <unistd.h> |
33 | #include "config.h" | 27 | #include "config.h" |
34 | #include "system.h" | 28 | #include "system.h" |
@@ -37,83 +31,40 @@ | |||
37 | 31 | ||
38 | 32 | ||
39 | 33 | ||
40 | #if !defined(DX50) && !defined(DX90) | ||
41 | /* global fields for use with various JNI calls */ | 34 | /* global fields for use with various JNI calls */ |
42 | static JavaVM *vm_ptr; | 35 | static JavaVM *vm_ptr; |
43 | JNIEnv *env_ptr; | 36 | JNIEnv *env_ptr; |
44 | jobject RockboxService_instance; | 37 | jobject RockboxService_instance; |
45 | jclass RockboxService_class; | 38 | jclass RockboxService_class; |
46 | #endif /* !DX50 && !DX90 */ | ||
47 | 39 | ||
48 | uintptr_t *stackbegin; | 40 | uintptr_t *stackbegin; |
49 | uintptr_t *stackend; | 41 | uintptr_t *stackend; |
50 | 42 | ||
51 | extern int main(void); | 43 | extern int main(void); |
52 | #if !defined(DX50) && !defined(DX90) | ||
53 | extern void telephony_init_device(void); | 44 | extern void telephony_init_device(void); |
54 | #endif | 45 | |
55 | void system_exception_wait(void) | 46 | void system_exception_wait(void) |
56 | { | 47 | { |
57 | #if defined(DX50) || defined(DX90) | ||
58 | while(1); | ||
59 | #else | ||
60 | intptr_t dummy = 0; | 48 | intptr_t dummy = 0; |
61 | while(button_read_device(&dummy) != BUTTON_BACK); | 49 | while(button_read_device(&dummy) != BUTTON_BACK); |
62 | #endif /* DX50 || DX90 */ | ||
63 | } | 50 | } |
64 | 51 | ||
65 | void system_reboot(void) | 52 | void system_reboot(void) |
66 | { | 53 | { |
67 | #if defined(DX50) || defined(DX90) | ||
68 | reboot(RB_AUTOBOOT); | ||
69 | #else | ||
70 | power_off(); | 54 | power_off(); |
71 | #endif /* DX50 || DX90 */ | ||
72 | } | 55 | } |
73 | 56 | ||
74 | #if !defined(DX50) && !defined(DX90) | ||
75 | /* this is used to return from the entry point of the native library. */ | 57 | /* this is used to return from the entry point of the native library. */ |
76 | static jmp_buf poweroff_buf; | 58 | static jmp_buf poweroff_buf; |
77 | #endif | ||
78 | |||
79 | void power_off(void) | 59 | void power_off(void) |
80 | { | 60 | { |
81 | #if defined(DX50) || defined(DX90) | ||
82 | reboot(RB_POWER_OFF); | ||
83 | #else | ||
84 | longjmp(poweroff_buf, 1); | 61 | longjmp(poweroff_buf, 1); |
85 | #endif /* DX50 || DX90 */ | ||
86 | } | 62 | } |
87 | 63 | ||
88 | void system_init(void) | 64 | void system_init(void) |
89 | { | 65 | { |
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 | ||
114 | /* no better place yet */ | 66 | /* no better place yet */ |
115 | telephony_init_device(); | 67 | telephony_init_device(); |
116 | #endif /* DX50 || DX90 */ | ||
117 | } | 68 | } |
118 | 69 | ||
119 | int hostfs_init(void) | 70 | int hostfs_init(void) |
@@ -128,7 +79,6 @@ int hostfs_flush(void) | |||
128 | return 0; | 79 | return 0; |
129 | } | 80 | } |
130 | 81 | ||
131 | #if !defined(DX50) && !defined(DX90) | ||
132 | JNIEXPORT jint JNICALL | 82 | JNIEXPORT jint JNICALL |
133 | JNI_OnLoad(JavaVM *vm, void* reserved) | 83 | JNI_OnLoad(JavaVM *vm, void* reserved) |
134 | { | 84 | { |
@@ -169,7 +119,7 @@ Java_org_rockbox_RockboxService_main(JNIEnv *env, jobject this) | |||
169 | /* simply return here. this will allow the VM to clean up objects and do | 119 | /* simply return here. this will allow the VM to clean up objects and do |
170 | * garbage collection */ | 120 | * garbage collection */ |
171 | } | 121 | } |
172 | #endif /* !DX50 && !DX90 */ | 122 | |
173 | 123 | ||
174 | /* below is the facility for external (from other java threads) to safely call | 124 | /* below is the facility for external (from other java threads) to safely call |
175 | * into our snative code. When extracting rockbox.zip the main function is | 125 | * into our snative code. When extracting rockbox.zip the main function is |
diff --git a/firmware/target/hosted/filesystem-app.c b/firmware/target/hosted/filesystem-app.c index 0c9943b635..826ab5bbb1 100644 --- a/firmware/target/hosted/filesystem-app.c +++ b/firmware/target/hosted/filesystem-app.c | |||
@@ -47,7 +47,7 @@ static const char *rbhome; | |||
47 | static const char rbhome[] = HOME_DIR; | 47 | static const char rbhome[] = HOME_DIR; |
48 | #endif | 48 | #endif |
49 | 49 | ||
50 | #if !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1)) && !defined(__PCTOOL__) | 50 | #if !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1) || defined(DX50) || defined(DX90)) && !defined(__PCTOOL__) |
51 | /* Special dirs are user-accessible (and user-writable) dirs which take priority | 51 | /* Special dirs are user-accessible (and user-writable) dirs which take priority |
52 | * over the ones where Rockbox is installed to. Classic example would be | 52 | * over the ones where Rockbox is installed to. Classic example would be |
53 | * $HOME/.config/rockbox.org vs /usr/share/rockbox */ | 53 | * $HOME/.config/rockbox.org vs /usr/share/rockbox */ |
diff --git a/firmware/target/hosted/ibasso/android_ndk.make b/firmware/target/hosted/ibasso/android_ndk.make new file mode 100644 index 0000000000..e2f5c93db8 --- /dev/null +++ b/firmware/target/hosted/ibasso/android_ndk.make | |||
@@ -0,0 +1,49 @@ | |||
1 | # __________ __ ___ | ||
2 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
3 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
4 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
5 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
6 | # \/ \/ \/ \/ \/ | ||
7 | # | ||
8 | # Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
9 | # Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
10 | # Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
11 | # Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
12 | # | ||
13 | # This program is free software; you can redistribute it and/or | ||
14 | # modify it under the terms of the GNU General Public License | ||
15 | # as published by the Free Software Foundation; either version 2 | ||
16 | # of the License, or (at your option) any later version. | ||
17 | # | ||
18 | # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | # KIND, either express or implied. | ||
20 | |||
21 | |||
22 | # This is a glibc compatibility hack to provide a get_nprocs() replacement. | ||
23 | # The NDK ships cpu-features.c which has a compatible function android_getCpuCount() | ||
24 | CPUFEAT = $(ANDROID_NDK_PATH)/sources/android/cpufeatures | ||
25 | CPUFEAT_BUILD = $(BUILDDIR)/android-ndk/sources/android/cpufeatures | ||
26 | INCLUDES += -I$(CPUFEAT) | ||
27 | OTHER_SRC += $(CPUFEAT)/cpu-features.c | ||
28 | CLEANOBJS += $(CPUFEAT_BUILD)/cpu-features.o | ||
29 | $(CPUFEAT_BUILD)/cpu-features.o: $(CPUFEAT)/cpu-features.c | ||
30 | $(SILENT)mkdir -p $(dir $@) | ||
31 | $(call PRINTS,CC $(subst $(CPUFEAT)/,,$<))$(CC) -o $@ -c $(CPUFEAT)/cpu-features.c $(GCCOPTS) -Wno-unused | ||
32 | |||
33 | .SECONDEXPANSION: | ||
34 | .PHONY: clean dirs | ||
35 | |||
36 | DIRS += $(CPUFEAT_BUILD) | ||
37 | |||
38 | .PHONY: | ||
39 | $(BUILDDIR)/$(BINARY): $$(OBJ) $(FIRMLIB) $(VOICESPEEXLIB) $(CORE_LIBS) $(CPUFEAT_BUILD)/cpu-features.o | ||
40 | $(call PRINTS,LD $(BINARY))$(CC) -o $@ $^ $(LDOPTS) $(GLOBAL_LDOPTS) -Wl,-Map,$(BUILDDIR)/rockbox.map | ||
41 | $(call PRINTS,OC $(@F))$(call objcopy,$@,$@) | ||
42 | |||
43 | $(DIRS): | ||
44 | $(SILENT)mkdir -p $@ | ||
45 | |||
46 | dirs: $(DIRS) | ||
47 | |||
48 | clean:: | ||
49 | $(SILENT)rm -rf $(BUILDDIR)/android-ndk | ||
diff --git a/firmware/target/hosted/ibasso/audiohw-ibasso.c b/firmware/target/hosted/ibasso/audiohw-ibasso.c new file mode 100644 index 0000000000..447e133eba --- /dev/null +++ b/firmware/target/hosted/ibasso/audiohw-ibasso.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include "config.h" | ||
26 | #include "debug.h" | ||
27 | #include "pcm_sw_volume.h" | ||
28 | #include "settings.h" | ||
29 | |||
30 | #include "debug-ibasso.h" | ||
31 | #include "pcm-ibasso.h" | ||
32 | |||
33 | |||
34 | void audiohw_close(void) | ||
35 | { | ||
36 | TRACE; | ||
37 | |||
38 | pcm_close_device(); | ||
39 | } | ||
40 | |||
41 | |||
42 | void set_software_volume(void) | ||
43 | { | ||
44 | /* -73dB (?) minimum software volume in decibels. See pcm-internal.h. */ | ||
45 | static const int SW_VOLUME_MIN = 730; | ||
46 | |||
47 | int sw_volume_l = 0; | ||
48 | int sw_volume_r = 0; | ||
49 | |||
50 | if(global_settings.balance > 0) | ||
51 | { | ||
52 | if(global_settings.balance == 100) | ||
53 | { | ||
54 | sw_volume_l = PCM_MUTE_LEVEL; | ||
55 | } | ||
56 | else | ||
57 | { | ||
58 | sw_volume_l -= SW_VOLUME_MIN * global_settings.balance / 100; | ||
59 | } | ||
60 | } | ||
61 | else if(global_settings.balance < 0) | ||
62 | { | ||
63 | if(global_settings.balance == -100) | ||
64 | { | ||
65 | sw_volume_r = PCM_MUTE_LEVEL; | ||
66 | } | ||
67 | else | ||
68 | { | ||
69 | sw_volume_r = SW_VOLUME_MIN * global_settings.balance / 100; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | DEBUGF("DEBUG %s: global_settings.balance: %d, sw_volume_l: %d, sw_volume_r: %d.", | ||
74 | __func__, | ||
75 | global_settings.balance, | ||
76 | sw_volume_l, | ||
77 | sw_volume_r); | ||
78 | |||
79 | /* Emulate balance with software volume. */ | ||
80 | pcm_set_master_volume(sw_volume_l, sw_volume_r); | ||
81 | } | ||
diff --git a/firmware/target/hosted/ibasso/backlight-ibasso.c b/firmware/target/hosted/ibasso/backlight-ibasso.c new file mode 100644 index 0000000000..907980e01a --- /dev/null +++ b/firmware/target/hosted/ibasso/backlight-ibasso.c | |||
@@ -0,0 +1,132 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <stdbool.h> | ||
26 | |||
27 | #include "config.h" | ||
28 | #include "debug.h" | ||
29 | #include "lcd.h" | ||
30 | #include "panic.h" | ||
31 | |||
32 | #include "debug-ibasso.h" | ||
33 | #include "sysfs-ibasso.h" | ||
34 | |||
35 | |||
36 | /* | ||
37 | Prevent excessive backlight_hw_on usage. | ||
38 | Required for proper seeking. | ||
39 | */ | ||
40 | static bool _backlight_enabled = false; | ||
41 | |||
42 | |||
43 | bool backlight_hw_init(void) | ||
44 | { | ||
45 | TRACE; | ||
46 | |||
47 | /* | ||
48 | /sys/devices/platform/rk29_backlight/backlight/rk28_bl/bl_power | ||
49 | 0: backlight on | ||
50 | */ | ||
51 | if(! sysfs_set_int(SYSFS_BACKLIGHT_POWER, 0)) | ||
52 | { | ||
53 | DEBUGF("ERROR %s: Can not enable backlight.", __func__); | ||
54 | panicf("ERROR %s: Can not enable backlight.", __func__); | ||
55 | return false; | ||
56 | } | ||
57 | |||
58 | _backlight_enabled = true; | ||
59 | |||
60 | return true; | ||
61 | } | ||
62 | |||
63 | |||
64 | void backlight_hw_on(void) | ||
65 | { | ||
66 | if(! _backlight_enabled) | ||
67 | { | ||
68 | backlight_hw_init(); | ||
69 | lcd_enable(true); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | |||
74 | void backlight_hw_off(void) | ||
75 | { | ||
76 | TRACE; | ||
77 | |||
78 | /* | ||
79 | /sys/devices/platform/rk29_backlight/backlight/rk28_bl/bl_power | ||
80 | 1: backlight off | ||
81 | */ | ||
82 | if(! sysfs_set_int(SYSFS_BACKLIGHT_POWER, 1)) | ||
83 | { | ||
84 | DEBUGF("ERROR %s: Can not disable backlight.", __func__); | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | lcd_enable(false); | ||
89 | |||
90 | _backlight_enabled = false; | ||
91 | } | ||
92 | |||
93 | |||
94 | /* | ||
95 | Prevent excessive backlight_hw_brightness usage. | ||
96 | Required for proper seeking. | ||
97 | */ | ||
98 | static int _current_brightness = -1; | ||
99 | |||
100 | |||
101 | void backlight_hw_brightness(int brightness) | ||
102 | { | ||
103 | if(brightness > MAX_BRIGHTNESS_SETTING) | ||
104 | { | ||
105 | DEBUGF("DEBUG %s: Adjusting brightness from %d to MAX.", __func__, brightness); | ||
106 | brightness = MAX_BRIGHTNESS_SETTING; | ||
107 | } | ||
108 | if(brightness < MIN_BRIGHTNESS_SETTING) | ||
109 | { | ||
110 | DEBUGF("DEBUG %s: Adjusting brightness from %d to MIN.", __func__, brightness); | ||
111 | brightness = MIN_BRIGHTNESS_SETTING; | ||
112 | } | ||
113 | |||
114 | if(_current_brightness == brightness) | ||
115 | { | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | TRACE; | ||
120 | |||
121 | _current_brightness = brightness; | ||
122 | |||
123 | /* | ||
124 | /sys/devices/platform/rk29_backlight/backlight/rk28_bl/max_brightness | ||
125 | 0 ... 255 | ||
126 | */ | ||
127 | if(! sysfs_set_int(SYSFS_BACKLIGHT_BRIGHTNESS, _current_brightness)) | ||
128 | { | ||
129 | DEBUGF("ERROR %s: Can not set brightness.", __func__); | ||
130 | return; | ||
131 | } | ||
132 | } | ||
diff --git a/firmware/target/hosted/android/dx50/backlight-target.h b/firmware/target/hosted/ibasso/backlight-target.h index 0dc7ce387a..aa8fafab04 100644 --- a/firmware/target/hosted/android/dx50/backlight-target.h +++ b/firmware/target/hosted/ibasso/backlight-target.h | |||
@@ -1,13 +1,15 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * __________ __ ___. | 2 | * __________ __ ___ |
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | ||
9 | * | 8 | * |
10 | * Copyright (C) 2008 by Maurus Cuelenaere | 9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 |
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
11 | * | 13 | * |
12 | * This program is free software; you can redistribute it and/or | 14 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 15 | * modify it under the terms of the GNU General Public License |
@@ -18,14 +20,20 @@ | |||
18 | * KIND, either express or implied. | 20 | * KIND, either express or implied. |
19 | * | 21 | * |
20 | ****************************************************************************/ | 22 | ****************************************************************************/ |
21 | #ifndef BACKLIGHT_TARGET_H | 23 | |
22 | #define BACKLIGHT_TARGET_H | 24 | |
25 | #ifndef _BACKLIGHT_TARGET_H_ | ||
26 | #define _BACKLIGHT_TARGET_H_ | ||
27 | |||
23 | 28 | ||
24 | #include <stdbool.h> | 29 | #include <stdbool.h> |
25 | 30 | ||
31 | |||
32 | /* See backlight.c */ | ||
26 | bool backlight_hw_init(void); | 33 | bool backlight_hw_init(void); |
27 | void backlight_hw_on(void); | 34 | void backlight_hw_on(void); |
28 | void backlight_hw_off(void); | 35 | void backlight_hw_off(void); |
29 | void backlight_hw_brightness(int brightness); | 36 | void backlight_hw_brightness(int brightness); |
30 | 37 | ||
31 | #endif /* BACKLIGHT_TARGET_H */ | 38 | |
39 | #endif | ||
diff --git a/firmware/target/hosted/ibasso/button-ibasso.c b/firmware/target/hosted/ibasso/button-ibasso.c new file mode 100644 index 0000000000..1694992ea4 --- /dev/null +++ b/firmware/target/hosted/ibasso/button-ibasso.c | |||
@@ -0,0 +1,420 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <dirent.h> | ||
26 | #include <errno.h> | ||
27 | #include <fcntl.h> | ||
28 | #include <stdbool.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <string.h> | ||
31 | #include <unistd.h> | ||
32 | #include <linux/input.h> | ||
33 | #include <sys/inotify.h> | ||
34 | #include <sys/limits.h> | ||
35 | #include <sys/poll.h> | ||
36 | |||
37 | #include "config.h" | ||
38 | #include "backlight.h" | ||
39 | #include "button.h" | ||
40 | #include "debug.h" | ||
41 | #include "panic.h" | ||
42 | #include "settings.h" | ||
43 | #include "touchscreen.h" | ||
44 | |||
45 | #include "button-ibasso.h" | ||
46 | #include "button-target.h" | ||
47 | #include "debug-ibasso.h" | ||
48 | #include "sysfs-ibasso.h" | ||
49 | |||
50 | |||
51 | #define EVENT_TYPE_BUTTON 1 | ||
52 | |||
53 | /* /dev/input/event0 */ | ||
54 | #define EVENT_CODE_BUTTON_LINEOUT 113 | ||
55 | #define EVENT_CODE_BUTTON_SPDIF 114 | ||
56 | #define EVENT_CODE_BUTTON_HOLD 115 | ||
57 | |||
58 | /* /dev/input/event1 */ | ||
59 | #define EVENT_CODE_BUTTON_SDCARD 143 | ||
60 | |||
61 | |||
62 | #define EVENT_TYPE_TOUCHSCREEN 3 | ||
63 | |||
64 | /* /dev/input/event2 */ | ||
65 | #define EVENT_CODE_TOUCHSCREEN_X 53 | ||
66 | #define EVENT_CODE_TOUCHSCREEN_Y 54 | ||
67 | #define EVENT_CODE_TOUCHSCREEN 57 | ||
68 | |||
69 | #define EVENT_VALUE_TOUCHSCREEN_PRESS 1 | ||
70 | #define EVENT_VALUE_TOUCHSCREEN_RELEASE -1 | ||
71 | |||
72 | |||
73 | /* | ||
74 | Changing bit, when hold switch is toggled. | ||
75 | Bit is off when hold switch is engaged. | ||
76 | */ | ||
77 | #define HOLD_SWITCH_BIT 16 | ||
78 | |||
79 | /* | ||
80 | Changing bit, when coaxial out is plugged. | ||
81 | Bit is off when coaxial out is plugged in. | ||
82 | */ | ||
83 | #define COAX_BIT 32 | ||
84 | |||
85 | /* | ||
86 | Changing bit, when line out is plugged. | ||
87 | Bit is off when line out is plugged in. | ||
88 | */ | ||
89 | #define SPDIF_BIT 64 | ||
90 | |||
91 | |||
92 | /* State of the hold switch; true: hold switch engaged. */ | ||
93 | static bool _hold = false; | ||
94 | |||
95 | |||
96 | /* See button.h. */ | ||
97 | bool button_hold(void) | ||
98 | { | ||
99 | char hold_state; | ||
100 | if(! sysfs_get_char(SYSFS_HOLDKEY, &hold_state)) | ||
101 | { | ||
102 | DEBUGF("ERROR %s: Can not get hold switch state.", __func__); | ||
103 | hold_state = HOLD_SWITCH_BIT; | ||
104 | } | ||
105 | |||
106 | /*DEBUGF("%s: hold_state: %d, %c.", __func__, hold_state, hold_state);*/ | ||
107 | |||
108 | /*bool coax_connected = ! (hold_state & COAX_BIT); | ||
109 | bool spdif_connected = ! (hold_state & SPDIF_BIT);*/ | ||
110 | |||
111 | _hold = ! (hold_state & HOLD_SWITCH_BIT); | ||
112 | |||
113 | /*DEBUGF("%s: _hold: %d, coax_connected: %d, spdif_connected: %d.", __func__, _hold, coax_connected, spdif_connected);*/ | ||
114 | |||
115 | return _hold; | ||
116 | } | ||
117 | |||
118 | |||
119 | /* Input devices monitored with poll API. */ | ||
120 | static struct pollfd* _fds = NULL; | ||
121 | |||
122 | |||
123 | /* Number of input devices monitored with poll API. */ | ||
124 | static nfds_t _nfds = 0; | ||
125 | |||
126 | |||
127 | /* The names of the devices in _fds. */ | ||
128 | static char** _device_names = NULL; | ||
129 | |||
130 | |||
131 | /* Open device device_name and add it to the list of polled devices. */ | ||
132 | static bool open_device(const char* device_name) | ||
133 | { | ||
134 | int fd = open(device_name, O_RDONLY); | ||
135 | if(fd == -1) | ||
136 | { | ||
137 | DEBUGF("ERROR %s: open failed on %s.", __func__, device_name); | ||
138 | return false; | ||
139 | } | ||
140 | |||
141 | struct pollfd* new_fds = realloc(_fds, sizeof(struct pollfd) * (_nfds + 1)); | ||
142 | if(new_fds == NULL) | ||
143 | { | ||
144 | DEBUGF("ERROR %s: realloc for _fds failed.", __func__); | ||
145 | panicf("ERROR %s: realloc for _fds failed.", __func__); | ||
146 | return false; | ||
147 | } | ||
148 | |||
149 | _fds = new_fds; | ||
150 | _fds[_nfds].fd = fd; | ||
151 | _fds[_nfds].events = POLLIN; | ||
152 | |||
153 | char** new_device_names = realloc(_device_names, sizeof(char*) * (_nfds + 1)); | ||
154 | if(new_device_names == NULL) | ||
155 | { | ||
156 | DEBUGF("ERROR %s: realloc for _device_names failed.", __func__); | ||
157 | panicf("ERROR %s: realloc for _device_names failed.", __func__); | ||
158 | return false; | ||
159 | } | ||
160 | |||
161 | _device_names = new_device_names; | ||
162 | _device_names[_nfds] = strdup(device_name); | ||
163 | if(_device_names[_nfds] == NULL) | ||
164 | { | ||
165 | DEBUGF("ERROR %s: strdup failed.", __func__); | ||
166 | panicf("ERROR %s: strdup failed.", __func__); | ||
167 | return false; | ||
168 | } | ||
169 | |||
170 | ++_nfds; | ||
171 | |||
172 | DEBUGF("DEBUG %s: Opened device %s.", __func__, device_name); | ||
173 | |||
174 | return true; | ||
175 | } | ||
176 | |||
177 | |||
178 | /* See button.h. */ | ||
179 | void button_init_device(void) | ||
180 | { | ||
181 | TRACE; | ||
182 | |||
183 | if((_fds != NULL) || (_nfds != 0) || (_device_names != NULL)) | ||
184 | { | ||
185 | DEBUGF("ERROR %s: Allready initialized.", __func__); | ||
186 | panicf("ERROR %s: Allready initialized.", __func__); | ||
187 | return; | ||
188 | } | ||
189 | |||
190 | /* The input device directory. */ | ||
191 | static const char device_path[] = "/dev/input"; | ||
192 | |||
193 | /* Path delimeter. */ | ||
194 | static const char delimeter[] = "/"; | ||
195 | |||
196 | /* Open all devices in device_path. */ | ||
197 | DIR* dir = opendir(device_path); | ||
198 | if(dir == NULL) | ||
199 | { | ||
200 | DEBUGF("ERROR %s: opendir failed: errno: %d.", __func__, errno); | ||
201 | panicf("ERROR %s: opendir failed: errno: %d.", __func__, errno); | ||
202 | return; | ||
203 | } | ||
204 | |||
205 | char device_name[PATH_MAX]; | ||
206 | strcpy(device_name, device_path); | ||
207 | strcat(device_name, delimeter); | ||
208 | char* device_name_idx = device_name + strlen(device_name); | ||
209 | |||
210 | struct dirent* dir_entry; | ||
211 | while((dir_entry = readdir(dir))) | ||
212 | { | ||
213 | if( ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '\0')) | ||
214 | || ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '.') && (dir_entry->d_name[2] == '\0'))) | ||
215 | { | ||
216 | continue; | ||
217 | } | ||
218 | |||
219 | strcpy(device_name_idx, dir_entry->d_name); | ||
220 | |||
221 | /* Open and add device to _fds. */ | ||
222 | open_device(device_name); | ||
223 | } | ||
224 | |||
225 | closedir(dir); | ||
226 | |||
227 | /* Sanity check. */ | ||
228 | if(_nfds < 2) | ||
229 | { | ||
230 | DEBUGF("ERROR %s: No input devices.", __func__); | ||
231 | panicf("ERROR %s: No input devices.", __func__); | ||
232 | return; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | Hold switch has a separate interface for its state. | ||
237 | Input events just report that it has been toggled, but not the state. | ||
238 | */ | ||
239 | button_hold(); | ||
240 | } | ||
241 | |||
242 | |||
243 | /* Last known touchscreen coordinates. */ | ||
244 | static int _last_x = 0; | ||
245 | static int _last_y = 0; | ||
246 | |||
247 | |||
248 | /* Last known touchscreen state. */ | ||
249 | static enum | ||
250 | { | ||
251 | TOUCHSCREEN_STATE_UNKNOWN = 0, | ||
252 | TOUCHSCREEN_STATE_UP, | ||
253 | TOUCHSCREEN_STATE_DOWN | ||
254 | } _last_touch_state = TOUCHSCREEN_STATE_UNKNOWN; | ||
255 | |||
256 | |||
257 | static bool handle_touchscreen_event(__u16 code, __s32 value) | ||
258 | { | ||
259 | bool read_more = false; | ||
260 | |||
261 | switch(code) | ||
262 | { | ||
263 | case EVENT_CODE_TOUCHSCREEN_X: | ||
264 | { | ||
265 | _last_x = value; | ||
266 | |||
267 | /* x -> next will be y. */ | ||
268 | read_more = true; | ||
269 | |||
270 | break; | ||
271 | } | ||
272 | |||
273 | case EVENT_CODE_TOUCHSCREEN_Y: | ||
274 | { | ||
275 | _last_y = value; | ||
276 | break; | ||
277 | } | ||
278 | |||
279 | case EVENT_CODE_TOUCHSCREEN: | ||
280 | { | ||
281 | if(value == EVENT_VALUE_TOUCHSCREEN_PRESS) | ||
282 | { | ||
283 | _last_touch_state = TOUCHSCREEN_STATE_DOWN; | ||
284 | |||
285 | /* Press -> next will be x. */ | ||
286 | read_more = true; | ||
287 | } | ||
288 | else | ||
289 | { | ||
290 | _last_touch_state = TOUCHSCREEN_STATE_UP; | ||
291 | } | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | return read_more; | ||
297 | } | ||
298 | |||
299 | |||
300 | /* Last known hardware buttons pressed. */ | ||
301 | static int _last_btns = BUTTON_NONE; | ||
302 | |||
303 | |||
304 | /* See button.h. */ | ||
305 | int button_read_device(int *data) | ||
306 | { | ||
307 | bool read_more = true; | ||
308 | while(read_more) | ||
309 | { | ||
310 | read_more = false; | ||
311 | |||
312 | /* Poll all input devices. */ | ||
313 | poll(_fds, _nfds, 0); | ||
314 | |||
315 | for(nfds_t fds_idx = 0; fds_idx < _nfds; ++fds_idx) | ||
316 | { | ||
317 | if(! (_fds[fds_idx].revents & POLLIN)) | ||
318 | { | ||
319 | continue; | ||
320 | } | ||
321 | |||
322 | struct input_event event; | ||
323 | if(read(_fds[fds_idx].fd, &event, sizeof(event)) < (int) sizeof(event)) | ||
324 | { | ||
325 | DEBUGF("ERROR %s: Read of input devices failed.", __func__); | ||
326 | continue; | ||
327 | } | ||
328 | |||
329 | /*DEBUGF("DEBUG %s: device: %s, event.type: %d, event.code: %d, event.value: %d", __func__, _device_names[fds_idx], event.type, event.code, event.value);*/ | ||
330 | |||
331 | switch(event.type) | ||
332 | { | ||
333 | case EVENT_TYPE_BUTTON: | ||
334 | { | ||
335 | if(event.code == EVENT_CODE_BUTTON_HOLD) | ||
336 | { | ||
337 | /* Hold switch toggled, update hold switch state. */ | ||
338 | button_hold(); | ||
339 | backlight_hold_changed(_hold); | ||
340 | |||
341 | _last_btns = BUTTON_NONE; | ||
342 | break; | ||
343 | } | ||
344 | |||
345 | _last_btns = handle_button_event(event.code, event.value, _last_btns); | ||
346 | |||
347 | if(_hold) | ||
348 | { | ||
349 | /* Hold switch engaged. Ignore all button events. */ | ||
350 | _last_btns = BUTTON_NONE; | ||
351 | } | ||
352 | |||
353 | /*DEBUGF("DEBUG %s: _last_btns: %#8.8x", __func__, _last_btns);*/ | ||
354 | break; | ||
355 | } | ||
356 | |||
357 | case EVENT_TYPE_TOUCHSCREEN: | ||
358 | { | ||
359 | if(_hold) | ||
360 | { | ||
361 | /* Hold switch engaged, ignore all touchscreen events. */ | ||
362 | _last_touch_state = TOUCHSCREEN_STATE_UNKNOWN; | ||
363 | _last_btns = BUTTON_NONE; | ||
364 | } | ||
365 | else | ||
366 | { | ||
367 | read_more = handle_touchscreen_event(event.code, event.value); | ||
368 | /*DEBUGF("DEBUG %s: _last_touch_state: %d, _last_x: %d, _last_y: %d, read_more: %s", __func__, _last_touch_state, _last_x, _last_y, read_more ? "true" : "false");*/ | ||
369 | } | ||
370 | break; | ||
371 | } | ||
372 | } | ||
373 | } | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | Get grid button/coordinates based on the current touchscreen mode | ||
378 | Caveat: The caller seemingly depends on *data always being filled with | ||
379 | the last known touchscreen position, so always call | ||
380 | touchscreen_to_pixels(). | ||
381 | */ | ||
382 | int touch = touchscreen_to_pixels(_last_x, _last_y, data); | ||
383 | |||
384 | if(_last_touch_state == TOUCHSCREEN_STATE_DOWN) | ||
385 | { | ||
386 | return _last_btns | touch; | ||
387 | } | ||
388 | |||
389 | /*DEBUGF("DEBUG %s: _last_btns: %#8.8x.", __func__, _last_btns);*/ | ||
390 | |||
391 | return _last_btns; | ||
392 | } | ||
393 | |||
394 | |||
395 | void button_close_device(void) | ||
396 | { | ||
397 | TRACE; | ||
398 | |||
399 | if(_fds) | ||
400 | { | ||
401 | for(nfds_t fds_idx = 0; fds_idx < _nfds; ++fds_idx) | ||
402 | { | ||
403 | close(_fds[fds_idx].fd); | ||
404 | } | ||
405 | free(_fds); | ||
406 | _fds = NULL; | ||
407 | } | ||
408 | |||
409 | if(_device_names) | ||
410 | { | ||
411 | for(nfds_t fds_idx = 0; fds_idx < _nfds; ++fds_idx) | ||
412 | { | ||
413 | free(_device_names[fds_idx]); | ||
414 | } | ||
415 | free(_device_names); | ||
416 | _device_names = NULL; | ||
417 | } | ||
418 | |||
419 | _nfds = 0; | ||
420 | } | ||
diff --git a/firmware/target/hosted/ibasso/button-ibasso.h b/firmware/target/hosted/ibasso/button-ibasso.h new file mode 100644 index 0000000000..09c09e7c83 --- /dev/null +++ b/firmware/target/hosted/ibasso/button-ibasso.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #ifndef _BUTTON_IBASSO_H_ | ||
26 | #define _BUTTON_IBASSO_H_ | ||
27 | |||
28 | |||
29 | #include <sys/types.h> | ||
30 | |||
31 | |||
32 | /* /dev/input/event0 */ | ||
33 | #define EVENT_CODE_BUTTON_PWR 116 | ||
34 | #define EVENT_CODE_BUTTON_PWR_LONG 117 | ||
35 | |||
36 | /* /dev/input/event1 */ | ||
37 | #define EVENT_CODE_BUTTON_VOLPLUS 158 | ||
38 | #define EVENT_CODE_BUTTON_VOLMINUS 159 | ||
39 | #define EVENT_CODE_BUTTON_REV 160 | ||
40 | #define EVENT_CODE_BUTTON_PLAY 161 | ||
41 | #define EVENT_CODE_BUTTON_NEXT 162 | ||
42 | |||
43 | #define EVENT_VALUE_BUTTON_PRESS 1 | ||
44 | #define EVENT_VALUE_BUTTON_RELEASE 0 | ||
45 | |||
46 | |||
47 | /* | ||
48 | Handle hardware button events. | ||
49 | code: Input event code. | ||
50 | value: Input event value. | ||
51 | last_btns: Last known pressed buttons. | ||
52 | Returns: Currently pressed buttons as bitmask (BUTTON_ values in button-target.h). | ||
53 | */ | ||
54 | int handle_button_event(__u16 code, __s32 value, int last_btns); | ||
55 | |||
56 | |||
57 | /* Clean up the button device handler. */ | ||
58 | void button_close_device(void); | ||
59 | |||
60 | |||
61 | #endif | ||
diff --git a/firmware/target/hosted/android/dx50/button-target.h b/firmware/target/hosted/ibasso/button-target.h index adc9cf6bfd..d1b3c8a8de 100644 --- a/firmware/target/hosted/android/dx50/button-target.h +++ b/firmware/target/hosted/ibasso/button-target.h | |||
@@ -1,32 +1,32 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * __________ __ ___. | 2 | * __________ __ ___ |
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | ||
9 | * | 8 | * |
10 | * Copyright (C) 2007 by Rob Purchase | 9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 |
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
11 | * | 13 | * |
12 | * This program is free software; you can redistribute it and/or | 14 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 15 | * modify it under the terms of the GNU General Public License |
14 | * as published by the Free Software Foundation; either version 2 | 16 | * as published by the Free Software Foundation; either version 2 |
15 | * of the License, or (at your option) any later version.r | 17 | * of the License, or (at your option) any later version. |
16 | * | 18 | * |
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | 19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
18 | * KIND, either express or implied. | 20 | * KIND, either express or implied. |
19 | * | 21 | * |
20 | ****************************************************************************/ | 22 | ****************************************************************************/ |
21 | 23 | ||
24 | |||
22 | #ifndef _BUTTON_TARGET_H_ | 25 | #ifndef _BUTTON_TARGET_H_ |
23 | #define _BUTTON_TARGET_H_ | 26 | #define _BUTTON_TARGET_H_ |
24 | 27 | ||
25 | #include <stdbool.h> | ||
26 | |||
27 | #define HAS_BUTTON_HOLD | ||
28 | 28 | ||
29 | /* Main unit's buttons */ | 29 | /* Hardware buttons. */ |
30 | #define BUTTON_LEFT 0x00000001 | 30 | #define BUTTON_LEFT 0x00000001 |
31 | #define BUTTON_RIGHT 0x00000002 | 31 | #define BUTTON_RIGHT 0x00000002 |
32 | #define BUTTON_PLAY 0x00000004 | 32 | #define BUTTON_PLAY 0x00000004 |
@@ -35,25 +35,15 @@ | |||
35 | #define BUTTON_VOL_DOWN 0x00000020 | 35 | #define BUTTON_VOL_DOWN 0x00000020 |
36 | #define BUTTON_POWER_LONG 0x00000040 | 36 | #define BUTTON_POWER_LONG 0x00000040 |
37 | 37 | ||
38 | #define BUTTON_MAIN (BUTTON_LEFT|BUTTON_VOL_UP|BUTTON_VOL_DOWN\ | 38 | #define BUTTON_MAIN ( BUTTON_LEFT | BUTTON_VOL_UP | BUTTON_VOL_DOWN | BUTTON_RIGHT \ |
39 | |BUTTON_RIGHT|BUTTON_PLAY|BUTTON_POWER|BUTTON_POWER_LONG) | 39 | | BUTTON_PLAY | BUTTON_POWER | BUTTON_POWER_LONG) |
40 | |||
40 | 41 | ||
41 | #define KEYCODE_LINEOUT 113 | 42 | #define STATE_SPDIF_UNPLUGGED 32 |
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 | 43 | #define STATE_LINEOUT_UNPLUGGED 64 |
55 | 44 | ||
56 | /* Touch Screen Area Buttons */ | 45 | |
46 | /* Touchscreen area buttons 3x3 grid. */ | ||
57 | #define BUTTON_TOPLEFT 0x00001000 | 47 | #define BUTTON_TOPLEFT 0x00001000 |
58 | #define BUTTON_TOPMIDDLE 0x00002000 | 48 | #define BUTTON_TOPMIDDLE 0x00002000 |
59 | #define BUTTON_TOPRIGHT 0x00004000 | 49 | #define BUTTON_TOPRIGHT 0x00004000 |
@@ -65,8 +55,9 @@ | |||
65 | #define BUTTON_BOTTOMRIGHT 0x00100000 | 55 | #define BUTTON_BOTTOMRIGHT 0x00100000 |
66 | 56 | ||
67 | 57 | ||
68 | /* Software power-off */ | 58 | /* Power-off */ |
69 | #define POWEROFF_BUTTON BUTTON_POWER_LONG | 59 | #define POWEROFF_BUTTON BUTTON_POWER_LONG |
70 | #define POWEROFF_COUNT 0 | 60 | #define POWEROFF_COUNT 0 |
61 | |||
71 | 62 | ||
72 | #endif /* _BUTTON_TARGET_H_ */ | 63 | #endif |
diff --git a/firmware/target/hosted/ibasso/debug-ibasso.c b/firmware/target/hosted/ibasso/debug-ibasso.c new file mode 100644 index 0000000000..6295de1f6c --- /dev/null +++ b/firmware/target/hosted/ibasso/debug-ibasso.c | |||
@@ -0,0 +1,70 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <stdarg.h> | ||
26 | #include <stdio.h> | ||
27 | #include <string.h> | ||
28 | #include <android/log.h> | ||
29 | |||
30 | #include "config.h" | ||
31 | #include "debug.h" | ||
32 | |||
33 | #include "debug-ibasso.h" | ||
34 | |||
35 | |||
36 | static const char log_tag[] = "Rockbox"; | ||
37 | |||
38 | |||
39 | void debug_init(void) | ||
40 | {} | ||
41 | |||
42 | |||
43 | void debugf(const char *fmt, ...) | ||
44 | { | ||
45 | va_list ap; | ||
46 | va_start(ap, fmt); | ||
47 | __android_log_vprint(ANDROID_LOG_DEBUG, log_tag, fmt, ap); | ||
48 | va_end(ap); | ||
49 | } | ||
50 | |||
51 | |||
52 | void ldebugf(const char* file, int line, const char *fmt, ...) | ||
53 | { | ||
54 | va_list ap; | ||
55 | /* 13: 5 literal chars and 8 chars for the line number. */ | ||
56 | char buf[strlen(file) + strlen(fmt) + 13]; | ||
57 | snprintf(buf, sizeof(buf), "%s (%d): %s", file, line, fmt); | ||
58 | va_start(ap, fmt); | ||
59 | __android_log_vprint(ANDROID_LOG_DEBUG, log_tag, buf, ap); | ||
60 | va_end(ap); | ||
61 | } | ||
62 | |||
63 | |||
64 | void debug_trace(const char* function) | ||
65 | { | ||
66 | static const char trace_tag[] = "TRACE: "; | ||
67 | char msg[strlen(trace_tag) + strlen(function) + 1]; | ||
68 | snprintf(msg, sizeof(msg), "%s%s", trace_tag, function); | ||
69 | __android_log_write(ANDROID_LOG_DEBUG, log_tag, msg); | ||
70 | } | ||
diff --git a/firmware/target/hosted/ibasso/debug-ibasso.h b/firmware/target/hosted/ibasso/debug-ibasso.h new file mode 100644 index 0000000000..456f189a5a --- /dev/null +++ b/firmware/target/hosted/ibasso/debug-ibasso.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #ifndef _DEBUG_IBASSO_H_ | ||
26 | #define _DEBUG_IBASSO_H_ | ||
27 | |||
28 | |||
29 | void debug_trace(const char* function); | ||
30 | |||
31 | |||
32 | #ifdef DEBUG | ||
33 | #define TRACE debug_trace(__func__) | ||
34 | #else | ||
35 | #define TRACE | ||
36 | #endif | ||
37 | |||
38 | #endif \ No newline at end of file | ||
diff --git a/firmware/target/hosted/ibasso/dx50/audiohw-dx50.c b/firmware/target/hosted/ibasso/dx50/audiohw-dx50.c new file mode 100644 index 0000000000..5e61348c8d --- /dev/null +++ b/firmware/target/hosted/ibasso/dx50/audiohw-dx50.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include "config.h" | ||
26 | #include "debug.h" | ||
27 | |||
28 | #include "debug-ibasso.h" | ||
29 | #include "sysfs-ibasso.h" | ||
30 | |||
31 | |||
32 | extern void set_software_volume(void); | ||
33 | |||
34 | |||
35 | void audiohw_set_volume(int volume) | ||
36 | { | ||
37 | set_software_volume(); | ||
38 | |||
39 | /* | ||
40 | See codec-dx50.h. | ||
41 | -128db -> -1 (adjusted to 0, mute) | ||
42 | -127dB to 0dB -> 1 to 255 in steps of 2 | ||
43 | volume is in centibels (tenth-decibels). | ||
44 | */ | ||
45 | int volume_adjusted = (volume / 10) * 2 + 255; | ||
46 | |||
47 | DEBUGF("DEBUG %s: volume: %d, volume_adjusted: %d.", __func__, volume, volume_adjusted); | ||
48 | |||
49 | if(volume_adjusted > 255) | ||
50 | { | ||
51 | DEBUGF("DEBUG %s: Adjusting volume from %d to 255.", __func__, volume); | ||
52 | volume_adjusted = 255; | ||
53 | } | ||
54 | if(volume_adjusted < 0) | ||
55 | { | ||
56 | DEBUGF("DEBUG %s: Adjusting volume from %d to 0.", __func__, volume); | ||
57 | volume_adjusted = 0; | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | /dev/codec_volume | ||
62 | 0 ... 255 | ||
63 | */ | ||
64 | if(! sysfs_set_int(SYSFS_DX50_CODEC_VOLUME, volume_adjusted)) | ||
65 | { | ||
66 | DEBUGF("ERROR %s: Can not set volume.", __func__); | ||
67 | } | ||
68 | } | ||
diff --git a/firmware/target/hosted/ibasso/dx50/button-dx50.c b/firmware/target/hosted/ibasso/dx50/button-dx50.c new file mode 100644 index 0000000000..b4f6952d44 --- /dev/null +++ b/firmware/target/hosted/ibasso/dx50/button-dx50.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include "config.h" | ||
26 | #include "button.h" | ||
27 | |||
28 | #include "button-ibasso.h" | ||
29 | |||
30 | |||
31 | int handle_button_event(__u16 code, __s32 value, int last_btns) | ||
32 | { | ||
33 | int button = BUTTON_NONE; | ||
34 | |||
35 | switch(code) | ||
36 | { | ||
37 | case EVENT_CODE_BUTTON_PWR: | ||
38 | { | ||
39 | button = BUTTON_POWER; | ||
40 | break; | ||
41 | } | ||
42 | |||
43 | case EVENT_CODE_BUTTON_PWR_LONG: | ||
44 | { | ||
45 | button = BUTTON_POWER_LONG; | ||
46 | break; | ||
47 | } | ||
48 | |||
49 | case EVENT_CODE_BUTTON_VOLPLUS: | ||
50 | { | ||
51 | button = BUTTON_VOL_UP; | ||
52 | break; | ||
53 | } | ||
54 | |||
55 | case EVENT_CODE_BUTTON_VOLMINUS: | ||
56 | { | ||
57 | button = BUTTON_VOL_DOWN; | ||
58 | break; | ||
59 | } | ||
60 | |||
61 | case EVENT_CODE_BUTTON_REV: | ||
62 | { | ||
63 | button = BUTTON_LEFT; | ||
64 | break; | ||
65 | } | ||
66 | |||
67 | case EVENT_CODE_BUTTON_PLAY: | ||
68 | { | ||
69 | button = BUTTON_PLAY; | ||
70 | break; | ||
71 | } | ||
72 | |||
73 | case EVENT_CODE_BUTTON_NEXT: | ||
74 | { | ||
75 | button = BUTTON_RIGHT; | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | default: | ||
80 | { | ||
81 | return BUTTON_NONE; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | int buttons = last_btns; | ||
86 | if(value == EVENT_VALUE_BUTTON_PRESS) | ||
87 | { | ||
88 | buttons = (last_btns | button); | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | buttons = (last_btns & (~ button)); | ||
93 | } | ||
94 | |||
95 | return buttons; | ||
96 | } | ||
diff --git a/firmware/target/hosted/ibasso/dx50/codec-dx50.h b/firmware/target/hosted/ibasso/dx50/codec-dx50.h new file mode 100644 index 0000000000..89a1a3f1c4 --- /dev/null +++ b/firmware/target/hosted/ibasso/dx50/codec-dx50.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #ifndef _CODEC_DX50_H_ | ||
26 | #define _CODEC_DX50_H_ | ||
27 | |||
28 | |||
29 | #define AUDIOHW_CAPS MONO_VOL_CAP | ||
30 | |||
31 | |||
32 | /* | ||
33 | http://www.wolfsonmicro.com/media/76425/WM8740.pdf | ||
34 | |||
35 | 0.5 * ( x - 255 ) = ydB 1 <= x <= 255 | ||
36 | mute x = 0 | ||
37 | |||
38 | x = 255 -> 0dB | ||
39 | . | ||
40 | . | ||
41 | . | ||
42 | x = 2 -> -126.5dB | ||
43 | x = 1 -> -127dB | ||
44 | x = 0 -> -128dB | ||
45 | |||
46 | See audiohw.h, sound.c. | ||
47 | */ | ||
48 | AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -128, 0, -30) | ||
49 | |||
50 | |||
51 | #endif | ||
diff --git a/firmware/target/hosted/ibasso/dx90/audiohw-dx90.c b/firmware/target/hosted/ibasso/dx90/audiohw-dx90.c new file mode 100644 index 0000000000..ef18aae4bd --- /dev/null +++ b/firmware/target/hosted/ibasso/dx90/audiohw-dx90.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include "config.h" | ||
26 | #include "debug.h" | ||
27 | |||
28 | #include "debug-ibasso.h" | ||
29 | #include "sysfs-ibasso.h" | ||
30 | |||
31 | |||
32 | extern void set_software_volume(void); | ||
33 | |||
34 | |||
35 | void audiohw_set_volume(int volume) | ||
36 | { | ||
37 | set_software_volume(); | ||
38 | |||
39 | /* See codec-dx90.h. -2550 to 0 -> 0 to 255 */ | ||
40 | int volume_adjusted = ((volume + 2550) / 10); | ||
41 | |||
42 | DEBUGF("DEBUG %s: volume: %d, volume_adjusted: %d.", __func__, volume, volume_adjusted); | ||
43 | |||
44 | if(volume_adjusted > 255) | ||
45 | { | ||
46 | DEBUGF("DEBUG %s: Adjusting volume from %d to 255.", __func__, volume); | ||
47 | volume_adjusted = 255; | ||
48 | } | ||
49 | if(volume_adjusted < 0) | ||
50 | { | ||
51 | DEBUGF("DEBUG %s: Adjusting volume from %d to 0.", __func__, volume); | ||
52 | volume_adjusted = 0; | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | /sys/class/codec/es9018_volume | ||
57 | 0 ... 255 | ||
58 | */ | ||
59 | if(! sysfs_set_int(SYSFS_DX90_ES9018_VOLUME, volume_adjusted)) | ||
60 | { | ||
61 | DEBUGF("ERROR %s: Can not set volume.", __func__); | ||
62 | } | ||
63 | } | ||
diff --git a/firmware/target/hosted/ibasso/dx90/button-dx90.c b/firmware/target/hosted/ibasso/dx90/button-dx90.c new file mode 100644 index 0000000000..27e4be0c1e --- /dev/null +++ b/firmware/target/hosted/ibasso/dx90/button-dx90.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include "config.h" | ||
26 | #include "button.h" | ||
27 | |||
28 | #include "button-ibasso.h" | ||
29 | |||
30 | |||
31 | int handle_button_event(__u16 code, __s32 value, int last_btns) | ||
32 | { | ||
33 | int button = BUTTON_NONE; | ||
34 | |||
35 | switch(code) | ||
36 | { | ||
37 | case EVENT_CODE_BUTTON_PWR: | ||
38 | { | ||
39 | button = BUTTON_POWER; | ||
40 | break; | ||
41 | } | ||
42 | |||
43 | case EVENT_CODE_BUTTON_PWR_LONG: | ||
44 | { | ||
45 | button = BUTTON_POWER_LONG; | ||
46 | break; | ||
47 | } | ||
48 | |||
49 | case EVENT_CODE_BUTTON_VOLPLUS: | ||
50 | { | ||
51 | button = BUTTON_VOL_UP; | ||
52 | break; | ||
53 | } | ||
54 | |||
55 | case EVENT_CODE_BUTTON_VOLMINUS: | ||
56 | { | ||
57 | button = BUTTON_VOL_DOWN; | ||
58 | break; | ||
59 | } | ||
60 | |||
61 | case EVENT_CODE_BUTTON_REV: | ||
62 | { | ||
63 | button = BUTTON_LEFT; | ||
64 | break; | ||
65 | } | ||
66 | |||
67 | case EVENT_CODE_BUTTON_PLAY: | ||
68 | { | ||
69 | button = BUTTON_PLAY; | ||
70 | break; | ||
71 | } | ||
72 | |||
73 | case EVENT_CODE_BUTTON_NEXT: | ||
74 | { | ||
75 | button = BUTTON_RIGHT; | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | default: | ||
80 | { | ||
81 | return BUTTON_NONE; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | if( (button == BUTTON_RIGHT) | ||
86 | && ((last_btns & BUTTON_LEFT) == BUTTON_LEFT) | ||
87 | && (value == EVENT_VALUE_BUTTON_RELEASE)) | ||
88 | { | ||
89 | /* Workaround for a wrong feedback, only present with DX90. */ | ||
90 | button = BUTTON_LEFT; | ||
91 | } | ||
92 | |||
93 | int buttons = last_btns; | ||
94 | if(value == EVENT_VALUE_BUTTON_PRESS) | ||
95 | { | ||
96 | buttons = (last_btns | button); | ||
97 | } | ||
98 | else | ||
99 | { | ||
100 | buttons = (last_btns & (~button)); | ||
101 | } | ||
102 | |||
103 | return buttons; | ||
104 | } | ||
diff --git a/firmware/target/hosted/ibasso/dx90/codec-dx90.h b/firmware/target/hosted/ibasso/dx90/codec-dx90.h new file mode 100644 index 0000000000..b96377dfec --- /dev/null +++ b/firmware/target/hosted/ibasso/dx90/codec-dx90.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #ifndef _CODEC_DX90_H_ | ||
26 | #define _CODEC_DX90_H_ | ||
27 | |||
28 | |||
29 | #define AUDIOHW_CAPS MONO_VOL_CAP | ||
30 | |||
31 | |||
32 | AUDIOHW_SETTING(VOLUME, "", 0, 1, -255, 0, -128) | ||
33 | |||
34 | |||
35 | #endif | ||
diff --git a/firmware/target/hosted/ibasso/hostfs-ibasso.c b/firmware/target/hosted/ibasso/hostfs-ibasso.c new file mode 100644 index 0000000000..3970d06987 --- /dev/null +++ b/firmware/target/hosted/ibasso/hostfs-ibasso.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <unistd.h> | ||
26 | |||
27 | #include "debug-ibasso.h" | ||
28 | |||
29 | |||
30 | /* See hostfs.h. */ | ||
31 | |||
32 | |||
33 | int hostfs_init(void) | ||
34 | { | ||
35 | TRACE; | ||
36 | |||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | |||
41 | int hostfs_flush(void) | ||
42 | { | ||
43 | TRACE; | ||
44 | |||
45 | sync(); | ||
46 | return 0; | ||
47 | } | ||
diff --git a/firmware/target/hosted/ibasso/lcd-ibasso.c b/firmware/target/hosted/ibasso/lcd-ibasso.c new file mode 100644 index 0000000000..4e03ba7e50 --- /dev/null +++ b/firmware/target/hosted/ibasso/lcd-ibasso.c | |||
@@ -0,0 +1,195 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <errno.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <stdbool.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <linux/fb.h> | ||
30 | #include <sys/ioctl.h> | ||
31 | #include <sys/mman.h> | ||
32 | #include <sys/stat.h> | ||
33 | #include <sys/types.h> | ||
34 | |||
35 | #include "config.h" | ||
36 | #include "debug.h" | ||
37 | #include "events.h" | ||
38 | #include "panic.h" | ||
39 | |||
40 | #include "debug-ibasso.h" | ||
41 | #include "lcd-target.h" | ||
42 | #include "sysfs-ibasso.h" | ||
43 | |||
44 | |||
45 | fb_data *dev_fb = 0; | ||
46 | |||
47 | |||
48 | /* Framebuffer device handle. */ | ||
49 | static int dev_fd = 0; | ||
50 | |||
51 | |||
52 | void lcd_init_device(void) | ||
53 | { | ||
54 | TRACE; | ||
55 | |||
56 | dev_fd = open("/dev/graphics/fb0", O_RDWR); | ||
57 | if(dev_fd == -1) | ||
58 | { | ||
59 | DEBUGF("ERROR %s: open failed on /dev/graphics/fb0, errno: %d.", __func__, errno); | ||
60 | exit(errno); | ||
61 | } | ||
62 | |||
63 | /* Get the changeable information. */ | ||
64 | struct fb_var_screeninfo vinfo; | ||
65 | if(ioctl(dev_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) | ||
66 | { | ||
67 | DEBUGF("ERROR %s: ioctl FBIOGET_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno); | ||
68 | exit(errno); | ||
69 | } | ||
70 | |||
71 | DEBUGF("DEBUG %s: bits_per_pixel: %u, width: %u, height: %u.", __func__, vinfo.bits_per_pixel, vinfo.width, vinfo.height); | ||
72 | |||
73 | /* | ||
74 | Framebuffer does not fit the screen, a bug of iBassos Firmware, not Rockbox. | ||
75 | Cannot be solved with parameters. | ||
76 | */ | ||
77 | /*vinfo.bits_per_pixel = LCD_DEPTH; | ||
78 | vinfo.xres = LCD_WIDTH; | ||
79 | vinfo.xres_virtual = LCD_WIDTH; | ||
80 | vinfo.width = LCD_WIDTH; | ||
81 | vinfo.yres = LCD_HEIGHT; | ||
82 | vinfo.yres_virtual = LCD_HEIGHT; | ||
83 | vinfo.height = LCD_HEIGHT; | ||
84 | vinfo.activate = FB_ACTIVATE_NOW; | ||
85 | if(ioctl(dev_fd, FBIOPUT_VSCREENINFO, &vinfo) == -1) | ||
86 | { | ||
87 | DEBUGF("ERROR %s: ioctl FBIOPUT_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno); | ||
88 | exit(EXIT_FAILURE); | ||
89 | }*/ | ||
90 | |||
91 | |||
92 | /* Sanity check: Does framebuffer config match Rockbox config? */ | ||
93 | size_t screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; | ||
94 | if(screensize != FRAMEBUFFER_SIZE) | ||
95 | { | ||
96 | DEBUGF("ERROR %s: Screen size does not match config: %d != %d.", __func__, screensize, FRAMEBUFFER_SIZE); | ||
97 | exit(EXIT_FAILURE); | ||
98 | } | ||
99 | |||
100 | /* Map the device to memory. */ | ||
101 | dev_fb = mmap(0, FRAMEBUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0); | ||
102 | if(dev_fb == MAP_FAILED) | ||
103 | { | ||
104 | DEBUGF("ERROR %s: mmap failed on /dev/graphics/fb0, errno: %d.", __func__, errno); | ||
105 | exit(errno); | ||
106 | } | ||
107 | |||
108 | /* Activate Rockbox LCD. */ | ||
109 | lcd_enable(true); | ||
110 | } | ||
111 | |||
112 | |||
113 | void lcd_shutdown(void) | ||
114 | { | ||
115 | TRACE; | ||
116 | |||
117 | lcd_set_active(false); | ||
118 | munmap(dev_fb, FRAMEBUFFER_SIZE); | ||
119 | close(dev_fd) ; | ||
120 | } | ||
121 | |||
122 | |||
123 | /* | ||
124 | Left as reference. Unblanking does not work as expected, will not enable LCD after a few | ||
125 | seconds of power down. | ||
126 | Instead the backlight power is toggled. | ||
127 | */ | ||
128 | /*void lcd_power_on(void) | ||
129 | { | ||
130 | TRACE; | ||
131 | |||
132 | if(ioctl(dev_fd, FBIOBLANK, VESA_NO_BLANKING) == -1) | ||
133 | { | ||
134 | DEBUGF("ERROR %s: ioctl FBIOBLANK failed on /dev/graphics/fb0, errno: %d.", __func__, errno); | ||
135 | panicf("ERROR %s: ioctl FBIOBLANK failed on /dev/graphics/fb0, errno: %d.", __func__, errno); | ||
136 | return; | ||
137 | } | ||
138 | |||
139 | lcd_set_active(true); | ||
140 | send_event(LCD_EVENT_ACTIVATION, NULL); | ||
141 | } | ||
142 | |||
143 | |||
144 | void lcd_power_off(void) | ||
145 | { | ||
146 | TRACE; | ||
147 | |||
148 | lcd_set_active(false); | ||
149 | |||
150 | if(ioctl(dev_fd, FBIOBLANK, VESA_POWERDOWN) == -1) | ||
151 | { | ||
152 | DEBUGF("ERROR %s: ioctl FBIOBLANK failed on /dev/graphics/fb0, errno: %d.", __func__, errno); | ||
153 | panicf("ERROR %s: ioctl FBIOBLANK failed on /dev/graphics/fb0, errno: %d.", __func__, errno); | ||
154 | return; | ||
155 | } | ||
156 | }*/ | ||
157 | |||
158 | |||
159 | void lcd_enable(bool on) | ||
160 | { | ||
161 | TRACE; | ||
162 | |||
163 | lcd_set_active(on); | ||
164 | |||
165 | if(on) | ||
166 | { | ||
167 | /* | ||
168 | /sys/power/state | ||
169 | on: Cancel suspend. | ||
170 | */ | ||
171 | if(! sysfs_set_string(SYSFS_POWER_STATE, "on")) | ||
172 | { | ||
173 | DEBUGF("ERROR %s: Can not set power state.", __func__); | ||
174 | } | ||
175 | |||
176 | send_event(LCD_EVENT_ACTIVATION, NULL); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | |||
181 | void lcd_sleep(void) | ||
182 | { | ||
183 | TRACE; | ||
184 | |||
185 | /* | ||
186 | See system_init(). Without suspend blocker und mute prevention this will interrupt playback. | ||
187 | Essentially, we are turning off the touch screen. | ||
188 | /sys/power/state | ||
189 | mem: Suspend to RAM. | ||
190 | */ | ||
191 | if(! sysfs_set_string(SYSFS_POWER_STATE, "mem")) | ||
192 | { | ||
193 | DEBUGF("ERROR %s: Can not set power state.", __func__); | ||
194 | } | ||
195 | } | ||
diff --git a/firmware/target/hosted/ibasso/lcd-target.h b/firmware/target/hosted/ibasso/lcd-target.h new file mode 100644 index 0000000000..50cc92599d --- /dev/null +++ b/firmware/target/hosted/ibasso/lcd-target.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #ifndef __LCD_TARGET_H__ | ||
26 | #define __LCD_TARGET_H__ | ||
27 | |||
28 | |||
29 | #include "lcd.h" | ||
30 | |||
31 | |||
32 | /* | ||
33 | Framebuffer device and framebuffer access. | ||
34 | See lcd-memframe.c | ||
35 | */ | ||
36 | extern fb_data *dev_fb; | ||
37 | #define LCD_FRAMEBUF_ADDR(col, row) (dev_fb + row * LCD_WIDTH + col) | ||
38 | |||
39 | |||
40 | /* See lcd-memframe.c */ | ||
41 | extern void lcd_set_active(bool active); | ||
42 | |||
43 | |||
44 | #endif | ||
diff --git a/firmware/target/hosted/ibasso/pcm-ibasso.c b/firmware/target/hosted/ibasso/pcm-ibasso.c new file mode 100644 index 0000000000..14ef298af0 --- /dev/null +++ b/firmware/target/hosted/ibasso/pcm-ibasso.c | |||
@@ -0,0 +1,488 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <pthread.h> | ||
26 | #include <stdbool.h> | ||
27 | #include <unistd.h> | ||
28 | |||
29 | #include "config.h" | ||
30 | #include "debug.h" | ||
31 | #include "panic.h" | ||
32 | #include "pcm.h" | ||
33 | #include "pcm-internal.h" | ||
34 | |||
35 | #include "sound/asound.h" | ||
36 | #include "tinyalsa/asoundlib.h" | ||
37 | |||
38 | #include "debug-ibasso.h" | ||
39 | #include "sysfs-ibasso.h" | ||
40 | |||
41 | |||
42 | /* Tiny alsa handle. */ | ||
43 | static struct pcm* _alsa_handle = NULL; | ||
44 | |||
45 | |||
46 | /* Bytes left in the Rockbox PCM frame buffer. */ | ||
47 | static size_t _pcm_buffer_size = 0; | ||
48 | |||
49 | |||
50 | /* Rockbox PCM frame buffer. */ | ||
51 | static const void *_pcm_buffer = NULL; | ||
52 | |||
53 | |||
54 | /* | ||
55 | 1: PCM thread suspended. | ||
56 | 0: PCM thread running. | ||
57 | These are used by pcm_play_[lock|unlock] or pcm_play_dma_[start|stop|pause]. These need to be | ||
58 | separated because of nested calls for locking and stopping. | ||
59 | */ | ||
60 | static volatile sig_atomic_t _dma_stopped = 1; | ||
61 | static volatile sig_atomic_t _dma_locked = 1; | ||
62 | |||
63 | |||
64 | /* Mutex for PCM thread suspend/unsuspend. */ | ||
65 | static pthread_mutex_t _dma_suspended_mtx = PTHREAD_MUTEX_INITIALIZER; | ||
66 | |||
67 | |||
68 | /* Signal condition for PCM thread suspend/unsuspend. */ | ||
69 | static pthread_cond_t _dma_suspended_cond = PTHREAD_COND_INITIALIZER; | ||
70 | |||
71 | |||
72 | static void* pcm_thread_run(void* nothing) | ||
73 | { | ||
74 | (void) nothing; | ||
75 | |||
76 | DEBUGF("DEBUG %s: Thread start.", __func__); | ||
77 | |||
78 | while(true) | ||
79 | { | ||
80 | pthread_mutex_lock(&_dma_suspended_mtx); | ||
81 | while((_dma_stopped == 1) || (_dma_locked == 1)) | ||
82 | { | ||
83 | DEBUGF("DEBUG %s: Playback suspended.", __func__); | ||
84 | pthread_cond_wait(&_dma_suspended_cond, &_dma_suspended_mtx); | ||
85 | DEBUGF("DEBUG %s: Playback resumed.", __func__); | ||
86 | } | ||
87 | pthread_mutex_unlock(&_dma_suspended_mtx); | ||
88 | |||
89 | if(_pcm_buffer_size == 0) | ||
90 | { | ||
91 | /* Retrive a new PCM buffer from Rockbox. */ | ||
92 | if(! pcm_play_dma_complete_callback(PCM_DMAST_OK, &_pcm_buffer, &_pcm_buffer_size)) | ||
93 | { | ||
94 | DEBUGF("DEBUG %s: No new buffer.", __func__); | ||
95 | |||
96 | usleep( 10000 ); | ||
97 | continue; | ||
98 | } | ||
99 | } | ||
100 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); | ||
101 | |||
102 | /* This relies on Rockbox PCM frame buffer size == ALSA PCM frame buffer size. */ | ||
103 | if(pcm_write(_alsa_handle, _pcm_buffer, _pcm_buffer_size) != 0) | ||
104 | { | ||
105 | DEBUGF("ERROR %s: pcm_write failed: %s.", __func__, pcm_get_error(_alsa_handle)); | ||
106 | |||
107 | usleep( 10000 ); | ||
108 | continue; | ||
109 | } | ||
110 | |||
111 | _pcm_buffer_size = 0; | ||
112 | |||
113 | /*DEBUGF("DEBUG %s: Thread running.", __func__);*/ | ||
114 | } | ||
115 | |||
116 | DEBUGF("DEBUG %s: Thread end.", __func__); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | |||
122 | #ifdef DEBUG | ||
123 | |||
124 | /* https://github.com/tinyalsa/tinyalsa/blob/master/tinypcminfo.c */ | ||
125 | |||
126 | static const char* format_lookup[] = | ||
127 | { | ||
128 | /*[0] =*/ "S8", | ||
129 | "U8", | ||
130 | "S16_LE", | ||
131 | "S16_BE", | ||
132 | "U16_LE", | ||
133 | "U16_BE", | ||
134 | "S24_LE", | ||
135 | "S24_BE", | ||
136 | "U24_LE", | ||
137 | "U24_BE", | ||
138 | "S32_LE", | ||
139 | "S32_BE", | ||
140 | "U32_LE", | ||
141 | "U32_BE", | ||
142 | "FLOAT_LE", | ||
143 | "FLOAT_BE", | ||
144 | "FLOAT64_LE", | ||
145 | "FLOAT64_BE", | ||
146 | "IEC958_SUBFRAME_LE", | ||
147 | "IEC958_SUBFRAME_BE", | ||
148 | "MU_LAW", | ||
149 | "A_LAW", | ||
150 | "IMA_ADPCM", | ||
151 | "MPEG", | ||
152 | /*[24] =*/ "GSM", | ||
153 | [31] = "SPECIAL", | ||
154 | "S24_3LE", | ||
155 | "S24_3BE", | ||
156 | "U24_3LE", | ||
157 | "U24_3BE", | ||
158 | "S20_3LE", | ||
159 | "S20_3BE", | ||
160 | "U20_3LE", | ||
161 | "U20_3BE", | ||
162 | "S18_3LE", | ||
163 | "S18_3BE", | ||
164 | "U18_3LE", | ||
165 | /*[43] =*/ "U18_3BE" | ||
166 | }; | ||
167 | |||
168 | |||
169 | static const char* pcm_get_format_name(unsigned int bit_index) | ||
170 | { | ||
171 | return(bit_index < 43 ? format_lookup[bit_index] : NULL); | ||
172 | } | ||
173 | |||
174 | #endif | ||
175 | |||
176 | |||
177 | /* Thread that copies the Rockbox PCM buffer to ALSA. */ | ||
178 | static pthread_t _pcm_thread; | ||
179 | |||
180 | |||
181 | /* ALSA card and device. */ | ||
182 | static const unsigned int CARD = 0; | ||
183 | static const unsigned int DEVICE = 0; | ||
184 | |||
185 | |||
186 | /* ALSA config. */ | ||
187 | static struct pcm_config _config; | ||
188 | |||
189 | |||
190 | void pcm_play_dma_init(void) | ||
191 | { | ||
192 | TRACE; | ||
193 | |||
194 | #ifdef DEBUG | ||
195 | |||
196 | /* | ||
197 | DEBUG pcm_play_dma_init: Access: 0x000009 | ||
198 | DEBUG pcm_play_dma_init: Format[0]: 0x000044 | ||
199 | DEBUG pcm_play_dma_init: Format[1]: 0x000010 | ||
200 | DEBUG pcm_play_dma_init: Format: S16_LE | ||
201 | DEBUG pcm_play_dma_init: Format: S24_LE | ||
202 | DEBUG pcm_play_dma_init: Format: S20_3LE | ||
203 | DEBUG pcm_play_dma_init: Subformat: 0x000001 | ||
204 | DEBUG pcm_play_dma_init: Rate: min = 8000Hz, max = 192000Hz | ||
205 | DEBUG pcm_play_dma_init: Channels: min = 2, max = 2 | ||
206 | DEBUG pcm_play_dma_init: Sample bits: min=16, max=32 | ||
207 | DEBUG pcm_play_dma_init: Period size: min=8, max=10922 | ||
208 | DEBUG pcm_play_dma_init: Period count: min=3, max=128 | ||
209 | DEBUG pcm_play_dma_init: 0 mixer controls. | ||
210 | */ | ||
211 | |||
212 | struct pcm_params* params = pcm_params_get(CARD, DEVICE, PCM_OUT); | ||
213 | if(params == NULL) | ||
214 | { | ||
215 | DEBUGF("ERROR %s: Card/device does not exist.", __func__); | ||
216 | panicf("ERROR %s: Card/device does not exist.", __func__); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | struct pcm_mask* m = pcm_params_get_mask(params, PCM_PARAM_ACCESS); | ||
221 | if(m) | ||
222 | { | ||
223 | DEBUGF("DEBUG %s: Access: %#08x", __func__, m->bits[0]); | ||
224 | } | ||
225 | |||
226 | m = pcm_params_get_mask(params, PCM_PARAM_FORMAT); | ||
227 | if(m) | ||
228 | { | ||
229 | DEBUGF("DEBUG %s: Format[0]: %#08x", __func__, m->bits[0]); | ||
230 | DEBUGF("DEBUG %s: Format[1]: %#08x", __func__, m->bits[1]); | ||
231 | |||
232 | unsigned int j; | ||
233 | unsigned int k; | ||
234 | const unsigned int bitcount = sizeof(m->bits[0]) * 8; | ||
235 | for(k = 0; k < 2; ++k) | ||
236 | { | ||
237 | for(j = 0; j < bitcount; ++j) | ||
238 | { | ||
239 | const char* name; | ||
240 | if(m->bits[k] & (1 << j)) | ||
241 | { | ||
242 | name = pcm_get_format_name(j + (k * bitcount)); | ||
243 | if(name) | ||
244 | { | ||
245 | DEBUGF("DEBUG %s: Format: %s", __func__, name); | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | } | ||
251 | |||
252 | m = pcm_params_get_mask(params, PCM_PARAM_SUBFORMAT); | ||
253 | if(m) | ||
254 | { | ||
255 | DEBUGF("DEBUG %s: Subformat: %#08x", __func__, m->bits[0]); | ||
256 | } | ||
257 | |||
258 | unsigned int min = pcm_params_get_min(params, PCM_PARAM_RATE); | ||
259 | unsigned int max = pcm_params_get_max(params, PCM_PARAM_RATE) ; | ||
260 | DEBUGF("DEBUG %s: Rate: min = %uHz, max = %uHz", __func__, min, max); | ||
261 | |||
262 | min = pcm_params_get_min(params, PCM_PARAM_CHANNELS); | ||
263 | max = pcm_params_get_max(params, PCM_PARAM_CHANNELS); | ||
264 | DEBUGF("DEBUG %s: Channels: min = %u, max = %u", __func__, min, max); | ||
265 | |||
266 | min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS); | ||
267 | max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS); | ||
268 | DEBUGF("DEBUG %s: Sample bits: min=%u, max=%u", __func__, min, max); | ||
269 | |||
270 | min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE); | ||
271 | max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE); | ||
272 | DEBUGF("DEBUG %s: Period size: min=%u, max=%u", __func__, min, max); | ||
273 | |||
274 | min = pcm_params_get_min(params, PCM_PARAM_PERIODS); | ||
275 | max = pcm_params_get_max(params, PCM_PARAM_PERIODS); | ||
276 | DEBUGF("DEBUG %s: Period count: min=%u, max=%u", __func__, min, max); | ||
277 | |||
278 | pcm_params_free(params); | ||
279 | |||
280 | struct mixer* mixer = mixer_open(CARD); | ||
281 | if(! mixer) | ||
282 | { | ||
283 | DEBUGF("ERROR %s: Failed to open mixer.", __func__); | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | int num_ctls = mixer_get_num_ctls(mixer); | ||
288 | |||
289 | DEBUGF("DEBUG %s: %d mixer controls.", __func__, num_ctls); | ||
290 | |||
291 | mixer_close(mixer); | ||
292 | } | ||
293 | |||
294 | #endif | ||
295 | |||
296 | if(_alsa_handle != NULL) | ||
297 | { | ||
298 | DEBUGF("ERROR %s: Allready initialized.", __func__); | ||
299 | panicf("ERROR %s: Allready initialized.", __func__); | ||
300 | return; | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | Rockbox outputs 16 Bit/44.1kHz stereo by default. | ||
305 | |||
306 | ALSA frame buffer size = config.period_count * config.period_size * config.channels * (16 \ 8) | ||
307 | = 4 * 256 * 2 * 2 | ||
308 | = 4096 | ||
309 | = Rockbox PCM buffer size | ||
310 | pcm_thread_run relies on this size match. See pcm_mixer.h. | ||
311 | */ | ||
312 | _config.channels = 2; | ||
313 | _config.rate = 44100; | ||
314 | _config.period_size = 256; | ||
315 | _config.period_count = 4; | ||
316 | _config.format = PCM_FORMAT_S16_LE; | ||
317 | _config.start_threshold = 0; | ||
318 | _config.stop_threshold = 0; | ||
319 | _config.silence_threshold = 0; | ||
320 | |||
321 | _alsa_handle = pcm_open(CARD, DEVICE, PCM_OUT, &_config); | ||
322 | if(! pcm_is_ready(_alsa_handle)) | ||
323 | { | ||
324 | DEBUGF("ERROR %s: pcm_open failed: %s.", __func__, pcm_get_error(_alsa_handle)); | ||
325 | panicf("ERROR %s: pcm_open failed: %s.", __func__, pcm_get_error(_alsa_handle)); | ||
326 | return; | ||
327 | } | ||
328 | |||
329 | DEBUGF("DEBUG %s: ALSA PCM frame buffer size: %d.", __func__, pcm_frames_to_bytes(_alsa_handle, pcm_get_buffer_size(_alsa_handle))); | ||
330 | |||
331 | /* Create pcm thread in the suspended state. */ | ||
332 | pthread_mutex_lock(&_dma_suspended_mtx); | ||
333 | _dma_stopped = 1; | ||
334 | _dma_locked = 1; | ||
335 | pthread_create(&_pcm_thread, NULL, pcm_thread_run, NULL); | ||
336 | pthread_mutex_unlock(&_dma_suspended_mtx); | ||
337 | } | ||
338 | |||
339 | |||
340 | void pcm_play_dma_start(const void *addr, size_t size) | ||
341 | { | ||
342 | TRACE; | ||
343 | |||
344 | /* | ||
345 | DX50 | ||
346 | /sys/class/codec/mute | ||
347 | Mute: echo 'A' > /sys/class/codec/mute | ||
348 | Unmute: echo 'B' > /sys/class/codec/mute | ||
349 | |||
350 | DX90? | ||
351 | */ | ||
352 | if(! sysfs_set_char(SYSFS_MUTE, 'B')) | ||
353 | { | ||
354 | DEBUGF("ERROR %s: Could not unmute.", __func__); | ||
355 | panicf("ERROR %s: Could not unmute.", __func__); | ||
356 | } | ||
357 | |||
358 | _pcm_buffer = addr; | ||
359 | _pcm_buffer_size = size; | ||
360 | |||
361 | pthread_mutex_lock(&_dma_suspended_mtx); | ||
362 | _dma_stopped = 0; | ||
363 | pthread_cond_signal(&_dma_suspended_cond); | ||
364 | pthread_mutex_unlock(&_dma_suspended_mtx); | ||
365 | } | ||
366 | |||
367 | |||
368 | /* TODO: Why is this in the API if it gets never called? */ | ||
369 | void pcm_play_dma_pause(bool pause) | ||
370 | { | ||
371 | TRACE; | ||
372 | |||
373 | pthread_mutex_lock(&_dma_suspended_mtx); | ||
374 | _dma_stopped = pause ? 1 : 0; | ||
375 | if(_dma_stopped == 0) | ||
376 | { | ||
377 | pthread_cond_signal(&_dma_suspended_cond); | ||
378 | } | ||
379 | pthread_mutex_unlock(&_dma_suspended_mtx); | ||
380 | } | ||
381 | |||
382 | |||
383 | void pcm_play_dma_stop(void) | ||
384 | { | ||
385 | TRACE; | ||
386 | |||
387 | pthread_mutex_lock(&_dma_suspended_mtx); | ||
388 | _dma_stopped = 1; | ||
389 | pcm_stop(_alsa_handle); | ||
390 | pthread_mutex_unlock(&_dma_suspended_mtx); | ||
391 | } | ||
392 | |||
393 | |||
394 | /* Unessecary play locks before pcm_play_dma_postinit. */ | ||
395 | static int _play_lock_recursion_count = -10000; | ||
396 | |||
397 | |||
398 | void pcm_play_dma_postinit(void) | ||
399 | { | ||
400 | TRACE; | ||
401 | |||
402 | _play_lock_recursion_count = 0; | ||
403 | } | ||
404 | |||
405 | |||
406 | void pcm_play_lock(void) | ||
407 | { | ||
408 | TRACE; | ||
409 | |||
410 | ++_play_lock_recursion_count; | ||
411 | |||
412 | if(_play_lock_recursion_count == 1) | ||
413 | { | ||
414 | pthread_mutex_lock(&_dma_suspended_mtx); | ||
415 | _dma_locked = 1; | ||
416 | pthread_mutex_unlock(&_dma_suspended_mtx); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | |||
421 | void pcm_play_unlock(void) | ||
422 | { | ||
423 | TRACE; | ||
424 | |||
425 | --_play_lock_recursion_count; | ||
426 | |||
427 | if(_play_lock_recursion_count == 0) | ||
428 | { | ||
429 | pthread_mutex_lock(&_dma_suspended_mtx); | ||
430 | _dma_locked = 0; | ||
431 | pthread_cond_signal(&_dma_suspended_cond); | ||
432 | pthread_mutex_unlock(&_dma_suspended_mtx); | ||
433 | } | ||
434 | } | ||
435 | |||
436 | |||
437 | void pcm_dma_apply_settings(void) | ||
438 | { | ||
439 | unsigned int rate = pcm_get_frequency(); | ||
440 | |||
441 | DEBUGF("DEBUG %s: Current sample rate: %u, next sampe rate: %u.", __func__, _config.rate, rate); | ||
442 | |||
443 | if(( _config.rate != rate) && (rate >= 8000) && (rate <= 192000)) | ||
444 | { | ||
445 | _config.rate = rate; | ||
446 | |||
447 | pcm_close(_alsa_handle); | ||
448 | _alsa_handle = pcm_open(CARD, DEVICE, PCM_OUT, &_config); | ||
449 | |||
450 | if(! pcm_is_ready(_alsa_handle)) | ||
451 | { | ||
452 | DEBUGF("ERROR %s: pcm_open failed: %s.", __func__, pcm_get_error(_alsa_handle)); | ||
453 | panicf("ERROR %s: pcm_open failed: %s.", __func__, pcm_get_error(_alsa_handle)); | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | |||
458 | |||
459 | size_t pcm_get_bytes_waiting(void) | ||
460 | { | ||
461 | TRACE; | ||
462 | |||
463 | return _pcm_buffer_size; | ||
464 | } | ||
465 | |||
466 | |||
467 | /* TODO: WTF */ | ||
468 | const void* pcm_play_dma_get_peak_buffer(int* count) | ||
469 | { | ||
470 | TRACE; | ||
471 | |||
472 | uintptr_t addr = (uintptr_t) _pcm_buffer; | ||
473 | *count = _pcm_buffer_size / 4; | ||
474 | return (void*) ((addr + 3) & ~3); | ||
475 | } | ||
476 | |||
477 | |||
478 | void pcm_close_device(void) | ||
479 | { | ||
480 | TRACE; | ||
481 | |||
482 | pthread_mutex_lock(&_dma_suspended_mtx); | ||
483 | _dma_stopped = 1; | ||
484 | pthread_mutex_unlock(&_dma_suspended_mtx); | ||
485 | |||
486 | pcm_close(_alsa_handle); | ||
487 | _alsa_handle = NULL; | ||
488 | } | ||
diff --git a/firmware/target/hosted/ibasso/pcm-ibasso.h b/firmware/target/hosted/ibasso/pcm-ibasso.h new file mode 100644 index 0000000000..588c4dfb9b --- /dev/null +++ b/firmware/target/hosted/ibasso/pcm-ibasso.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #ifndef __PCM_IBASSO_H__ | ||
26 | #define __PCM_IBASSO_H__ | ||
27 | |||
28 | |||
29 | /* Clean up the audio device handler. */ | ||
30 | void pcm_close_device(void); | ||
31 | |||
32 | |||
33 | #endif | ||
diff --git a/firmware/target/hosted/ibasso/power-ibasso.c b/firmware/target/hosted/ibasso/power-ibasso.c new file mode 100644 index 0000000000..8257de5f33 --- /dev/null +++ b/firmware/target/hosted/ibasso/power-ibasso.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <stdbool.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <sys/reboot.h> | ||
28 | |||
29 | #include "config.h" | ||
30 | #include "debug.h" | ||
31 | #include "power.h" | ||
32 | |||
33 | #include "button-ibasso.h" | ||
34 | #include "debug-ibasso.h" | ||
35 | #include "pcm-ibasso.h" | ||
36 | #include "sysfs-ibasso.h" | ||
37 | #include "vold-ibasso.h" | ||
38 | |||
39 | |||
40 | unsigned int power_input_status(void) | ||
41 | { | ||
42 | /*TRACE;*/ | ||
43 | |||
44 | /* | ||
45 | /sys/class/power_supply/usb/present | ||
46 | 0: No external power supply connected. | ||
47 | 1: External power supply connected. | ||
48 | */ | ||
49 | int val = 0; | ||
50 | if(! sysfs_get_int(SYSFS_USB_POWER_PRESENT, &val)) | ||
51 | { | ||
52 | DEBUGF("ERROR %s: Can not get power supply status.", __func__); | ||
53 | return POWER_INPUT_NONE; | ||
54 | } | ||
55 | |||
56 | return val ? POWER_INPUT_USB_CHARGER : POWER_INPUT_NONE; | ||
57 | } | ||
58 | |||
59 | |||
60 | void power_off(void) | ||
61 | { | ||
62 | TRACE; | ||
63 | |||
64 | button_close_device(); | ||
65 | |||
66 | if(vold_monitor_forced_close_imminent()) | ||
67 | { | ||
68 | /* | ||
69 | We are here, because Android Vold is going to kill Rockbox. Instead of powering off, | ||
70 | we exit into the loader. | ||
71 | */ | ||
72 | DEBUGF("DEBUG %s: Exit Rockbox.", __func__); | ||
73 | exit(42); | ||
74 | } | ||
75 | |||
76 | reboot(RB_POWER_OFF); | ||
77 | } | ||
78 | |||
79 | |||
80 | /* Returns true, if battery is charging, false else. */ | ||
81 | bool charging_state(void) | ||
82 | { | ||
83 | /*TRACE;*/ | ||
84 | |||
85 | /* | ||
86 | /sys/class/power_supply/battery/status | ||
87 | "Full", "Charging", "Discharging" | ||
88 | */ | ||
89 | char state[9]; | ||
90 | if(! sysfs_get_string(SYSFS_BATTERY_STATUS, state, 9)) | ||
91 | { | ||
92 | DEBUGF("ERROR %s: Can not get battery charging state.", __func__); | ||
93 | return false; | ||
94 | } | ||
95 | |||
96 | return(strcmp(state, "Charging") == 0);; | ||
97 | } | ||
diff --git a/firmware/target/hosted/ibasso/powermgmt-ibasso.c b/firmware/target/hosted/ibasso/powermgmt-ibasso.c new file mode 100644 index 0000000000..7df0064097 --- /dev/null +++ b/firmware/target/hosted/ibasso/powermgmt-ibasso.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <stdio.h> | ||
26 | |||
27 | #include "config.h" | ||
28 | #include "debug.h" | ||
29 | #include "panic.h" | ||
30 | |||
31 | #include "debug-ibasso.h" | ||
32 | #include "sysfs-ibasso.h" | ||
33 | |||
34 | |||
35 | /* Based on batterymonitor with PISEN and Samsung SIII battery. */ | ||
36 | |||
37 | |||
38 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = | ||
39 | { | ||
40 | 3600 | ||
41 | }; | ||
42 | |||
43 | |||
44 | const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = | ||
45 | { | ||
46 | 3500 | ||
47 | }; | ||
48 | |||
49 | |||
50 | /* | ||
51 | Averages at percent of running time from five measuremnts with PISEN and Samsung SIII battery | ||
52 | during normal usage. | ||
53 | |||
54 | Mongo default values (?) | ||
55 | < 3660 (0%), < 3730 (1% - 10%), < 3780 (11% - 20%), < 3830 (21% - 40%), < 3950 (41% - 60%), | ||
56 | < 4080 (61% - 80%), > 4081 (81% - 100%) | ||
57 | */ | ||
58 | const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = | ||
59 | { | ||
60 | { 3522, 3660, 3720, 3752, 3784, 3827, 3896, 3978, 4072, 4168, 4255 } | ||
61 | }; | ||
62 | |||
63 | |||
64 | /* Copied from percent_to_volt_discharge. */ | ||
65 | const unsigned short percent_to_volt_charge[11] = | ||
66 | { | ||
67 | 3500, 3544, 3578, 3623, 3660, 3773, 3782, 3853, 3980, 4130, 4360 | ||
68 | }; | ||
69 | |||
70 | |||
71 | static int _battery_present = -1; | ||
72 | |||
73 | |||
74 | int _battery_voltage(void) | ||
75 | { | ||
76 | /*TRACE;*/ | ||
77 | |||
78 | if( (_battery_present == -1) | ||
79 | && (! sysfs_get_int(SYSFS_BATTERY_PRESENT, &_battery_present))) | ||
80 | { | ||
81 | /* This check is only done once at startup. */ | ||
82 | |||
83 | DEBUGF("ERROR %s: Can not get current battery availabilty.", __func__); | ||
84 | _battery_present = 1; | ||
85 | } | ||
86 | |||
87 | int val; | ||
88 | |||
89 | if(_battery_present == 1) | ||
90 | { | ||
91 | /* Battery is present. */ | ||
92 | |||
93 | /* | ||
94 | /sys/class/power_supply/battery/voltage_now | ||
95 | Voltage in microvolt. | ||
96 | */ | ||
97 | if(! sysfs_get_int(SYSFS_BATTERY_VOLTAGE_NOW, &val)) | ||
98 | { | ||
99 | DEBUGF("ERROR %s: Can not get current battery voltage.", __func__); | ||
100 | return 0; | ||
101 | } | ||
102 | } | ||
103 | else | ||
104 | { | ||
105 | /* | ||
106 | No battery, so we have to be running solely from USB power. | ||
107 | This will prevent Rockbox from forcing shutdown due to low power. | ||
108 | */ | ||
109 | |||
110 | /* | ||
111 | /sys/class/power_supply/usb/voltage_now | ||
112 | Voltage in microvolt. | ||
113 | */ | ||
114 | if(! sysfs_get_int(SYSFS_USB_POWER_VOLTAGE_NOW, &val)) | ||
115 | { | ||
116 | DEBUGF("ERROR %s: Can not get current USB voltage.", __func__); | ||
117 | return 0; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | return(val / 1000); | ||
122 | } | ||
diff --git a/firmware/target/hosted/ibasso/sysfs-ibasso.c b/firmware/target/hosted/ibasso/sysfs-ibasso.c new file mode 100644 index 0000000000..8ca3edf387 --- /dev/null +++ b/firmware/target/hosted/ibasso/sysfs-ibasso.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <stdio.h> | ||
26 | #include <string.h> | ||
27 | |||
28 | #include "config.h" | ||
29 | #include "debug.h" | ||
30 | |||
31 | #include "debug-ibasso.h" | ||
32 | #include "sysfs-ibasso.h" | ||
33 | |||
34 | |||
35 | static const char* SYSFS_PATHS[] = | ||
36 | { | ||
37 | /* SYSFS_DX50_CODEC_VOLUME */ | ||
38 | "/dev/codec_volume", | ||
39 | |||
40 | /* SYSFS_HOLDKEY */ | ||
41 | "/sys/class/axppower/holdkey", | ||
42 | |||
43 | /* SYSFS_DX90_ES9018_VOLUME */ | ||
44 | "/sys/class/codec/es9018_volume", | ||
45 | |||
46 | /* SYSFS_MUTE */ | ||
47 | "/sys/class/codec/mute", | ||
48 | |||
49 | /* SYSFS_WM8740_MUTE */ | ||
50 | "/sys/class/codec/wm8740_mute", | ||
51 | |||
52 | /* SYSFS_BATTERY_CAPACITY */ | ||
53 | "/sys/class/power_supply/battery/capacity", | ||
54 | |||
55 | /* SYSFS_BATTERY_CURRENT_NOW */ | ||
56 | "/sys/class/power_supply/battery/current_now", | ||
57 | |||
58 | /* SYSFS_BATTERY_ENERGY_FULL_DESIGN */ | ||
59 | "/sys/class/power_supply/battery/energy_full_design", | ||
60 | |||
61 | /* SYSFS_BATTERY_HEALTH */ | ||
62 | "/sys/class/power_supply/battery/health", | ||
63 | |||
64 | /* SYSFS_BATTERY_MODEL_NAME */ | ||
65 | "/sys/class/power_supply/battery/model_name", | ||
66 | |||
67 | /* SYSFS_BATTERY_ONLINE */ | ||
68 | "/sys/class/power_supply/battery/online", | ||
69 | |||
70 | /* SYSFS_BATTERY_PRESENT */ | ||
71 | "/sys/class/power_supply/battery/present", | ||
72 | |||
73 | /* SYSFS_BATTERY_STATUS */ | ||
74 | "/sys/class/power_supply/battery/status", | ||
75 | |||
76 | /* SYSFS_BATTERY_TECHNOLOGY */ | ||
77 | "/sys/class/power_supply/battery/technology", | ||
78 | |||
79 | /* SYSFS_BATTERY_TEMP */ | ||
80 | "/sys/class/power_supply/battery/temp", | ||
81 | |||
82 | /* SYSFS_BATTERY_TYPE */ | ||
83 | "/sys/class/power_supply/battery/type", | ||
84 | |||
85 | /* SYSFS_BATTERY_VOLTAGE_MAX_DESIGN */ | ||
86 | "/sys/class/power_supply/battery/voltage_max_design", | ||
87 | |||
88 | /* SYSFS_BATTERY_VOLTAGE_MIN_DESIGN */ | ||
89 | "/sys/class/power_supply/battery/voltage_min_design", | ||
90 | |||
91 | /* SYSFS_BATTERY_VOLTAGE_NOW */ | ||
92 | "/sys/class/power_supply/battery/voltage_now", | ||
93 | |||
94 | /* SYSFS_USB_POWER_CURRENT_NOW */ | ||
95 | "/sys/class/power_supply/usb/current_now", | ||
96 | |||
97 | /* SYSFS_USB_POWER_ONLINE */ | ||
98 | "/sys/class/power_supply/usb/online", | ||
99 | |||
100 | /* SYSFS_USB_POWER_PRESENT */ | ||
101 | "/sys/class/power_supply/usb/present", | ||
102 | |||
103 | /* SYSFS_USB_POWER_VOLTAGE_NOW */ | ||
104 | "/sys/class/power_supply/usb/voltage_now", | ||
105 | |||
106 | /* SYSFS_BACKLIGHT_POWER */ | ||
107 | "/sys/devices/platform/rk29_backlight/backlight/rk28_bl/bl_power", | ||
108 | |||
109 | /* SYSFS_BACKLIGHT_BRIGHTNESS */ | ||
110 | "/sys/devices/platform/rk29_backlight/backlight/rk28_bl/brightness", | ||
111 | |||
112 | /* SYSFS_POWER_STATE */ | ||
113 | "/sys/power/state", | ||
114 | |||
115 | /* SYSFS_POWER_WAKE_LOCK */ | ||
116 | "/sys/power/wake_lock" | ||
117 | }; | ||
118 | |||
119 | |||
120 | static FILE* open_read(const char* file_name) | ||
121 | { | ||
122 | FILE *f = fopen(file_name, "r"); | ||
123 | if(f == NULL) | ||
124 | { | ||
125 | DEBUGF("ERROR %s: Can not open %s for reading.", __func__, file_name); | ||
126 | } | ||
127 | |||
128 | return f; | ||
129 | } | ||
130 | |||
131 | |||
132 | static FILE* open_write(const char* file_name) | ||
133 | { | ||
134 | FILE *f = fopen(file_name, "w"); | ||
135 | if(f == NULL) | ||
136 | { | ||
137 | DEBUGF("ERROR %s: Can not open %s for writing.", __func__, file_name); | ||
138 | } | ||
139 | |||
140 | return f; | ||
141 | } | ||
142 | |||
143 | |||
144 | bool sysfs_get_int(enum sys_fs_interface_id id, int* value) | ||
145 | { | ||
146 | *value = -1; | ||
147 | |||
148 | switch(id) | ||
149 | { | ||
150 | case SYSFS_BATTERY_CAPACITY: | ||
151 | case SYSFS_BATTERY_CURRENT_NOW: | ||
152 | case SYSFS_BATTERY_ENERGY_FULL_DESIGN: | ||
153 | case SYSFS_BATTERY_ONLINE: | ||
154 | case SYSFS_BATTERY_PRESENT: | ||
155 | case SYSFS_BATTERY_TEMP: | ||
156 | case SYSFS_BATTERY_VOLTAGE_MAX_DESIGN: | ||
157 | case SYSFS_BATTERY_VOLTAGE_MIN_DESIGN: | ||
158 | case SYSFS_BATTERY_VOLTAGE_NOW: | ||
159 | case SYSFS_USB_POWER_CURRENT_NOW: | ||
160 | case SYSFS_USB_POWER_VOLTAGE_NOW: | ||
161 | case SYSFS_USB_POWER_ONLINE: | ||
162 | case SYSFS_USB_POWER_PRESENT: | ||
163 | { | ||
164 | break; | ||
165 | } | ||
166 | |||
167 | default: | ||
168 | { | ||
169 | DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id); | ||
170 | return false; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | const char* interface = SYSFS_PATHS[id]; | ||
175 | |||
176 | /*DEBUGF("%s: interface: %s.", __func__, interface);*/ | ||
177 | |||
178 | FILE *f = open_read(interface); | ||
179 | if(f == NULL) | ||
180 | { | ||
181 | return false; | ||
182 | } | ||
183 | |||
184 | bool success = true; | ||
185 | if(fscanf(f, "%d", value) == EOF) | ||
186 | { | ||
187 | DEBUGF("ERROR %s: Read failed for %s.", __func__, interface); | ||
188 | success = false; | ||
189 | } | ||
190 | |||
191 | fclose(f); | ||
192 | return success; | ||
193 | } | ||
194 | |||
195 | |||
196 | bool sysfs_set_int(enum sys_fs_interface_id id, int value) | ||
197 | { | ||
198 | switch(id) | ||
199 | { | ||
200 | case SYSFS_BACKLIGHT_POWER: | ||
201 | case SYSFS_BACKLIGHT_BRIGHTNESS: | ||
202 | case SYSFS_DX50_CODEC_VOLUME: | ||
203 | case SYSFS_DX90_ES9018_VOLUME: | ||
204 | { | ||
205 | break; | ||
206 | } | ||
207 | |||
208 | default: | ||
209 | { | ||
210 | DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id); | ||
211 | return false; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | const char* interface = SYSFS_PATHS[id]; | ||
216 | |||
217 | /*DEBUGF("%s: interface: %s, value: %d.", __func__, interface, value);*/ | ||
218 | |||
219 | FILE *f = open_write(interface); | ||
220 | if(f == NULL) | ||
221 | { | ||
222 | return false; | ||
223 | } | ||
224 | |||
225 | bool success = true; | ||
226 | if(fprintf(f, "%d", value) < 1) | ||
227 | { | ||
228 | DEBUGF("ERROR %s: Write failed for %s.", __func__, interface); | ||
229 | success = false; | ||
230 | } | ||
231 | |||
232 | fclose(f); | ||
233 | return success; | ||
234 | } | ||
235 | |||
236 | |||
237 | bool sysfs_get_char(enum sys_fs_interface_id id, char* value) | ||
238 | { | ||
239 | *value = '\0'; | ||
240 | |||
241 | switch(id) | ||
242 | { | ||
243 | case SYSFS_HOLDKEY: | ||
244 | { | ||
245 | break; | ||
246 | } | ||
247 | |||
248 | default: | ||
249 | { | ||
250 | DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id); | ||
251 | return false; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | const char* interface = SYSFS_PATHS[id]; | ||
256 | |||
257 | /*DEBUGF("%s: interface: %s.", __func__, interface);*/ | ||
258 | |||
259 | FILE *f = open_read(interface); | ||
260 | if(f == NULL) | ||
261 | { | ||
262 | return false; | ||
263 | } | ||
264 | |||
265 | bool success = true; | ||
266 | if(fscanf(f, "%c", value) == EOF) | ||
267 | { | ||
268 | DEBUGF("ERROR %s: Read failed for %s.", __func__, interface); | ||
269 | success = false; | ||
270 | } | ||
271 | |||
272 | fclose(f); | ||
273 | return success; | ||
274 | } | ||
275 | |||
276 | |||
277 | bool sysfs_set_char(enum sys_fs_interface_id id, char value) | ||
278 | { | ||
279 | switch(id) | ||
280 | { | ||
281 | case SYSFS_MUTE: | ||
282 | case SYSFS_WM8740_MUTE: | ||
283 | { | ||
284 | break; | ||
285 | } | ||
286 | |||
287 | default: | ||
288 | { | ||
289 | DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id); | ||
290 | return false; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | const char* interface = SYSFS_PATHS[id]; | ||
295 | |||
296 | /*DEBUGF("%s: interface: %s, value: %c.", __func__, interface, value);*/ | ||
297 | |||
298 | FILE *f = open_write(interface); | ||
299 | if(f == NULL) | ||
300 | { | ||
301 | return false; | ||
302 | } | ||
303 | |||
304 | bool success = true; | ||
305 | if(fprintf(f, "%c", value) < 1) | ||
306 | { | ||
307 | DEBUGF("ERROR %s: Write failed for %s.", __func__, interface); | ||
308 | success = false; | ||
309 | } | ||
310 | |||
311 | fclose(f); | ||
312 | return success; | ||
313 | } | ||
314 | |||
315 | |||
316 | bool sysfs_get_string(enum sys_fs_interface_id id, char* value, int size) | ||
317 | { | ||
318 | value[0] = '\0'; | ||
319 | |||
320 | switch(id) | ||
321 | { | ||
322 | case SYSFS_BATTERY_STATUS: | ||
323 | case SYSFS_BATTERY_HEALTH: | ||
324 | case SYSFS_BATTERY_MODEL_NAME: | ||
325 | case SYSFS_BATTERY_TECHNOLOGY: | ||
326 | case SYSFS_BATTERY_TYPE: | ||
327 | { | ||
328 | break; | ||
329 | } | ||
330 | |||
331 | default: | ||
332 | { | ||
333 | DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id); | ||
334 | return false; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | const char* interface = SYSFS_PATHS[id]; | ||
339 | |||
340 | /*DEBUGF("%s: interface: %s, size: %d.", __func__, interface, size);*/ | ||
341 | |||
342 | FILE *f = open_read(interface); | ||
343 | if(f == NULL) | ||
344 | { | ||
345 | return false; | ||
346 | } | ||
347 | |||
348 | bool success = true; | ||
349 | if(fgets(value, size, f) == NULL) | ||
350 | { | ||
351 | DEBUGF("ERROR %s: Read failed for %s.", __func__, interface); | ||
352 | success = false; | ||
353 | } | ||
354 | else | ||
355 | { | ||
356 | size_t length = strlen(value); | ||
357 | if((length > 0) && value[length - 1] == '\n') | ||
358 | { | ||
359 | value[length - 1] = '\0'; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | fclose(f); | ||
364 | return success; | ||
365 | } | ||
366 | |||
367 | |||
368 | bool sysfs_set_string(enum sys_fs_interface_id id, char* value) | ||
369 | { | ||
370 | switch(id) | ||
371 | { | ||
372 | case SYSFS_POWER_STATE: | ||
373 | case SYSFS_POWER_WAKE_LOCK: | ||
374 | { | ||
375 | break; | ||
376 | } | ||
377 | |||
378 | default: | ||
379 | { | ||
380 | DEBUGF("ERROR %s: Unknown interface id: %d.", __func__, id); | ||
381 | return false; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | const char* interface = SYSFS_PATHS[id]; | ||
386 | |||
387 | /*DEBUGF("%s: interface: %s, value: %s.", __func__, interface, value);*/ | ||
388 | |||
389 | FILE *f = open_write(interface); | ||
390 | if(f == NULL) | ||
391 | { | ||
392 | return false; | ||
393 | } | ||
394 | |||
395 | bool success = true; | ||
396 | if(fprintf(f, "%s", value) < 1) | ||
397 | { | ||
398 | DEBUGF("ERROR %s: Write failed for %s.", __func__, interface); | ||
399 | success = false; | ||
400 | } | ||
401 | |||
402 | fclose(f); | ||
403 | return success; | ||
404 | } | ||
diff --git a/firmware/target/hosted/ibasso/sysfs-ibasso.h b/firmware/target/hosted/ibasso/sysfs-ibasso.h new file mode 100644 index 0000000000..fec8a082f9 --- /dev/null +++ b/firmware/target/hosted/ibasso/sysfs-ibasso.h | |||
@@ -0,0 +1,111 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #ifndef _SYSFS_IBASSO_H_ | ||
26 | #define _SYSFS_IBASSO_H_ | ||
27 | |||
28 | |||
29 | #include <stdbool.h> | ||
30 | |||
31 | |||
32 | /* | ||
33 | Sys FS path identifiers. | ||
34 | See SYSFS_PATHS in sysfs-ibasso.c. | ||
35 | */ | ||
36 | enum sys_fs_interface_id | ||
37 | { | ||
38 | SYSFS_DX50_CODEC_VOLUME = 0, | ||
39 | SYSFS_HOLDKEY, | ||
40 | SYSFS_DX90_ES9018_VOLUME, | ||
41 | SYSFS_MUTE, | ||
42 | SYSFS_WM8740_MUTE, | ||
43 | SYSFS_BATTERY_CAPACITY, | ||
44 | SYSFS_BATTERY_CURRENT_NOW, | ||
45 | SYSFS_BATTERY_ENERGY_FULL_DESIGN, | ||
46 | SYSFS_BATTERY_HEALTH, | ||
47 | SYSFS_BATTERY_MODEL_NAME, | ||
48 | SYSFS_BATTERY_ONLINE, | ||
49 | SYSFS_BATTERY_PRESENT, | ||
50 | SYSFS_BATTERY_STATUS, | ||
51 | SYSFS_BATTERY_TECHNOLOGY, | ||
52 | SYSFS_BATTERY_TEMP, | ||
53 | SYSFS_BATTERY_TYPE, | ||
54 | SYSFS_BATTERY_VOLTAGE_MAX_DESIGN, | ||
55 | SYSFS_BATTERY_VOLTAGE_MIN_DESIGN, | ||
56 | SYSFS_BATTERY_VOLTAGE_NOW, | ||
57 | SYSFS_USB_POWER_CURRENT_NOW, | ||
58 | SYSFS_USB_POWER_ONLINE, | ||
59 | SYSFS_USB_POWER_PRESENT, | ||
60 | SYSFS_USB_POWER_VOLTAGE_NOW, | ||
61 | SYSFS_BACKLIGHT_POWER, | ||
62 | SYSFS_BACKLIGHT_BRIGHTNESS, | ||
63 | SYSFS_POWER_STATE, | ||
64 | SYSFS_POWER_WAKE_LOCK | ||
65 | }; | ||
66 | |||
67 | |||
68 | /* | ||
69 | Read a integer value from the sys fs interface given by id. | ||
70 | Returns true on success, false else. | ||
71 | */ | ||
72 | bool sysfs_get_int(enum sys_fs_interface_id id, int* value); | ||
73 | |||
74 | |||
75 | /* | ||
76 | Write a integer value to the sys fs interface given by id. | ||
77 | Returns true on success, false else. | ||
78 | */ | ||
79 | bool sysfs_set_int(enum sys_fs_interface_id id, int value); | ||
80 | |||
81 | |||
82 | /* | ||
83 | Read a char value from the sys fs interface given by id. | ||
84 | Returns true on success, false else. | ||
85 | */ | ||
86 | bool sysfs_get_char(enum sys_fs_interface_id id, char* value); | ||
87 | |||
88 | |||
89 | /* | ||
90 | Write a char value to the sys fs interface given by id. | ||
91 | Returns true on success, false else. | ||
92 | */ | ||
93 | bool sysfs_set_char(enum sys_fs_interface_id id, char value); | ||
94 | |||
95 | /* | ||
96 | Read a single line of text from the sys fs interface given by id. | ||
97 | A newline will be discarded. | ||
98 | size: The size of value. | ||
99 | Returns true on success, false else. | ||
100 | */ | ||
101 | bool sysfs_get_string(enum sys_fs_interface_id id, char* value, int size); | ||
102 | |||
103 | |||
104 | /* | ||
105 | Write text to the sys fs interface given by id. | ||
106 | Returns true on success, false else. | ||
107 | */ | ||
108 | bool sysfs_set_string(enum sys_fs_interface_id id, char* value); | ||
109 | |||
110 | |||
111 | #endif | ||
diff --git a/firmware/target/hosted/ibasso/system-ibasso.c b/firmware/target/hosted/ibasso/system-ibasso.c new file mode 100644 index 0000000000..00f8669ae0 --- /dev/null +++ b/firmware/target/hosted/ibasso/system-ibasso.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <stdint.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <sys/reboot.h> | ||
28 | |||
29 | #include "config.h" | ||
30 | #include "cpufreq-linux.h" | ||
31 | #include "debug.h" | ||
32 | |||
33 | #include "button-ibasso.h" | ||
34 | #include "debug-ibasso.h" | ||
35 | #include "sysfs-ibasso.h" | ||
36 | #include "usb-ibasso.h" | ||
37 | #include "vold-ibasso.h" | ||
38 | |||
39 | |||
40 | /* Fake stack. */ | ||
41 | uintptr_t* stackbegin; | ||
42 | uintptr_t* stackend; | ||
43 | |||
44 | |||
45 | void system_init(void) | ||
46 | { | ||
47 | TRACE; | ||
48 | |||
49 | /* Fake stack. */ | ||
50 | volatile uintptr_t stack = 0; | ||
51 | stackbegin = stackend = (uintptr_t*) &stack; | ||
52 | |||
53 | cpufreq_set_governor("powersave", CPUFREQ_ALL_CPUS); | ||
54 | vold_monitor_start(); | ||
55 | ibasso_set_usb_mode(USB_MODE_MASS_STORAGE); | ||
56 | |||
57 | /* | ||
58 | Prevent device from deep sleeping, which will interrupt playback. | ||
59 | /sys/power/wake_lock | ||
60 | */ | ||
61 | if(! sysfs_set_string(SYSFS_POWER_WAKE_LOCK, "rockbox")) | ||
62 | { | ||
63 | DEBUGF("ERROR %s: Can not set suspend blocker.", __func__); | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | Prevent device to mute, which will cause tinyalsa pcm_writes to fail. | ||
68 | /sys/class/codec/wm8740_mute | ||
69 | */ | ||
70 | if(! sysfs_set_char(SYSFS_WM8740_MUTE, '0')) | ||
71 | { | ||
72 | DEBUGF("ERROR %s: Can not set WM8740 lock.", __func__); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | |||
77 | void system_reboot(void) | ||
78 | { | ||
79 | TRACE; | ||
80 | |||
81 | button_close_device(); | ||
82 | |||
83 | if(vold_monitor_forced_close_imminent()) | ||
84 | { | ||
85 | /* | ||
86 | We are here, because Android Vold is going to kill Rockbox. Instead of powering off, | ||
87 | we exit into the loader. | ||
88 | */ | ||
89 | exit(42); | ||
90 | } | ||
91 | |||
92 | reboot(RB_AUTOBOOT); | ||
93 | } | ||
94 | |||
95 | |||
96 | void system_exception_wait(void) | ||
97 | { | ||
98 | TRACE; | ||
99 | |||
100 | while(1) {}; | ||
101 | } | ||
diff --git a/firmware/target/hosted/android/dx50/lcd-target.h b/firmware/target/hosted/ibasso/system-target.h index 900350eca2..17b1238380 100644 --- a/firmware/target/hosted/android/dx50/lcd-target.h +++ b/firmware/target/hosted/ibasso/system-target.h | |||
@@ -1,11 +1,15 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * __________ __ ___. | 2 | * __________ __ ___ |
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * |
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
9 | * | 13 | * |
10 | * This program is free software; you can redistribute it and/or | 14 | * This program is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU General Public License | 15 | * modify it under the terms of the GNU General Public License |
@@ -17,13 +21,13 @@ | |||
17 | * | 21 | * |
18 | ****************************************************************************/ | 22 | ****************************************************************************/ |
19 | 23 | ||
20 | #ifndef __LCD_TARGET_H__ | ||
21 | #define __LCD_TARGET_H__ | ||
22 | 24 | ||
23 | extern fb_data *dev_fb; | 25 | #ifndef __SYSTEM_TARGET_H__ |
24 | #define LCD_FRAMEBUF_ADDR(col, row) (dev_fb + row*LCD_WIDTH + col) | 26 | #define __SYSTEM_TARGET_H__ |
25 | #ifdef HAVE_LCD_ENABLE | 27 | |
26 | extern void lcd_set_active(bool active); | 28 | |
27 | extern void lcd_enable(bool enable); | 29 | #include "kernel-unix.h" |
28 | #endif | 30 | #include "system-hosted.h" |
31 | |||
32 | |||
29 | #endif | 33 | #endif |
diff --git a/firmware/target/hosted/android/dx50/tinyalsa/asound.h b/firmware/target/hosted/ibasso/tinyalsa/include/sound/asound.h index fc1e4f6d67..9dd66fe169 100644 --- a/firmware/target/hosted/android/dx50/tinyalsa/asound.h +++ b/firmware/target/hosted/ibasso/tinyalsa/include/sound/asound.h | |||
@@ -818,4 +818,3 @@ struct snd_ctl_event { | |||
818 | #define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what | 818 | #define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what |
819 | 819 | ||
820 | #endif | 820 | #endif |
821 | |||
diff --git a/firmware/target/hosted/android/dx50/tinyalsa/asoundlib.h b/firmware/target/hosted/ibasso/tinyalsa/include/tinyalsa/asoundlib.h index 6aacae46d6..ba58bdcdfc 100644 --- a/firmware/target/hosted/android/dx50/tinyalsa/asoundlib.h +++ b/firmware/target/hosted/ibasso/tinyalsa/include/tinyalsa/asoundlib.h | |||
@@ -55,17 +55,14 @@ struct pcm; | |||
55 | * second call to pcm_write will attempt to | 55 | * second call to pcm_write will attempt to |
56 | * restart the stream. | 56 | * restart the stream. |
57 | */ | 57 | */ |
58 | #define PCM_MONOTONIC 0x00000008 /* see pcm_get_htimestamp */ | ||
58 | 59 | ||
59 | /* PCM runtime states */ | 60 | /* PCM runtime states */ |
60 | #define PCM_STATE_OPEN 0 | 61 | #define PCM_STATE_RUNNING 3 |
61 | #define PCM_STATE_SETUP 1 | 62 | #define PCM_STATE_XRUN 4 |
62 | #define PCM_STATE_PREPARED 2 | 63 | #define PCM_STATE_DRAINING 5 |
63 | #define PCM_STATE_RUNNING 3 | 64 | #define PCM_STATE_SUSPENDED 7 |
64 | #define PCM_STATE_XRUN 4 | 65 | #define PCM_STATE_DISCONNECTED 8 |
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 | 66 | ||
70 | /* Bit formats */ | 67 | /* Bit formats */ |
71 | enum pcm_format { | 68 | enum pcm_format { |
@@ -77,6 +74,11 @@ enum pcm_format { | |||
77 | PCM_FORMAT_MAX, | 74 | PCM_FORMAT_MAX, |
78 | }; | 75 | }; |
79 | 76 | ||
77 | /* Bitmask has 256 bits (32 bytes) in asound.h */ | ||
78 | struct pcm_mask { | ||
79 | unsigned int bits[32 / sizeof(unsigned int)]; | ||
80 | }; | ||
81 | |||
80 | /* Configuration for a stream */ | 82 | /* Configuration for a stream */ |
81 | struct pcm_config { | 83 | struct pcm_config { |
82 | unsigned int channels; | 84 | unsigned int channels; |
@@ -101,6 +103,11 @@ struct pcm_config { | |||
101 | /* PCM parameters */ | 103 | /* PCM parameters */ |
102 | enum pcm_param | 104 | enum pcm_param |
103 | { | 105 | { |
106 | /* mask parameters */ | ||
107 | PCM_PARAM_ACCESS, | ||
108 | PCM_PARAM_FORMAT, | ||
109 | PCM_PARAM_SUBFORMAT, | ||
110 | /* interval parameters */ | ||
104 | PCM_PARAM_SAMPLE_BITS, | 111 | PCM_PARAM_SAMPLE_BITS, |
105 | PCM_PARAM_FRAME_BITS, | 112 | PCM_PARAM_FRAME_BITS, |
106 | PCM_PARAM_CHANNELS, | 113 | PCM_PARAM_CHANNELS, |
@@ -138,15 +145,14 @@ int pcm_is_ready(struct pcm *pcm); | |||
138 | struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, | 145 | struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, |
139 | unsigned int flags); | 146 | unsigned int flags); |
140 | void pcm_params_free(struct pcm_params *pcm_params); | 147 | void pcm_params_free(struct pcm_params *pcm_params); |
148 | |||
149 | struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params, | ||
150 | enum pcm_param param); | ||
141 | unsigned int pcm_params_get_min(struct pcm_params *pcm_params, | 151 | unsigned int pcm_params_get_min(struct pcm_params *pcm_params, |
142 | enum pcm_param param); | 152 | enum pcm_param param); |
143 | unsigned int pcm_params_get_max(struct pcm_params *pcm_params, | 153 | unsigned int pcm_params_get_max(struct pcm_params *pcm_params, |
144 | enum pcm_param param); | 154 | enum pcm_param param); |
145 | 155 | ||
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 */ | 156 | /* Returns a human readable reason for the last error */ |
151 | const char *pcm_get_error(struct pcm *pcm); | 157 | const char *pcm_get_error(struct pcm *pcm); |
152 | 158 | ||
@@ -162,10 +168,9 @@ unsigned int pcm_get_buffer_size(struct pcm *pcm); | |||
162 | unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames); | 168 | 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); | 169 | unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes); |
164 | 170 | ||
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. | 171 | /* Returns available frames in pcm buffer and corresponding time stamp. |
172 | * The clock is CLOCK_MONOTONIC if flag PCM_MONOTONIC was specified in pcm_open, | ||
173 | * otherwise the clock is CLOCK_REALTIME. | ||
169 | * For an input stream, frames available are frames ready for the | 174 | * For an input stream, frames available are frames ready for the |
170 | * application to read. | 175 | * application to read. |
171 | * For an output stream, frames available are the number of empty frames available | 176 | * For an output stream, frames available are the number of empty frames available |
@@ -185,11 +190,13 @@ int pcm_read(struct pcm *pcm, void *data, unsigned int count); | |||
185 | * mmap() support. | 190 | * mmap() support. |
186 | */ | 191 | */ |
187 | int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count); | 192 | int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count); |
193 | int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count); | ||
188 | int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, | 194 | int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, |
189 | unsigned int *frames); | 195 | unsigned int *frames); |
190 | int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames); | 196 | int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames); |
191 | 197 | ||
192 | 198 | /* Prepare the PCM substream to be triggerable */ | |
199 | int pcm_prepare(struct pcm *pcm); | ||
193 | /* Start and stop a PCM channel that doesn't transfer data */ | 200 | /* Start and stop a PCM channel that doesn't transfer data */ |
194 | int pcm_start(struct pcm *pcm); | 201 | int pcm_start(struct pcm *pcm); |
195 | int pcm_stop(struct pcm *pcm); | 202 | int pcm_stop(struct pcm *pcm); |
@@ -197,10 +204,6 @@ int pcm_stop(struct pcm *pcm); | |||
197 | /* Interrupt driven API */ | 204 | /* Interrupt driven API */ |
198 | int pcm_wait(struct pcm *pcm, int timeout); | 205 | int pcm_wait(struct pcm *pcm, int timeout); |
199 | 206 | ||
200 | int pcm_avail_update(struct pcm *pcm); | ||
201 | |||
202 | int pcm_state(struct pcm *pcm); | ||
203 | |||
204 | 207 | ||
205 | /* | 208 | /* |
206 | * MIXER API | 209 | * MIXER API |
diff --git a/firmware/target/hosted/android/dx50/tinyalsa/mixer.c b/firmware/target/hosted/ibasso/tinyalsa/mixer.c index f75dec488a..24e94f4f1d 100644 --- a/firmware/target/hosted/android/dx50/tinyalsa/mixer.c +++ b/firmware/target/hosted/ibasso/tinyalsa/mixer.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #define __force | 40 | #define __force |
41 | #define __bitwise | 41 | #define __bitwise |
42 | #define __user | 42 | #define __user |
43 | #include <tinyalsa/asound.h> | 43 | #include <sound/asound.h> |
44 | 44 | ||
45 | #include <tinyalsa/asoundlib.h> | 45 | #include <tinyalsa/asoundlib.h> |
46 | 46 | ||
@@ -259,14 +259,11 @@ unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl) | |||
259 | 259 | ||
260 | static int percent_to_int(struct snd_ctl_elem_info *ei, int percent) | 260 | static int percent_to_int(struct snd_ctl_elem_info *ei, int percent) |
261 | { | 261 | { |
262 | int range; | 262 | if ((percent > 100) || (percent < 0)) { |
263 | 263 | return -EINVAL; | |
264 | if (percent > 100) | 264 | } |
265 | percent = 100; | ||
266 | else if (percent < 0) | ||
267 | percent = 0; | ||
268 | 265 | ||
269 | range = (ei->value.integer.max - ei->value.integer.min); | 266 | int range = (ei->value.integer.max - ei->value.integer.min); |
270 | 267 | ||
271 | return ei->value.integer.min + (range * percent) / 100; | 268 | return ei->value.integer.min + (range * percent) / 100; |
272 | } | 269 | } |
@@ -389,6 +386,11 @@ int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value) | |||
389 | break; | 386 | break; |
390 | 387 | ||
391 | case SNDRV_CTL_ELEM_TYPE_INTEGER: | 388 | case SNDRV_CTL_ELEM_TYPE_INTEGER: |
389 | if ((value < mixer_ctl_get_range_min(ctl)) || | ||
390 | (value > mixer_ctl_get_range_max(ctl))) { | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
392 | ev.value.integer.value[id] = value; | 394 | ev.value.integer.value[id] = value; |
393 | break; | 395 | break; |
394 | 396 | ||
@@ -396,6 +398,10 @@ int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value) | |||
396 | ev.value.enumerated.item[id] = value; | 398 | ev.value.enumerated.item[id] = value; |
397 | break; | 399 | break; |
398 | 400 | ||
401 | case SNDRV_CTL_ELEM_TYPE_BYTES: | ||
402 | ev.value.bytes.data[id] = value; | ||
403 | break; | ||
404 | |||
399 | default: | 405 | default: |
400 | return -EINVAL; | 406 | return -EINVAL; |
401 | } | 407 | } |
@@ -494,4 +500,3 @@ int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string) | |||
494 | 500 | ||
495 | return -EINVAL; | 501 | return -EINVAL; |
496 | } | 502 | } |
497 | |||
diff --git a/firmware/target/hosted/android/dx50/tinyalsa/pcm.c b/firmware/target/hosted/ibasso/tinyalsa/pcm.c index bd44dce52f..0d2f0adf08 100644 --- a/firmware/target/hosted/android/dx50/tinyalsa/pcm.c +++ b/firmware/target/hosted/ibasso/tinyalsa/pcm.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #define __force | 44 | #define __force |
45 | #define __bitwise | 45 | #define __bitwise |
46 | #define __user | 46 | #define __user |
47 | #include <tinyalsa/asound.h> | 47 | #include <sound/asound.h> |
48 | 48 | ||
49 | #include <tinyalsa/asoundlib.h> | 49 | #include <tinyalsa/asoundlib.h> |
50 | 50 | ||
@@ -159,6 +159,7 @@ struct pcm { | |||
159 | int fd; | 159 | int fd; |
160 | unsigned int flags; | 160 | unsigned int flags; |
161 | int running:1; | 161 | int running:1; |
162 | int prepared:1; | ||
162 | int underruns; | 163 | int underruns; |
163 | unsigned int buffer_size; | 164 | unsigned int buffer_size; |
164 | unsigned int boundary; | 165 | unsigned int boundary; |
@@ -300,7 +301,7 @@ static void pcm_hw_munmap_status(struct pcm *pcm) { | |||
300 | } | 301 | } |
301 | 302 | ||
302 | static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset, | 303 | static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset, |
303 | const char *src, unsigned int src_offset, | 304 | char *buf, unsigned int src_offset, |
304 | unsigned int frames) | 305 | unsigned int frames) |
305 | { | 306 | { |
306 | int size_bytes = pcm_frames_to_bytes(pcm, frames); | 307 | int size_bytes = pcm_frames_to_bytes(pcm, frames); |
@@ -308,12 +309,18 @@ static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset, | |||
308 | int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset); | 309 | int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset); |
309 | 310 | ||
310 | /* interleaved only atm */ | 311 | /* interleaved only atm */ |
311 | memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes, | 312 | if (pcm->flags & PCM_IN) |
312 | src + src_offset_bytes, size_bytes); | 313 | memcpy(buf + src_offset_bytes, |
314 | (char*)pcm->mmap_buffer + pcm_offset_bytes, | ||
315 | size_bytes); | ||
316 | else | ||
317 | memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes, | ||
318 | buf + src_offset_bytes, | ||
319 | size_bytes); | ||
313 | return 0; | 320 | return 0; |
314 | } | 321 | } |
315 | 322 | ||
316 | static int pcm_mmap_write_areas(struct pcm *pcm, const char *src, | 323 | static int pcm_mmap_transfer_areas(struct pcm *pcm, char *buf, |
317 | unsigned int offset, unsigned int size) | 324 | unsigned int offset, unsigned int size) |
318 | { | 325 | { |
319 | void *pcm_areas; | 326 | void *pcm_areas; |
@@ -323,7 +330,7 @@ static int pcm_mmap_write_areas(struct pcm *pcm, const char *src, | |||
323 | while (size > 0) { | 330 | while (size > 0) { |
324 | frames = size; | 331 | frames = size; |
325 | pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); | 332 | pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); |
326 | pcm_areas_copy(pcm, pcm_offset, src, offset, frames); | 333 | pcm_areas_copy(pcm, pcm_offset, buf, offset, frames); |
327 | commit = pcm_mmap_commit(pcm, pcm_offset, frames); | 334 | commit = pcm_mmap_commit(pcm, pcm_offset, frames); |
328 | if (commit < 0) { | 335 | if (commit < 0) { |
329 | oops(pcm, commit, "failed to commit %d frames\n", frames); | 336 | oops(pcm, commit, "failed to commit %d frames\n", frames); |
@@ -386,14 +393,16 @@ int pcm_write(struct pcm *pcm, const void *data, unsigned int count) | |||
386 | 393 | ||
387 | for (;;) { | 394 | for (;;) { |
388 | if (!pcm->running) { | 395 | if (!pcm->running) { |
389 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) | 396 | int prepare_error = pcm_prepare(pcm); |
390 | return oops(pcm, errno, "cannot prepare channel"); | 397 | if (prepare_error) |
398 | return prepare_error; | ||
391 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) | 399 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) |
392 | return oops(pcm, errno, "cannot write initial data"); | 400 | return oops(pcm, errno, "cannot write initial data"); |
393 | pcm->running = 1; | 401 | pcm->running = 1; |
394 | return 0; | 402 | return 0; |
395 | } | 403 | } |
396 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { | 404 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { |
405 | pcm->prepared = 0; | ||
397 | pcm->running = 0; | 406 | pcm->running = 0; |
398 | if (errno == EPIPE) { | 407 | if (errno == EPIPE) { |
399 | /* we failed to make our window -- try to restart if we are | 408 | /* we failed to make our window -- try to restart if we are |
@@ -429,6 +438,7 @@ int pcm_read(struct pcm *pcm, void *data, unsigned int count) | |||
429 | } | 438 | } |
430 | } | 439 | } |
431 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { | 440 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { |
441 | pcm->prepared = 0; | ||
432 | pcm->running = 0; | 442 | pcm->running = 0; |
433 | if (errno == EPIPE) { | 443 | if (errno == EPIPE) { |
434 | /* we failed to make our window -- try to restart */ | 444 | /* we failed to make our window -- try to restart */ |
@@ -494,6 +504,12 @@ void pcm_params_free(struct pcm_params *pcm_params) | |||
494 | static int pcm_param_to_alsa(enum pcm_param param) | 504 | static int pcm_param_to_alsa(enum pcm_param param) |
495 | { | 505 | { |
496 | switch (param) { | 506 | switch (param) { |
507 | case PCM_PARAM_ACCESS: | ||
508 | return SNDRV_PCM_HW_PARAM_ACCESS; | ||
509 | case PCM_PARAM_FORMAT: | ||
510 | return SNDRV_PCM_HW_PARAM_FORMAT; | ||
511 | case PCM_PARAM_SUBFORMAT: | ||
512 | return SNDRV_PCM_HW_PARAM_SUBFORMAT; | ||
497 | case PCM_PARAM_SAMPLE_BITS: | 513 | case PCM_PARAM_SAMPLE_BITS: |
498 | return SNDRV_PCM_HW_PARAM_SAMPLE_BITS; | 514 | return SNDRV_PCM_HW_PARAM_SAMPLE_BITS; |
499 | break; | 515 | break; |
@@ -536,6 +552,23 @@ static int pcm_param_to_alsa(enum pcm_param param) | |||
536 | } | 552 | } |
537 | } | 553 | } |
538 | 554 | ||
555 | struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params, | ||
556 | enum pcm_param param) | ||
557 | { | ||
558 | int p; | ||
559 | struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; | ||
560 | if (params == NULL) { | ||
561 | return NULL; | ||
562 | } | ||
563 | |||
564 | p = pcm_param_to_alsa(param); | ||
565 | if (p < 0 || !param_is_mask(p)) { | ||
566 | return NULL; | ||
567 | } | ||
568 | |||
569 | return (struct pcm_mask *)param_to_mask(params, p); | ||
570 | } | ||
571 | |||
539 | unsigned int pcm_params_get_min(struct pcm_params *pcm_params, | 572 | unsigned int pcm_params_get_min(struct pcm_params *pcm_params, |
540 | enum pcm_param param) | 573 | enum pcm_param param) |
541 | { | 574 | { |
@@ -582,6 +615,7 @@ int pcm_close(struct pcm *pcm) | |||
582 | 615 | ||
583 | if (pcm->fd >= 0) | 616 | if (pcm->fd >= 0) |
584 | close(pcm->fd); | 617 | close(pcm->fd); |
618 | pcm->prepared = 0; | ||
585 | pcm->running = 0; | 619 | pcm->running = 0; |
586 | pcm->buffer_size = 0; | 620 | pcm->buffer_size = 0; |
587 | pcm->fd = -1; | 621 | pcm->fd = -1; |
@@ -706,7 +740,7 @@ struct pcm *pcm_open(unsigned int card, unsigned int device, | |||
706 | pcm->boundary = sparams.boundary = pcm->buffer_size; | 740 | pcm->boundary = sparams.boundary = pcm->buffer_size; |
707 | 741 | ||
708 | while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) | 742 | while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) |
709 | pcm->boundary *= 2; | 743 | pcm->boundary *= 2; |
710 | 744 | ||
711 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { | 745 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { |
712 | oops(pcm, errno, "cannot set sw params"); | 746 | oops(pcm, errno, "cannot set sw params"); |
@@ -719,6 +753,17 @@ struct pcm *pcm_open(unsigned int card, unsigned int device, | |||
719 | goto fail; | 753 | goto fail; |
720 | } | 754 | } |
721 | 755 | ||
756 | #ifdef SNDRV_PCM_IOCTL_TTSTAMP | ||
757 | if (pcm->flags & PCM_MONOTONIC) { | ||
758 | int arg = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; | ||
759 | rc = ioctl(pcm->fd, SNDRV_PCM_IOCTL_TTSTAMP, &arg); | ||
760 | if (rc < 0) { | ||
761 | oops(pcm, rc, "cannot set timestamp type"); | ||
762 | goto fail; | ||
763 | } | ||
764 | } | ||
765 | #endif | ||
766 | |||
722 | pcm->underruns = 0; | 767 | pcm->underruns = 0; |
723 | return pcm; | 768 | return pcm; |
724 | 769 | ||
@@ -736,13 +781,26 @@ int pcm_is_ready(struct pcm *pcm) | |||
736 | return pcm->fd >= 0; | 781 | return pcm->fd >= 0; |
737 | } | 782 | } |
738 | 783 | ||
739 | int pcm_start(struct pcm *pcm) | 784 | int pcm_prepare(struct pcm *pcm) |
740 | { | 785 | { |
786 | if (pcm->prepared) | ||
787 | return 0; | ||
788 | |||
741 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) | 789 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) |
742 | return oops(pcm, errno, "cannot prepare channel"); | 790 | return oops(pcm, errno, "cannot prepare channel"); |
743 | 791 | ||
792 | pcm->prepared = 1; | ||
793 | return 0; | ||
794 | } | ||
795 | |||
796 | int pcm_start(struct pcm *pcm) | ||
797 | { | ||
798 | int prepare_error = pcm_prepare(pcm); | ||
799 | if (prepare_error) | ||
800 | return prepare_error; | ||
801 | |||
744 | if (pcm->flags & PCM_MMAP) | 802 | if (pcm->flags & PCM_MMAP) |
745 | pcm_sync_ptr(pcm, 0); | 803 | pcm_sync_ptr(pcm, 0); |
746 | 804 | ||
747 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0) | 805 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0) |
748 | return oops(pcm, errno, "cannot start channel"); | 806 | return oops(pcm, errno, "cannot start channel"); |
@@ -756,6 +814,7 @@ int pcm_stop(struct pcm *pcm) | |||
756 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) | 814 | if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) |
757 | return oops(pcm, errno, "cannot stop channel"); | 815 | return oops(pcm, errno, "cannot stop channel"); |
758 | 816 | ||
817 | pcm->prepared = 0; | ||
759 | pcm->running = 0; | 818 | pcm->running = 0; |
760 | return 0; | 819 | return 0; |
761 | } | 820 | } |
@@ -831,7 +890,7 @@ int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, | |||
831 | 890 | ||
832 | int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames) | 891 | int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames) |
833 | { | 892 | { |
834 | (void)offset; | 893 | (void) offset; |
835 | /* update the application pointer in userspace and kernel */ | 894 | /* update the application pointer in userspace and kernel */ |
836 | pcm_mmap_appl_forward(pcm, frames); | 895 | pcm_mmap_appl_forward(pcm, frames); |
837 | pcm_sync_ptr(pcm, 0); | 896 | pcm_sync_ptr(pcm, 0); |
@@ -895,7 +954,7 @@ int pcm_wait(struct pcm *pcm, int timeout) | |||
895 | return 1; | 954 | return 1; |
896 | } | 955 | } |
897 | 956 | ||
898 | int pcm_mmap_write(struct pcm *pcm, const void *buffer, unsigned int bytes) | 957 | int pcm_mmap_transfer(struct pcm *pcm, const void *buffer, unsigned int bytes) |
899 | { | 958 | { |
900 | int err = 0, frames, avail; | 959 | int err = 0, frames, avail; |
901 | unsigned int offset = 0, count; | 960 | unsigned int offset = 0, count; |
@@ -915,7 +974,7 @@ int pcm_mmap_write(struct pcm *pcm, const void *buffer, unsigned int bytes) | |||
915 | } | 974 | } |
916 | 975 | ||
917 | /* start the audio if we reach the threshold */ | 976 | /* start the audio if we reach the threshold */ |
918 | if (!pcm->running && | 977 | if (!pcm->running && |
919 | (pcm->buffer_size - avail) >= pcm->config.start_threshold) { | 978 | (pcm->buffer_size - avail) >= pcm->config.start_threshold) { |
920 | if (pcm_start(pcm) < 0) { | 979 | if (pcm_start(pcm) < 0) { |
921 | fprintf(stderr, "start error: hw 0x%x app 0x%x avail 0x%x\n", | 980 | fprintf(stderr, "start error: hw 0x%x app 0x%x avail 0x%x\n", |
@@ -937,6 +996,7 @@ int pcm_mmap_write(struct pcm *pcm, const void *buffer, unsigned int bytes) | |||
937 | 996 | ||
938 | err = pcm_wait(pcm, time); | 997 | err = pcm_wait(pcm, time); |
939 | if (err < 0) { | 998 | if (err < 0) { |
999 | pcm->prepared = 0; | ||
940 | pcm->running = 0; | 1000 | pcm->running = 0; |
941 | fprintf(stderr, "wait error: hw 0x%x app 0x%x avail 0x%x\n", | 1001 | fprintf(stderr, "wait error: hw 0x%x app 0x%x avail 0x%x\n", |
942 | (unsigned int)pcm->mmap_status->hw_ptr, | 1002 | (unsigned int)pcm->mmap_status->hw_ptr, |
@@ -956,7 +1016,7 @@ int pcm_mmap_write(struct pcm *pcm, const void *buffer, unsigned int bytes) | |||
956 | break; | 1016 | break; |
957 | 1017 | ||
958 | /* copy frames from buffer */ | 1018 | /* copy frames from buffer */ |
959 | frames = pcm_mmap_write_areas(pcm, buffer, offset, frames); | 1019 | frames = pcm_mmap_transfer_areas(pcm, (void *)buffer, offset, frames); |
960 | if (frames < 0) { | 1020 | if (frames < 0) { |
961 | fprintf(stderr, "write error: hw 0x%x app 0x%x avail 0x%x\n", | 1021 | fprintf(stderr, "write error: hw 0x%x app 0x%x avail 0x%x\n", |
962 | (unsigned int)pcm->mmap_status->hw_ptr, | 1022 | (unsigned int)pcm->mmap_status->hw_ptr, |
@@ -971,3 +1031,19 @@ int pcm_mmap_write(struct pcm *pcm, const void *buffer, unsigned int bytes) | |||
971 | 1031 | ||
972 | return 0; | 1032 | return 0; |
973 | } | 1033 | } |
1034 | |||
1035 | int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count) | ||
1036 | { | ||
1037 | if ((~pcm->flags) & (PCM_OUT | PCM_MMAP)) | ||
1038 | return -ENOSYS; | ||
1039 | |||
1040 | return pcm_mmap_transfer(pcm, (void *)data, count); | ||
1041 | } | ||
1042 | |||
1043 | int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count) | ||
1044 | { | ||
1045 | if ((~pcm->flags) & (PCM_IN | PCM_MMAP)) | ||
1046 | return -ENOSYS; | ||
1047 | |||
1048 | return pcm_mmap_transfer(pcm, data, count); | ||
1049 | } | ||
diff --git a/firmware/target/hosted/ibasso/usb-ibasso.c b/firmware/target/hosted/ibasso/usb-ibasso.c new file mode 100644 index 0000000000..e1b134e545 --- /dev/null +++ b/firmware/target/hosted/ibasso/usb-ibasso.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <stdlib.h> | ||
26 | |||
27 | #include "config.h" | ||
28 | #include "debug.h" | ||
29 | |||
30 | #include "debug-ibasso.h" | ||
31 | #include "usb-ibasso.h" | ||
32 | |||
33 | |||
34 | static void usb_enable_adb(void) | ||
35 | { | ||
36 | TRACE; | ||
37 | |||
38 | if(system(NULL)) | ||
39 | { | ||
40 | system("setprop persist.sys.usb.config adb"); | ||
41 | system("setprop persist.usb.debug 1"); | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | DEBUGF("ERROR %s: No command processor available.", __func__); | ||
46 | } | ||
47 | |||
48 | |||
49 | static void usb_enable_mass_storage(void) | ||
50 | { | ||
51 | TRACE; | ||
52 | |||
53 | if(system(NULL)) | ||
54 | { | ||
55 | system("setprop persist.sys.usb.config mass_storage"); | ||
56 | system("setprop persist.usb.debug 0"); | ||
57 | return; | ||
58 | } | ||
59 | |||
60 | DEBUGF("ERROR %s: No command processor available.", __func__); | ||
61 | } | ||
62 | |||
63 | |||
64 | /* Default at boot not known. */ | ||
65 | static int _last_usb_mode = -1; | ||
66 | |||
67 | |||
68 | void ibasso_set_usb_mode(int mode) | ||
69 | { | ||
70 | DEBUGF("DEBUG %s: _last_usb_mode: %d, mode: %d.", __func__, _last_usb_mode, mode); | ||
71 | |||
72 | if(_last_usb_mode != mode) | ||
73 | { | ||
74 | switch(mode) | ||
75 | { | ||
76 | case USB_MODE_MASS_STORAGE: | ||
77 | { | ||
78 | _last_usb_mode = mode; | ||
79 | usb_enable_mass_storage(); | ||
80 | break; | ||
81 | } | ||
82 | |||
83 | case USB_MODE_CHARGE: /* Work around. */ | ||
84 | case USB_MODE_ADB: | ||
85 | { | ||
86 | _last_usb_mode = mode; | ||
87 | usb_enable_adb(); | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | } | ||
diff --git a/firmware/target/hosted/ibasso/usb-ibasso.h b/firmware/target/hosted/ibasso/usb-ibasso.h new file mode 100644 index 0000000000..f509d43038 --- /dev/null +++ b/firmware/target/hosted/ibasso/usb-ibasso.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #ifndef _USB_DX50_H_ | ||
26 | #define _USB_DX50_H_ | ||
27 | |||
28 | |||
29 | /* Supported usb modes. */ | ||
30 | enum ibasso_usb_mode | ||
31 | { | ||
32 | /* | ||
33 | USB mass storage mode. On USB connection, Rockbox will terminate and the internel and | ||
34 | external storage gets exported to the connected client. | ||
35 | */ | ||
36 | USB_MODE_MASS_STORAGE = 0, | ||
37 | |||
38 | /* | ||
39 | Actually the same, since we to not have proper USB detection. | ||
40 | Starts the adb server and enables adb connection over USB. Rockbox will continue to run. | ||
41 | */ | ||
42 | USB_MODE_CHARGE, | ||
43 | USB_MODE_ADB | ||
44 | }; | ||
45 | |||
46 | |||
47 | /* | ||
48 | Set the usb mode. | ||
49 | mode: ibasso_usb_mode | ||
50 | */ | ||
51 | void ibasso_set_usb_mode(int mode); | ||
52 | |||
53 | |||
54 | #endif | ||
diff --git a/firmware/target/hosted/ibasso/vold-ibasso.c b/firmware/target/hosted/ibasso/vold-ibasso.c new file mode 100644 index 0000000000..c92b86d364 --- /dev/null +++ b/firmware/target/hosted/ibasso/vold-ibasso.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #include <pthread.h> | ||
26 | #include <stdbool.h> | ||
27 | #include <string.h> | ||
28 | #include <unistd.h> | ||
29 | #include <sys/poll.h> | ||
30 | #include <sys/socket.h> | ||
31 | #include <sys/types.h> | ||
32 | #include <sys/un.h> | ||
33 | |||
34 | #include "config.h" | ||
35 | #include "debug.h" | ||
36 | #include "powermgmt.h" | ||
37 | |||
38 | #include "debug-ibasso.h" | ||
39 | |||
40 | |||
41 | /* | ||
42 | Without this socket iBasso Vold will not start. | ||
43 | iBasso Vold uses this to send status messages about storage devices. | ||
44 | */ | ||
45 | static const char VOLD_MONITOR_SOCKET_NAME[] = "UNIX_domain"; | ||
46 | static int _vold_monitor_socket_fd = -1; | ||
47 | |||
48 | |||
49 | static void vold_monitor_open_socket(void) | ||
50 | { | ||
51 | TRACE; | ||
52 | |||
53 | unlink(VOLD_MONITOR_SOCKET_NAME); | ||
54 | |||
55 | _vold_monitor_socket_fd = socket(AF_UNIX, SOCK_STREAM, 0); | ||
56 | |||
57 | if(_vold_monitor_socket_fd < 0) | ||
58 | { | ||
59 | _vold_monitor_socket_fd = -1; | ||
60 | return; | ||
61 | } | ||
62 | |||
63 | struct sockaddr_un addr; | ||
64 | memset(&addr, 0, sizeof(addr)); | ||
65 | addr.sun_family = AF_UNIX; | ||
66 | strncpy(addr.sun_path, VOLD_MONITOR_SOCKET_NAME, sizeof(addr.sun_path) -1); | ||
67 | |||
68 | if(bind(_vold_monitor_socket_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) | ||
69 | { | ||
70 | close(_vold_monitor_socket_fd); | ||
71 | unlink(VOLD_MONITOR_SOCKET_NAME); | ||
72 | _vold_monitor_socket_fd = -1; | ||
73 | return; | ||
74 | } | ||
75 | |||
76 | if(listen(_vold_monitor_socket_fd, 1) < 0) | ||
77 | { | ||
78 | close(_vold_monitor_socket_fd); | ||
79 | unlink(VOLD_MONITOR_SOCKET_NAME); | ||
80 | _vold_monitor_socket_fd = -1; | ||
81 | return; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | |||
86 | /* | ||
87 | bionic does not have pthread_cancel. | ||
88 | 0: Vold monitor thread stopped/ending. | ||
89 | 1: Vold monitor thread started/running. | ||
90 | */ | ||
91 | static volatile sig_atomic_t _vold_monitor_active = 0; | ||
92 | |||
93 | |||
94 | /* | ||
95 | 1: /mnt/sdcard is unmounting | ||
96 | 0: else | ||
97 | */ | ||
98 | static volatile sig_atomic_t _vold_monitor_forced_close_imminent = 0; | ||
99 | |||
100 | |||
101 | static void* vold_monitor_run(void* nothing) | ||
102 | { | ||
103 | _vold_monitor_active = 1; | ||
104 | |||
105 | (void) nothing; | ||
106 | |||
107 | DEBUGF("DEBUG %s: Thread start.", __func__); | ||
108 | |||
109 | vold_monitor_open_socket(); | ||
110 | if(_vold_monitor_socket_fd < 0) | ||
111 | { | ||
112 | DEBUGF("ERROR %s: Thread end: No socket.", __func__); | ||
113 | |||
114 | _vold_monitor_active = 0; | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | struct pollfd fds[1]; | ||
119 | fds[0].fd = _vold_monitor_socket_fd; | ||
120 | fds[0].events = POLLIN; | ||
121 | |||
122 | while(_vold_monitor_active == 1) | ||
123 | { | ||
124 | poll(fds, 1, 10); | ||
125 | if(! (fds[0].revents & POLLIN)) | ||
126 | { | ||
127 | continue; | ||
128 | } | ||
129 | |||
130 | int socket_fd = accept(_vold_monitor_socket_fd, NULL, NULL); | ||
131 | |||
132 | if(socket_fd < 0) | ||
133 | { | ||
134 | DEBUGF("ERROR %s: accept failed.", __func__); | ||
135 | |||
136 | continue; | ||
137 | } | ||
138 | |||
139 | while(true) | ||
140 | { | ||
141 | char msg[1024]; | ||
142 | memset(msg, 0, sizeof(msg)); | ||
143 | int length = read(socket_fd, msg, sizeof(msg)); | ||
144 | |||
145 | if(length <= 0) | ||
146 | { | ||
147 | close(socket_fd); | ||
148 | break; | ||
149 | } | ||
150 | |||
151 | DEBUGF("%s: msg: %s", __func__, msg); | ||
152 | |||
153 | if(strcmp(msg, "Volume flash /mnt/sdcard state changed from 4 (Mounted) to 5 (Unmounting)") == 0) | ||
154 | { | ||
155 | /* We are losing /mnt/sdcard, shutdown Rockbox before it is forced closed. */ | ||
156 | |||
157 | _vold_monitor_forced_close_imminent = 1; | ||
158 | sys_poweroff(); | ||
159 | _vold_monitor_active = 0; | ||
160 | } | ||
161 | else if(strcmp(msg, "Volume sdcard /mnt/external_sd state changed from 4 (Mounted) to 5 (Unmounting)") == 0) | ||
162 | { | ||
163 | /* We are loosing the external sdcard, inform Rockbox. */ | ||
164 | } | ||
165 | else if(strcmp(msg, "Volume sdcard /mnt/external_sd state changed from 3 (Checking) to 4 (Mounted)") == 0) | ||
166 | { | ||
167 | /* The external sdcard is back, inform Rockbox. */ | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | |||
172 | close(_vold_monitor_socket_fd); | ||
173 | unlink(VOLD_MONITOR_SOCKET_NAME); | ||
174 | _vold_monitor_socket_fd = -1; | ||
175 | |||
176 | DEBUGF("%s: Thread end.", __func__); | ||
177 | |||
178 | _vold_monitor_active = 0; | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | |||
183 | /* Vold monitor thread. */ | ||
184 | static pthread_t _vold_monitor_thread; | ||
185 | |||
186 | |||
187 | void vold_monitor_start(void) | ||
188 | { | ||
189 | TRACE; | ||
190 | |||
191 | if(_vold_monitor_active == 0) | ||
192 | { | ||
193 | pthread_create(&_vold_monitor_thread, NULL, vold_monitor_run, NULL); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | |||
198 | bool vold_monitor_forced_close_imminent(void) | ||
199 | { | ||
200 | TRACE; | ||
201 | |||
202 | return(_vold_monitor_forced_close_imminent == 1); | ||
203 | } | ||
diff --git a/firmware/target/hosted/ibasso/vold-ibasso.h b/firmware/target/hosted/ibasso/vold-ibasso.h new file mode 100644 index 0000000000..18012b7e16 --- /dev/null +++ b/firmware/target/hosted/ibasso/vold-ibasso.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___ | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50 | ||
10 | * Copyright (C) 2014 by Mario Basister: iBasso DX90 port | ||
11 | * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features | ||
12 | * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | |||
25 | #ifndef __VOLD_IBASSO_H__ | ||
26 | #define __VOLD_IBASSO_H__ | ||
27 | |||
28 | |||
29 | /* Start the vold monitor thread. */ | ||
30 | void vold_monitor_start(void); | ||
31 | |||
32 | |||
33 | /* | ||
34 | Used to change Rockbox shutdown from reboot/power off to program exit. | ||
35 | true: vold monitor has detected, that vold is remounting /mnt/sdcard for USB mass storage | ||
36 | access. | ||
37 | false: else. | ||
38 | */ | ||
39 | bool vold_monitor_forced_close_imminent(void); | ||
40 | |||
41 | |||
42 | #endif | ||