A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Heikki Hannikainen
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 "config.h"
23#include <stdlib.h>
24#include <stdio.h>
25#include <stdbool.h>
26#include <string-extra.h>
27#include "lcd.h"
28#include "lang.h"
29#include "menu.h"
30#include "debug_menu.h"
31#include "kernel.h"
32#include "action.h"
33#include "debug.h"
34#include "thread.h"
35#include "powermgmt.h"
36#include "system.h"
37#include "font.h"
38#include "audio.h"
39#include "settings.h"
40#include "list.h"
41#include "dir.h"
42#include "panic.h"
43#include "screens.h"
44#include "misc.h"
45#include "splash.h"
46#include "shortcuts.h"
47#include "dircache.h"
48#include "viewport.h"
49#ifdef HAVE_TAGCACHE
50#include "tagcache.h"
51#endif
52#ifdef HAVE_REMOTE_LCD
53#include "lcd-remote.h"
54#endif
55#include "crc32.h"
56#include "logf.h"
57#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
58#include "disk.h"
59#include "adc.h"
60#include "usb.h"
61#include "rtc.h"
62#include "storage.h"
63#include "fs_defines.h"
64#include "eeprom_24cxx.h"
65#if (CONFIG_STORAGE & STORAGE_MMC) || (CONFIG_STORAGE & STORAGE_SD)
66#include "sdmmc.h"
67#endif
68#if (CONFIG_STORAGE & STORAGE_ATA)
69#include "ata.h"
70#endif
71#endif /* CONFIG_PLATFORM & PLATFORM_NATIVE */
72#include "power.h"
73
74#if ((CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1) \
75 || defined(SONY_NWZ_LINUX)) \
76 && CONFIG_TUNER != 0
77#include "tuner.h"
78#include "radio.h"
79#endif
80
81#include "scrollbar.h"
82#include "peakmeter.h"
83#include "skin_engine/skin_engine.h"
84#include "logfdisp.h"
85#include "core_alloc.h"
86#include "pcmbuf.h"
87#include "buffering.h"
88#include "playback.h"
89#if defined(HAVE_SPDIF_OUT) || defined(HAVE_SPDIF_IN)
90#include "spdif.h"
91#endif
92#ifdef IRIVER_H300_SERIES
93#include "pcf50606.h" /* for pcf50606_read */
94#endif
95#ifdef IAUDIO_X5
96#include "ds2411.h"
97#endif
98#include "hwcompat.h"
99#include "button.h"
100#if CONFIG_RTC == RTC_PCF50605
101#include "pcf50605.h"
102#endif
103#include "appevents.h"
104
105#if defined(HAVE_AS3514) && CONFIG_CHARGING
106#include "ascodec.h"
107#endif
108
109#ifdef IPOD_NANO2G
110#include "pmu-target.h"
111#endif
112
113#ifdef SANSA_CONNECT
114#include "avr-sansaconnect.h"
115#endif
116
117#ifdef HAVE_USBSTACK
118#include "usb_core.h"
119#ifdef USB_ENABLE_AUDIO
120#include "../usbstack/usb_audio.h"
121#endif
122#endif
123
124#include "talk.h"
125
126#if defined(HAVE_DEVICEDATA)// && !defined(SIMULATOR)
127#include "devicedata.h"
128#endif
129
130#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR)
131#include "bootdata.h"
132#include "multiboot.h"
133#include "rbpaths.h"
134#include "pathfuncs.h"
135#include "rb-loader.h"
136#endif
137
138#if defined(IPOD_6G) && !defined(SIMULATOR)
139#include "norboot-target.h"
140#endif
141
142#if defined(IPOD_ACCESSORY_PROTOCOL)
143#include "iap.h"
144#endif
145
146#define SCREEN_MAX_CHARS (LCD_WIDTH / SYSFONT_WIDTH)
147
148static const char* threads_getname(int selected_item, void *data,
149 char *buffer, size_t buffer_len)
150{
151 int *x_offset = (int*) data;
152
153#if NUM_CORES > 1
154 if (selected_item < (int)NUM_CORES)
155 {
156 struct core_debug_info coreinfo;
157 core_get_debug_info(selected_item, &coreinfo);
158 snprintf(buffer, buffer_len, "Idle (%2d): %2d%%", selected_item,
159 coreinfo.idle_stack_usage);
160 return buffer;
161 }
162
163 selected_item -= NUM_CORES;
164#endif
165
166 const char *fmtstr = "%2d: ---";
167
168 struct thread_debug_info threadinfo;
169 if (thread_get_debug_info(selected_item, &threadinfo) > 0)
170 {
171 fmtstr = "%2d:" IF_COP(" (%d)") " %s%n" IF_PRIO(" %2d %2d")
172 IFN_SDL(" %2d%% %2d%%") " %s";
173 }
174 int status_len;
175 size_t len = snprintf(buffer, buffer_len, fmtstr,
176 selected_item,
177 IF_COP(threadinfo.core,)
178 threadinfo.statusstr,
179 &status_len,
180 IF_PRIO(threadinfo.base_priority, threadinfo.current_priority,)
181 IFN_SDL(threadinfo.stack_usage_cur, threadinfo.stack_usage,)
182 threadinfo.name);
183
184 int start = 0;
185#if LCD_WIDTH <= 128
186 if (len >= SCREEN_MAX_CHARS)
187 {
188 int ch_offset = (*x_offset)%(len-1);
189 int rem = SCREEN_MAX_CHARS - (len - ch_offset);
190 if (rem > 0)
191 ch_offset -= rem;
192
193 if (ch_offset > 0)
194 {
195 /* don't scroll the # and status */
196 status_len++;
197 if ((unsigned int)ch_offset + status_len < buffer_len)
198 memmove(&buffer[ch_offset], &buffer[0], status_len);
199 start = ch_offset;
200 }
201 }
202#else
203 (void) x_offset;
204 (void) len;
205#endif
206 return &buffer[start];
207}
208
209static int dbg_threads_action_callback(int action, struct gui_synclist *lists)
210{
211
212 if (action == ACTION_NONE)
213 {
214 return ACTION_REDRAW;
215 }
216#if LCD_WIDTH <= 128
217 int *x_offset = ((int*) lists->data);
218 if (action == ACTION_STD_OK)
219 {
220 *x_offset += 1;
221 action = ACTION_REDRAW;
222 }
223 else if (IS_SYSEVENT(action))
224 {
225 return ACTION_REDRAW;
226 }
227 else if (action != ACTION_UNKNOWN)
228 {
229 *x_offset = 0;
230 }
231#else
232 (void) lists;
233#endif
234 return action;
235}
236/* Test code!!! */
237static bool dbg_os(void)
238{
239 struct simplelist_info info;
240 int xoffset = 0;
241
242 simplelist_info_init(&info, IF_COP("Core and ") "Stack usage:",
243 MAXTHREADS IF_COP( + NUM_CORES ), &xoffset);
244 info.scroll_all = false;
245 info.action_callback = dbg_threads_action_callback;
246 info.get_name = threads_getname;
247 return simplelist_show_list(&info);
248}
249
250#ifdef __linux__
251#include "cpuinfo-linux.h"
252
253#define MAX_STATES 16
254static struct time_state states[MAX_STATES];
255
256static const char* get_cpuinfo(int selected_item, void *data,
257 char *buffer, size_t buffer_len)
258{
259 (void)data;(void)buffer_len;
260 const char* text;
261 long time, diff;
262 struct cpuusage us;
263 static struct cpuusage last_us;
264 int state_count = *(int*)data;
265
266 if (cpuusage_linux(&us) != 0)
267 return NULL;
268
269 switch(selected_item)
270 {
271 case 0:
272 diff = abs(last_us.usage - us.usage);
273 sprintf(buffer, "Usage: %ld.%02ld%% (%c %ld.%02ld)",
274 us.usage/100, us.usage%100,
275 (us.usage >= last_us.usage) ? '+':'-',
276 diff/100, diff%100);
277 last_us.usage = us.usage;
278 return buffer;
279 case 1:
280 text = "User";
281 time = us.utime;
282 diff = us.utime - last_us.utime;
283 last_us.utime = us.utime;
284 break;
285 case 2:
286 text = "Sys";
287 time = us.stime;
288 diff = us.stime - last_us.stime;
289 last_us.stime = us.stime;
290 break;
291 case 3:
292 text = "Real";
293 time = us.rtime;
294 diff = us.rtime - last_us.rtime;
295 last_us.rtime = us.rtime;
296 break;
297 case 4:
298 return "*** Per CPU freq stats ***";
299 default:
300 {
301 int cpu = (selected_item - 5) / (state_count + 1);
302 int cpu_line = (selected_item - 5) % (state_count + 1);
303
304 /* scaling info */
305 int min_freq = min_scaling_frequency(cpu);
306 int cur_freq = current_scaling_frequency(cpu);
307 /* fallback if scaling frequency is not available */
308 if(cur_freq <= 0)
309 cur_freq = frequency_linux(cpu);
310 int max_freq = max_scaling_frequency(cpu);
311 char governor[20];
312 bool have_governor = current_scaling_governor(cpu, governor, sizeof(governor));
313 if(cpu_line == 0)
314 {
315 sprintf(buffer,
316 " CPU%d: %s: %d/%d/%d MHz",
317 cpu,
318 have_governor ? governor : "Min/Cur/Max freq",
319 min_freq > 0 ? min_freq/1000 : -1,
320 cur_freq > 0 ? cur_freq/1000 : -1,
321 max_freq > 0 ? max_freq/1000 : -1);
322 }
323 else
324 {
325 cpustatetimes_linux(cpu, states, ARRAYLEN(states));
326 snprintf(buffer, buffer_len, " %ld %ld",
327 states[cpu_line-1].frequency,
328 states[cpu_line-1].time);
329 }
330 return buffer;
331 }
332 }
333 sprintf(buffer, "%s: %ld.%02lds (+ %ld.%02ld)", text,
334 time / us.hz, time % us.hz,
335 diff / us.hz, diff % us.hz);
336 return buffer;
337}
338
339static int cpuinfo_cb(int action, struct gui_synclist *lists)
340{
341 (void)lists;
342 if (action == ACTION_NONE)
343 action = ACTION_REDRAW;
344 return action;
345}
346
347static bool dbg_cpuinfo(void)
348{
349 struct simplelist_info info;
350 int cpu_count = MAX(cpucount_linux(), 1);
351 int state_count = cpustatetimes_linux(0, states, ARRAYLEN(states));
352 printf("%s(): %d %d\n", __func__, cpu_count, state_count);
353 simplelist_info_init(&info, "CPU info:", 5 + cpu_count*(state_count+1), &state_count);
354 info.get_name = get_cpuinfo;
355 info.action_callback = cpuinfo_cb;
356 info.timeout = HZ;
357 info.scroll_all = true;
358 return simplelist_show_list(&info);
359}
360
361#endif
362
363static unsigned int ticks, freq_sum;
364#ifndef CPU_MULTI_FREQUENCY
365static unsigned int boost_ticks;
366#endif
367
368static void dbg_audio_task(void)
369{
370#ifdef CPUFREQ_NORMAL
371#ifndef CPU_MULTI_FREQUENCY
372 if(FREQ > CPUFREQ_NORMAL)
373 boost_ticks++;
374#endif
375 freq_sum += FREQ/1000000; /* in MHz */
376#endif
377 ticks++;
378}
379
380static bool dbg_buffering_thread(void)
381{
382 int button;
383 int line;
384 bool done = false;
385 size_t bufused;
386 size_t bufsize = pcmbuf_get_bufsize();
387 int pcmbufdescs = pcmbuf_descs();
388 struct buffering_debug d;
389 size_t filebuflen = audio_get_filebuflen();
390 /* This is a size_t, but call it a long so it puts a - when it's bad. */
391#if LCD_WIDTH > 96
392 #define STR_DATAREM "data_rem"
393 const char * const fmt_used = "%s: %6ld/%ld";
394#else /* clipzip, ?*/
395 #define STR_DATAREM "remain"
396 const char * const fmt_used = "%s:%ld/%ld";
397#endif
398
399#ifndef CPU_MULTI_FREQUENCY
400 boost_ticks = 0;
401#endif
402 ticks = freq_sum = 0;
403
404 tick_add_task(dbg_audio_task);
405
406 FOR_NB_SCREENS(i)
407 screens[i].setfont(FONT_SYSFIXED);
408
409 while(!done)
410 {
411 button = get_action(CONTEXT_STD,HZ/5);
412 switch(button)
413 {
414 case ACTION_STD_NEXT:
415 audio_next();
416 break;
417 case ACTION_STD_PREV:
418 audio_prev();
419 break;
420 case ACTION_STD_CANCEL:
421 done = true;
422 break;
423 }
424
425 buffering_get_debugdata(&d);
426 bufused = bufsize - pcmbuf_free();
427
428 FOR_NB_SCREENS(i)
429 {
430 line = 0;
431 screens[i].clear_display();
432
433
434 screens[i].putsf(0, line++, fmt_used, "pcm", (long) bufused, (long) bufsize);
435
436 gui_scrollbar_draw(&screens[i],0, line*SYSFONT_HEIGHT, screens[i].lcdwidth, 6,
437 bufsize, 0, bufused, HORIZONTAL);
438 line++;
439
440 screens[i].putsf(0, line++, fmt_used, "alloc", audio_filebufused(),
441 (long) filebuflen);
442
443#if LCD_HEIGHT > 80 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_HEIGHT > 80)
444 if (screens[i].lcdheight > 80)
445 {
446 gui_scrollbar_draw(&screens[i],0, line*SYSFONT_HEIGHT, screens[i].lcdwidth, 6,
447 filebuflen, 0, audio_filebufused(), HORIZONTAL);
448 line++;
449
450 screens[i].putsf(0, line++, fmt_used, "real", (long)d.buffered_data,
451 (long)filebuflen);
452
453 gui_scrollbar_draw(&screens[i],0, line*SYSFONT_HEIGHT, screens[i].lcdwidth, 6,
454 filebuflen, 0, (long)d.buffered_data, HORIZONTAL);
455 line++;
456 }
457#endif
458
459 screens[i].putsf(0, line++, fmt_used, "usefl", (long)(d.useful_data),
460 (long)filebuflen);
461
462#if LCD_HEIGHT > 80 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_HEIGHT > 80)
463 if (screens[i].lcdheight > 80)
464 {
465 gui_scrollbar_draw(&screens[i],0, line*SYSFONT_HEIGHT, screens[i].lcdwidth, 6,
466 filebuflen, 0, d.useful_data, HORIZONTAL);
467 line++;
468 }
469#endif
470
471 screens[i].putsf(0, line++, "%s: %ld", STR_DATAREM, (long)d.data_rem);
472
473 screens[i].putsf(0, line++, "track count: %2u", audio_track_count());
474
475 screens[i].putsf(0, line++, "handle count: %d", (int)d.num_handles);
476
477#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
478 screens[i].putsf(0, line++, "cpu freq: %3dMHz",
479 (int)((FREQ + 500000) / 1000000));
480#endif
481
482 if (ticks > 0)
483 {
484 int avgclock = freq_sum * 10 / ticks; /* in 100 kHz */
485#ifdef CPU_MULTI_FREQUENCY
486 int boostquota = (avgclock * 100 - CPUFREQ_NORMAL/1000) /
487 ((CPUFREQ_MAX - CPUFREQ_NORMAL) / 1000000); /* in 0.1 % */
488#else
489 int boostquota = boost_ticks * 1000 / ticks; /* in 0.1 % */
490#endif
491 screens[i].putsf(0, line++, "boost:%3d.%d%% (%d.%dMHz)",
492 boostquota/10, boostquota%10, avgclock/10, avgclock%10);
493 }
494
495 screens[i].putsf(0, line++, "pcmbufdesc: %2d/%2d",
496 pcmbuf_used_descs(), pcmbufdescs);
497 screens[i].putsf(0, line++, "watermark: %6d",
498 (int)(d.watermark));
499
500 screens[i].update();
501 }
502 }
503
504 tick_remove_task(dbg_audio_task);
505
506 FOR_NB_SCREENS(i)
507 screens[i].setfont(FONT_UI);
508
509 return false;
510#undef STR_DATAREM
511}
512
513#ifdef BUFLIB_DEBUG_PRINT
514static const char* bf_getname(int selected_item, void *data,
515 char *buffer, size_t buffer_len)
516{
517 (void)data;
518 core_print_block_at(selected_item, buffer, buffer_len);
519 return buffer;
520}
521
522static int bf_action_cb(int action, struct gui_synclist* list)
523{
524 if (action == ACTION_STD_OK)
525 {
526 if (gui_synclist_get_sel_pos(list) == 0 && core_test_free())
527 {
528 splash(HZ, "Freed test handle. New alloc should trigger compact");
529 }
530 else
531 {
532 splash(HZ/1, "Attempting a 64k allocation");
533 int handle = core_alloc(64<<10);
534 splash(HZ/2, (handle > 0) ? "Success":"Fail");
535 /* for some reason simplelist doesn't allow adding items here if
536 * info.get_name is given, so use normal list api */
537 gui_synclist_set_nb_items(list, core_get_num_blocks());
538 core_free(handle);
539 }
540 action = ACTION_REDRAW;
541 }
542 return action;
543}
544
545static bool dbg_buflib_allocs(void)
546{
547 struct simplelist_info info;
548 simplelist_info_init(&info, "mem allocs", core_get_num_blocks(), NULL);
549 info.get_name = bf_getname;
550 info.action_callback = bf_action_cb;
551 info.timeout = HZ;
552 return simplelist_show_list(&info);
553}
554#endif /* BUFLIB_DEBUG_PRINT */
555
556#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
557static const char* dbg_partitions_getname(int selected_item, void *data,
558 char *buffer, size_t buffer_len)
559{
560 (void)data;
561 int partition = selected_item/2;
562
563 struct partinfo p;
564 if (!disk_partinfo(partition, &p))
565 return buffer;
566
567 // XXX fix this up to use logical sector size
568 // XXX and if mounted, show free info...
569 if (selected_item%2)
570 {
571 snprintf(buffer, buffer_len, " T:%x %lu MB", p.type,
572 (unsigned long)(p.size / ( 2048 / ( SECTOR_SIZE / 512 ))));
573 }
574 else
575 {
576 snprintf(buffer, buffer_len, "P%d: S:%llx", partition, (unsigned long long)p.start);
577 }
578 return buffer;
579}
580
581static bool dbg_partitions(void)
582{
583 struct simplelist_info info;
584 simplelist_info_init(&info, "Partition Info", NUM_DRIVES * MAX_PARTITIONS_PER_DRIVE, NULL);
585 info.selection_size = 2;
586 info.scroll_all = true;
587 info.get_name = dbg_partitions_getname;
588 return simplelist_show_list(&info);
589}
590#endif /* PLATFORM_NATIVE */
591
592#if defined(CPU_COLDFIRE) && defined(HAVE_SPDIF_OUT)
593static bool dbg_spdif(void)
594{
595 int line;
596 unsigned int control;
597 int x;
598 char *s;
599 int category;
600 int generation;
601 unsigned int interruptstat;
602 bool valnogood, symbolerr, parityerr;
603 bool done = false;
604 bool spdif_src_on;
605 int spdif_source = spdif_get_output_source(&spdif_src_on);
606 spdif_set_output_source(AUDIO_SRC_SPDIF IF_SPDIF_POWER_(, true));
607
608 lcd_clear_display();
609 lcd_setfont(FONT_SYSFIXED);
610
611#ifdef HAVE_SPDIF_POWER
612 spdif_power_enable(true); /* We need SPDIF power for both sending & receiving */
613#endif
614
615 while (!done)
616 {
617 line = 0;
618
619 control = EBU1RCVCCHANNEL1;
620 interruptstat = INTERRUPTSTAT;
621 INTERRUPTCLEAR = 0x03c00000;
622
623 valnogood = (interruptstat & 0x01000000)?true:false;
624 symbolerr = (interruptstat & 0x00800000)?true:false;
625 parityerr = (interruptstat & 0x00400000)?true:false;
626
627 lcd_putsf(0, line++, "Val: %s Sym: %s Par: %s",
628 valnogood?"--":"OK",
629 symbolerr?"--":"OK",
630 parityerr?"--":"OK");
631
632 lcd_putsf(0, line++, "Status word: %08x", (int)control);
633
634 line++;
635
636 x = control >> 31;
637 lcd_putsf(0, line++, "PRO: %d (%s)",
638 x, x?"Professional":"Consumer");
639
640 x = (control >> 30) & 1;
641 lcd_putsf(0, line++, "Audio: %d (%s)",
642 x, x?"Non-PCM":"PCM");
643
644 x = (control >> 29) & 1;
645 lcd_putsf(0, line++, "Copy: %d (%s)",
646 x, x?"Permitted":"Inhibited");
647
648 x = (control >> 27) & 7;
649 switch(x)
650 {
651 case 0:
652 s = "None";
653 break;
654 case 1:
655 s = "50/15us";
656 break;
657 default:
658 s = "Reserved";
659 break;
660 }
661 lcd_putsf(0, line++, "Preemphasis: %d (%s)", x, s);
662
663 x = (control >> 24) & 3;
664 lcd_putsf(0, line++, "Mode: %d", x);
665
666 category = (control >> 17) & 127;
667 switch(category)
668 {
669 case 0x00:
670 s = "General";
671 break;
672 case 0x40:
673 s = "Audio CD";
674 break;
675 default:
676 s = "Unknown";
677 }
678 lcd_putsf(0, line++, "Category: 0x%02x (%s)", category, s);
679
680 x = (control >> 16) & 1;
681 generation = x;
682 if(((category & 0x70) == 0x10) ||
683 ((category & 0x70) == 0x40) ||
684 ((category & 0x78) == 0x38))
685 {
686 generation = !generation;
687 }
688 lcd_putsf(0, line++, "Generation: %d (%s)",
689 x, generation?"Original":"No ind.");
690
691 x = (control >> 12) & 15;
692 lcd_putsf(0, line++, "Source: %d", x);
693
694
695 x = (control >> 8) & 15;
696 switch(x)
697 {
698 case 0:
699 s = "Unspecified";
700 break;
701 case 8:
702 s = "A (Left)";
703 break;
704 case 4:
705 s = "B (Right)";
706 break;
707 default:
708 s = "";
709 break;
710 }
711 lcd_putsf(0, line++, "Channel: %d (%s)", x, s);
712
713 x = (control >> 4) & 15;
714 switch(x)
715 {
716 case 0:
717 s = "44.1kHz";
718 break;
719 case 0x4:
720 s = "48kHz";
721 break;
722 case 0xc:
723 s = "32kHz";
724 break;
725 }
726 lcd_putsf(0, line++, "Frequency: %d (%s)", x, s);
727
728 x = (control >> 2) & 3;
729 lcd_putsf(0, line++, "Clock accuracy: %d", x);
730 line++;
731
732#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
733 lcd_putsf(0, line++, "Measured freq: %ldHz",
734 spdif_measure_frequency());
735#endif
736
737 lcd_update();
738
739 if (action_userabort(HZ/10))
740 break;
741 }
742
743 spdif_set_output_source(spdif_source IF_SPDIF_POWER_(, spdif_src_on));
744
745#ifdef HAVE_SPDIF_POWER
746 spdif_power_enable(global_settings.spdif_enable);
747#endif
748
749 lcd_setfont(FONT_UI);
750 return false;
751}
752#endif /* CPU_COLDFIRE */
753
754#if (CONFIG_RTC == RTC_PCF50605) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
755static bool dbg_pcf(void)
756{
757 int line;
758
759 lcd_setfont(FONT_SYSFIXED);
760 lcd_clear_display();
761
762 while(1)
763 {
764 line = 0;
765
766 lcd_putsf(0, line++, "DCDC1: %02x", pcf50605_read(0x1b));
767 lcd_putsf(0, line++, "DCDC2: %02x", pcf50605_read(0x1c));
768 lcd_putsf(0, line++, "DCDC3: %02x", pcf50605_read(0x1d));
769 lcd_putsf(0, line++, "DCDC4: %02x", pcf50605_read(0x1e));
770 lcd_putsf(0, line++, "DCDEC1: %02x", pcf50605_read(0x1f));
771 lcd_putsf(0, line++, "DCDEC2: %02x", pcf50605_read(0x20));
772 lcd_putsf(0, line++, "DCUDC1: %02x", pcf50605_read(0x21));
773 lcd_putsf(0, line++, "DCUDC2: %02x", pcf50605_read(0x22));
774 lcd_putsf(0, line++, "IOREGC: %02x", pcf50605_read(0x23));
775 lcd_putsf(0, line++, "D1REGC: %02x", pcf50605_read(0x24));
776 lcd_putsf(0, line++, "D2REGC: %02x", pcf50605_read(0x25));
777 lcd_putsf(0, line++, "D3REGC: %02x", pcf50605_read(0x26));
778 lcd_putsf(0, line++, "LPREG1: %02x", pcf50605_read(0x27));
779 lcd_update();
780 if (action_userabort(HZ/10))
781 {
782 lcd_setfont(FONT_UI);
783 return false;
784 }
785 }
786
787 lcd_setfont(FONT_UI);
788 return false;
789}
790#endif
791
792#ifdef HAVE_ADJUSTABLE_CPU_FREQ
793static bool dbg_cpufreq(void)
794{
795 int line;
796 int button;
797 int x = 0;
798 bool done = false;
799
800 lcd_setfont(FONT_SYSFIXED);
801 lcd_clear_display();
802
803 while(!done)
804 {
805 line = 0;
806
807 int temp = FREQ / 1000;
808 lcd_putsf(x, line++, "Frequency: %ld.%ld MHz", temp / 1000, temp % 1000);
809 lcd_putsf(x, line++, "boost_counter: %d", get_cpu_boost_counter());
810
811#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
812 extern int get_cpu_voltage_setting(void);
813 temp = get_cpu_voltage_setting();
814 lcd_putsf(x, line++, "CPU voltage: %d.%03dV", temp / 1000, temp % 1000);
815#endif
816
817 lcd_update();
818 button = get_action(CONTEXT_STD,HZ/10);
819
820 switch(button)
821 {
822 case ACTION_STD_PREV:
823 cpu_boost(true);
824 break;
825
826 case ACTION_STD_NEXT:
827 cpu_boost(false);
828 break;
829 case ACTION_STD_MENU:
830 x--;
831 break;
832 case ACTION_STD_OK:
833 x = 0;
834 while (get_cpu_boost_counter() > 0)
835 cpu_boost(false);
836 set_cpu_frequency(CPUFREQ_DEFAULT);
837 break;
838
839 case ACTION_STD_CANCEL:
840 done = true;;
841 }
842 lcd_clear_display();
843 }
844 lcd_setfont(FONT_UI);
845 return false;
846}
847#endif /* HAVE_ADJUSTABLE_CPU_FREQ */
848
849#if defined(HAVE_TSC2100) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
850#include "tsc2100.h"
851static const char* tsc2100_debug_getname(int selected_item, void * data,
852 char *buffer, size_t buffer_len)
853{
854 int *page = (int*)data;
855 bool reserved = false;
856 switch (*page)
857 {
858 case 0:
859 if ((selected_item > 0x0a) ||
860 (selected_item == 0x04) ||
861 (selected_item == 0x08))
862 reserved = true;
863 break;
864 case 1:
865 if ((selected_item > 0x05) ||
866 (selected_item == 0x02))
867 reserved = true;
868 break;
869 case 2:
870 if (selected_item > 0x1e)
871 reserved = true;
872 break;
873 }
874 if (reserved)
875 snprintf(buffer, buffer_len, "%02x: RSVD", selected_item);
876 else
877 snprintf(buffer, buffer_len, "%02x: %04x", selected_item,
878 tsc2100_readreg(*page, selected_item)&0xffff);
879 return buffer;
880}
881static int tsc2100debug_action_callback(int action, struct gui_synclist *lists)
882{
883 int *page = (int*)lists->data;
884 if (action == ACTION_STD_OK)
885 {
886 *page = (*page+1)%3;
887 snprintf((char*)lists->title, 32, "tsc2100 registers - Page %d", *page);
888 return ACTION_REDRAW;
889 }
890 return action;
891}
892static bool tsc2100_debug(void)
893{
894 int page = 0;
895 char title[32];
896 snprintf(title, 32, "tsc2100 registers - Page %d", page);
897 struct simplelist_info info;
898 simplelist_info_init(&info, title, 32, &page);
899 info.timeout = HZ/100;
900 info.get_name = tsc2100_debug_getname;
901 info.action_callback= tsc2100debug_action_callback;
902 return simplelist_show_list(&info);
903}
904#endif
905#if (CONFIG_BATTERY_MEASURE != 0) && !defined(SIMULATOR)
906/*
907 * view_battery() shows a automatically scaled graph of the battery voltage
908 * over time. Usable for estimating battery life / charging rate.
909 * The power_history array is updated in power_thread of powermgmt.c.
910 */
911
912#define BAT_LAST_VAL MIN(LCD_WIDTH, POWER_HISTORY_LEN)
913#define BAT_TSPACE 20
914#define BAT_YSPACE (LCD_HEIGHT - BAT_TSPACE)
915
916
917static bool view_battery(void)
918{
919 extern struct battery_tables_t device_battery_tables; /* powermgmt.c */
920 unsigned short *power_history = device_battery_tables.history;
921 int view = 0;
922 int i, x, y, z, y1, y2, grid, graph;
923 unsigned short maxv, minv;
924 lcd_setfont(FONT_SYSFIXED);
925
926 while(1)
927 {
928 lcd_clear_display();
929 switch (view) {
930 case 0: /* voltage history graph */
931 /* Find maximum and minimum voltage for scaling */
932 minv = power_history[0];
933 maxv = minv + 1;
934 for (i = 1; i < BAT_LAST_VAL && power_history[i]; i++) {
935 if (power_history[i] > maxv)
936 maxv = power_history[i];
937 if (power_history[i] < minv)
938 minv = power_history[i];
939 }
940 /* print header */
941#if (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE)
942 /* adjust grid scale */
943 if ((maxv - minv) > 50)
944 grid = 50;
945 else
946 grid = 5;
947
948 lcd_putsf(0, 0, "%s %d.%03dV", "Battery", power_history[0] / 1000,
949 power_history[0] % 1000);
950 lcd_putsf(0, 1, "%d.%03d-%d.%03dV (%2dmV)",
951 minv / 1000, minv % 1000, maxv / 1000, maxv % 1000,
952 grid);
953#elif (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE)
954 /* adjust grid scale */
955 if ((maxv - minv) > 10)
956 grid = 10;
957 else
958 grid = 1;
959 lcd_putsf(0, 0, "%s %d%%", "Battery", power_history[0]);
960 lcd_putsf(0, 1, "%d%%-%d%% (%d %%)", minv, maxv, grid);
961#endif
962
963 i = 1;
964 while ((y = (minv - (minv % grid)+i*grid)) < maxv)
965 {
966 graph = ((y-minv)*BAT_YSPACE)/(maxv-minv);
967 graph = LCD_HEIGHT-1 - graph;
968
969 /* draw dotted horizontal grid line */
970 for (x=0; x<LCD_WIDTH;x=x+2)
971 lcd_drawpixel(x,graph);
972
973 i++;
974 }
975
976 x = 0;
977 /* draw plot of power history
978 * skip empty entries
979 */
980 for (i = BAT_LAST_VAL - 1; i > 0; i--)
981 {
982 if (power_history[i] && power_history[i-1])
983 {
984 y1 = (power_history[i] - minv) * BAT_YSPACE /
985 (maxv - minv);
986 y1 = MIN(MAX(LCD_HEIGHT-1 - y1, BAT_TSPACE),
987 LCD_HEIGHT-1);
988 y2 = (power_history[i-1] - minv) * BAT_YSPACE /
989 (maxv - minv);
990 y2 = MIN(MAX(LCD_HEIGHT-1 - y2, BAT_TSPACE),
991 LCD_HEIGHT-1);
992
993 lcd_set_drawmode(DRMODE_SOLID);
994
995 /* make line thicker */
996 lcd_drawline(((x*LCD_WIDTH)/(BAT_LAST_VAL)),
997 y1,
998 (((x+1)*LCD_WIDTH)/(BAT_LAST_VAL)),
999 y2);
1000 lcd_drawline(((x*LCD_WIDTH)/(BAT_LAST_VAL))+1,
1001 y1+1,
1002 (((x+1)*LCD_WIDTH)/(BAT_LAST_VAL))+1,
1003 y2+1);
1004 x++;
1005 }
1006 }
1007 break;
1008
1009 case 1: /* status: */
1010#if CONFIG_CHARGING >= CHARGING_MONITOR
1011 lcd_putsf(0, 0, "Pwr status: %s",
1012 charging_state() ? "charging" : "discharging");
1013#else
1014 lcd_putsf(0, 0, "Pwr status: %s", "unknown");
1015#endif
1016 battery_read_info(&y, &z);
1017 if (y > 0)
1018 lcd_putsf(0, 1, "%s: %d.%03d V (%d %%)", "Battery", y / 1000, y % 1000, z);
1019 else if (z > 0)
1020 lcd_putsf(0, 1, "%s: %d %%", "Battery", z);
1021#ifdef ADC_EXT_POWER
1022 y = (adc_read(ADC_EXT_POWER) * EXT_SCALE_FACTOR) / 1000;
1023 lcd_putsf(0, 2, "%s: %d.%03d V", "External", y / 1000, y % 1000);
1024#endif
1025#if CONFIG_CHARGING
1026#if defined IPOD_NANO || defined IPOD_VIDEO
1027 int usb_pwr = (GPIOL_INPUT_VAL & 0x10)?true:false;
1028 int ext_pwr = (GPIOL_INPUT_VAL & 0x08)?false:true;
1029 int dock = (GPIOA_INPUT_VAL & 0x10)?true:false;
1030 int charging = (GPIOB_INPUT_VAL & 0x01)?false:true;
1031 int headphone= (GPIOA_INPUT_VAL & 0x80)?true:false;
1032
1033 lcd_putsf(0, 3, "USB pwr: %s",
1034 usb_pwr ? "present" : "absent");
1035 lcd_putsf(0, 4, "EXT pwr: %s",
1036 ext_pwr ? "present" : "absent");
1037 lcd_putsf(0, 5, "%s: %s", "Battery",
1038 charging ? "charging" : (usb_pwr||ext_pwr) ? "charged" : "discharging");
1039 lcd_putsf(0, 6, "Dock mode: %s",
1040 dock ? "enabled" : "disabled");
1041 lcd_putsf(0, 7, "Headphone: %s",
1042 headphone ? "connected" : "disconnected");
1043#ifdef IPOD_VIDEO
1044 if(probed_ramsize == 64)
1045 x = (adc_read(ADC_4066_ISTAT) * 2400) / (1024 * 2);
1046 else
1047#endif
1048 x = (adc_read(ADC_4066_ISTAT) * 2400) / (1024 * 3);
1049 lcd_putsf(0, 8, "Ibat: %d mA", x);
1050 lcd_putsf(0, 9, "Vbat * Ibat: %d mW", x * y / 1000);
1051#elif defined TOSHIBA_GIGABEAT_S
1052 int line = 3;
1053 unsigned int st;
1054
1055 static const unsigned char * const chrgstate_strings[] =
1056 {
1057 "Disabled",
1058 "Error",
1059 "Discharging",
1060 "Precharge",
1061 "Constant Voltage",
1062 "Constant Current",
1063 "<unknown>",
1064 };
1065
1066 lcd_putsf(0, line++, "Charger: %s",
1067 charger_inserted() ? "present" : "absent");
1068
1069 st = power_input_status() &
1070 (POWER_INPUT_CHARGER | POWER_INPUT_BATTERY);
1071
1072 lcd_putsf(0, line++, "%.*s%.*s",
1073 !!(st & POWER_INPUT_MAIN_CHARGER)*5, " Main",
1074 !!(st & POWER_INPUT_USB_CHARGER)*4, " USB");
1075
1076 y = ARRAYLEN(chrgstate_strings) - 1;
1077
1078 switch (charge_state)
1079 {
1080 case CHARGE_STATE_DISABLED: y--;
1081 case CHARGE_STATE_ERROR: y--;
1082 case DISCHARGING: y--;
1083 case TRICKLE: y--;
1084 case TOPOFF: y--;
1085 case CHARGING: y--;
1086 default:;
1087 }
1088
1089 lcd_putsf(0, line++, "State: %s", chrgstate_strings[y]);
1090
1091 lcd_putsf(0, line++, "%s Switch: %s", "Battery",
1092 (st & POWER_INPUT_BATTERY) ? "On" : "Off");
1093
1094 y = chrgraw_adc_voltage();
1095 lcd_putsf(0, line++, "CHRGRAW: %d.%03d V",
1096 y / 1000, y % 1000);
1097
1098 y = application_supply_adc_voltage();
1099 lcd_putsf(0, line++, "BP : %d.%03d V",
1100 y / 1000, y % 1000);
1101
1102 y = battery_adc_charge_current();
1103 lcd_putsf(0, line++, "CHRGISN:% d mA", y);
1104
1105 y = cccv_regulator_dissipation();
1106 lcd_putsf(0, line++, "P CCCV : %d mW", y);
1107
1108 y = battery_charge_current();
1109 lcd_putsf(0, line++, "I Charge:% d mA", y);
1110
1111 y = battery_adc_temp();
1112
1113 if (y != INT_MIN) {
1114 lcd_putsf(0, line++, "T %s: %d\u00b0C (%d\u00b0F)",
1115 "Battery", y, (9*y + 160) / 5);
1116 } else {
1117 /* Conversion disabled */
1118 lcd_putsf(0, line++, "T %s: ?", "Battery");
1119 }
1120#elif defined(HAVE_AS3514) && CONFIG_CHARGING
1121 static const char * const chrgstate_strings[] =
1122 {
1123 [CHARGE_STATE_DISABLED - CHARGE_STATE_DISABLED]= "Disabled",
1124 [CHARGE_STATE_ERROR - CHARGE_STATE_DISABLED] = "Error",
1125 [DISCHARGING - CHARGE_STATE_DISABLED] = "Discharging",
1126 [CHARGING - CHARGE_STATE_DISABLED] = "Charging",
1127 };
1128 const char *str = NULL;
1129
1130 lcd_putsf(0, 3, "Charger: %s",
1131 charger_inserted() ? "present" : "absent");
1132
1133 y = charge_state - CHARGE_STATE_DISABLED;
1134 if ((unsigned)y < ARRAYLEN(chrgstate_strings))
1135 str = chrgstate_strings[y];
1136
1137 lcd_putsf(0, 4, "State: %s",
1138 str ? str : "<unknown>");
1139
1140 lcd_putsf(0, 5, "CHARGER: %02X", ascodec_read_charger());
1141#elif defined(IPOD_NANO2G)
1142 y = pmu_read_battery_voltage();
1143 lcd_putsf(17, 1, "RAW: %d.%03d V", y / 1000, y % 1000);
1144 y = pmu_read_battery_current();
1145 lcd_putsf(0, 2, "%s current: %d mA", "Battery", y);
1146 lcd_putsf(0, 3, "PWRCON: %08x %08x", PWRCON, PWRCONEXT);
1147 lcd_putsf(0, 4, "CLKCON: %08x %03x %03x", CLKCON, CLKCON2, CLKCON3);
1148 lcd_putsf(0, 5, "PLL: %06x %06x %06x", PLL0PMS, PLL1PMS, PLL2PMS);
1149 x = pmu_read(0x1b) & 0xf;
1150 y = pmu_read(0x1a) * 25 + 625;
1151 lcd_putsf(0, 6, "AUTO: %x / %d mV", x, y);
1152 x = pmu_read(0x1f) & 0xf;
1153 y = pmu_read(0x1e) * 25 + 625;
1154 lcd_putsf(0, 7, "DOWN1: %x / %d mV", x, y);
1155 x = pmu_read(0x23) & 0xf;
1156 y = pmu_read(0x22) * 25 + 625;
1157 lcd_putsf(0, 8, "DOWN2: %x / %d mV", x, y);
1158 x = pmu_read(0x27) & 0xf;
1159 y = pmu_read(0x26) * 100 + 900;
1160 lcd_putsf(0, 9, "MEMLDO: %x / %d mV", x, y);
1161 for (i = 0; i < 6; i++)
1162 {
1163 x = pmu_read(0x2e + (i << 1)) & 0xf;
1164 y = pmu_read(0x2d + (i << 1)) * 100 + 900;
1165 lcd_putsf(0, 10 + i, "LDO%d: %x / %d mV", i + 1, x, y);
1166 }
1167#elif defined(SANSA_CONNECT)
1168 lcd_putsf(0, 3, "Charger: %s",
1169 charger_inserted() ? "present" : "absent");
1170 x = (avr_hid_hdq_read_short(HDQ_REG_TEMP) / 4) - 273;
1171 lcd_putsf(0, 4, "%s temperature: %d C", "Battery", x);
1172 x = (avr_hid_hdq_read_short(HDQ_REG_AI) * 357) / 200;
1173 lcd_putsf(0, 5, "%s current: %d.%01d mA", "Battery", x / 10, x % 10);
1174 x = (avr_hid_hdq_read_short(HDQ_REG_AP) * 292) / 20;
1175 lcd_putsf(0, 6, "Discharge power: %d.%01d mW", x / 10, x % 10);
1176 x = (avr_hid_hdq_read_short(HDQ_REG_SAE) * 292) / 2;
1177 lcd_putsf(0, 7, "Available energy: %d.%01d mWh", x / 10, x % 10);
1178#else
1179 lcd_putsf(0, 3, "Charger: %s",
1180 charger_inserted() ? "present" : "absent");
1181#endif /* target type */
1182#endif /* CONFIG_CHARGING */
1183 break;
1184 case 2: /* voltage deltas: */
1185#if (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE)
1186 lcd_puts(0, 0, "Voltage deltas:");
1187 for (i = 0; i < POWER_HISTORY_LEN-1; i++) {
1188 y = power_history[i] - power_history[i+1];
1189 lcd_putsf(0, i+1, "-%d min: %c%d.%03d V", i,
1190 (y < 0) ? '-' : ' ', ((y < 0) ? y * -1 : y) / 1000,
1191 ((y < 0) ? y * -1 : y ) % 1000);
1192 }
1193#elif (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE)
1194 lcd_puts(0, 0, "Percentage deltas:");
1195 for (i = 0; i < POWER_HISTORY_LEN-1; i++) {
1196 y = power_history[i] - power_history[i+1];
1197 lcd_putsf(0, i+1, "-%d min: %c%d%%", i,
1198 (y < 0) ? '-' : ' ', ((y < 0) ? y * -1 : y));
1199 }
1200#endif
1201 break;
1202
1203 case 3: /* remaining time estimation: */
1204
1205#if (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE)
1206 lcd_putsf(0, 5, "Last PwrHist: %d.%03dV",
1207 power_history[0] / 1000,
1208 power_history[0] % 1000);
1209#endif
1210
1211 lcd_putsf(0, 6, "%s level: %d%%", "Battery", battery_level());
1212
1213 int time_left = battery_time();
1214 if (time_left >= 0)
1215 lcd_putsf(0, 7, "Est. remain: %d m", time_left);
1216 else
1217 lcd_puts(0, 7, "Estimation n/a");
1218
1219#if (CONFIG_BATTERY_MEASURE & CURRENT_MEASURE)
1220 lcd_putsf(0, 8, "%s current: %d mA", "Battery", battery_current());
1221#endif
1222 break;
1223 }
1224
1225 lcd_update();
1226
1227 switch(get_action(CONTEXT_STD,HZ/2))
1228 {
1229 case ACTION_STD_PREV:
1230 if (view)
1231 view--;
1232 break;
1233
1234 case ACTION_STD_NEXT:
1235 if (view < 3)
1236 view++;
1237 break;
1238
1239 case ACTION_STD_CANCEL:
1240 lcd_setfont(FONT_UI);
1241 return false;
1242 }
1243 }
1244 lcd_setfont(FONT_UI);
1245 return false;
1246}
1247
1248#endif /* (CONFIG_BATTERY_MEASURE != 0) */
1249
1250#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
1251#if (CONFIG_STORAGE & STORAGE_MMC) || (CONFIG_STORAGE & STORAGE_SD)
1252
1253#if (CONFIG_STORAGE & STORAGE_MMC)
1254#define CARDTYPE "MMC"
1255#elif (CONFIG_STORAGE & STORAGE_SD)
1256#define CARDTYPE "microSD"
1257#endif
1258
1259static int disk_callback(int btn, struct gui_synclist *lists)
1260{
1261 tCardInfo *card;
1262 int *cardnum = (int*)lists->data;
1263 unsigned char card_name[6];
1264 unsigned char pbuf[32];
1265 /* Casting away const is safe; the buffer is defined as non-const. */
1266 char *title = (char *)lists->title;
1267 static const unsigned char i_vmin[] = { 0, 1, 5, 10, 25, 35, 60, 100 };
1268 static const unsigned char i_vmax[] = { 1, 5, 10, 25, 35, 45, 80, 200 };
1269 static const unsigned char * const kbit_units[] = { "kBit/s", "MBit/s", "GBit/s" };
1270 static const unsigned char * const nsec_units[] = { "ns", "µs", "ms" };
1271#if (CONFIG_STORAGE & STORAGE_MMC)
1272 static const char * const mmc_spec_vers[] = { "1.0-1.2", "1.4", "2.0-2.2",
1273 "3.1-3.31", "4.0" };
1274#endif
1275
1276 if ((btn == ACTION_STD_OK) || (btn == SYS_FS_CHANGED) || (btn == ACTION_REDRAW))
1277 {
1278#ifdef HAVE_HOTSWAP
1279 if (btn == ACTION_STD_OK)
1280 {
1281 *cardnum ^= 0x1; /* change cards */
1282 }
1283#endif
1284
1285 simplelist_reset_lines();
1286
1287 card = card_get_info(*cardnum);
1288
1289 if (card->initialized > 0)
1290 {
1291 unsigned i;
1292 for (i=0; i<sizeof(card_name); i++)
1293 {
1294 card_name[i] = card_extract_bits(card->cid, (103-8*i), 8);
1295 }
1296 strmemccpy(card_name, card_name, sizeof(card_name));
1297 simplelist_addline(
1298 "%s Rev %d.%d", card_name,
1299 (int) card_extract_bits(card->cid, 63, 4),
1300 (int) card_extract_bits(card->cid, 59, 4));
1301 simplelist_addline(
1302 "Prod: %d/%d",
1303#if (CONFIG_STORAGE & STORAGE_SD)
1304 (int) card_extract_bits(card->cid, 11, 4),
1305 (int) card_extract_bits(card->cid, 19, 8) + 2000
1306#elif (CONFIG_STORAGE & STORAGE_MMC)
1307 (int) card_extract_bits(card->cid, 15, 4),
1308 (int) card_extract_bits(card->cid, 11, 4) + 1997
1309#endif
1310 );
1311 simplelist_addline(
1312#if (CONFIG_STORAGE & STORAGE_SD)
1313 "Ser#: 0x%08lx",
1314 card_extract_bits(card->cid, 55, 32)
1315#elif (CONFIG_STORAGE & STORAGE_MMC)
1316 "Ser#: 0x%04lx",
1317 card_extract_bits(card->cid, 47, 16)
1318#endif
1319 );
1320
1321 simplelist_addline("M=%02x, "
1322#if (CONFIG_STORAGE & STORAGE_SD)
1323 "O=%c%c",
1324 (int) card_extract_bits(card->cid, 127, 8),
1325 (int) card_extract_bits(card->cid, 119, 8),
1326 (int) card_extract_bits(card->cid, 111, 8)
1327#elif (CONFIG_STORAGE & STORAGE_MMC)
1328 "O=%04x",
1329 (int) card_extract_bits(card->cid, 127, 8),
1330 (int) card_extract_bits(card->cid, 119, 16)
1331#endif
1332 );
1333
1334#if (CONFIG_STORAGE & STORAGE_MMC)
1335 int temp = card_extract_bits(card->csd, 125, 4);
1336 simplelist_addline(
1337 "MMC v%s", temp < 5 ?
1338 mmc_spec_vers[temp] : "?.?");
1339#endif
1340 simplelist_addline(
1341 "Blocks: 0x%08lx", card->numblocks);
1342 output_dyn_value(pbuf, sizeof pbuf, card->speed / 1000,
1343 kbit_units, 3, false);
1344 simplelist_addline(
1345 "Speed: %s", pbuf);
1346 output_dyn_value(pbuf, sizeof pbuf, card->taac,
1347 nsec_units, 3, false);
1348 simplelist_addline(
1349 "Taac: %s", pbuf);
1350 simplelist_addline(
1351 "Nsac: %d clk", card->nsac);
1352 simplelist_addline(
1353 "R2W: *%d", 1 << card->r2w_factor);
1354#if (CONFIG_STORAGE & STORAGE_SD)
1355 int csd_structure = card_extract_bits(card->csd, 127, 2);
1356 const char *ver;
1357 switch(csd_structure) {
1358 case 0:
1359 ver = "1 (SD)";
1360 break;
1361 case 1:
1362 ver = "2 (SDHC/SDXC)";
1363 break;
1364 case 2:
1365 ver = "3 (SDUC)";
1366 break;
1367 default:
1368 ver = "Unknown";
1369 break;
1370 }
1371 simplelist_addline("SDVer: %s", ver);
1372 if (csd_structure == 0) /* CSD version 1.0 */
1373#endif
1374 {
1375 simplelist_addline(
1376 "IRmax: %d..%d mA",
1377 i_vmin[card_extract_bits(card->csd, 61, 3)],
1378 i_vmax[card_extract_bits(card->csd, 58, 3)]);
1379 simplelist_addline(
1380 "IWmax: %d..%d mA",
1381 i_vmin[card_extract_bits(card->csd, 55, 3)],
1382 i_vmax[card_extract_bits(card->csd, 52, 3)]);
1383 }
1384 }
1385 else if (card->initialized == 0)
1386 {
1387 simplelist_setline("Not Found!");
1388 }
1389#if (CONFIG_STORAGE & STORAGE_SD)
1390 else /* card->initialized < 0 */
1391 {
1392 simplelist_addline("Init Error! (%d)", card->initialized);
1393 }
1394#endif
1395 snprintf(title, 16, "[" CARDTYPE " %d]", *cardnum);
1396 gui_synclist_set_title(lists, title, Icon_NOICON);
1397 gui_synclist_set_nb_items(lists, simplelist_get_line_count());
1398 gui_synclist_select_item(lists, 0);
1399 btn = ACTION_REDRAW;
1400 }
1401 return btn;
1402}
1403#elif (CONFIG_STORAGE & STORAGE_ATA)
1404static int disk_callback(int btn, struct gui_synclist *lists)
1405{
1406 static const char atanums[] = { " 0 1 2 3 4 5 6" };
1407
1408 (void)lists;
1409 int i;
1410 char buf[128];
1411 unsigned short* identify_info = ata_get_identify();
1412 bool timing_info_present = false;
1413 (void)btn;
1414
1415 simplelist_reset_lines();
1416
1417 for (i=0; i < 20; i++)
1418 ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
1419 buf[40]=0;
1420 /* kill trailing space */
1421 for (i=39; i && buf[i]==' '; i--)
1422 buf[i] = 0;
1423 simplelist_addline("Model: %s", buf);
1424 for (i=0; i < 10; i++)
1425 ((unsigned short*)buf)[i]=htobe16(identify_info[i+10]);
1426 buf[20]=0;
1427 /* kill trailing space */
1428 for (i=19; i && buf[i]==' '; i--)
1429 buf[i] = 0;
1430 simplelist_addline("Serial number: %s", buf);
1431 for (i=0; i < 4; i++)
1432 ((unsigned short*)buf)[i]=htobe16(identify_info[i+23]);
1433 buf[8]=0;
1434 simplelist_addline(
1435 "Firmware: %s", buf);
1436
1437 uint64_t total_sectors = (identify_info[61] << 16) | identify_info[60];
1438#ifdef HAVE_LBA48
1439 if (identify_info[83] & 0x0400 && total_sectors == 0x0FFFFFFF)
1440 total_sectors = ((uint64_t)identify_info[103] << 48) |
1441 ((uint64_t)identify_info[102] << 32) |
1442 ((uint64_t)identify_info[101] << 16) |
1443 identify_info[100];
1444#endif
1445
1446 uint32_t sector_size;
1447
1448 /* Logical sector size > 512B ? */
1449 if ((identify_info[106] & 0xd000) == 0x5000) /* B14, B12 */
1450 sector_size = (identify_info[117] | (identify_info[118] << 16)) * 2;
1451 else
1452 sector_size = 512;
1453
1454 total_sectors *= sector_size; /* Convert to bytes */
1455 total_sectors /= (1024 * 1024); /* Convert to MB */
1456
1457 simplelist_addline("Size: %lu MB", (unsigned long)total_sectors);
1458 simplelist_addline("Logical sector size: %lu B", sector_size);
1459#ifdef MAX_VIRT_SECTOR_SIZE
1460 simplelist_addline("Sector multiplier: %u", disk_get_sector_multiplier());
1461#endif
1462
1463 if((identify_info[106] & 0xe000) == 0x6000) /* B14, B13 */
1464 sector_size *= BIT_N(identify_info[106] & 0x000f);
1465 simplelist_addline(
1466 "Physical sector size: %lu B", sector_size);
1467
1468#ifndef HAVE_MULTIVOLUME
1469 // XXX this needs to be fixed for multi-volume setups
1470 sector_t free;
1471 volume_size( IF_MV(0,) NULL, &free );
1472 simplelist_addline(
1473 "Free: %lu MB", (unsigned long)(free / 1024));
1474#endif
1475
1476 simplelist_addline("SSD detected: %s", ata_disk_isssd() ? "yes" : "no");
1477 simplelist_addline(
1478 "Spinup time: %d ms", storage_spinup_time() * (1000/HZ));
1479 i = identify_info[82] & (1<<3);
1480 simplelist_addline(
1481 "Power mgmt: %s", i ? "enabled" : "unsupported");
1482 i = identify_info[83] & (1<<3);
1483 simplelist_addline(
1484 "Adv Power mgmt: %s", i ? "enabled" : "unsupported");
1485 i = identify_info[83] & (1<<9);
1486 simplelist_addline(
1487 "Noise mgmt: %s", i ? "enabled" : "unsupported");
1488 i = identify_info[85] & (1<<0);
1489 simplelist_addline(
1490 "SMART: %s", i ? "enabled" : "unsupported");
1491 simplelist_addline(
1492 "Flush cache: %s", identify_info[83] & (1<<13) ? "extended" : identify_info[83] & (1<<12) ? "standard" : identify_info[80] >= (1<<5) ? "ATA-5" : "unsupported");
1493 i = identify_info[82] & (1<<6);
1494 simplelist_addline(
1495 "Read-ahead: %s", i ? "enabled" : "unsupported");
1496 timing_info_present = identify_info[53] & (1<<1);
1497 if(timing_info_present) {
1498 simplelist_addline(
1499 "PIO modes: 0 1 2%.*s%.*s",
1500 (identify_info[64] & (1<<0)) << 1, &atanums[3*2],
1501 (identify_info[64] & (1<<1)) , &atanums[4*2]);
1502 }
1503 else {
1504 simplelist_setline(
1505 "No PIO mode info");
1506 }
1507 timing_info_present = identify_info[53] & (1<<1);
1508 if(timing_info_present) {
1509 simplelist_addline(
1510 "Cycle times %dns/%dns",
1511 identify_info[67],
1512 identify_info[68] );
1513 } else {
1514 simplelist_setline(
1515 "No timing info");
1516 }
1517
1518#ifdef HAVE_ATA_DMA
1519 if (identify_info[63] & (1<<0)) {
1520 simplelist_addline(
1521 "MDMA modes:%.*s%.*s%.*s",
1522 (identify_info[63] & (1<<0)) << 1, &atanums[0*2],
1523 (identify_info[63] & (1<<1)) , &atanums[1*2],
1524 (identify_info[63] & (1<<2)) >> 1, &atanums[2*2]);
1525 simplelist_addline(
1526 "MDMA Cycle times %dns/%dns",
1527 identify_info[65],
1528 identify_info[66] );
1529 }
1530 else {
1531 simplelist_setline(
1532 "No MDMA mode info");
1533 }
1534 if (identify_info[53] & (1<<2)) {
1535 simplelist_addline(
1536 "UDMA modes:%.*s%.*s%.*s%.*s%.*s%.*s%.*s",
1537 (identify_info[88] & (1<<0)) << 1, &atanums[0*2],
1538 (identify_info[88] & (1<<1)) , &atanums[1*2],
1539 (identify_info[88] & (1<<2)) >> 1, &atanums[2*2],
1540 (identify_info[88] & (1<<3)) >> 2, &atanums[3*2],
1541 (identify_info[88] & (1<<4)) >> 3, &atanums[4*2],
1542 (identify_info[88] & (1<<5)) >> 4, &atanums[5*2],
1543 (identify_info[88] & (1<<6)) >> 5, &atanums[6*2]);
1544 }
1545 else {
1546 simplelist_setline("No UDMA mode info");
1547 }
1548#endif /* HAVE_ATA_DMA */
1549 timing_info_present = identify_info[53] & (1<<1);
1550 if(timing_info_present) {
1551 i = identify_info[49] & (1<<11);
1552 simplelist_addline(
1553 "IORDY support: %s", i ? "yes" : "no");
1554 i = identify_info[49] & (1<<10);
1555 simplelist_addline(
1556 "IORDY disable: %s", i ? "yes" : "no");
1557 } else {
1558 simplelist_setline("No timing info");
1559 }
1560 simplelist_addline(
1561 "Cluster size: %d bytes", volume_get_cluster_size(IF_MV(0)));
1562#ifdef HAVE_ATA_DMA
1563 i = ata_get_dma_mode();
1564 if (i == 0) {
1565 simplelist_setline("DMA not enabled");
1566 } else if (i == 0xff) {
1567 simplelist_setline("CE-ATA mode");
1568 } else {
1569 simplelist_addline(
1570 "DMA mode: %s %c",
1571 (i & 0x40) ? "UDMA" : "MDMA",
1572 '0' + (i & 7));
1573 }
1574#endif /* HAVE_ATA_DMA */
1575 i = identify_info[83] & (1 << 2);
1576 simplelist_addline(
1577 "CFA compatible: %s", i ? "yes" : "no");
1578 i = identify_info[0] & (1 << 6);
1579 simplelist_addline(
1580 "Fixed device: %s", i ? "yes" : "no");
1581 i = identify_info[0] & (1 << 7);
1582 simplelist_addline(
1583 "Removeable media: %s", i ? "yes" : "no");
1584
1585 return btn;
1586}
1587
1588#ifdef HAVE_ATA_SMART
1589static struct ata_smart_values smart_data STORAGE_ALIGN_ATTR;
1590
1591static const char * ata_smart_get_attr_name(unsigned char id)
1592{
1593 if (id == 1) return "Raw Read Error Rate";
1594 if (id == 2) return "Throughput Performance";
1595 if (id == 3) return "Spin-Up Time";
1596 if (id == 4) return "Start/Stop Count";
1597 if (id == 5) return "Reallocated Sector Count";
1598 if (id == 7) return "Seek Error Rate";
1599 if (id == 8) return "Seek Time Performance";
1600 if (id == 9) return "Power-On Hours Count";
1601 if (id == 10) return "Spin-Up Retry Count";
1602 if (id == 12) return "Power Cycle Count";
1603 if (id == 191) return "G-Sense Error Rate";
1604 if (id == 192) return "Power-Off Retract Count";
1605 if (id == 193) return "Load/Unload Cycle Count";
1606 if (id == 194) return "HDA Temperature";
1607 if (id == 195) return "Hardware ECC Recovered";
1608 if (id == 196) return "Reallocated Event Count";
1609 if (id == 197) return "Current Pending Sector Count";
1610 if (id == 198) return "Uncorrectable Sector Count";
1611 if (id == 199) return "UDMA CRC Error Count";
1612 if (id == 200) return "Write Error Rate";
1613 if (id == 201) return "TA Counter Detected";
1614 if (id == 220) return "Disk Shift";
1615 if (id == 222) return "Loaded Hours";
1616 if (id == 223) return "Load/Unload Retry Count";
1617 if (id == 224) return "Load Friction";
1618 if (id == 225) return "Load Cycle Count";
1619 if (id == 226) return "Load-In Time";
1620 if (id == 240) return "Transfer Error Rate"; /* Fujitsu */
1621 return "Unknown Attribute";
1622};
1623
1624static int ata_smart_get_attr_rawfmt(unsigned char id)
1625{
1626 if (id == 3) /* Spin-up time */
1627 return RAWFMT_RAW16_OPT_AVG16;
1628
1629 if (id == 5 || /* Reallocated sector count */
1630 id == 196) /* Reallocated event count */
1631 return RAWFMT_RAW16_OPT_RAW16;
1632
1633 if (id == 190 || /* Airflow Temperature */
1634 id == 194) /* HDA Temperature */
1635 return RAWFMT_TEMPMINMAX;
1636
1637 return RAWFMT_RAW48;
1638};
1639
1640static int ata_smart_attr_to_string(
1641 struct ata_smart_attribute *attr, char *str, int size)
1642{
1643 uint16_t w[3]; /* 3 words to store 6 bytes of raw data */
1644 char buf[size]; /* temp string to store attribute data */
1645 int len, slen;
1646 int id = attr->id;
1647
1648 if (id == 0)
1649 return 0; /* null attribute */
1650
1651 /* align and convert raw data */
1652 memcpy(w, attr->raw, 6);
1653 w[0] = letoh16(w[0]);
1654 w[1] = letoh16(w[1]);
1655 w[2] = letoh16(w[2]);
1656
1657 len = snprintf(buf, size, ": %u,%u ", attr->current, attr->worst);
1658
1659 switch (ata_smart_get_attr_rawfmt(id))
1660 {
1661 case RAWFMT_RAW16_OPT_RAW16:
1662 len += snprintf(buf+len, size-len, "%u", w[0]);
1663 if ((w[1] || w[2]) && (len < size))
1664 len += snprintf(buf+len, size-len, " %u %u", w[1],w[2]);
1665 break;
1666
1667 case RAWFMT_RAW16_OPT_AVG16:
1668 len += snprintf(buf+len, size-len, "%u", w[0]);
1669 if (w[1] && (len < size))
1670 len += snprintf(buf+len, size-len, " Avg: %u", w[1]);
1671 break;
1672
1673 case RAWFMT_TEMPMINMAX:
1674 len += snprintf(buf+len, size-len, "%u -/+: %u/%u", w[0],w[1],w[2]);
1675 break;
1676
1677 case RAWFMT_RAW48:
1678 default: {
1679 uint32_t tmp;
1680 memcpy(&tmp, w, sizeof(tmp));
1681 /* shows first 4 bytes of raw data as uint32 LE,
1682 and the ramaining 2 bytes as uint16 LE */
1683 len += snprintf(buf+len, size-len, "%lu", letoh32(tmp));
1684 if (w[2] && (len < size))
1685 len += snprintf(buf+len, size-len, " %u", w[2]);
1686 break;
1687 }
1688 }
1689 /* ignore trailing \0 when truncated */
1690 if (len >= size) len = size-1;
1691
1692 /* fill return string; when max. size is exceded: first truncate
1693 attribute name, then attribute data and finally attribute id */
1694 slen = snprintf(str, size, "%d ", id);
1695 if (slen < size) {
1696 /* maximum space disponible for attribute name,
1697 including initial space separator */
1698 int name_sz = size - (slen + len);
1699 if (name_sz > 1) {
1700 len = snprintf(str+slen, name_sz, " %s",
1701 ata_smart_get_attr_name(id));
1702 if (len >= name_sz) len = name_sz-1;
1703 slen += len;
1704 }
1705
1706 strmemccpy(str+slen, buf, size-slen);
1707 }
1708
1709 return 1; /* ok */
1710}
1711
1712static bool ata_smart_dump(void)
1713{
1714 int fd;
1715
1716 fd = creat("/smart_data.bin", 0666);
1717 if(fd >= 0)
1718 {
1719 write(fd, &smart_data, sizeof(struct ata_smart_values));
1720 close(fd);
1721 }
1722
1723 fd = creat("/smart_data.txt", 0666);
1724 if(fd >= 0)
1725 {
1726 int i;
1727 char buf[128];
1728 for (i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++)
1729 {
1730 if (ata_smart_attr_to_string(
1731 &smart_data.vendor_attributes[i], buf, sizeof(buf)))
1732 {
1733 write(fd, buf, strlen(buf));
1734 write(fd, "\n", 1);
1735 }
1736 }
1737 close(fd);
1738 }
1739
1740 return false;
1741}
1742
1743static int ata_smart_callback(int btn, struct gui_synclist *lists)
1744{
1745 (void)lists;
1746 static bool read_done = false;
1747
1748 if (btn == ACTION_STD_CANCEL)
1749 {
1750 read_done = false;
1751 return btn;
1752 }
1753
1754 /* read S.M.A.R.T. data only on first redraw */
1755 if (!read_done)
1756 {
1757 int rc;
1758 memset(&smart_data, 0, sizeof(struct ata_smart_values));
1759 rc = ata_read_smart(&smart_data, ATA_SMART_READ_DATA);
1760 simplelist_reset_lines();
1761 if (rc == 0)
1762 {
1763 int i;
1764 char buf[SIMPLELIST_MAX_LINELENGTH];
1765 simplelist_setline("Id Name: Current,Worst Raw");
1766 for (i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++)
1767 {
1768 if (ata_smart_attr_to_string(
1769 &smart_data.vendor_attributes[i], buf, sizeof(buf)))
1770 {
1771 simplelist_addline(buf);
1772 }
1773 }
1774 }
1775 else
1776 {
1777 simplelist_addline("ATA SMART error: %#x", rc);
1778 }
1779 read_done = true;
1780 }
1781
1782 if (btn == ACTION_STD_CONTEXT)
1783 {
1784 splash(0, "Dumping data...");
1785 ata_smart_dump();
1786 splash(HZ, "SMART data dumped");
1787 }
1788
1789 return btn;
1790}
1791
1792static bool dbg_ata_smart(void)
1793{
1794 struct simplelist_info info;
1795 simplelist_info_init(&info, "S.M.A.R.T. Data [CONTEXT to dump]", 1, NULL);
1796 info.action_callback = ata_smart_callback;
1797 info.scroll_all = true;
1798 return simplelist_show_list(&info);
1799}
1800#endif /* HAVE_ATA_SMART */
1801#else /* No SD, MMC or ATA */
1802static int disk_callback(int btn, struct gui_synclist *lists)
1803{
1804 (void)lists;
1805 struct storage_info info;
1806 storage_get_info(0,&info);
1807 simplelist_addline("Vendor: %s", info.vendor);
1808 simplelist_addline("Model: %s", info.product);
1809 simplelist_addline("Firmware: %s", info.revision);
1810 simplelist_addline(
1811 "Size: %lu MB", (unsigned long)(info.num_sectors*(info.sector_size/512)/2048));
1812 sector_t free;
1813 volume_size( IF_MV(0,) NULL, &free );
1814 simplelist_addline(
1815 "Free: %ld MB", free / 1024);
1816 simplelist_addline(
1817 "Cluster size: %d bytes", volume_get_cluster_size(IF_MV(0)));
1818 return btn;
1819}
1820#endif
1821
1822#if (CONFIG_STORAGE & STORAGE_ATA)
1823static bool dbg_identify_info(void)
1824{
1825 int fd = creat("/identify_info.bin", 0666);
1826 if(fd >= 0)
1827 {
1828 const unsigned short *identify_info = ata_get_identify();
1829#ifdef ROCKBOX_LITTLE_ENDIAN
1830 /* this is a pointer to a driver buffer so we can't modify it */
1831 for (int i = 0; i < ATA_IDENTIFY_WORDS; ++i)
1832 {
1833 unsigned short word = swap16(identify_info[i]);
1834 write(fd, &word, 2);
1835 }
1836#else
1837 write(fd, identify_info, ATA_IDENTIFY_WORDS*2);
1838#endif
1839 close(fd);
1840 }
1841 return false;
1842}
1843#endif
1844
1845static bool dbg_disk_info(void)
1846{
1847 struct simplelist_info info;
1848 simplelist_info_init(&info, "Disk Info", 1, NULL);
1849#if (CONFIG_STORAGE & STORAGE_MMC) || (CONFIG_STORAGE & STORAGE_SD)
1850 char title[16];
1851 int card = 0;
1852 info.callback_data = (void*)&card;
1853 info.title = title;
1854#endif
1855 info.action_callback = disk_callback;
1856 info.scroll_all = true;
1857 return simplelist_show_list(&info);
1858}
1859#endif /* PLATFORM_NATIVE */
1860
1861#ifdef HAVE_DIRCACHE
1862static int dircache_callback(int btn, struct gui_synclist *lists)
1863{
1864 (void)lists;
1865 struct dircache_info info;
1866 dircache_get_info(&info);
1867
1868 if (global_settings.dircache)
1869 {
1870 switch (btn)
1871 {
1872 case ACTION_STD_CONTEXT:
1873 splash(HZ/2, "Rebuilding cache");
1874 dircache_suspend();
1875 *(int *)lists->data = dircache_resume();
1876 /* Fallthrough */
1877 case ACTION_UNKNOWN:
1878 btn = ACTION_NONE;
1879 break;
1880 #ifdef DIRCACHE_DUMPSTER
1881 case ACTION_STD_OK:
1882 splash(0, "Dumping cache");
1883 dircache_dump();
1884 btn = ACTION_NONE;
1885 break;
1886 #endif /* DIRCACHE_DUMPSTER */
1887 case ACTION_STD_CANCEL:
1888 if (*(int *)lists->data > 0 && info.status == DIRCACHE_SCANNING)
1889 {
1890 splash(HZ, ID2P(LANG_SCANNING_DISK));
1891 btn = ACTION_NONE;
1892 }
1893 break;
1894 }
1895 }
1896
1897 simplelist_reset_lines();
1898
1899 simplelist_addline("Cache status: %s", info.statusdesc);
1900 simplelist_addline("Last size: %zu B", info.last_size);
1901 simplelist_addline("Size: %zu B", info.size);
1902 unsigned int utilized = info.size ? 1000ull*info.sizeused / info.size : 0;
1903 simplelist_addline("Used: %zu B (%u.%u%%)", info.sizeused,
1904 utilized / 10, utilized % 10);
1905 simplelist_addline("Limit: %zu B", info.size_limit);
1906 simplelist_addline("Reserve: %zu/%zu B", info.reserve_used, info.reserve);
1907 long ticks = ALIGN_UP(info.build_ticks, HZ / 10);
1908 simplelist_addline("Scanning took: %ld.%ld s",
1909 ticks / HZ, (ticks*10 / HZ) % 10);
1910 simplelist_addline("Entry count: %u", info.entry_count);
1911
1912 return btn;
1913}
1914
1915static bool dbg_dircache_info(void)
1916{
1917 struct simplelist_info info;
1918 int syncbuild = 0;
1919 simplelist_info_init(&info, "Dircache Info", 0, &syncbuild);
1920 info.action_callback = dircache_callback;
1921 info.scroll_all = true;
1922 return simplelist_show_list(&info);
1923}
1924
1925#endif /* HAVE_DIRCACHE */
1926
1927#ifdef HAVE_TAGCACHE
1928static int database_callback(int btn, struct gui_synclist *lists)
1929{
1930 (void)lists;
1931 struct tagcache_stat *stat = tagcache_get_stat();
1932 static bool synced = false;
1933 static int update_entries = 0;
1934
1935 simplelist_reset_lines();
1936
1937 simplelist_addline("Initialized: %s",
1938 stat->initialized ? "Yes" : "No");
1939 simplelist_addline("DB %s: %s", "Ready",
1940 stat->ready ? "Yes" : "No");
1941 simplelist_addline("DB Path: %s", stat->db_path);
1942 simplelist_addline("RAM Cache: %s",
1943 stat->ramcache ? "Yes" : "No");
1944 simplelist_addline("RAM: %d/%d B",
1945 stat->ramcache_used, stat->ramcache_allocated);
1946 simplelist_addline("Total entries: %d",
1947 stat->total_entries);
1948 simplelist_setline("Progress:");
1949 simplelist_addline(" %d%% (%d entries)",
1950 stat->progress, stat->processed_entries);
1951 simplelist_setline("Curfile:");
1952 simplelist_addline(" %s", stat->curentry ? stat->curentry : "---");
1953 simplelist_addline("Commit step: %d",
1954 stat->commit_step);
1955 simplelist_addline("Commit delayed: %s",
1956 stat->commit_delayed ? "Yes" : "No");
1957
1958 simplelist_addline("Queue length: %d",
1959 stat->queue_length);
1960
1961 if (synced)
1962 {
1963 synced = false;
1964 tagcache_screensync_event();
1965 }
1966
1967 if (!btn && stat->curentry)
1968 {
1969 synced = true;
1970 if (update_entries <= stat->processed_entries)
1971 {
1972 update_entries = stat->processed_entries + 100;
1973 return ACTION_REDRAW;
1974 }
1975 return ACTION_NONE;
1976 }
1977
1978 if (btn == ACTION_STD_CANCEL)
1979 {
1980 update_entries = 0;
1981 tagcache_screensync_enable(false);
1982 }
1983 return btn;
1984}
1985static bool dbg_tagcache_info(void)
1986{
1987 struct simplelist_info info;
1988 simplelist_info_init(&info, "Database Info", 0, NULL);
1989 info.action_callback = database_callback;
1990 info.scroll_all = true;
1991
1992 /* Don't do nonblock here, must give enough processing time
1993 for tagcache thread. */
1994 /* info.timeout = TIMEOUT_NOBLOCK; */
1995 info.timeout = 1;
1996 tagcache_screensync_enable(true);
1997 return simplelist_show_list(&info);
1998}
1999#endif
2000
2001#if defined CPU_COLDFIRE
2002static bool dbg_save_roms(void)
2003{
2004 int fd;
2005 int oldmode = system_memory_guard(MEMGUARD_NONE);
2006
2007#if defined(IRIVER_H100_SERIES)
2008 fd = creat("/internal_rom_000000-1FFFFF.bin", 0666);
2009#elif defined(IRIVER_H300_SERIES)
2010 fd = creat("/internal_rom_000000-3FFFFF.bin", 0666);
2011#elif defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(IAUDIO_M3)
2012 fd = creat("/internal_rom_000000-3FFFFF.bin", 0666);
2013#elif defined(MPIO_HD200) || defined(MPIO_HD300)
2014 fd = creat("/internal_rom_000000-1FFFFF.bin", 0666);
2015#endif
2016 if(fd >= 0)
2017 {
2018 write(fd, (void *)0, FLASH_SIZE);
2019 close(fd);
2020 }
2021 system_memory_guard(oldmode);
2022
2023#ifdef HAVE_EEPROM
2024 fd = creat("/internal_eeprom.bin", 0666);
2025 if (fd >= 0)
2026 {
2027 int old_irq_level;
2028 char buf[EEPROM_SIZE];
2029 int err;
2030
2031 old_irq_level = disable_irq_save();
2032
2033 err = eeprom_24cxx_read(0, buf, sizeof buf);
2034
2035 restore_irq(old_irq_level);
2036
2037 if (err)
2038 splashf(HZ*3, "Eeprom read failure (%d)", err);
2039 else
2040 {
2041 write(fd, buf, sizeof buf);
2042 }
2043
2044 close(fd);
2045 }
2046#endif
2047
2048 return false;
2049}
2050#elif defined(CPU_PP) && !(CONFIG_STORAGE & STORAGE_SD)
2051static bool dbg_save_roms(void)
2052{
2053 int fd = creat("/internal_rom_000000-0FFFFF.bin", 0666);
2054 if(fd >= 0)
2055 {
2056 write(fd, (void *)0x20000000, FLASH_SIZE);
2057 close(fd);
2058 }
2059
2060 return false;
2061}
2062#elif CONFIG_CPU == AS3525v2 || CONFIG_CPU == AS3525
2063static bool dbg_save_roms(void)
2064{
2065 int fd = creat("/rom.bin", 0666);
2066 if(fd >= 0)
2067 {
2068 write(fd, (void *)0x80000000, 0x20000);
2069 close(fd);
2070 }
2071
2072 return false;
2073}
2074#elif CONFIG_CPU == IMX31L
2075bool __dbg_dvfs_dptc(void);
2076static bool dbg_save_roms(void)
2077{
2078 int fd = creat("/flash_rom_A0000000-A01FFFFF.bin", 0666);
2079 if (fd >= 0)
2080 {
2081 write(fd, (void*)0xa0000000, FLASH_SIZE);
2082 close(fd);
2083 }
2084
2085 return false;
2086}
2087#elif defined(CPU_TCC780X)
2088static bool dbg_save_roms(void)
2089{
2090 int fd = creat("/eeprom_E0000000-E0001FFF.bin", 0666);
2091 if (fd >= 0)
2092 {
2093 write(fd, (void*)0xe0000000, 0x2000);
2094 close(fd);
2095 }
2096
2097 return false;
2098}
2099#elif CONFIG_CPU == RK27XX
2100static bool dbg_save_roms(void)
2101{
2102 char buf[0x200];
2103
2104 int fd = creat("/rom.bin", 0666);
2105 if(fd < 0)
2106 return false;
2107
2108 for(int addr = 0; addr < 0x2000; addr += sizeof(buf))
2109 {
2110 int old_irq = disable_irq_save();
2111
2112 /* map rom at 0 */
2113 SCU_REMAP = 0;
2114 commit_discard_idcache();
2115
2116 /* copy rom */
2117 memcpy((void *)buf, (void *)addr, sizeof(buf));
2118
2119 /* map iram back at 0 */
2120 SCU_REMAP = 0xdeadbeef;
2121 commit_discard_idcache();
2122
2123 restore_irq(old_irq);
2124
2125 write(fd, (void *)buf, sizeof(buf));
2126 }
2127 close(fd);
2128
2129 return false;
2130}
2131#endif /* CPU */
2132
2133#ifndef SIMULATOR
2134#if CONFIG_TUNER
2135
2136#ifdef CONFIG_TUNER_MULTI
2137static int tuner_type = 0;
2138#define IF_TUNER_TYPE(type) if(tuner_type==type)
2139#else
2140#define IF_TUNER_TYPE(type)
2141#endif
2142
2143static int radio_callback(int btn, struct gui_synclist *lists)
2144{
2145 (void)lists;
2146 if (btn == ACTION_STD_CANCEL)
2147 return btn;
2148 simplelist_reset_lines();
2149 simplelist_setline("HW detected: yes");
2150
2151#if (CONFIG_TUNER & LV24020LP)
2152 simplelist_addline(
2153 "CTRL_STAT: %02X", lv24020lp_get(LV24020LP_CTRL_STAT) );
2154 simplelist_addline(
2155 "RADIO_STAT: %02X", lv24020lp_get(LV24020LP_REG_STAT) );
2156 simplelist_addline(
2157 "MSS_FM: %d kHz", lv24020lp_get(LV24020LP_MSS_FM) );
2158 simplelist_addline(
2159 "MSS_IF: %d Hz", lv24020lp_get(LV24020LP_MSS_IF) );
2160 simplelist_addline(
2161 "MSS_SD: %d Hz", lv24020lp_get(LV24020LP_MSS_SD) );
2162 simplelist_addline(
2163 "if_set: %d Hz", lv24020lp_get(LV24020LP_IF_SET) );
2164 simplelist_addline(
2165 "sd_set: %d Hz", lv24020lp_get(LV24020LP_SD_SET) );
2166#endif /* LV24020LP */
2167#if (CONFIG_TUNER & TEA5767)
2168 struct tea5767_dbg_info nfo;
2169 tea5767_dbg_info(&nfo);
2170 simplelist_setline("Philips regs:");
2171 simplelist_addline(
2172 " %s: %02X %02X %02X %02X %02X", "Read",
2173 (unsigned)nfo.read_regs[0], (unsigned)nfo.read_regs[1],
2174 (unsigned)nfo.read_regs[2], (unsigned)nfo.read_regs[3],
2175 (unsigned)nfo.read_regs[4]);
2176 simplelist_addline(
2177 " %s: %02X %02X %02X %02X %02X", "Write",
2178 (unsigned)nfo.write_regs[0], (unsigned)nfo.write_regs[1],
2179 (unsigned)nfo.write_regs[2], (unsigned)nfo.write_regs[3],
2180 (unsigned)nfo.write_regs[4]);
2181#endif /* TEA5767 */
2182#if (CONFIG_TUNER & SI4700)
2183 IF_TUNER_TYPE(SI4700)
2184 {
2185 struct si4700_dbg_info nfo;
2186 si4700_dbg_info(&nfo);
2187 simplelist_setline("SI4700 regs:");
2188 for (int i = 0; i < 16; i += 4) {
2189 simplelist_addline("%02X: %04X %04X %04X %04X",
2190 i, nfo.regs[i], nfo.regs[i+1], nfo.regs[i+2], nfo.regs[i+3]);
2191 }
2192 }
2193#endif /* SI4700 */
2194#if (CONFIG_TUNER & RDA5802)
2195 IF_TUNER_TYPE(RDA5802)
2196 {
2197 struct rda5802_dbg_info nfo;
2198 rda5802_dbg_info(&nfo);
2199 simplelist_setline("RDA5802 regs:");
2200 for (int i = 0; i < 16; i += 4) {
2201 simplelist_addline("%02X: %04X %04X %04X %04X",
2202 i, nfo.regs[i], nfo.regs[i+1], nfo.regs[i+2], nfo.regs[i+3]);
2203 }
2204 }
2205#endif /* RDA55802 */
2206#if (CONFIG_TUNER & STFM1000)
2207 IF_TUNER_TYPE(STFM1000)
2208 {
2209 struct stfm1000_dbg_info nfo;
2210 stfm1000_dbg_info(&nfo);
2211 simplelist_setline("STFM1000 regs:");
2212 simplelist_addline("chipid: 0x%lx", nfo.chipid);
2213 }
2214#endif /* STFM1000 */
2215#if (CONFIG_TUNER & TEA5760)
2216 IF_TUNER_TYPE(TEA5760)
2217 {
2218 struct tea5760_dbg_info nfo;
2219 tea5760_dbg_info(&nfo);
2220 simplelist_setline("TEA5760 regs:");
2221 for (int i = 0; i < 16; i += 4) {
2222 simplelist_addline("%02X: %02X %02X %02X %02X",
2223 i, nfo.read_regs[i], nfo.read_regs[i+1], nfo.read_regs[i+2], nfo.read_regs[i+3]);
2224 }
2225 }
2226#endif /* TEA5760 */
2227
2228#ifdef HAVE_RDS_CAP
2229 {
2230 char buf[65*4];
2231 uint16_t pi;
2232 time_t seconds;
2233
2234 tuner_get_rds_info(RADIO_RDS_NAME, buf, sizeof (buf));
2235 tuner_get_rds_info(RADIO_RDS_PROGRAM_INFO, &pi, sizeof (pi));
2236 simplelist_addline("PI:%04X PS:'%-8s'", pi, buf);
2237 tuner_get_rds_info(RADIO_RDS_TEXT, buf, sizeof (buf));
2238 simplelist_addline("RT:%s", buf);
2239 tuner_get_rds_info(RADIO_RDS_CURRENT_TIME, &seconds, sizeof (seconds));
2240
2241 struct tm* time = gmtime(&seconds);
2242 simplelist_addline(
2243 "CT:%4d-%02d-%02d %02d:%02d:%02d",
2244 time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
2245 time->tm_hour, time->tm_min, time->tm_sec);
2246 }
2247#endif /* HAVE_RDS_CAP */
2248 return ACTION_REDRAW;
2249}
2250static bool dbg_fm_radio(void)
2251{
2252 struct simplelist_info info;
2253#ifdef CONFIG_TUNER_MULTI
2254 tuner_type = tuner_detect_type();
2255#endif
2256 info.scroll_all = true;
2257 simplelist_info_init(&info, "FM Radio", 0, NULL);
2258 simplelist_reset_lines();
2259 simplelist_setline("HW detected: no");
2260
2261 info.action_callback = radio_hardware_present()?radio_callback : NULL;
2262 return simplelist_show_list(&info);
2263}
2264#endif /* CONFIG_TUNER */
2265#endif /* !SIMULATOR */
2266
2267#if !defined(APPLICATION)
2268extern bool do_screendump_instead_of_usb;
2269
2270static bool dbg_screendump(void)
2271{
2272 do_screendump_instead_of_usb = !do_screendump_instead_of_usb;
2273 splashf(HZ, "Screendump %sabled", do_screendump_instead_of_usb?"en":"dis");
2274 return false;
2275}
2276#endif /* !APPLICATION */
2277
2278extern bool write_metadata_log;
2279
2280static bool dbg_metadatalog(void)
2281{
2282 write_metadata_log = !write_metadata_log;
2283 splashf(HZ, "Metadata log %sabled", write_metadata_log ? "en" : "dis");
2284 return false;
2285}
2286
2287#if defined(CPU_COLDFIRE)
2288static bool dbg_set_memory_guard(void)
2289{
2290 static const struct opt_items names[MAXMEMGUARD] = {
2291 { "None", -1 },
2292 { "Flash ROM writes", -1 },
2293 { "Zero area (all)", -1 }
2294 };
2295 int mode = system_memory_guard(MEMGUARD_KEEP);
2296
2297 set_option( "Catch mem accesses", &mode, RB_INT, names, MAXMEMGUARD, NULL);
2298 system_memory_guard(mode);
2299
2300 return false;
2301}
2302#endif /* defined(CPU_COLDFIRE) */
2303
2304#if defined(HAVE_EEPROM) && !defined(HAVE_EEPROM_SETTINGS)
2305static bool dbg_write_eeprom(void)
2306{
2307 int fd = open("/internal_eeprom.bin", O_RDONLY);
2308
2309 if (fd >= 0)
2310 {
2311 char buf[EEPROM_SIZE];
2312 int rc = read(fd, buf, EEPROM_SIZE);
2313
2314 if(rc == EEPROM_SIZE)
2315 {
2316 int old_irq_level = disable_irq_save();
2317
2318 int err = eeprom_24cxx_write(0, buf, sizeof buf);
2319 if (err)
2320 splashf(HZ*3, "Eeprom write failure (%d)", err);
2321 else
2322 splash(HZ*3, "Eeprom written successfully");
2323
2324 restore_irq(old_irq_level);
2325 }
2326 else
2327 {
2328 splashf(HZ*3, "File read error (%d)",rc);
2329 }
2330 close(fd);
2331 }
2332 else
2333 {
2334 splash(HZ*3, "Failed to open 'internal_eeprom.bin'");
2335 }
2336
2337 return false;
2338}
2339#endif /* defined(HAVE_EEPROM) && !defined(HAVE_EEPROM_SETTINGS) */
2340#ifdef CPU_BOOST_LOGGING
2341static bool cpu_boost_log(void)
2342{
2343 int count = cpu_boost_log_getcount();
2344 char *str = cpu_boost_log_getlog_first();
2345 bool done;
2346 lcd_setfont(FONT_SYSFIXED);
2347 for (int i = 0; i < count ;)
2348 {
2349 lcd_clear_display();
2350 for(int j=0; j<LCD_HEIGHT/SYSFONT_HEIGHT; j++,i++)
2351 {
2352 if (!str)
2353 str = cpu_boost_log_getlog_next();
2354 if (str)
2355 {
2356 if(strlen(str) > LCD_WIDTH/SYSFONT_WIDTH)
2357 lcd_puts_scroll(0, j, str);
2358 else
2359 lcd_puts(0, j,str);
2360 }
2361 str = NULL;
2362 }
2363 lcd_update();
2364 done = false;
2365 while (!done)
2366 {
2367 switch(get_action(CONTEXT_STD,TIMEOUT_BLOCK))
2368 {
2369 case ACTION_STD_OK:
2370 case ACTION_STD_PREV:
2371 case ACTION_STD_NEXT:
2372 done = true;
2373 break;
2374 case ACTION_STD_CANCEL:
2375 i = count;
2376 done = true;
2377 break;
2378 }
2379 }
2380 }
2381 lcd_scroll_stop();
2382 get_action(CONTEXT_STD,TIMEOUT_BLOCK);
2383 lcd_setfont(FONT_UI);
2384 return false;
2385}
2386
2387static bool cpu_boost_log_dump(void)
2388{
2389 int fd;
2390 int count = cpu_boost_log_getcount();
2391 char *str = cpu_boost_log_getlog_first();
2392
2393 splashf(HZ, "Boost Log File Dumped");
2394
2395 /* nothing to print ? */
2396 if(count == 0)
2397 return false;
2398
2399#if CONFIG_RTC
2400 char fname[MAX_PATH];
2401 struct tm *nowtm = get_time();
2402 fd = open_pathfmt(fname, sizeof(fname), O_CREAT|O_WRONLY|O_TRUNC,
2403 "%s/boostlog_%04d%02d%02d%02d%02d%02d.txt", ROCKBOX_DIR,
2404 nowtm->tm_year + 1900, nowtm->tm_mon + 1, nowtm->tm_mday,
2405 nowtm->tm_hour, nowtm->tm_min, nowtm->tm_sec);
2406#else
2407 fd = open(ROCKBOX_DIR "/boostlog.txt", O_CREAT|O_WRONLY|O_TRUNC, 0666);
2408#endif
2409 if(-1 != fd) {
2410 for (int i = 0; i < count; i++)
2411 {
2412 if (!str)
2413 str = cpu_boost_log_getlog_next();
2414 if (str)
2415 {
2416 fdprintf(fd, "%s\n", str);
2417 str = NULL;
2418 }
2419 }
2420
2421 close(fd);
2422 return true;
2423 }
2424
2425 return false;
2426}
2427#endif
2428
2429#if (defined(HAVE_WHEEL_ACCELERATION) && (CONFIG_KEYPAD==IPOD_4G_PAD) \
2430 && !defined(IPOD_MINI) && !defined(SIMULATOR))
2431extern bool wheel_is_touched;
2432extern int old_wheel_value;
2433extern int new_wheel_value;
2434extern int wheel_delta;
2435extern unsigned int accumulated_wheel_delta;
2436extern unsigned int wheel_velocity;
2437
2438static bool dbg_scrollwheel(void)
2439{
2440 lcd_setfont(FONT_SYSFIXED);
2441
2442 while (1)
2443 {
2444 if (action_userabort(HZ/10))
2445 break;
2446
2447 lcd_clear_display();
2448
2449 /* show internal variables of scrollwheel driver */
2450 lcd_putsf(0, 0, "wheel touched: %s", (wheel_is_touched) ? "true" : "false");
2451 lcd_putsf(0, 1, "new position: %2d", new_wheel_value);
2452 lcd_putsf(0, 2, "old position: %2d", old_wheel_value);
2453 lcd_putsf(0, 3, "wheel delta: %2d", wheel_delta);
2454 lcd_putsf(0, 4, "accumulated delta: %2d", accumulated_wheel_delta);
2455 lcd_putsf(0, 5, "velo [deg/s]: %4d", (int)wheel_velocity);
2456
2457 /* show effective accelerated scrollspeed */
2458 lcd_putsf(0, 6, "accel. speed: %4d",
2459 button_apply_acceleration((1<<31)|(1<<24)|wheel_velocity) );
2460
2461 lcd_update();
2462 }
2463 lcd_setfont(FONT_UI);
2464 return false;
2465}
2466#endif
2467
2468static bool dbg_talk(void)
2469{
2470 struct simplelist_info list;
2471 struct talk_debug_data data;
2472 talk_get_debug_data(&data);
2473
2474 simplelist_info_init(&list, "Voice Information:", 0, NULL);
2475
2476 list.scroll_all = true;
2477 list.timeout = HZ;
2478
2479 simplelist_reset_lines();
2480
2481 simplelist_setline("Current voice file:");
2482 if (data.status != TALK_STATUS_ERR_NOFILE)
2483 simplelist_addline(" %s", data.voicefile);
2484 else
2485 simplelist_setline(" No voice information available");
2486
2487 if (data.status != TALK_STATUS_OK)
2488 {
2489 simplelist_addline("Talk Status: ERR (%i)",
2490 data.status);
2491 return simplelist_show_list(&list);
2492 }
2493 else
2494 simplelist_setline("Talk Status: OK");
2495 simplelist_setline("Number of (empty) clips in voice file:");
2496 simplelist_addline(" (%d) %d", data.num_empty_clips, data.num_clips);
2497 simplelist_setline("Min/Avg/Max size of clips:");
2498 simplelist_addline(" %d / %d / %d",
2499 data.min_clipsize, data.avg_clipsize, data.max_clipsize);
2500 simplelist_setline("Memory allocated:");
2501 simplelist_addline(" %ld.%02ld KB",
2502 data.memory_allocated / 1024, data.memory_allocated % 1024);
2503 simplelist_addline("Memory used:");
2504 simplelist_addline(" %ld.%02ld KB",
2505 data.memory_used / 1024, data.memory_used % 1024);
2506 simplelist_setline("Number of clips in cache:");
2507 simplelist_addline(" %d", data.cached_clips);
2508 simplelist_setline("Cache hits / misses:");
2509 simplelist_addline("%d / %d", data.cache_hits, data.cache_misses);
2510
2511 return simplelist_show_list(&list);
2512}
2513
2514#ifdef HAVE_USBSTACK
2515#if (defined(ROCKBOX_HAS_LOGF) && defined(USB_ENABLE_SERIAL))
2516static bool toggle_usb_core_driver(int driver, char *msg)
2517{
2518 bool enabled = !usb_core_driver_enabled(driver);
2519
2520 usb_core_enable_driver(driver,enabled);
2521 splashf(HZ, "%s %s", msg, enabled ? "enabled" : "disabled");
2522
2523 return false;
2524}
2525
2526#ifdef USB_ENABLE_SERIAL
2527static bool toggle_usb_serial(void)
2528{
2529 return toggle_usb_core_driver(USB_DRIVER_SERIAL, "USB Serial");
2530}
2531#endif /* USB_ENABLE_SERIAL */
2532#endif
2533
2534#ifdef USB_ENABLE_AUDIO
2535static int dbg_usb_audio_cb(int action, struct gui_synclist *lists)
2536{
2537 (void)lists;
2538 simplelist_reset_lines();
2539 simplelist_addline("%sabled", usb_core_driver_enabled(USB_DRIVER_AUDIO)?"En":"Dis");
2540 simplelist_addline("%sPlaying", usb_audio_get_playing()?"":"Not ");
2541 simplelist_addline("iface: %d alt: %d", usb_audio_get_main_intf(), usb_audio_get_alt_intf());
2542 simplelist_addline("out ep: 0x%X in ep: 0x%X", usb_audio_get_out_ep(), usb_audio_get_in_ep());
2543 simplelist_addline("Volume: %d", usb_audio_get_cur_volume());
2544 simplelist_addline("Playback Frequency: %lu", usb_audio_get_playback_sampling_frequency());
2545 simplelist_addline("Frames dropped: %d", usb_audio_get_frames_dropped());
2546 simplelist_addline("Buffers filled: %f", (double)usb_audio_get_prebuffering_avg()/(1<<16)); // convert from 16.16 fixed to float
2547 simplelist_addline("Min: %d / Max: %d", usb_audio_get_prebuffering_maxmin(false), usb_audio_get_prebuffering_maxmin(true));
2548 simplelist_addline("Samples used per Frame: %f", (double)usb_audio_get_samplesperframe()/(1<<16)); // convert from 16.16 fixed to float
2549 simplelist_addline("Samples received per frame: %f", (double)usb_audio_get_samples_rx_perframe()/(1<<16)); // convert from 16.16 fixed to float
2550 simplelist_addline("Samples diff: %f", (double)(usb_audio_get_samplesperframe()-usb_audio_get_samples_rx_perframe())/(1<<16)); // convert from 16.16 fixed to float
2551 simplelist_addline("%s", usb_audio_get_underflow()?"UNDERFLOW!":" ");
2552 simplelist_addline("%s", usb_audio_get_overflow()?"OVERFLOW!":" ");
2553 simplelist_addline("%s", usb_audio_get_alloc_failed()?"ALLOC FAILED!":" ");
2554 if (action == ACTION_NONE)
2555 {
2556 action = ACTION_REDRAW;
2557 }
2558 return action;
2559}
2560static bool dbg_usb_audio(void)
2561{
2562 struct simplelist_info info;
2563 simplelist_info_init(&info, "USB Audio", 0, NULL);
2564 info.scroll_all = true;
2565 info.action_callback = dbg_usb_audio_cb;
2566 return simplelist_show_list(&info);
2567}
2568#endif /* USB_ENABLE_AUDIO */
2569#endif /* HAVE_USBSTACK */
2570
2571#if CONFIG_USBOTG == USBOTG_ISP1583
2572extern int dbg_usb_num_items(void);
2573extern const char* dbg_usb_item(int selected_item, void *data,
2574 char *buffer, size_t buffer_len);
2575
2576static int isp1583_action_callback(int action, struct gui_synclist *lists)
2577{
2578 (void)lists;
2579 if (action == ACTION_NONE)
2580 action = ACTION_REDRAW;
2581 return action;
2582}
2583
2584static bool dbg_isp1583(void)
2585{
2586 struct simplelist_info isp1583;
2587 isp1583.scroll_all = true;
2588 simplelist_info_init(&isp1583, "ISP1583", dbg_usb_num_items(), NULL);
2589 isp1583.timeout = HZ/100;
2590 isp1583.get_name = dbg_usb_item;
2591 isp1583.action_callback = isp1583_action_callback;
2592 return simplelist_show_list(&isp1583);
2593}
2594#endif
2595
2596#if defined(CREATIVE_ZVx) && !defined(SIMULATOR)
2597extern int pic_dbg_num_items(void);
2598extern const char* pic_dbg_item(int selected_item, void *data,
2599 char *buffer, size_t buffer_len);
2600
2601static int pic_action_callback(int action, struct gui_synclist *lists)
2602{
2603 (void)lists;
2604 if (action == ACTION_NONE)
2605 action = ACTION_REDRAW;
2606 return action;
2607}
2608
2609static bool dbg_pic(void)
2610{
2611 struct simplelist_info pic;
2612 pic.scroll_all = true;
2613 simplelist_info_init(&pic, "PIC", pic_dbg_num_items(), NULL);
2614 pic.timeout = HZ/100;
2615 pic.get_name = pic_dbg_item;
2616 pic.action_callback = pic_action_callback;
2617 return simplelist_show_list(&pic);
2618}
2619#endif
2620
2621#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR)
2622static bool dbg_boot_data(void)
2623{
2624 struct simplelist_info info;
2625 info.scroll_all = true;
2626 simplelist_info_init(&info, "Boot data", 0, NULL);
2627 simplelist_reset_lines();
2628
2629 if (!boot_data_valid)
2630 {
2631 simplelist_setline("Boot data invalid");
2632 simplelist_addline("Magic[0]: %08lx", boot_data.magic[0]);
2633 simplelist_addline("Magic[1]: %08lx", boot_data.magic[1]);
2634 simplelist_addline("Length: %lu", boot_data.length);
2635 }
2636 else
2637 {
2638 simplelist_setline("Boot data valid");
2639 simplelist_addline("Version: %d", (int)boot_data.version);
2640
2641 if (boot_data.version == 0)
2642 {
2643 simplelist_addline("Boot volume: %d", (int)boot_data._boot_volume);
2644 }
2645 else if (boot_data.version == 1)
2646 {
2647 simplelist_addline("Boot drive: %d", (int)boot_data.boot_drive);
2648 simplelist_addline("Boot partition: %d", (int)boot_data.boot_partition);
2649 }
2650 simplelist_setline("Boot path:");
2651 simplelist_addline(" %s%s/%s", root_realpath(), BOOTDIR, BOOTFILE);
2652 }
2653
2654 simplelist_setline("Bootdata RAW:");
2655 for (size_t i = 0; i < boot_data.length; i += 4)
2656 {
2657 simplelist_addline("%02x: %02x %02x %02x %02x", i,
2658 boot_data.payload[i + 0], boot_data.payload[i + 1],
2659 boot_data.payload[i + 2], boot_data.payload[i + 3]);
2660 }
2661
2662 return simplelist_show_list(&info);
2663}
2664#endif /* defined(HAVE_BOOTDATA) && !defined(SIMULATOR) */
2665
2666#if defined(HAVE_DEVICEDATA)// && !defined(SIMULATOR)
2667static bool dbg_device_data(void)
2668{
2669 struct simplelist_info info;
2670 info.scroll_all = true;
2671 simplelist_info_init(&info, "Device data", 0, NULL);
2672 simplelist_reset_lines();
2673
2674 simplelist_setline("Device data");
2675
2676#if defined(EROS_QN)
2677 simplelist_addline("Hardware Revision: %d", (int)device_data.hw_rev);
2678#endif
2679 simplelist_addline("Struct Ver: %d", (int)device_data.version);
2680
2681 simplelist_setline("Device data RAW:");
2682 for (size_t i = 0; i < device_data.length; i += 4)
2683 {
2684 simplelist_addline("%02zx: %02x %02x %02x %02x", i,
2685 device_data.payload[i + 0], device_data.payload[i + 1],
2686 device_data.payload[i + 2], device_data.payload[i + 3]);
2687 }
2688
2689 return simplelist_show_list(&info);
2690}
2691#endif /* defined(HAVE_DEVICEDATA)*/
2692
2693
2694#if defined(IPOD_6G) && !defined(SIMULATOR)
2695static bool dbg_syscfg(void) {
2696 struct simplelist_info info;
2697 struct SysCfg syscfg;
2698
2699 simplelist_info_init(&info, "SysCfg NOR contents", 0, NULL);
2700 simplelist_reset_lines();
2701
2702 const ssize_t result = syscfg_read(&syscfg);
2703
2704 if (result == -1) {
2705 simplelist_setline("SCfg magic not found");
2706 return simplelist_show_list(&info);
2707 }
2708
2709 simplelist_addline("Total size: %lu bytes, %lu entries", syscfg.header.size, syscfg.header.num_entries);
2710
2711 if (result > 0) {
2712 simplelist_addline("Wrong size: expected %ld, got %lu", result, syscfg.header.size);
2713 return simplelist_show_list(&info);
2714 }
2715
2716 if (syscfg.header.num_entries > SYSCFG_MAX_ENTRIES) {
2717 simplelist_addline("Too many entries, showing only first %u", SYSCFG_MAX_ENTRIES);
2718 }
2719
2720 const size_t syscfg_num_entries = MIN(syscfg.header.num_entries, SYSCFG_MAX_ENTRIES);
2721
2722 for (size_t i = 0; i < syscfg_num_entries; i++) {
2723 const struct SysCfgEntry* entry = &syscfg.entries[i];
2724 const char* tag = (char *)&entry->tag;
2725 const uint32_t* data32 = (uint32_t *)entry->data;
2726
2727 switch (entry->tag) {
2728 case SYSCFG_TAG_SRNM:
2729 simplelist_addline("Serial number (SrNm): %s", entry->data);
2730 break;
2731 case SYSCFG_TAG_FWID:
2732 simplelist_addline("Firmware ID (FwId): %07lX", data32[1] & 0x0FFFFFFF);
2733 break;
2734 case SYSCFG_TAG_HWID:
2735 simplelist_addline("Hardware ID (HwId): %08lX", data32[0]);
2736 break;
2737 case SYSCFG_TAG_HWVR:
2738 simplelist_addline("Hardware version (HwVr): %06lX", data32[1]);
2739 break;
2740 case SYSCFG_TAG_CODC:
2741 simplelist_addline("Codec (Codc): %s", entry->data);
2742 break;
2743 case SYSCFG_TAG_SWVR:
2744 simplelist_addline("Software version (SwVr): %s", entry->data);
2745 break;
2746 case SYSCFG_TAG_MLBN:
2747 simplelist_addline("Logic board serial number (MLBN): %s", entry->data);
2748 break;
2749 case SYSCFG_TAG_MODN:
2750 simplelist_addline("Model number (Mod#): %s", entry->data);
2751 break;
2752 case SYSCFG_TAG_REGN:
2753 simplelist_addline("Sales region (Regn): %08lX %08lX", data32[0], data32[1]);
2754 break;
2755 default:
2756 simplelist_addline("%c%c%c%c: %08lX %08lX %08lX %08lX",
2757 tag[3], tag[2], tag[1], tag[0],
2758 data32[0], data32[1], data32[2], data32[3]
2759 );
2760 break;
2761 }
2762 }
2763
2764 return simplelist_show_list(&info);
2765}
2766
2767#define FLASH_PAGES (FLASH_SIZE >> 12)
2768#define FLASH_PAGE_SIZE (FLASH_SIZE >> 8)
2769
2770static bool dbg_bootflash_dump(void) {
2771 splashf(HZ, "Please wait...");
2772
2773 int fd;
2774
2775 fd = creat("/bootflash.bin", 0666);
2776
2777 if (fd < 0)
2778 {
2779 splashf(HZ * 3, "Error opening file");
2780 return false;
2781 }
2782
2783 uint8_t page[FLASH_PAGE_SIZE];
2784 bootflash_init(SPI_PORT);
2785
2786 for (int i = 0; i < FLASH_PAGES; i++) {
2787 bootflash_read(SPI_PORT, i << 12, FLASH_PAGE_SIZE, page);
2788 write(fd, page, FLASH_PAGE_SIZE);
2789 }
2790
2791 bootflash_close(SPI_PORT);
2792 close(fd);
2793 splashf(HZ * 3, "Dump saved to /bootflash.bin");
2794
2795 return false;
2796}
2797#endif
2798
2799/****** The menu *********/
2800static const struct {
2801 unsigned char *desc; /* string or ID */
2802 bool (*function) (void); /* return true if USB was connected */
2803} menuitems[] = {
2804#if defined(CPU_COLDFIRE) || \
2805 (defined(CPU_PP) && !(CONFIG_STORAGE & STORAGE_SD)) || \
2806 CONFIG_CPU == IMX31L || defined(CPU_TCC780X) || CONFIG_CPU == AS3525v2 || \
2807 CONFIG_CPU == AS3525 || CONFIG_CPU == RK27XX
2808 { "Dump ROM contents", dbg_save_roms },
2809#endif
2810#if defined(CPU_COLDFIRE) || defined(CPU_PP) \
2811 || CONFIG_CPU == S3C2440 || CONFIG_CPU == IMX31L || CONFIG_CPU == AS3525 \
2812 || CONFIG_CPU == DM320 || defined(CPU_S5L87XX) || CONFIG_CPU == AS3525v2 \
2813 || CONFIG_CPU == RK27XX || CONFIG_CPU == JZ4760B
2814 { "View I/O ports", dbg_ports },
2815#endif
2816#if (CONFIG_RTC == RTC_PCF50605) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
2817 { "View PCF registers", dbg_pcf },
2818#endif
2819#if defined(HAVE_TSC2100) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
2820 { "TSC2100 debug", tsc2100_debug },
2821#endif
2822#ifdef HAVE_ADJUSTABLE_CPU_FREQ
2823 { "CPU frequency", dbg_cpufreq },
2824#endif
2825#if CONFIG_CPU == IMX31L
2826 { "DVFS/DPTC", __dbg_dvfs_dptc },
2827#endif
2828#if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR)
2829 { "S/PDIF analyzer", dbg_spdif },
2830#endif
2831#if defined(CPU_COLDFIRE)
2832 { "Catch mem accesses", dbg_set_memory_guard },
2833#endif
2834 { "View OS stacks", dbg_os },
2835#ifdef __linux__
2836 { "View CPU stats", dbg_cpuinfo },
2837#endif
2838#if (CONFIG_BATTERY_MEASURE != 0) && !defined(SIMULATOR)
2839 { "View battery", view_battery },
2840#endif
2841#ifndef APPLICATION
2842 { "Screendump", dbg_screendump },
2843#endif
2844 { "Skin Engine RAM usage", dbg_skin_engine },
2845#if ((CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SONY_NWZ_LINUX) || defined(HIBY_LINUX) || defined(FIIO_M3K_LINUX)) && !defined(SIMULATOR)
2846 { "View HW info", dbg_hw_info },
2847#endif
2848#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
2849 { "View partitions", dbg_partitions },
2850#endif
2851#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
2852 { "View disk info", dbg_disk_info },
2853#if (CONFIG_STORAGE & STORAGE_ATA)
2854 { "Dump ATA identify info", dbg_identify_info},
2855#ifdef HAVE_ATA_SMART
2856 { "View/Dump S.M.A.R.T. data", dbg_ata_smart},
2857#endif
2858#endif
2859#endif
2860 { "Metadata log", dbg_metadatalog },
2861#ifdef HAVE_DIRCACHE
2862 { "View dircache info", dbg_dircache_info },
2863#endif
2864#ifdef HAVE_TAGCACHE
2865 { "View database info", dbg_tagcache_info },
2866#endif
2867 { "View buffering thread", dbg_buffering_thread },
2868#ifdef PM_DEBUG
2869 { "pm histogram", peak_meter_histogram},
2870#endif /* PM_DEBUG */
2871#ifdef BUFLIB_DEBUG_PRINT
2872 { "View buflib allocs", dbg_buflib_allocs },
2873#endif
2874#ifndef SIMULATOR
2875#if CONFIG_TUNER
2876 { "FM Radio", dbg_fm_radio },
2877#endif
2878#endif
2879#if defined(HAVE_EEPROM) && !defined(HAVE_EEPROM_SETTINGS)
2880 { "Write back EEPROM", dbg_write_eeprom },
2881#endif
2882#if CONFIG_USBOTG == USBOTG_ISP1583
2883 { "View ISP1583 info", dbg_isp1583 },
2884#endif
2885#if defined(CREATIVE_ZVx) && !defined(SIMULATOR)
2886 { "View PIC info", dbg_pic },
2887#endif
2888#ifdef ROCKBOX_HAS_LOGF
2889 {"Show Log File", logfdisplay },
2890 {"Dump Log File", logfdump },
2891#endif
2892#if defined(HAVE_USBSTACK)
2893#if defined(ROCKBOX_HAS_LOGF) && defined(USB_ENABLE_SERIAL)
2894 {"USB Serial driver (logf)", toggle_usb_serial },
2895#endif
2896#if defined(USB_ENABLE_AUDIO)
2897 {"USB-DAC", dbg_usb_audio},
2898#endif
2899#endif /* HAVE_USBSTACK */
2900#ifdef CPU_BOOST_LOGGING
2901 {"Show cpu_boost log",cpu_boost_log},
2902 {"Dump cpu_boost log",cpu_boost_log_dump},
2903#endif
2904#if (defined(HAVE_WHEEL_ACCELERATION) && (CONFIG_KEYPAD==IPOD_4G_PAD) \
2905 && !defined(IPOD_MINI) && !defined(SIMULATOR))
2906 {"Debug scrollwheel", dbg_scrollwheel },
2907#endif
2908#if defined(IPOD_ACCESSORY_PROTOCOL)
2909 {"Debug IAP", dbg_iap },
2910#endif
2911 {"Talk engine stats", dbg_talk },
2912#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR)
2913 {"Boot data", dbg_boot_data },
2914#endif
2915
2916#if defined(HAVE_DEVICEDATA)// && !defined(SIMULATOR)
2917 {"Device data", dbg_device_data },
2918#endif
2919
2920#if defined(IPOD_6G) && !defined(SIMULATOR)
2921 {"View SysCfg", dbg_syscfg },
2922 {"Dump bootflash to file", dbg_bootflash_dump },
2923#endif
2924};
2925
2926static int menu_action_callback(int btn, struct gui_synclist *lists)
2927{
2928 int selection = gui_synclist_get_sel_pos(lists);
2929 if (btn == ACTION_STD_OK)
2930 {
2931 FOR_NB_SCREENS(i)
2932 viewportmanager_theme_enable(i, false, NULL);
2933 menuitems[selection].function();
2934 btn = ACTION_REDRAW;
2935 FOR_NB_SCREENS(i)
2936 viewportmanager_theme_undo(i, false);
2937 }
2938 else if (btn == ACTION_STD_CONTEXT)
2939 {
2940 MENUITEM_STRINGLIST(menu_items, "Debug Menu", NULL, ID2P(LANG_ADD_TO_FAVES));
2941 if (do_menu(&menu_items, NULL, NULL, false) == 0)
2942 shortcuts_add(SHORTCUT_DEBUGITEM, menuitems[selection].desc);
2943 return ACTION_STD_CANCEL;
2944 }
2945 return btn;
2946}
2947
2948static const char* menu_get_name(int item, void * data,
2949 char *buffer, size_t buffer_len)
2950{
2951 (void)data; (void)buffer; (void)buffer_len;
2952 return menuitems[item].desc;
2953}
2954
2955static int menu_get_talk(int item, void *data)
2956{
2957 (void)data;
2958 if (global_settings.talk_menu && menuitems[item].desc)
2959 {
2960 talk_number(item + 1, true);
2961 talk_id(VOICE_PAUSE, true);
2962#if 0 /* no debug items currently have lang ids */
2963 long id = P2ID((const unsigned char *)(menuitems[item].desc));
2964 if(id>=0)
2965 talk_id(id, true);
2966 else
2967#endif
2968 talk_spell(menuitems[item].desc, true);
2969 }
2970 return 0;
2971}
2972
2973int debug_menu(void)
2974{
2975 struct simplelist_info info;
2976
2977 simplelist_info_init(&info, "Debug Menu", ARRAYLEN(menuitems), NULL);
2978 info.action_callback = menu_action_callback;
2979 info.get_name = menu_get_name;
2980 info.get_talk = menu_get_talk;
2981 return (simplelist_show_list(&info)) ? 1 : 0;
2982}
2983
2984bool run_debug_screen(char* screen)
2985{
2986 for (unsigned i=0; i<ARRAYLEN(menuitems); i++)
2987 if (!strcasecmp(screen, menuitems[i].desc))
2988 {
2989 FOR_NB_SCREENS(j)
2990 viewportmanager_theme_enable(j, false, NULL);
2991 menuitems[i].function();
2992 FOR_NB_SCREENS(j)
2993 viewportmanager_theme_undo(j, false);
2994 return true;
2995 }
2996
2997 return false;
2998}