mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-05-12 11:43:16 -04:00
Compare commits
65 commits
1c3e9c181e
...
1f30d9efe3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f30d9efe3 | ||
|
|
2a4cb29b27 | ||
|
|
62200ff4d7 | ||
|
|
83420e0a95 | ||
|
|
30ff611529 | ||
|
|
b349eea2c9 | ||
|
|
eb69211791 | ||
|
|
fce8248267 | ||
|
|
a5b589cf5b | ||
|
|
41f9285def | ||
|
|
7b77752aff | ||
|
|
d15bb5f848 | ||
|
|
77f30202d0 | ||
|
|
2b09078b92 | ||
|
|
e1d10c938a | ||
|
|
33678c6c3c | ||
|
|
b562c9d58f | ||
|
|
89cf5b57e6 | ||
|
|
33d0a3efa3 | ||
|
|
1951c17e0b | ||
|
|
d5506dfa22 | ||
|
|
603c5bb2be | ||
|
|
7868e45edb | ||
|
|
843322f898 | ||
|
|
a610998ea4 | ||
|
|
21ba79d431 | ||
|
|
f642d19c20 | ||
|
|
ecb8014a06 | ||
|
|
98990df08f | ||
|
|
174b33cc07 | ||
|
|
bd73e0dd42 | ||
|
|
e3bf9210ab | ||
|
|
0f5c42122c | ||
|
|
58ace97a4e | ||
|
|
db8494d4e0 | ||
|
|
b056191e89 | ||
|
|
721bfac475 | ||
|
|
1afa2ca50d | ||
|
|
025d641d1f | ||
|
|
86c975ee88 | ||
|
|
319fdcc506 | ||
|
|
6035b1fc1b | ||
|
|
4e4d5ac25b | ||
|
|
65b97917ca | ||
|
|
eea0c128f4 | ||
|
|
386be9dfcc | ||
|
|
9471cec2ab | ||
|
|
62332841cf | ||
|
|
b76cb3bf62 | ||
|
|
7f0bc4bd95 | ||
|
|
5af0a50031 | ||
|
|
2b6029ae8d | ||
|
|
b3683c84d8 | ||
|
|
a0bd28a408 | ||
|
|
1194a968bd | ||
|
|
163c3723bc | ||
|
|
d7a2aa7208 | ||
|
|
72dd8bc4d0 | ||
|
|
80fec463df | ||
|
|
a74ee4c04f | ||
|
|
5442622d88 | ||
|
|
0474dca7c3 | ||
|
|
17faa6abc7 | ||
|
|
c80723b539 | ||
|
|
3c6b9bb458 |
107 changed files with 2585 additions and 999 deletions
|
|
@ -101,7 +101,7 @@ static void NORETURN_ATTR audio_thread(void)
|
|||
case SYS_USB_CONNECTED:
|
||||
LOGFQUEUE("audio < SYS_USB_CONNECTED");
|
||||
voice_stop();
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
usb_wait_for_disconnect(&audio_queue);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ static void usb_screens_draw(struct usb_screen_vps_t *usb_screen_vps_ar)
|
|||
}
|
||||
}
|
||||
|
||||
void gui_usb_screen_run(bool early_usb)
|
||||
void gui_usb_screen_run(bool early_usb, intptr_t seqnum)
|
||||
{
|
||||
#ifdef SIMULATOR /* the sim allows toggling USB fast enough to overflow viewportmanagers stack */
|
||||
static bool in_usb_screen = false;
|
||||
|
|
@ -297,7 +297,7 @@ void gui_usb_screen_run(bool early_usb)
|
|||
font_disable_all();
|
||||
}
|
||||
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, seqnum);
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,10 +21,12 @@
|
|||
#ifndef _USB_SCREEN_H_
|
||||
#define _USB_SCREEN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef USB_NONE
|
||||
#define gui_usb_screen_run(early_usb) do {} while(0)
|
||||
#define gui_usb_screen_run(early_usb, seqnum) do {(void)seqnum;} while(0)
|
||||
#else
|
||||
extern void gui_usb_screen_run(bool early_usb);
|
||||
extern void gui_usb_screen_run(bool early_usb, intptr_t seqnum);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ static void iap_thread(void)
|
|||
/* Ack USB thread */
|
||||
case SYS_USB_CONNECTED:
|
||||
{
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2025 Aidan MacDonald
|
||||
* Copyright (C) 2026 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
|
@ -29,14 +29,166 @@
|
|||
/* {Action Code, Button code, Prereq button code } */
|
||||
|
||||
static const struct button_mapping button_context_standard[] = {
|
||||
{ACTION_STD_PREV, BUTTON_UP, BUTTON_NONE},
|
||||
{ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE},
|
||||
{ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_OK, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_STD_CONTEXT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_QUICKSCREEN, BUTTON_B, BUTTON_NONE},
|
||||
{ACTION_STD_MENU, BUTTON_Y, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_standard */
|
||||
|
||||
static const struct button_mapping button_context_wps[] = {
|
||||
{ACTION_WPS_PLAY, BUTTON_DOWN|BUTTON_REL, BUTTON_DOWN},
|
||||
{ACTION_WPS_STOP, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_WPS_VIEW_PLAYLIST, BUTTON_UP|BUTTON_REL, BUTTON_UP},
|
||||
{ACTION_WPS_CONTEXT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_WPS_VOLUP, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_WPS_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_WPS_SKIPNEXT, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT},
|
||||
{ACTION_WPS_SKIPPREV, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT},
|
||||
{ACTION_WPS_SEEKFWD, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_WPS_STOPSEEK, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT|BUTTON_REPEAT},
|
||||
{ACTION_WPS_SEEKBACK, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_WPS_STOPSEEK, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT|BUTTON_REPEAT},
|
||||
{ACTION_WPS_QUICKSCREEN, BUTTON_B, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_wps */
|
||||
|
||||
static const struct button_mapping button_context_tree[] = {
|
||||
{ACTION_TREE_WPS, BUTTON_X, BUTTON_NONE},
|
||||
{ACTION_TREE_HOTKEY, BUTTON_Y, BUTTON_NONE},
|
||||
{ACTION_TREE_STOP, BUTTON_START|BUTTON_REPEAT, BUTTON_START},
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST)
|
||||
}; /* button_context_tree */
|
||||
|
||||
static const struct button_mapping button_context_list[] = {
|
||||
{ACTION_LISTTREE_PGUP, BUTTON_UP|BUTTON_SELECT, BUTTON_NONE},
|
||||
{ACTION_LISTTREE_PGUP, BUTTON_UP|BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_LISTTREE_PGDOWN, BUTTON_DOWN|BUTTON_SELECT, BUTTON_NONE},
|
||||
{ACTION_LISTTREE_PGDOWN, BUTTON_DOWN|BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_LIST_VOLUP, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_LIST_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_LIST_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_LIST_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
||||
}; /* button_context_list */
|
||||
|
||||
static const struct button_mapping button_context_settings[] = {
|
||||
{ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_INCREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_INCBIGSTEP, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DECREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DECBIGSTEP, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_OK, BUTTON_A, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_X, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
||||
}; /* button_context_settings */
|
||||
|
||||
static const struct button_mapping button_context_settings_eq[] = {
|
||||
{ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_INCBIGSTEP, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DECBIGSTEP, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_STD_OK, BUTTON_A, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_X, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
||||
}; /* button_context_settings_eq */
|
||||
|
||||
static const struct button_mapping button_context_quickscreen[] = {
|
||||
{ACTION_QS_TOP, BUTTON_UP, BUTTON_NONE},
|
||||
{ACTION_QS_TOP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_QS_DOWN, BUTTON_DOWN, BUTTON_NONE},
|
||||
{ACTION_QS_DOWN, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_QS_LEFT, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_QS_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_QS_RIGHT, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_QS_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_QS_VOLUP, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_QS_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_QS_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_QS_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_CONTEXT, BUTTON_B|BUTTON_REPEAT, BUTTON_B},
|
||||
{ACTION_STD_CANCEL, BUTTON_B|BUTTON_REL, BUTTON_B},
|
||||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_quickscreen */
|
||||
|
||||
static const struct button_mapping button_context_yesnoscreen[] = {
|
||||
{ACTION_YESNO_ACCEPT, BUTTON_A, BUTTON_NONE},
|
||||
{ACTION_YESNO_ACCEPT, BUTTON_X, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_B, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_Y, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_START, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_SELECT, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
||||
}; /* button_context_yesnoscreen */
|
||||
|
||||
static const struct button_mapping button_context_keyboard[] = {
|
||||
{ACTION_KBD_UP, BUTTON_UP, BUTTON_NONE},
|
||||
{ACTION_KBD_UP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_DOWN, BUTTON_DOWN, BUTTON_NONE},
|
||||
{ACTION_KBD_DOWN, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_RIGHT, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_KBD_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_SELECT, BUTTON_SELECT, BUTTON_NONE},
|
||||
{ACTION_KBD_BACKSPACE, BUTTON_X, BUTTON_NONE},
|
||||
{ACTION_KBD_BACKSPACE, BUTTON_X|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_DONE, BUTTON_A, BUTTON_NONE},
|
||||
{ACTION_KBD_ABORT, BUTTON_POWER, BUTTON_NONE},
|
||||
{ACTION_KBD_PAGE_FLIP, BUTTON_START, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_LEFT, BUTTON_Y, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_LEFT, BUTTON_Y|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_RIGHT, BUTTON_B, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_RIGHT, BUTTON_B|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_LEFT, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_LEFT, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_RIGHT, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_RIGHT, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_keyboard */
|
||||
|
||||
const struct button_mapping* get_context_mapping(int context)
|
||||
{
|
||||
switch (context)
|
||||
{
|
||||
default:
|
||||
case CONTEXT_STD:
|
||||
return button_context_standard;
|
||||
case CONTEXT_WPS:
|
||||
return button_context_wps;
|
||||
case CONTEXT_TREE:
|
||||
case CONTEXT_MAINMENU:
|
||||
return button_context_tree;
|
||||
case CONTEXT_LIST:
|
||||
return button_context_list;
|
||||
case CONTEXT_SETTINGS:
|
||||
case CONTEXT_SETTINGS_TIME:
|
||||
return button_context_settings;
|
||||
case CONTEXT_SETTINGS_EQ:
|
||||
case CONTEXT_SETTINGS_COLOURCHOOSER:
|
||||
return button_context_settings_eq;
|
||||
case CONTEXT_QUICKSCREEN:
|
||||
return button_context_quickscreen;
|
||||
case CONTEXT_YESNOSCREEN:
|
||||
return button_context_yesnoscreen;
|
||||
case CONTEXT_KEYBOARD:
|
||||
return button_context_keyboard;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16964,3 +16964,17 @@
|
|||
general_purpose_led: "LED Indikatoren verwenden"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_ANNOUNCE_STATUS
|
||||
desc: announnnce_status plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Announce Status"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Status mitteilen"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Status mitteilen"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
|
|
|||
|
|
@ -16942,3 +16942,17 @@
|
|||
general_purpose_led: "Use LED indicators"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_ANNOUNCE_STATUS
|
||||
desc: announnnce_status plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Announce Status"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Announce Status"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Announce Status"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
|
|
|||
|
|
@ -15077,6 +15077,20 @@
|
|||
hotkey: "Announcement format"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_ANNOUNCE_STATUS
|
||||
desc: announnnce_status plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Announce Status"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Announce Status"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Announce Status"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_REMAIN
|
||||
desc: for constructs such as number of tracks remaining etc
|
||||
|
|
|
|||
|
|
@ -16946,3 +16946,17 @@
|
|||
general_purpose_led: "Usa indicatori led"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_ANNOUNCE_STATUS
|
||||
desc: announnnce_status plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Announce Status"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Annuncia Lo Stato"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Annuncia Lo Stato"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
|
|
|||
|
|
@ -16960,3 +16960,17 @@
|
|||
general_purpose_led: "LED 표시기 사용"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_ANNOUNCE_STATUS
|
||||
desc: announnnce_status plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Announce Status"
|
||||
</source>
|
||||
<dest>
|
||||
*: "상태 발표"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "상태 발표"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
|
|
|||
|
|
@ -16952,3 +16952,17 @@
|
|||
general_purpose_led: "Użyj wskaźników led"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_ANNOUNCE_STATUS
|
||||
desc: announnnce_status plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Announce Status"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Informuj o stanie"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Informuj o stanie"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
|
|
|||
|
|
@ -16946,3 +16946,17 @@
|
|||
general_purpose_led: "Používať LED indikátory"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_ANNOUNCE_STATUS
|
||||
desc: announnnce_status plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Announce Status"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Oznámiť status"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Oznámiť status"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
|
|
|||
|
|
@ -12615,20 +12615,6 @@
|
|||
*: "Просечни битски проток"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_PLAYTIME_ERROR
|
||||
desc: playing time screen
|
||||
user: core
|
||||
<source>
|
||||
*: "Error while gathering info"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Грешка током прикупљања инфо"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Грешка током прикупљања инфо"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_PLAYING_TIME
|
||||
desc: onplay menu
|
||||
|
|
@ -15940,20 +15926,6 @@
|
|||
*: "Подраз. прегледач"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_AMAZE_MENU
|
||||
desc: Amaze game
|
||||
user: core
|
||||
<source>
|
||||
*: "Amaze Main Menu"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Amaze главни мени"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Амејз главни мени"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_SET_MAZE_SIZE
|
||||
desc: Maze size in Amaze game
|
||||
|
|
@ -16206,34 +16178,6 @@
|
|||
*: "Мик мод подешавања"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_MIKMOD_MENU
|
||||
desc: mikmod plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Mikmod Menu"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Mikmod мени"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Мик мод мени"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_CHESSBOX_MENU
|
||||
desc: chessbox plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Chessbox Menu"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Chessbox мени"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Чес бокс мени"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: VOICE_INVALID_VOICE_FILE
|
||||
desc: played if the voice file fails to load
|
||||
|
|
@ -16983,3 +16927,34 @@
|
|||
usbdac: "У Ес Бе - ДАК активан"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_ANNOUNCE_STATUS
|
||||
desc: announnnce_status plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Announce Status"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Објави статус"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Објави статус"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_USE_LED_INDICATORS
|
||||
desc: LED indicators setting
|
||||
user: core
|
||||
<source>
|
||||
*: none
|
||||
general_purpose_led: "Use LED indicators"
|
||||
</source>
|
||||
<dest>
|
||||
*: none
|
||||
general_purpose_led: "Користи LED индикаторе"
|
||||
</dest>
|
||||
<voice>
|
||||
*: none
|
||||
general_purpose_led: "Користи LED индикаторе"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
|
|
|||
|
|
@ -16944,3 +16944,17 @@
|
|||
general_purpose_led: "Dùng đèn hiệu LED"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_ANNOUNCE_STATUS
|
||||
desc: announnnce_status plugin
|
||||
user: core
|
||||
<source>
|
||||
*: "Announce Status"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Thông báo Trạng thái"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Thông báo trạng thái"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ static void init(void)
|
|||
(mmc_remove_request() == SYS_HOTSWAP_EXTRACTED))
|
||||
#endif
|
||||
{
|
||||
gui_usb_screen_run(true);
|
||||
gui_usb_screen_run(true, button_get_data());
|
||||
mounted = true; /* mounting done @ end of USB mode */
|
||||
}
|
||||
#ifdef HAVE_USB_POWER
|
||||
|
|
@ -675,7 +675,7 @@ static void init(void)
|
|||
#ifndef USB_NONE
|
||||
usb_start_monitoring();
|
||||
while(button_get(true) != SYS_USB_CONNECTED) {};
|
||||
gui_usb_screen_run(true);
|
||||
gui_usb_screen_run(true, button_get_data());
|
||||
#elif !defined(DEBUG) && !(CONFIG_STORAGE & STORAGE_RAMDISK)
|
||||
sleep(HZ*5);
|
||||
#endif
|
||||
|
|
|
|||
15
apps/misc.c
15
apps/misc.c
|
|
@ -656,24 +656,25 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
|
|||
}
|
||||
break;
|
||||
case SYS_USB_CONNECTED:
|
||||
{
|
||||
intptr_t seqnum = button_get_data();
|
||||
if (callback != NULL)
|
||||
callback(parameter);
|
||||
{
|
||||
system_flush();
|
||||
system_flush();
|
||||
#ifdef BOOTFILE
|
||||
#if !defined(USB_NONE) && !defined(USB_HANDLED_BY_OF)
|
||||
check_bootfile(false); /* gets initial size */
|
||||
check_bootfile(false); /* gets initial size */
|
||||
#endif
|
||||
#endif
|
||||
gui_usb_screen_run(false);
|
||||
gui_usb_screen_run(false, seqnum);
|
||||
#ifdef BOOTFILE
|
||||
#if !defined(USB_NONE) && !defined(USB_HANDLED_BY_OF)
|
||||
check_bootfile(true);
|
||||
check_bootfile(true);
|
||||
#endif
|
||||
#endif
|
||||
system_restore();
|
||||
}
|
||||
system_restore();
|
||||
return SYS_USB_CONNECTED;
|
||||
}
|
||||
|
||||
case SYS_POWEROFF:
|
||||
case SYS_REBOOT:
|
||||
|
|
|
|||
|
|
@ -1882,7 +1882,7 @@ static void dc_thread_playlist(void)
|
|||
}
|
||||
|
||||
case SYS_USB_CONNECTED:
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
usb_wait_for_disconnect(&playlist_queue);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -948,7 +948,7 @@ struct plugin_api {
|
|||
|
||||
/* usb */
|
||||
bool (*usb_inserted)(void);
|
||||
void (*usb_acknowledge)(long id);
|
||||
void (*usb_acknowledge)(long id, intptr_t seqnum);
|
||||
#ifdef USB_ENABLE_HID
|
||||
void (*usb_hid_send)(usage_page_t usage_page, int id);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ static const char keybd_layout[] =
|
|||
* - \n does not create a key, but it also consumes one element
|
||||
* - the final null terminator is equivalent to \n
|
||||
* - since sizeof includes the null terminator we don't need +1 for that. */
|
||||
static ucschar_t kbd_buf[sizeof(keybd_layout)];
|
||||
static ucschar_t kbd_buf[sizeof(keybd_layout) + 1];
|
||||
|
||||
/****************** prototypes ******************/
|
||||
void print_scroll(char* string); /* implements a scrolling screen */
|
||||
|
|
@ -84,7 +84,7 @@ void thread_create(void);
|
|||
void thread(void); /* the thread running it all */
|
||||
void thread_quit(void);
|
||||
static int voice_general_info(bool testing);
|
||||
static unsigned char* voice_info_group(unsigned char* current_token, bool testing);
|
||||
static const char* voice_info_group(const char* current_token, bool testing);
|
||||
|
||||
int plugin_main(const void* parameter); /* main loop */
|
||||
enum plugin_status plugin_start(const void* parameter); /* entry */
|
||||
|
|
@ -115,8 +115,9 @@ static struct
|
|||
int bin_added;
|
||||
|
||||
bool show_prompt;
|
||||
bool force_enqueue;
|
||||
|
||||
unsigned char wps_fmt[MAX_ANNOUNCE_WPS+1];
|
||||
char wps_fmt[MAX_ANNOUNCE_WPS+1];
|
||||
} gAnnounce;
|
||||
|
||||
static struct configdata config[] =
|
||||
|
|
@ -126,6 +127,7 @@ static struct configdata config[] =
|
|||
{TYPE_INT, 0, 10, { .int_p = &gAnnounce.grouping }, "Grouping", NULL},
|
||||
{TYPE_INT, 0, 10000, { .int_p = &gAnnounce.bin_added }, "Added", NULL},
|
||||
{TYPE_BOOL, 0, 1, { .bool_p = &gAnnounce.show_prompt }, "Prompt", NULL},
|
||||
{TYPE_BOOL, 0, 1, { .bool_p = &gAnnounce.force_enqueue }, "Enqueue", NULL},
|
||||
{TYPE_STRING, 0, MAX_ANNOUNCE_WPS+1,
|
||||
{ .string = (char*)&gAnnounce.wps_fmt }, "Fmt", NULL},
|
||||
};
|
||||
|
|
@ -165,6 +167,7 @@ static void config_set_defaults(void)
|
|||
gAnnounce.grouping = 0;
|
||||
gAnnounce.wps_fmt[0] = '\0';
|
||||
gAnnounce.show_prompt = true;
|
||||
gAnnounce.force_enqueue = true;
|
||||
}
|
||||
|
||||
static void config_reset_voice(void)
|
||||
|
|
@ -173,10 +176,10 @@ static void config_reset_voice(void)
|
|||
int interval = gAnnounce.interval;
|
||||
int announce = gAnnounce.announce_on;
|
||||
int grouping = gAnnounce.grouping;
|
||||
|
||||
if (configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER) < 0)
|
||||
int status = configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER);
|
||||
if (status < 0)
|
||||
{
|
||||
rb->splash(100, "ERROR!");
|
||||
rb->splashf(100, ID2P(LANG_FILE_ERROR), status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +197,8 @@ void announce(void)
|
|||
voice_general_info(false);
|
||||
if (rb->talk_id(VOICE_PAUSE, true) < 0)
|
||||
rb->beep_play(800, 100, 1000);
|
||||
//rb->talk_force_enqueue_next();
|
||||
if (gAnnounce.force_enqueue)
|
||||
rb->talk_force_enqueue_next();
|
||||
}
|
||||
|
||||
static void announce_test(void)
|
||||
|
|
@ -202,8 +206,8 @@ static void announce_test(void)
|
|||
rb->talk_force_shutup();
|
||||
rb->sleep(HZ / 2);
|
||||
voice_info_group(gAnnounce.wps_fmt, true);
|
||||
rb->splash(HZ, "...");
|
||||
//rb->talk_force_enqueue_next();
|
||||
if (gAnnounce.force_enqueue)
|
||||
rb->talk_force_enqueue_next();
|
||||
}
|
||||
|
||||
static void announce_add(const char *str)
|
||||
|
|
@ -329,7 +333,7 @@ static int announce_menu(void)
|
|||
{
|
||||
int selection = 0;
|
||||
|
||||
MENUITEM_STRINGLIST(announce_menu, "Announcements", announce_menu_cb,
|
||||
MENUITEM_STRINGLIST(announce_menu, ID2P(LANG_ANNOUNCEMENT_FMT), announce_menu_cb,
|
||||
ID2P(LANG_TIME),
|
||||
ID2P(LANG_DATE),
|
||||
ID2P(LANG_TRACK),
|
||||
|
|
@ -359,11 +363,12 @@ static int settings_menu(void)
|
|||
int selection = 0;
|
||||
//bool old_val;
|
||||
|
||||
MENUITEM_STRINGLIST(settings_menu, "Announce Settings", NULL,
|
||||
MENUITEM_STRINGLIST(settings_menu, ID2P(LANG_ANNOUNCE_STATUS), NULL,
|
||||
ID2P(LANG_TIMEOUT),
|
||||
ID2P(LANG_ANNOUNCE_ON),
|
||||
ID2P(LANG_GROUPING),
|
||||
ID2P(LANG_ANNOUNCEMENT_FMT),
|
||||
ID2P(LANG_QUEUE_FIRST),
|
||||
ID2P(VOICE_BLANK),
|
||||
ID2P(LANG_MENU_QUIT),
|
||||
ID2P(LANG_SAVE_EXIT));
|
||||
|
|
@ -392,12 +397,15 @@ static int settings_menu(void)
|
|||
case 3:
|
||||
announce_menu();
|
||||
break;
|
||||
case 4: /*sep*/
|
||||
case 4:
|
||||
rb->set_bool(rb->str(LANG_QUEUE_FIRST), &gAnnounce.force_enqueue);
|
||||
break;
|
||||
case 5: /*sep*/
|
||||
continue;
|
||||
case 5: /* quit the plugin */
|
||||
case 6: /* quit the plugin */
|
||||
return -1;
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER);
|
||||
return 0;
|
||||
break;
|
||||
|
|
@ -427,7 +435,7 @@ void thread(void)
|
|||
switch (ev.id)
|
||||
{
|
||||
case SYS_USB_CONNECTED:
|
||||
rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
rb->usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
in_usb = true;
|
||||
break;
|
||||
case SYS_USB_DISCONNECTED:
|
||||
|
|
@ -538,13 +546,15 @@ int plugin_main(const void* parameter)
|
|||
}
|
||||
else
|
||||
{
|
||||
rb->splash(HZ / 2, "Announce Status");
|
||||
rb->splashf(HZ / 2, "%s", rb->str(LANG_ANNOUNCE_STATUS)); /* no talking */
|
||||
if (gAnnounce.show_prompt)
|
||||
{
|
||||
#if 0 /* splash should announce for us */
|
||||
if (rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_PLAYING)
|
||||
{
|
||||
rb->talk_id(LANG_HOLD_FOR_SETTINGS, false);
|
||||
}
|
||||
#endif
|
||||
rb->splash(HZ, ID2P(LANG_HOLD_FOR_SETTINGS));
|
||||
}
|
||||
|
||||
|
|
@ -580,6 +590,19 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
return PLUGIN_USB_CONNECTED;
|
||||
|
||||
config_set_defaults();
|
||||
|
||||
if (parameter && parameter != rb->plugin_tsr)
|
||||
{
|
||||
const char *param = (const char*) parameter;
|
||||
if (param[0] != '\0')
|
||||
{
|
||||
voice_info_group(param, false);
|
||||
rb->talk_force_enqueue_next();
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER) < 0)
|
||||
{
|
||||
/* If the loading failed, save a new config file */
|
||||
|
|
@ -594,7 +617,7 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
|
||||
static int voice_general_info(bool testing)
|
||||
{
|
||||
unsigned char* infotemplate = gAnnounce.wps_fmt;
|
||||
const char* infotemplate = gAnnounce.wps_fmt;
|
||||
|
||||
if (gAnnounce.index >= rb->strlen(gAnnounce.wps_fmt))
|
||||
gAnnounce.index = 0;
|
||||
|
|
@ -629,9 +652,9 @@ static int voice_general_info(bool testing)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char* voice_info_group(unsigned char* current_token, bool testing)
|
||||
static const char* voice_info_group(const char* current_token, bool testing)
|
||||
{
|
||||
unsigned char current_char;
|
||||
char current_char;
|
||||
bool skip_next_group = false;
|
||||
gAnnounce.count = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -491,7 +491,7 @@ static void thread(void)
|
|||
{
|
||||
case SYS_USB_CONNECTED:
|
||||
in_usb_mode = true;
|
||||
rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
rb->usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
break;
|
||||
case SYS_USB_DISCONNECTED:
|
||||
in_usb_mode = false;
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ extern int TELL(void)
|
|||
|
||||
extern void *OPEN(char *f)
|
||||
{
|
||||
memset(buff, 0, sizeof(buff));
|
||||
printf("Opening %s\n", f);
|
||||
cur_buff_pos = length = file_pos = 0;
|
||||
fd = rb->open(f,O_RDONLY);
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ static int fd;
|
|||
|
||||
extern int GETC(void)
|
||||
{
|
||||
unsigned char x;
|
||||
rb->read(fd, &x, 1);
|
||||
unsigned char x = 0;
|
||||
rb->read(fd, &x, 1)
|
||||
return x;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,12 +36,11 @@
|
|||
*/
|
||||
int kbd_create_layout(const char *layout, ucschar_t *buf, int bufsz)
|
||||
{
|
||||
ucschar_t *pbuf;
|
||||
ucschar_t *pbuf = buf;
|
||||
const unsigned char *p = layout;
|
||||
int len = 0;
|
||||
int total_len = 0;
|
||||
pbuf = buf;
|
||||
while (*p && (pbuf - buf + (ptrdiff_t) sizeof(ucschar_t)) < bufsz)
|
||||
while (*p && (pbuf - buf + (ptrdiff_t) sizeof(*buf)) < bufsz)
|
||||
{
|
||||
p = rb->utf8decode(p, &pbuf[len+1]);
|
||||
if (pbuf[len+1] == '\n')
|
||||
|
|
@ -55,13 +54,14 @@ int kbd_create_layout(const char *layout, ucschar_t *buf, int bufsz)
|
|||
len++;
|
||||
}
|
||||
|
||||
if (len+1 < bufsz)
|
||||
if ((total_len + len + 1) * (int)sizeof(*buf) < bufsz)
|
||||
{
|
||||
*pbuf = len;
|
||||
pbuf[len+1] = 0xFEFF; /* mark end of characters */
|
||||
total_len += len + 1;
|
||||
return total_len * sizeof(ucschar_t);
|
||||
return total_len * sizeof(*buf);
|
||||
}
|
||||
|
||||
//rb->logf("%s %d %d\n", __func__, bufsz, (total_len + len + 1) * sizeof(*buf));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#ifdef PLUGIN
|
||||
#include "plugin.h"
|
||||
#include "lib/pluginlib_actions.h"
|
||||
#define lcd_getstringsize rb->lcd_getstringsize
|
||||
#define font_getstringsize rb->font_getstringsize
|
||||
#define lcd_clear_display rb->lcd_clear_display
|
||||
#define lcd_putsxy rb->lcd_putsxy
|
||||
#define lcd_update rb->lcd_update
|
||||
|
|
@ -66,7 +66,13 @@ int splash_scroller(int timeout, const char* str)
|
|||
if (!str)
|
||||
str = "[nil]";
|
||||
int w, ch_w, ch_h;
|
||||
lcd_getstringsize("W", &ch_w, &ch_h);
|
||||
|
||||
struct viewport vp;
|
||||
rb->viewport_set_defaults(&vp, SCREEN_MAIN);
|
||||
struct viewport *last_vp = rb->lcd_set_viewport(&vp);
|
||||
int fontnum = vp.font;
|
||||
|
||||
font_getstringsize("W", &ch_w, &ch_h, fontnum);
|
||||
|
||||
const int max_w = LCD_WIDTH - (ch_w * 2);
|
||||
const int max_lines = LCD_HEIGHT / ch_h - 1;
|
||||
|
|
@ -103,13 +109,13 @@ int splash_scroller(int timeout, const char* str)
|
|||
line[linepos] = ' ';
|
||||
beep_play(1000, HZ, 1000);
|
||||
}
|
||||
else if (ch[0] < ' ') /* Dont copy control characters */
|
||||
else if (ch[0] < ' ' && ch[0] > '\0') /* Dont copy control characters */
|
||||
line[linepos] = (linepos == 0) ? '\0' : ' ';
|
||||
else
|
||||
line[linepos] = ch[0];
|
||||
|
||||
line[linepos + 1] = '\0'; /* terminate to check text extent */
|
||||
lcd_getstringsize(line, &w, NULL);
|
||||
font_getstringsize(line, &w, NULL, fontnum);
|
||||
|
||||
/* try to not split in middle of words */
|
||||
if (w + wrap_thresh >= max_w &&
|
||||
|
|
@ -174,6 +180,8 @@ int splash_scroller(int timeout, const char* str)
|
|||
else
|
||||
break;
|
||||
}
|
||||
rb->lcd_set_viewport(last_vp);
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -672,6 +672,51 @@ function rotate_image(img)
|
|||
rb.sleep(rb.HZ * 10)]]
|
||||
end -- rotate_image
|
||||
|
||||
function flip_image(img)
|
||||
local blitop = _blit.BOR
|
||||
local d = 0
|
||||
local x, y, w, h
|
||||
|
||||
w = img:width()
|
||||
h = img:height()
|
||||
x = (_lcd.W - w) / 2
|
||||
y = (_lcd.H - h) / 2
|
||||
--make a copy of original screen for restoration
|
||||
local screen_img -- = _lcd:duplicate()
|
||||
screen_img =_img.new(w, h)
|
||||
screen_img :copy(_LCD, 1, 1, x, y, w, h)
|
||||
|
||||
--[[--Profiling code
|
||||
local timer = _timer.start()]]
|
||||
|
||||
while d >= 0 do
|
||||
-- copy our flipped image onto the background
|
||||
if d == 0 then
|
||||
_lcd:copy(img, x, y, 1, 1, w, h, false, blitop)
|
||||
elseif d == 1 then
|
||||
_lcd:copy(img, x, y, 1, 1, -w, h, false, blitop)
|
||||
elseif d == 2 then
|
||||
_lcd:copy(img, x, y, 1, 1, w, -h, false, blitop)
|
||||
elseif d == 3 then
|
||||
_lcd:copy(img, x, y, 1, 1, -w, -h, false, blitop)
|
||||
d = -1
|
||||
end
|
||||
_lcd:update()
|
||||
--restore the portion of the background we destroyed
|
||||
_lcd:copy(screen_img, x, y, 1, 1)
|
||||
|
||||
d = d + i
|
||||
|
||||
if rb.get_plugin_action(rb.HZ) == CANCEL_BUTTON then
|
||||
break;
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Profiling code
|
||||
_print.f("%d", _timer.stop(timer))
|
||||
rb.sleep(rb.HZ * 10)]]
|
||||
end -- flip_image
|
||||
|
||||
-- shows blitting with a mask
|
||||
function blit_mask(dst)
|
||||
local timer = _timer()
|
||||
|
|
@ -826,12 +871,13 @@ function main_menu()
|
|||
[6] = "Bouncing Ball (olive)",
|
||||
[7] = "The Twist",
|
||||
[8] = "Image Rotation",
|
||||
[9] = "Long Text",
|
||||
[10] = "Rainbow Image",
|
||||
[11] = "Random Image",
|
||||
[12] = "Clear Screen",
|
||||
[13] = "Save Screen",
|
||||
[14] = "Exit"
|
||||
[9] = "Image Flip",
|
||||
[10] = "Long Text",
|
||||
[11] = "Rainbow Image",
|
||||
[12] = "Random Image",
|
||||
[13] = "Clear Screen",
|
||||
[14] = "Save Screen",
|
||||
[15] = "Exit"
|
||||
}
|
||||
local ft = {
|
||||
[0] = exit_now, --if user cancels do this function
|
||||
|
|
@ -846,16 +892,17 @@ function main_menu()
|
|||
[6] = function(BOUNC) bounce_image(create_ball()) end,
|
||||
[7] = function(TWIST) twist(get_logo()) end,
|
||||
[8] = function(ROTAT) rotate_image(get_logo()) end,
|
||||
[9] = long_text,
|
||||
[10] = function(RAINB)
|
||||
[9] = function(FLIP) flip_image(get_logo()) end,
|
||||
[10] = long_text,
|
||||
[11] = function(RAINB)
|
||||
rainbow_img(_lcd()); _lcd:update(); rb.sleep(rb.HZ)
|
||||
end,
|
||||
[11] = function(RANDM)
|
||||
[12] = function(RANDM)
|
||||
random_img(_lcd()); _lcd:update(); rb.sleep(rb.HZ)
|
||||
end,
|
||||
[12] = function(CLEAR) _lcd:clear(BLACK); rock_lua() end,
|
||||
[13] = function(SAVEI) _LCD:invert(); _img_save(_LCD, "/rocklua.bmp") end,
|
||||
[14] = function(EXIT_) return true end
|
||||
[13] = function(CLEAR) _lcd:clear(BLACK); rock_lua() end,
|
||||
[14] = function(SAVEI) _LCD:invert(); _img_save(_LCD, "/rocklua.bmp") end,
|
||||
[15] = function(EXIT_) return true end
|
||||
}
|
||||
|
||||
if LCD_DEPTH < 2 then
|
||||
|
|
|
|||
|
|
@ -979,7 +979,7 @@ static void thread(void)
|
|||
switch (ev.id)
|
||||
{
|
||||
case SYS_USB_CONNECTED:
|
||||
rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
rb->usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
logenabled = false;
|
||||
break;
|
||||
case SYS_USB_DISCONNECTED:
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ static void main_loop(void)
|
|||
state = "connected";
|
||||
logf("test_usb: connect ack %ld", *rb->current_tick);
|
||||
DEBUGF("test_usb: connect ack %ld\n", *rb->current_tick);
|
||||
rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
rb->usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
break;
|
||||
|
||||
case SYS_USB_DISCONNECTED:
|
||||
|
|
|
|||
|
|
@ -5357,7 +5357,7 @@ static void tagcache_thread(void)
|
|||
|
||||
case SYS_USB_CONNECTED:
|
||||
logf("USB: TagCache");
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
usb_wait_for_disconnect(&tagcache_queue);
|
||||
break ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,5 +96,4 @@ x1000/recovery.c
|
|||
x1000/utils.c
|
||||
#elif defined(ECHO_R1)
|
||||
echoplayer.c
|
||||
show_logo.c
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -39,3 +39,4 @@ int load_raw_firmware(unsigned char* buf, char* firmware, int buffer_size);
|
|||
#ifdef ROCKBOX_HAS_LOGF
|
||||
void display_logf(void);
|
||||
#endif
|
||||
void show_logo(void);
|
||||
|
|
|
|||
|
|
@ -47,13 +47,13 @@ void main(void)
|
|||
int buffer_size;
|
||||
int(*kernel_entry)(void);
|
||||
int ret;
|
||||
|
||||
|
||||
/* Make sure interrupts are disabled */
|
||||
set_irq_level(IRQ_DISABLED);
|
||||
set_fiq_status(FIQ_DISABLED);
|
||||
system_init();
|
||||
kernel_init();
|
||||
|
||||
|
||||
/* Now enable interrupts */
|
||||
set_irq_level(IRQ_ENABLED);
|
||||
set_fiq_status(FIQ_ENABLED);
|
||||
|
|
@ -70,18 +70,18 @@ void main(void)
|
|||
reset_screen();
|
||||
printf("Rockbox boot loader");
|
||||
printf("Version %s", rbversion);
|
||||
|
||||
|
||||
ret = storage_init();
|
||||
if(ret)
|
||||
printf("ATA error: %d", ret);
|
||||
|
||||
filesystem_init();
|
||||
|
||||
|
||||
/* If no button is held, start the OF */
|
||||
if(button_read_device() == 0)
|
||||
{
|
||||
printf("Loading Creative firmware...");
|
||||
|
||||
|
||||
loadbuffer = (unsigned char*)0x00A00000;
|
||||
ret = load_minifs_file("creativeos.jrm", loadbuffer);
|
||||
if(ret != -1)
|
||||
|
|
@ -99,7 +99,7 @@ void main(void)
|
|||
ret = disk_mount_all();
|
||||
if (ret <= 0)
|
||||
error(EDISK, ret, true);
|
||||
|
||||
|
||||
printf("Loading Rockbox firmware...");
|
||||
|
||||
loadbuffer = (unsigned char*)0x00900000;
|
||||
|
|
@ -113,8 +113,8 @@ void main(void)
|
|||
ret = kernel_entry();
|
||||
printf("FAILED!");
|
||||
}
|
||||
|
||||
|
||||
storage_sleepnow();
|
||||
|
||||
|
||||
while(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,155 +21,457 @@
|
|||
#include "kernel/kernel-internal.h"
|
||||
#include "system.h"
|
||||
#include "power.h"
|
||||
#include "rtc.h"
|
||||
#include "lcd.h"
|
||||
#include "backlight.h"
|
||||
#include "button.h"
|
||||
#include "timefuncs.h"
|
||||
#include "storage.h"
|
||||
#include "disk.h"
|
||||
#include "file.h"
|
||||
#include "file_internal.h"
|
||||
#include "usb.h"
|
||||
#include "elf.h"
|
||||
#include "elf_loader.h"
|
||||
#include "rbversion.h"
|
||||
#include "system-echoplayer.h"
|
||||
#include "gpio-stm32h7.h"
|
||||
|
||||
static bool is_usb_connected = false;
|
||||
#define SDRAM_SIZE (MEMORYSIZE * 1024 * 1024)
|
||||
|
||||
extern void show_logo(void);
|
||||
/* Address where Rockbox .elf binary will be cached in RAM */
|
||||
#define LOAD_SIZE (2 * 1024 * 1024)
|
||||
#define LOAD_BUFFER_ADDR (STM32_SDRAM1_BASE + SDRAM_SIZE - LOAD_SIZE)
|
||||
|
||||
static void demo_rtc(void)
|
||||
/* Values at GDB_MAGICx */
|
||||
#define GDB_MAGICVAL1 0x726f636b
|
||||
#define GDB_MAGICVAL2 0x424f4f54
|
||||
#define GDB_MAGICVAL3 0x6764626c
|
||||
#define GDB_MAGICVAL4 0x6f616455
|
||||
|
||||
/* Addresses used by GDB boot protocol */
|
||||
#define GDB_MAGIC1 (*(volatile uint32_t*)(STM32_SRAM4_BASE + 0x00))
|
||||
#define GDB_MAGIC2 (*(volatile uint32_t*)(STM32_SRAM4_BASE + 0x04))
|
||||
#define GDB_MAGIC3 (*(volatile uint32_t*)(STM32_SRAM4_BASE + 0x08))
|
||||
#define GDB_MAGIC4 (*(volatile uint32_t*)(STM32_SRAM4_BASE + 0x0c))
|
||||
#define GDB_ELFADDR (*(volatile uint32_t*)(STM32_SRAM4_BASE + 0x10))
|
||||
#define GDB_ELFSIZE (*(volatile uint32_t*)(STM32_SRAM4_BASE + 0x14))
|
||||
|
||||
/* Events for the monitor callback to signal the main thread */
|
||||
#define EV_POWER_PRESSED MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0)
|
||||
#define EV_POWER_RELEASED MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 1)
|
||||
#define EV_USB_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 2)
|
||||
|
||||
/* Long press duration for power button */
|
||||
#define POWERBUTTON_LONG_PRESS_TIME (HZ)
|
||||
|
||||
/* Time to remain powered with no USB cable inserted */
|
||||
#define USB_UNPLUGGED_ACTIVE_TIME (30 * HZ)
|
||||
#define USB_UNPLUGGED_INACTIVE_TIME (3 * HZ)
|
||||
|
||||
static const struct elf_memory_map rb_elf_mmap[] = {
|
||||
{
|
||||
.addr = STM32_ITCM_BASE,
|
||||
.size = STM32_ITCM_SIZE,
|
||||
.flags = PF_R | PF_X,
|
||||
},
|
||||
{
|
||||
.addr = STM32_DTCM_BASE,
|
||||
.size = STM32_DTCM_SIZE,
|
||||
.flags = PF_R | PF_W,
|
||||
},
|
||||
{
|
||||
.addr = STM32_SDRAM1_BASE,
|
||||
.size = SDRAM_SIZE - LOAD_SIZE,
|
||||
.flags = PF_R | PF_W | PF_X,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct elf_load_context rb_elf_ctx = {
|
||||
.mmap = rb_elf_mmap,
|
||||
.num_mmap = ARRAYLEN(rb_elf_mmap),
|
||||
};
|
||||
|
||||
/* Power button monitor state */
|
||||
static bool pwr_curr_state;
|
||||
static bool pwr_prev_state;
|
||||
struct timeout pwr_stable_tmo;
|
||||
|
||||
/* USB monitor state */
|
||||
static bool usb_curr_state;
|
||||
static bool usb_prev_state;
|
||||
struct timeout usb_unplugged_tmo;
|
||||
|
||||
static volatile bool restart_pwr_stable_tmo;
|
||||
static volatile bool restart_usb_unplugged_tmo;
|
||||
|
||||
/*
|
||||
* Because power is always enabled while USB is plugged in the
|
||||
* bootloader decides whether to appear "active" or "inactive"
|
||||
* to the user.
|
||||
*/
|
||||
static bool is_active;
|
||||
|
||||
/*
|
||||
* This flag is set if the bootloader is entered after software
|
||||
* poweroff. The user may still be holding the power button and
|
||||
* we don't want to boot Rockbox because of this, so we have to
|
||||
* wait for the power button to be released first.
|
||||
*/
|
||||
static bool wait_for_power_released;
|
||||
|
||||
/* Optional error message displayed on LCD */
|
||||
static const char *status_msg = NULL;
|
||||
|
||||
/* Location of Rockbox ELF binary in memory */
|
||||
static void *elf_load_addr = NULL;
|
||||
static size_t elf_load_size = 0;
|
||||
|
||||
/* Helper functions */
|
||||
static bool is_power_button_pressed(void)
|
||||
{
|
||||
int y = 0;
|
||||
struct tm *time = get_time();
|
||||
|
||||
lcd_clear_display();
|
||||
|
||||
lcd_putsf(0, y++, "time: %02d:%02d:%02d",
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
lcd_putsf(0, y++, "year: %d", time->tm_year + 1900);
|
||||
lcd_putsf(0, y++, "month: %d", time->tm_mon);
|
||||
lcd_putsf(0, y++, "day: %d", time->tm_mday);
|
||||
|
||||
lcd_update();
|
||||
return button_status() & BUTTON_POWER;
|
||||
}
|
||||
|
||||
static void demo_storage(void)
|
||||
static bool is_usbmode_button_pressed(void)
|
||||
{
|
||||
int y = 0;
|
||||
return button_status() & BUTTON_DOWN;
|
||||
}
|
||||
|
||||
lcd_clear_display();
|
||||
lcd_putsf(0, y++, "tick %ld", current_tick);
|
||||
static int send_event_on_tmo(struct timeout *tmo)
|
||||
{
|
||||
button_queue_post(tmo->data, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_usb_connected)
|
||||
/*
|
||||
* Monitors the state of the power button and USB cable
|
||||
* insertion status. It will post an event to the main
|
||||
* thread when (a) the power button is continously held
|
||||
* or released for long enough, or (b) the USB cable is
|
||||
* unplugged for long enough.
|
||||
*/
|
||||
static void monitor_tick(void)
|
||||
{
|
||||
/* Power button state */
|
||||
pwr_prev_state = pwr_curr_state;
|
||||
pwr_curr_state = is_power_button_pressed();
|
||||
|
||||
if (pwr_curr_state != pwr_prev_state || restart_pwr_stable_tmo)
|
||||
{
|
||||
lcd_puts(0, y++, "storage disabled by USB");
|
||||
lcd_update();
|
||||
long event = pwr_curr_state ? EV_POWER_PRESSED : EV_POWER_RELEASED;
|
||||
int ticks = POWERBUTTON_LONG_PRESS_TIME;
|
||||
|
||||
restart_pwr_stable_tmo = false;
|
||||
timeout_register(&pwr_stable_tmo, send_event_on_tmo, ticks, event);
|
||||
}
|
||||
|
||||
/* USB cable state */
|
||||
usb_prev_state = usb_curr_state;
|
||||
usb_curr_state = usb_inserted();
|
||||
|
||||
/* Ignore cable state change in inactive state */
|
||||
if (usb_curr_state != usb_prev_state || restart_usb_unplugged_tmo)
|
||||
{
|
||||
long event = EV_USB_UNPLUGGED;
|
||||
int ticks = is_active ? USB_UNPLUGGED_ACTIVE_TIME : USB_UNPLUGGED_INACTIVE_TIME;
|
||||
|
||||
restart_usb_unplugged_tmo = false;
|
||||
|
||||
if (usb_curr_state)
|
||||
timeout_cancel(&usb_unplugged_tmo);
|
||||
else
|
||||
timeout_register(&usb_unplugged_tmo, send_event_on_tmo, ticks, event);
|
||||
}
|
||||
}
|
||||
|
||||
static void monitor_init(void)
|
||||
{
|
||||
pwr_curr_state = is_power_button_pressed();
|
||||
usb_curr_state = usb_inserted();
|
||||
|
||||
/* Make sure events fire even if inputs don't change after boot */
|
||||
restart_pwr_stable_tmo = true;
|
||||
restart_usb_unplugged_tmo = true;
|
||||
|
||||
tick_add_task(monitor_tick);
|
||||
}
|
||||
|
||||
static void go_active(void)
|
||||
{
|
||||
is_active = true;
|
||||
restart_usb_unplugged_tmo = true;
|
||||
|
||||
gpio_set_level(GPIO_CPU_POWER_ON, 1);
|
||||
storage_enable(true);
|
||||
disk_mount_all();
|
||||
}
|
||||
|
||||
static void go_inactive(void)
|
||||
{
|
||||
is_active = false;
|
||||
restart_usb_unplugged_tmo = true;
|
||||
|
||||
storage_enable(false);
|
||||
gpio_set_level(GPIO_CPU_POWER_ON, 0);
|
||||
}
|
||||
|
||||
static void refresh_display(void)
|
||||
{
|
||||
if (!is_active)
|
||||
{
|
||||
lcd_shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
struct partinfo pinfo;
|
||||
if (storage_present(IF_MD(0,)) && disk_partinfo(0, &pinfo))
|
||||
{
|
||||
lcd_putsf(0, y++, "start %d", (int)pinfo.start);
|
||||
lcd_putsf(0, y++, "count %d", (int)pinfo.size);
|
||||
lcd_putsf(0, y++, "type %d", (int)pinfo.type);
|
||||
|
||||
DIR *d = opendir("/");
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(d)))
|
||||
{
|
||||
lcd_putsf(0, y++, "/%s", ent->d_name);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
lcd_update();
|
||||
}
|
||||
|
||||
static void demo_usb(void)
|
||||
{
|
||||
static const char *phyname[] = {
|
||||
[STM32H743_USBOTG_PHY_ULPI_HS] = "ULPI HS",
|
||||
[STM32H743_USBOTG_PHY_ULPI_FS] = "ULPI FS",
|
||||
[STM32H743_USBOTG_PHY_INT_FS] = "internal FS",
|
||||
};
|
||||
|
||||
int y = 0;
|
||||
|
||||
lcd_clear_display();
|
||||
lcd_putsf(0, y++, "tick %ld", current_tick);
|
||||
lcd_putsf(0, y++, "usb connected %d", (int)is_usb_connected);
|
||||
|
||||
lcd_putsf(0, y++, "instance = USB%d", STM32H743_USBOTG_INSTANCE + 1);
|
||||
lcd_putsf(0, y++, "phy = %s", phyname[STM32H743_USBOTG_PHY]);
|
||||
lcd_putsf(0, y++, "Rockbox on %s", MODEL_NAME);
|
||||
y++;
|
||||
|
||||
if (status_msg)
|
||||
{
|
||||
lcd_putsf(0, y++, "Error: %s", status_msg);
|
||||
y++;
|
||||
}
|
||||
|
||||
if (!usb_inserted())
|
||||
{
|
||||
lcd_putsf(0, y++, "Hold POWER to power off");
|
||||
lcd_putsf(0, y++, "Connect USB cable for USB mode");
|
||||
y++;
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd_putsf(0, y++, "Bootloader USB mode");
|
||||
|
||||
if (charging_state())
|
||||
{
|
||||
lcd_putsf(0, y++, "Battery charging (%d mA)",
|
||||
usb_charging_maxcurrent());
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd_putsf(0, y++, "Battery charged");
|
||||
}
|
||||
|
||||
y++;
|
||||
}
|
||||
|
||||
lcd_putsf(0, y++, "Version: %s", RBVERSION);
|
||||
|
||||
lcd_update();
|
||||
lcd_enable(true);
|
||||
}
|
||||
|
||||
static void (*demo_funcs[]) (void) = {
|
||||
demo_rtc,
|
||||
demo_storage,
|
||||
demo_usb,
|
||||
};
|
||||
static bool load_rockbox(void)
|
||||
{
|
||||
int fd = open(BOOTDIR "/" BOOTFILE, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
status_msg = "Rockbox not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
void *tmp_buf = (void *)LOAD_BUFFER_ADDR;
|
||||
size_t tmp_size = LOAD_SIZE;
|
||||
|
||||
ssize_t ret = read(fd, tmp_buf, tmp_size);
|
||||
if (ret < 0)
|
||||
{
|
||||
status_msg = "I/O error loading Rockbox";
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((size_t)ret == tmp_size)
|
||||
{
|
||||
status_msg = "Rockbox binary too large";
|
||||
goto out;
|
||||
}
|
||||
|
||||
elf_load_addr = tmp_buf;
|
||||
elf_load_size = tmp_size;
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
return elf_load_addr != NULL;
|
||||
}
|
||||
|
||||
static void launch_elf(void)
|
||||
{
|
||||
void *entrypoint = NULL;
|
||||
void (*entry_fn) (void) = NULL;
|
||||
|
||||
if (elf_load_addr == NULL || elf_load_size == 0)
|
||||
return;
|
||||
|
||||
int err = elf_loadmem(elf_load_addr, elf_load_size, &rb_elf_ctx, &entrypoint);
|
||||
if (err)
|
||||
{
|
||||
status_msg = "Failed to execute Rockbox";
|
||||
return;
|
||||
}
|
||||
|
||||
disk_unmount_all();
|
||||
storage_enable(false);
|
||||
lcd_shutdown();
|
||||
|
||||
entry_fn = entrypoint;
|
||||
commit_discard_idcache();
|
||||
disable_irq();
|
||||
stm32_systick_disable();
|
||||
|
||||
entry_fn();
|
||||
}
|
||||
|
||||
static void launch(void)
|
||||
{
|
||||
/* No-op if USB mode was requested */
|
||||
if (is_usbmode_button_pressed())
|
||||
return;
|
||||
|
||||
load_rockbox();
|
||||
launch_elf();
|
||||
}
|
||||
|
||||
static bool handle_gdb_boot(void)
|
||||
{
|
||||
/* Look for magic values that signal the GDB boot protocol */
|
||||
bool gdb_boot = (GDB_MAGIC1 == GDB_MAGICVAL1 &&
|
||||
GDB_MAGIC2 == GDB_MAGICVAL2 &&
|
||||
GDB_MAGIC3 == GDB_MAGICVAL3 &&
|
||||
GDB_MAGIC4 == GDB_MAGICVAL4);
|
||||
|
||||
/* Clear them so they won't hang around on a system reset */
|
||||
GDB_MAGIC1 = 0;
|
||||
GDB_MAGIC2 = 0;
|
||||
GDB_MAGIC3 = 0;
|
||||
GDB_MAGIC4 = 0;
|
||||
|
||||
if (!gdb_boot)
|
||||
return false;
|
||||
|
||||
/* "Call" GDB by entering breakpoint */
|
||||
GDB_ELFADDR = 0;
|
||||
GDB_ELFSIZE = 0;
|
||||
asm volatile("bkpt");
|
||||
|
||||
/* Read location of the loaded binary */
|
||||
elf_load_addr = (void *)GDB_ELFADDR;
|
||||
elf_load_size = (size_t)GDB_ELFSIZE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
system_init();
|
||||
kernel_init();
|
||||
power_init();
|
||||
rtc_init();
|
||||
|
||||
lcd_init();
|
||||
button_init();
|
||||
|
||||
/* Start monitoring power button / usb state */
|
||||
monitor_init();
|
||||
|
||||
/* Prepare LCD in case we need to display something */
|
||||
lcd_init();
|
||||
backlight_init();
|
||||
backlight_on();
|
||||
|
||||
show_logo();
|
||||
|
||||
/*
|
||||
* Prepare storage subsystem, but keep SD card unpowered
|
||||
* until we actually need to access it.
|
||||
*/
|
||||
storage_init();
|
||||
storage_enable(false);
|
||||
|
||||
/*
|
||||
* Initialize fs/disk internal state, the disk will not
|
||||
* be mountable due to being disabled but this will not
|
||||
* cause any fatal errors.
|
||||
*/
|
||||
filesystem_init();
|
||||
disk_mount_all();
|
||||
|
||||
/* GDB assisted boot takes precedence */
|
||||
if (handle_gdb_boot())
|
||||
launch_elf();
|
||||
|
||||
if (echoplayer_boot_reason == ECHOPLAYER_BOOT_REASON_SW_REBOOT ||
|
||||
usb_detect() == USB_INSERTED)
|
||||
{
|
||||
/*
|
||||
* For software reboot we want to immediately launch Rockbox.
|
||||
*
|
||||
* We also do so if USB is plugged in at boot, because there's
|
||||
* no way to dynamically switch between charge only and mass
|
||||
* storage mode depending on the active/inactive state; to avoid
|
||||
* confusion, it is simpler to just boot Rockbox.
|
||||
*/
|
||||
go_active();
|
||||
launch();
|
||||
}
|
||||
else if (echoplayer_boot_reason == ECHOPLAYER_BOOT_REASON_SW_POWEROFF)
|
||||
{
|
||||
/* Ignore power button pressed event until button is first released */
|
||||
wait_for_power_released = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize USB so we can enumerate with the host and
|
||||
* negotiate charge current (needed even in inactive mode)
|
||||
*/
|
||||
usb_init();
|
||||
usb_start_monitoring();
|
||||
usb_charging_enable(USB_CHARGING_FORCE);
|
||||
|
||||
int demo_page = 0;
|
||||
const int num_pages = ARRAYLEN(demo_funcs);
|
||||
|
||||
while (1)
|
||||
for (;;)
|
||||
{
|
||||
int btn = button_get_w_tmo(HZ);
|
||||
switch (btn)
|
||||
refresh_display();
|
||||
|
||||
long refresh_tmo = is_active ? HZ : TIMEOUT_BLOCK;
|
||||
|
||||
switch (button_get_w_tmo(refresh_tmo))
|
||||
{
|
||||
case BUTTON_START:
|
||||
demo_page += 1;
|
||||
if (demo_page >= num_pages)
|
||||
demo_page = 0;
|
||||
case EV_POWER_PRESSED:
|
||||
if (wait_for_power_released)
|
||||
break;
|
||||
|
||||
if (!is_active)
|
||||
{
|
||||
/* Launch Rockbox due to user pressing power button */
|
||||
go_active();
|
||||
launch();
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* NOTE: The check for USB insertion here is only
|
||||
* because we can't change to charging only mode.
|
||||
*/
|
||||
if (!usb_inserted())
|
||||
go_inactive();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BUTTON_SELECT:
|
||||
if (demo_page == 0)
|
||||
demo_page = num_pages - 1;
|
||||
else
|
||||
demo_page -= 1;
|
||||
case EV_POWER_RELEASED:
|
||||
/*
|
||||
* This cuts power if the power button is not
|
||||
* held and we're not in the active state due
|
||||
* to USB mode, etc.
|
||||
*/
|
||||
wait_for_power_released = false;
|
||||
gpio_set_level(GPIO_CPU_POWER_ON, is_active);
|
||||
break;
|
||||
|
||||
case EV_USB_UNPLUGGED:
|
||||
go_inactive();
|
||||
break;
|
||||
|
||||
case SYS_USB_CONNECTED:
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
is_usb_connected = true;
|
||||
break;
|
||||
|
||||
case SYS_USB_DISCONNECTED:
|
||||
is_usb_connected = false;
|
||||
|
||||
case BUTTON_X:
|
||||
power_off();
|
||||
break;
|
||||
|
||||
default:
|
||||
go_active();
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, button_get_data());
|
||||
break;
|
||||
}
|
||||
|
||||
demo_funcs[demo_page]();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,9 +43,6 @@
|
|||
#include "lcd.h"
|
||||
#include "version.h"
|
||||
|
||||
/* Show the Rockbox logo - in show_logo.c */
|
||||
extern void show_logo(void);
|
||||
|
||||
#define TAR_CHUNK 512
|
||||
#define TAR_HEADER_SIZE 157
|
||||
|
||||
|
|
@ -126,7 +123,7 @@ static void handle_usb(int connect_timeout)
|
|||
/* Got the message - wait for disconnect */
|
||||
printf("Bootloader USB mode");
|
||||
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, button_get_data());
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ static void usb_mode(int connect_timeout)
|
|||
adc_init();
|
||||
|
||||
/* ack the SYS_USB_CONNECTED polled from the button queue */
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, button_get_data());
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ static void usb_mode(void)
|
|||
printf("Bootloader USB mode");
|
||||
|
||||
/* Ack the SYS_USB_CONNECTED polled from the button queue */
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, button_get_data());
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@
|
|||
#include "../kernel-internal.h"
|
||||
#include "system.h"
|
||||
|
||||
/* Show the Rockbox logo - in show_logo.c */
|
||||
extern void show_logo(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Initialize Rockbox kernel */
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
* Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
|
||||
* and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
|
|
@ -60,9 +60,6 @@
|
|||
void lcd_reset(void);
|
||||
#endif
|
||||
|
||||
/* Show the Rockbox logo - in show_logo.c */
|
||||
extern void show_logo(void);
|
||||
|
||||
/* Button definitions */
|
||||
#if CONFIG_KEYPAD == IRIVER_H10_PAD
|
||||
#define BOOTLOADER_BOOT_OF BUTTON_LEFT
|
||||
|
|
@ -132,21 +129,21 @@ int load_mi4_part(unsigned char* buf, struct partinfo* pinfo,
|
|||
struct mi4header_t mi4header;
|
||||
struct ppmi_header_t ppmi_header;
|
||||
unsigned long sum;
|
||||
|
||||
|
||||
/* Read header to find out how long the mi4 file is. */
|
||||
storage_read_sectors(IF_MD(0,) pinfo->start + PPMI_SECTOR_OFFSET,
|
||||
PPMI_SECTORS, &ppmi_header);
|
||||
|
||||
|
||||
/* The first four characters at 0x80000 (sector 1024) should be PPMI*/
|
||||
if( memcmp(ppmi_header.magic, "PPMI", 4) )
|
||||
return EFILE_NOT_FOUND;
|
||||
|
||||
|
||||
printf("BL mi4 size: %x", ppmi_header.length);
|
||||
|
||||
|
||||
/* Read mi4 header of the OF */
|
||||
storage_read_sectors(IF_MD(0,) pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS
|
||||
storage_read_sectors(IF_MD(0,) pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS
|
||||
+ (ppmi_header.length/512), MI4_HEADER_SECTORS, &mi4header);
|
||||
|
||||
|
||||
/* We don't support encrypted mi4 files yet */
|
||||
if( (mi4header.plaintext) != (mi4header.mi4size-MI4_HEADER_SIZE))
|
||||
return EINVALID_FORMAT;
|
||||
|
|
@ -178,14 +175,14 @@ int load_mi4_part(unsigned char* buf, struct partinfo* pinfo,
|
|||
|
||||
if(sum != mi4header.crc32)
|
||||
return EBAD_CHKSUM;
|
||||
|
||||
#ifdef SANSA_E200
|
||||
|
||||
#ifdef SANSA_E200
|
||||
if (disable_rebuild)
|
||||
{
|
||||
char block[512];
|
||||
|
||||
|
||||
printf("Disabling database rebuild");
|
||||
|
||||
|
||||
storage_read_sectors(IF_MD(0,) pinfo->start + 0x3c08, 1, block);
|
||||
block[0xe1] = 0;
|
||||
storage_write_sectors(IF_MD(0,) pinfo->start + 0x3c08, 1, block);
|
||||
|
|
@ -206,7 +203,7 @@ static int handle_usb(int connect_timeout)
|
|||
struct queue_event ev;
|
||||
int usb = USB_EXTRACTED;
|
||||
long end_tick = 0;
|
||||
|
||||
|
||||
if (!usb_plugged())
|
||||
return USB_EXTRACTED;
|
||||
|
||||
|
|
@ -233,7 +230,7 @@ static int handle_usb(int connect_timeout)
|
|||
printf("Bootloader USB mode");
|
||||
|
||||
usb = USB_HANDLED;
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
#if defined(SANSA_E200) && defined(HAVE_BOOTLOADER_USB_MODE)
|
||||
/* E200 misses unplug randomly
|
||||
probably fine for other targets too but needs tested */
|
||||
|
|
@ -394,7 +391,7 @@ void* main(void)
|
|||
error(EDISK,num_partitions, true);
|
||||
}
|
||||
|
||||
/* Just list the first 2 partitions since we don't have any devices yet
|
||||
/* Just list the first 2 partitions since we don't have any devices yet
|
||||
that have more than that */
|
||||
for(i=0; i<NUM_PARTITIONS; i++)
|
||||
{
|
||||
|
|
@ -496,7 +493,7 @@ void* main(void)
|
|||
#endif
|
||||
goto main_exit;
|
||||
}
|
||||
|
||||
|
||||
error(0, 0, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@
|
|||
#include "adc.h"
|
||||
#include "version.h"
|
||||
|
||||
extern void show_logo(void);
|
||||
extern void power_off(void);
|
||||
|
||||
static void show_splash(int timeout, const char *msg)
|
||||
|
|
@ -76,7 +75,7 @@ static void usb_mode(void)
|
|||
/* Got the message - wait for disconnect */
|
||||
show_splash(0, "Bootloader USB mode");
|
||||
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, button_get_data());
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@
|
|||
*/
|
||||
#define LOAD_SIZE 0x700000
|
||||
|
||||
extern void show_logo( void );
|
||||
|
||||
/* This function setup bare minimum
|
||||
* and jumps to rom in order to activate
|
||||
* hardcoded rkusb mode
|
||||
|
|
@ -153,9 +151,9 @@ void main(void)
|
|||
error(EDISK, ret, true);
|
||||
|
||||
loadbuffer = (unsigned char*)DRAM_ORIG; /* DRAM */
|
||||
|
||||
|
||||
if (boot == rb)
|
||||
snprintf(filename,sizeof(filename), BOOTDIR "/%s", BOOTFILE);
|
||||
snprintf(filename,sizeof(filename), BOOTDIR "/%s", BOOTFILE);
|
||||
else if (boot == of)
|
||||
snprintf(filename,sizeof(filename), BOOTDIR "/%s", "BASE.RKW");
|
||||
|
||||
|
|
@ -170,7 +168,7 @@ void main(void)
|
|||
|
||||
/* if we boot rockbox we shutdown on error
|
||||
* if we boot OF we fall back to rkusb mode on error
|
||||
*/
|
||||
*/
|
||||
if (boot == rb)
|
||||
{
|
||||
power_off();
|
||||
|
|
@ -213,7 +211,7 @@ void main(void)
|
|||
lcd_update();
|
||||
|
||||
enter_rkusb();
|
||||
}
|
||||
}
|
||||
|
||||
/* hang */
|
||||
while(1);
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ static void handle_usb(int connect_timeout)
|
|||
if (button_get_w_tmo(HZ/2) == SYS_USB_CONNECTED)
|
||||
{
|
||||
printf("Bootloader USB mode");
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, button_get_data());
|
||||
while (button_get_w_tmo(HZ/2) != SYS_USB_DISCONNECTED)
|
||||
{
|
||||
storage_spin();
|
||||
|
|
@ -215,8 +215,6 @@ static void handle_usb(int connect_timeout)
|
|||
usb_close();
|
||||
}
|
||||
|
||||
extern void show_logo(void);
|
||||
|
||||
void main(void)
|
||||
{
|
||||
unsigned char* loadbuffer;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
* Copyright (C) 2007 by Dave Chapman
|
||||
*
|
||||
* Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
|
|
@ -46,9 +46,6 @@
|
|||
#include "loader_strerror.h"
|
||||
#include "version.h"
|
||||
|
||||
/* Show the Rockbox logo - in show_logo.c */
|
||||
extern void show_logo(void);
|
||||
|
||||
/* Address to load main Rockbox image to */
|
||||
#define LOAD_ADDRESS 0x20000000 /* DRAM_START */
|
||||
|
||||
|
|
@ -63,12 +60,12 @@ void show_debug_screen(void)
|
|||
int power_count = 0;
|
||||
int count = 0;
|
||||
bool do_power_off = false;
|
||||
|
||||
|
||||
lcd_puts_scroll(0,0,"+++ this is a very very long line to test scrolling. ---");
|
||||
while (!do_power_off) {
|
||||
line = 1;
|
||||
button = button_get(false);
|
||||
|
||||
|
||||
/* Power-off if POWER button has been held for a time
|
||||
This loop is currently running at about 100 iterations/second
|
||||
*/
|
||||
|
|
@ -131,10 +128,10 @@ void* main(void)
|
|||
|
||||
system_init();
|
||||
power_init();
|
||||
|
||||
|
||||
kernel_init();
|
||||
enable_irq();
|
||||
|
||||
|
||||
lcd_init();
|
||||
|
||||
adc_init();
|
||||
|
|
@ -143,7 +140,7 @@ void* main(void)
|
|||
|
||||
font_init();
|
||||
lcd_setfont(FONT_SYSFIXED);
|
||||
|
||||
|
||||
show_logo();
|
||||
|
||||
backlight_hw_on();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
static bool lcd_inited = false;
|
||||
extern bool is_usb_connected;
|
||||
extern intptr_t usb_connection_seqnum;
|
||||
|
||||
void clearscreen(void)
|
||||
{
|
||||
|
|
@ -134,6 +135,7 @@ int get_button(int timeout)
|
|||
case SYS_USB_CONNECTED:
|
||||
case SYS_USB_DISCONNECTED:
|
||||
is_usb_connected = (btn == SYS_USB_CONNECTED);
|
||||
usb_connection_seqnum = button_get_data();
|
||||
break;
|
||||
#ifdef HAVE_SCREENDUMP
|
||||
case BL_SCREENSHOT:
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
* Handled by the gui code since that's how events are delivered
|
||||
* TODO: this is an ugly kludge */
|
||||
bool is_usb_connected = false;
|
||||
intptr_t usb_connection_seqnum = 0;
|
||||
|
||||
static bool screenshot_enabled = false;
|
||||
|
||||
|
|
@ -71,7 +72,7 @@ void usb_mode(void)
|
|||
return;
|
||||
|
||||
splashf(0, "USB mode");
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, usb_connection_seqnum);
|
||||
|
||||
while(is_usb_connected)
|
||||
get_button(TIMEOUT_BLOCK);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@
|
|||
|
||||
#define SHOW_LOGO
|
||||
|
||||
extern void show_logo(void);
|
||||
extern void power_off(void);
|
||||
|
||||
static int lcd_inited = 0;
|
||||
|
|
@ -69,7 +68,6 @@ void init_lcd(void)
|
|||
#ifdef HAVE_BOOTLOADER_USB_MODE
|
||||
static void show_splash(int timeout, const char *msg)
|
||||
{
|
||||
init_lcd();
|
||||
reset_screen();
|
||||
lcd_putsxy( (LCD_WIDTH - (SYSFONT_WIDTH * strlen(msg))) / 2,
|
||||
(LCD_HEIGHT - SYSFONT_HEIGHT) / 2, msg);
|
||||
|
|
@ -107,7 +105,7 @@ static void usb_mode(void)
|
|||
/* Got the message - wait for disconnect */
|
||||
show_splash(0, "Bootloader USB mode");
|
||||
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, button_get_data());
|
||||
|
||||
while(1) {
|
||||
button = button_get_w_tmo(HZ/2);
|
||||
|
|
@ -172,6 +170,9 @@ int main(void)
|
|||
init_lcd();
|
||||
#ifdef SHOW_LOGO
|
||||
show_logo();
|
||||
#else
|
||||
printf(MODEL_NAME" Rockbox Bootloader");
|
||||
printf("Version %s", rbversion);
|
||||
#endif
|
||||
|
||||
button_init();
|
||||
|
|
@ -198,11 +199,6 @@ int main(void)
|
|||
}
|
||||
#endif /* HAVE_BOOTLOADER_USB_MODE */
|
||||
|
||||
#ifndef SHOW_LOGO
|
||||
printf(MODEL_NAME" Rockbox Bootloader");
|
||||
printf("Version %s", rbversion);
|
||||
#endif
|
||||
|
||||
rc = boot_rockbox();
|
||||
|
||||
if(rc <= EFILE_EMPTY) {
|
||||
|
|
|
|||
|
|
@ -2996,9 +2996,10 @@ void unregister_storage_idle_func(void (*function)(void), bool run)
|
|||
\param run
|
||||
\description
|
||||
|
||||
void usb_acknowledge(long id)
|
||||
void usb_acknowledge(long id, intptr_t seqnum)
|
||||
\group usb
|
||||
\param id
|
||||
\param seqnum
|
||||
\description
|
||||
|
||||
void usb_hid_send(usage_page_t usage_page, int id)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ target/hosted/rolo.c
|
|||
lc-rock.c
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ELF)
|
||||
elf_loader.c
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_BOOTDATA) || defined(HAVE_MULTIBOOT)
|
||||
common/multiboot.c
|
||||
#ifndef BOOTLOADER
|
||||
|
|
@ -212,7 +216,7 @@ target/hosted/xduoo/xduoolinux_codec.c
|
|||
target/hosted/button-devinput.c
|
||||
#endif
|
||||
|
||||
#if defined(HIBY_LINUX) && !defined(HIBY_R3PROII) && !defined(HIBY_R1) && !defined(SIMULATOR)
|
||||
#if defined(HIBY_LINUX) && !defined(HIBY_R3PROII) && !defined(HIBY_R1) && !defined(SIMULATOR)
|
||||
target/hosted/usb-hiby.c
|
||||
#endif
|
||||
|
||||
|
|
@ -945,6 +949,7 @@ target/arm/s5l8702/lcd-asm-s5l8702.S
|
|||
#endif
|
||||
|
||||
/* USB Stack */
|
||||
// TODO: This needs to be HAVE_USBSTACK && (!BOOTLOADER || HAVE_USB_BOOTLOADER_MODE)
|
||||
#ifdef HAVE_USBSTACK
|
||||
usbstack/usb_core.c
|
||||
#ifdef USB_ENABLE_STORAGE
|
||||
|
|
@ -2024,7 +2029,6 @@ target/arm/rk27xx/ihifi2/audio-ihifi800.c
|
|||
target/arm/stm32/crt0-stm32h7.S
|
||||
target/arm/stm32/vectors-stm32h7.S
|
||||
target/arm/stm32/adc-stm32h7.c
|
||||
target/arm/stm32/clock-stm32h7.c
|
||||
target/arm/stm32/debug-stm32h7.c
|
||||
target/arm/stm32/gpio-stm32h7.c
|
||||
target/arm/stm32/i2c-stm32h7.c
|
||||
|
|
|
|||
|
|
@ -605,7 +605,7 @@ void backlight_thread(void)
|
|||
#endif /* HAVE_REMOTE_LCD/ HAVE_REMOTE_LCD_AS_MAIN */
|
||||
#endif /* !SIMULATOR */
|
||||
case SYS_USB_CONNECTED:
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
break;
|
||||
|
||||
#ifdef BACKLIGHT_DRIVER_CLOSE
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ void sdmmc_host_init(struct sdmmc_host *host,
|
|||
host->ops = ops;
|
||||
host->controller = controller;
|
||||
host->present = !config->is_removable;
|
||||
host->enabled = true;
|
||||
mutex_init(&host->lock);
|
||||
|
||||
array[i] = host;
|
||||
|
|
@ -188,6 +189,26 @@ static void sdmmc_host_bus_reset(struct sdmmc_host *host)
|
|||
memset(&host->cardinfo, 0, sizeof(host->cardinfo));
|
||||
}
|
||||
|
||||
/*
|
||||
* Call to enable/disable the host controller. If disabled then the
|
||||
* controller and device are powered off and no access to the storage
|
||||
* device is allowed.
|
||||
*/
|
||||
static void sdmmc_host_set_enabled(struct sdmmc_host *host, bool enabled)
|
||||
{
|
||||
mutex_lock(&host->lock);
|
||||
|
||||
if (enabled != host->enabled)
|
||||
{
|
||||
if (host->enabled)
|
||||
sdmmc_host_bus_reset(host);
|
||||
|
||||
host->enabled = enabled;
|
||||
}
|
||||
|
||||
mutex_unlock(&host->lock);
|
||||
}
|
||||
|
||||
#ifdef HAVE_HOTSWAP
|
||||
static void sdmmc_host_hotswap_event(struct sdmmc_host *host, bool is_present)
|
||||
{
|
||||
|
|
@ -629,6 +650,9 @@ static int sdmmc_host_transfer(struct sdmmc_host *host,
|
|||
|
||||
mutex_lock(&host->lock);
|
||||
|
||||
if (!host->enabled)
|
||||
goto out;
|
||||
|
||||
if (!sdmmc_host_medium_present(host))
|
||||
goto out;
|
||||
|
||||
|
|
@ -721,6 +745,16 @@ tCardInfo *card_get_info_target(int drive)
|
|||
return &sdmmc_sd_hosts[drive]->cardinfo;
|
||||
}
|
||||
|
||||
void sd_enable(bool enabled)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAYLEN(sdmmc_sd_hosts); ++i)
|
||||
{
|
||||
struct sdmmc_host *host = sdmmc_sd_hosts[i];
|
||||
|
||||
sdmmc_host_set_enabled(host, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
long sd_last_disk_activity(void)
|
||||
{
|
||||
return sdmmc_sd_last_activity;
|
||||
|
|
|
|||
|
|
@ -186,8 +186,8 @@ static const char* const dw_resp_str[3] =
|
|||
|
||||
static struct usb_dw_ep usb_dw_ep_list[USB_NUM_ENDPOINTS][USB_DW_NUM_DIRS];
|
||||
static struct usb_dw_ep0 ep0;
|
||||
uint8_t _ep0_buffer[64] USB_DEVBSS_ATTR __attribute__((aligned(32)));
|
||||
uint8_t* ep0_buffer; /* Uncached, unless NO_UNCACHED_ADDR is defined */
|
||||
static uint8_t _ep0_buffer[64] USB_DEVBSS_ATTR __attribute__((aligned(32)));
|
||||
static uint8_t* ep0_buffer; /* Uncached, unless NO_UNCACHED_ADDR is defined */
|
||||
|
||||
static uint32_t usb_endpoints; /* available EPs mask */
|
||||
|
||||
|
|
|
|||
211
firmware/elf_loader.c
Normal file
211
firmware/elf_loader.c
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2026 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "elf_loader.h"
|
||||
#include "elf-target.h"
|
||||
#include "file.h"
|
||||
|
||||
#if defined(ROCKBOX_LITTLE_ENDIAN)
|
||||
# define NATIVE_ELF_DATA ELFDATA2LSB
|
||||
#elif defined(ROCKBOX_BIG_ENDIAN)
|
||||
# define NATIVE_ELF_DATA ELFDATA2MSB
|
||||
#else
|
||||
# error "Unknown endianness!"
|
||||
#endif
|
||||
|
||||
_Static_assert(TARGET_ELF_DATA == NATIVE_ELF_DATA,
|
||||
"ELF binaries with foreign endianness not supported");
|
||||
|
||||
static int elf_validate_header(const struct elf_header *header)
|
||||
{
|
||||
if (header->ei_magic[0] != ELFMAG0 ||
|
||||
header->ei_magic[1] != ELFMAG1 ||
|
||||
header->ei_magic[2] != ELFMAG2 ||
|
||||
header->ei_magic[3] != ELFMAG3)
|
||||
return ELF_ERR_BADMAGIC;
|
||||
|
||||
if (header->ei_class != TARGET_ELF_CLASS ||
|
||||
header->ei_data != TARGET_ELF_DATA)
|
||||
return ELF_ERR_UNSUPP_ARCH;
|
||||
|
||||
if (header->ei_version != EV_CURRENT ||
|
||||
header->e_version != EV_CURRENT)
|
||||
return ELF_ERR_UNSUPP_VERSION;
|
||||
|
||||
if (header->ei_osabi != TARGET_ELF_OSABI ||
|
||||
header->ei_abiversion != TARGET_ELF_ABIVERSION)
|
||||
return ELF_ERR_UNSUPP_OS;
|
||||
|
||||
if (header->e_type != ET_EXEC)
|
||||
return ELF_ERR_UNSUPP_TYPE;
|
||||
|
||||
if (header->e_machine != TARGET_ELF_MACHINE)
|
||||
return ELF_ERR_UNSUPP_ARCH;
|
||||
|
||||
if (header->e_phoff == 0)
|
||||
return ELF_ERR_EMPTY;
|
||||
|
||||
if (header->e_phentsize < sizeof(struct elf_phdr))
|
||||
return ELF_ERR_UNSUPP_PHSIZE;
|
||||
|
||||
if (header->e_phnum == PN_XNUM)
|
||||
return ELF_ERR_TOO_MANY_PHDRS;
|
||||
|
||||
return ELF_OK;
|
||||
}
|
||||
|
||||
static int elf_validate_phdr(const struct elf_phdr *phdr,
|
||||
const struct elf_load_context *ctx)
|
||||
{
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
return ELF_ERR_UNSUPP_PHDR;
|
||||
|
||||
if (phdr->p_filesz > phdr->p_memsz)
|
||||
return ELF_ERR_INVALID_PHDR;
|
||||
|
||||
/* Ignore headers which occupy zero memory */
|
||||
if (phdr->p_memsz == 0)
|
||||
return 0;
|
||||
|
||||
for (size_t i = 0; i < ctx->num_mmap; ++i)
|
||||
{
|
||||
const struct elf_memory_map *entry = &ctx->mmap[i];
|
||||
if (phdr->p_vaddr >= entry->addr &&
|
||||
phdr->p_vaddr < entry->addr + entry->size &&
|
||||
phdr->p_memsz <= entry->size)
|
||||
{
|
||||
if ((phdr->p_flags & entry->flags) != phdr->p_flags)
|
||||
return ELF_ERR_MEM_INCOMPAT_FLAGS;
|
||||
|
||||
return ELF_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ELF_ERR_MEM_UNMAPPED;
|
||||
}
|
||||
|
||||
int elf_load(elf_read_callback_t read_cb,
|
||||
intptr_t read_arg,
|
||||
const struct elf_load_context *ctx,
|
||||
void **entrypoint)
|
||||
{
|
||||
struct elf_header ehdr;
|
||||
struct elf_phdr phdr;
|
||||
int err;
|
||||
|
||||
if (read_cb(read_arg, 0, &ehdr, sizeof(ehdr)))
|
||||
return ELF_ERR_IO;
|
||||
|
||||
err = elf_validate_header(&ehdr);
|
||||
if (err != ELF_OK)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Iterate over program headers, copying segments to memory
|
||||
*/
|
||||
for (size_t ph_index = 0; ph_index < ehdr.e_phnum; ++ph_index)
|
||||
{
|
||||
off_t ph_off = ehdr.e_phoff + (ph_index * ehdr.e_phentsize);
|
||||
if (read_cb(read_arg, ph_off, &phdr, sizeof(phdr)))
|
||||
return ELF_ERR_IO;
|
||||
|
||||
err = elf_validate_phdr(&phdr, ctx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Load file data to memory if needed */
|
||||
if (phdr.p_filesz > 0)
|
||||
{
|
||||
if (read_cb(read_arg, phdr.p_offset, (void *)phdr.p_vaddr, phdr.p_filesz))
|
||||
return ELF_ERR_IO;
|
||||
}
|
||||
|
||||
/* Zero out any memory not backed by file data */
|
||||
if (phdr.p_memsz > phdr.p_filesz)
|
||||
{
|
||||
void *addr = (void *)phdr.p_vaddr + phdr.p_filesz;
|
||||
size_t size = phdr.p_memsz - phdr.p_filesz;
|
||||
|
||||
memset(addr, 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
*entrypoint = (void *)ehdr.e_entry;
|
||||
return ELF_OK;
|
||||
}
|
||||
|
||||
int elf_loadfd(int fd,
|
||||
const struct elf_load_context *ctx,
|
||||
void **entrypoint)
|
||||
{
|
||||
return elf_load(elf_read_fd_callback, fd, ctx, entrypoint);
|
||||
}
|
||||
|
||||
int elf_read_fd_callback(intptr_t fd, off_t pos, void *buf, size_t size)
|
||||
{
|
||||
if (lseek(fd, pos, SEEK_SET) == (off_t)-1)
|
||||
return -1;
|
||||
|
||||
ssize_t nread = read(fd, buf, size);
|
||||
if (nread < 0 || (size_t)nread != size)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int elf_loadpath(const char *filename,
|
||||
const struct elf_load_context *ctx,
|
||||
void **entrypoint)
|
||||
{
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return ELF_ERR_FILE_NOT_FOUND;
|
||||
|
||||
int err = elf_loadfd(fd, ctx, entrypoint);
|
||||
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
int elf_loadmem(const void *elf_buffer,
|
||||
size_t elf_size,
|
||||
const struct elf_load_context *ctx,
|
||||
void **entrypoint)
|
||||
{
|
||||
struct elf_loadmem_state state = {
|
||||
.buffer = elf_buffer,
|
||||
.size = elf_size,
|
||||
};
|
||||
|
||||
return elf_load(elf_read_mem_callback, (intptr_t)&state, ctx, entrypoint);
|
||||
}
|
||||
|
||||
int elf_read_mem_callback(intptr_t loadmem_state, off_t pos, void *buf, size_t size)
|
||||
{
|
||||
struct elf_loadmem_state *state = (void *)loadmem_state;
|
||||
|
||||
if (pos < 0 || (size_t)pos >= state->size)
|
||||
return -1;
|
||||
if (state->size - (size_t)pos < size)
|
||||
return -1;
|
||||
|
||||
memcpy(buf, state->buffer + pos, size);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1025,12 +1025,12 @@ Lyre prototype 1 */
|
|||
#define USB_DETECT_BY_REQUEST
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_USBSTACK) && CONFIG_USBOTG == USBOTG_ARC
|
||||
#if CONFIG_USBOTG == USBOTG_ARC
|
||||
#define INCLUDE_TIMEOUT_API
|
||||
#define USB_DRIVER_CLOSE
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_USBSTACK) && CONFIG_USBOTG == USBOTG_TNETV105
|
||||
#if CONFIG_USBOTG == USBOTG_TNETV105
|
||||
#define INCLUDE_TIMEOUT_API
|
||||
#define USB_DRIVER_CLOSE
|
||||
#endif
|
||||
|
|
@ -1384,11 +1384,7 @@ Lyre prototype 1 */
|
|||
#ifdef BOOTLOADER
|
||||
|
||||
/* enable usb storage for targets that do bootloader usb */
|
||||
#if defined(HAVE_BOOTLOADER_USB_MODE) || \
|
||||
defined(CREATIVE_ZVx) || defined(CPU_TCC780X) || \
|
||||
CONFIG_USBOTG == USBOTG_JZ4740 || CONFIG_USBOTG == USBOTG_AS3525 || \
|
||||
CONFIG_USBOTG == USBOTG_S3C6400X || CONFIG_USBOTG == USBOTG_DESIGNWARE || \
|
||||
CONFIG_USBOTG == USBOTG_JZ4760
|
||||
#if defined(HAVE_BOOTLOADER_USB_MODE)
|
||||
#define USB_ENABLE_STORAGE
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
#define HAVE_LCD_COLOR
|
||||
#define HAVE_LCD_BITMAP
|
||||
#define HAVE_LCD_ENABLE
|
||||
#define HAVE_LCD_SHUTDOWN
|
||||
#define IRAM_LCDFRAMEBUFFER __attribute__((section(".framebuffer")))
|
||||
|
||||
/* Backlight defines */
|
||||
#define HAVE_BACKLIGHT
|
||||
|
|
@ -88,9 +90,9 @@
|
|||
#define BATTERY_CAPACITY_MAX 1100
|
||||
#define BATTERY_CAPACITY_INC 0
|
||||
|
||||
/* Multiboot */
|
||||
#define HAVE_BOOTDATA
|
||||
#define BOOT_REDIR "rockbox_main.echor1"
|
||||
/* TODO: Multiboot */
|
||||
//#define HAVE_BOOTDATA
|
||||
//#define BOOT_REDIR "rockbox_main.echor1"
|
||||
|
||||
/* USB support */
|
||||
#ifndef SIMULATOR
|
||||
|
|
@ -112,6 +114,11 @@
|
|||
#define HAVE_BOOTLOADER_USB_MODE
|
||||
#endif
|
||||
|
||||
#ifdef BOOTLOADER
|
||||
# define USB_READ_BUFFER_SIZE (32 * 1024)
|
||||
# define USB_WRITE_BUFFER_SIZE (32 * 1024)
|
||||
#endif
|
||||
|
||||
/* Rockbox capabilities */
|
||||
#define HAVE_FAT16SUPPORT
|
||||
#define HAVE_ALBUMART
|
||||
|
|
@ -123,3 +130,4 @@
|
|||
#define HAVE_HOTKEY
|
||||
#define AB_REPEAT_ENABLE
|
||||
#define HAVE_BOOTLOADER_SCREENDUMP
|
||||
#define HAVE_ELF
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@
|
|||
/* logf() over USB serial (http://www.rockbox.org/wiki/PortalPlayerUsb) */
|
||||
//#define USB_ENABLE_SERIAL
|
||||
#define HAVE_USBSTACK
|
||||
//#define HAVE_BOOTLOADER_USB_MODE
|
||||
#define HAVE_USB_HID_MOUSE
|
||||
#define USB_VENDOR_ID 0x05AC
|
||||
#define USB_PRODUCT_ID 0x1260
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ No access to the NAND yet..
|
|||
|
||||
#define CONFIG_USBOTG USBOTG_JZ4740
|
||||
#define HAVE_USBSTACK
|
||||
#define HAVE_BOOTLOADER_USB_MODE
|
||||
/* Connect by events, not by tick polling */
|
||||
#define USB_STATUS_BY_EVENT
|
||||
|
||||
|
|
|
|||
|
|
@ -157,7 +157,8 @@
|
|||
|
||||
#define CONFIG_USBOTG USBOTG_ISP1583
|
||||
#define HAVE_USBSTACK
|
||||
#define USB_VENDOR_ID 0x041e
|
||||
//#define HAVE_BOOTLOADER_USB_MODE
|
||||
#define USB_VENDOR_ID 0x041e
|
||||
#define USB_PRODUCT_ID 0x4133
|
||||
#define USB_NUM_ENDPOINTS 7
|
||||
|
||||
|
|
|
|||
|
|
@ -158,7 +158,8 @@
|
|||
|
||||
#define CONFIG_USBOTG USBOTG_ISP1583
|
||||
#define HAVE_USBSTACK
|
||||
#define USB_VENDOR_ID 0x041e
|
||||
//#define HAVE_BOOTLOADER_USB_MODE
|
||||
#define USB_VENDOR_ID 0x041e
|
||||
#define USB_PRODUCT_ID 0x4133
|
||||
#define USB_NUM_ENDPOINTS 7
|
||||
|
||||
|
|
|
|||
|
|
@ -158,7 +158,8 @@
|
|||
/* #define CONFIG_USBOTG USBOTG_ISP1761 */
|
||||
#define CONFIG_USBOTG USBOTG_ISP1583
|
||||
#define HAVE_USBSTACK
|
||||
#define USB_VENDOR_ID 0x041e
|
||||
//#define HAVE_BOOTLOADER_USB_MODE
|
||||
#define USB_VENDOR_ID 0x041e
|
||||
#define USB_PRODUCT_ID 0x4133
|
||||
#define USB_NUM_ENDPOINTS 7
|
||||
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@ struct sdmmc_host
|
|||
struct mutex lock;
|
||||
|
||||
/* Bus & device state flags; must only be accessed with lock held */
|
||||
bool enabled : 1;
|
||||
bool need_reset : 1;
|
||||
bool powered : 1;
|
||||
bool initialized : 1;
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@
|
|||
* mass storage mode, it will require exclusive access to the disk and ask all
|
||||
* threads to release any file handle and stop using the disks. It does so by
|
||||
* broadcasting a SYS_USB_CONNECTED message, which threads must acknowledge using
|
||||
* usb_acknowledge(SYS_USB_CONNECTED_ACK). They must not access the disk until
|
||||
* SYS_USB_DISCONNECTED is broadcast. To ease waiting, threads can call
|
||||
* usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data). They must not access the disk
|
||||
* until SYS_USB_DISCONNECTED is broadcast. To ease waiting, threads can call
|
||||
* usb_wait_for_disconnect() or usb_wait_for_disconnect_w_tmo() on their waiting
|
||||
* queue.
|
||||
*
|
||||
|
|
@ -119,6 +119,7 @@ enum
|
|||
USB_NOTIFY_SET_ADDR, /* Event */
|
||||
USB_NOTIFY_SET_CONFIG, /* Event */
|
||||
USB_NOTIFY_BUS_RESET, /* Event */
|
||||
USB_NOTIFY_CLASS_DRIVER, /* Event - notify_event() of specified class driver */
|
||||
#endif
|
||||
#ifdef USB_FIREWIRE_HANDLING
|
||||
USB_REQUEST_REBOOT, /* Event */
|
||||
|
|
@ -189,16 +190,14 @@ struct usb_transfer_completion_event_data
|
|||
void usb_init(void) INIT_ATTR;
|
||||
/* target must implement this to enable/disable the usb transceiver/core */
|
||||
void usb_enable(bool on);
|
||||
/* when one or more driver requires exclusive mode, this is called after all threads have acknowledged
|
||||
* exclusive mode and disk have been umounted; otherwise it is called immediately after host has
|
||||
* been detected */
|
||||
/* called after host has been detected */
|
||||
void usb_attach(void);
|
||||
/* enable usb detection monitoring; before this function is called, all usb
|
||||
* detection changes are ignored */
|
||||
void usb_start_monitoring(void) INIT_ATTR;
|
||||
void usb_close(void);
|
||||
/* acknowledge usb connection, typically with SYS_USB_CONNECTED_ACK */
|
||||
void usb_acknowledge(long id);
|
||||
void usb_acknowledge(long id, intptr_t seqnum);
|
||||
/* block the current thread until SYS_USB_DISCONNECTED has been broadcast */
|
||||
void usb_wait_for_disconnect(struct event_queue *q);
|
||||
/* same as usb_wait_for_disconnect() but with a timeout, returns 1 on timeout */
|
||||
|
|
@ -240,18 +239,34 @@ void usb_set_mode(int mode);
|
|||
/* USB driver call this function to notify that a transfer has completed */
|
||||
void usb_signal_transfer_completion(
|
||||
struct usb_transfer_completion_event_data *event_data);
|
||||
|
||||
/* Clear all signaled transfer completion events from event queue */
|
||||
void usb_clear_pending_transfer_completion_events(void);
|
||||
|
||||
/* notify the USB code that some important event has occurred which influences the
|
||||
* USB state (like USB_NOTIFY_SET_ADDR). USB drivers should call usb_core_notify_*
|
||||
* functions and not this function. */
|
||||
* functions and not this function.
|
||||
* for USB_NOTIFY_CLASS_DRIVER, use usb_signal_class_notify() instead */
|
||||
void usb_signal_notify(long id, intptr_t data);
|
||||
|
||||
/* wrapper for usb_signal_notify(USB_NOTIFY_CLASS_DRIVER)
|
||||
* class_num: target driver. USB_DRIVER_*
|
||||
* data: optional data. note that its upper 8 bits will be masked */
|
||||
static inline void usb_signal_class_notify(int8_t class_num, uint32_t data) {
|
||||
usb_signal_notify(USB_NOTIFY_CLASS_DRIVER, class_num << 24 | (data & 0x00ffffff));
|
||||
}
|
||||
|
||||
/* returns whether a USB_DRIVER_* is enabled (like HID, mass storage, ...) */
|
||||
bool usb_driver_enabled(int driver);
|
||||
/* returns whether exclusive storage is available for USB */
|
||||
bool usb_exclusive_storage(void);
|
||||
#endif /* HAVE_USBSTACK */
|
||||
|
||||
/* broadcast usb insertion event to enable exclusive storage */
|
||||
void usb_request_exclusive_storage(void);
|
||||
/* finish exclusive storage access if enabled and mount volumes */
|
||||
void usb_release_exclusive_storage(void);
|
||||
|
||||
#ifdef USB_FIREWIRE_HANDLING
|
||||
bool firewire_detect(void);
|
||||
void usb_firewire_connect_event(void);
|
||||
|
|
|
|||
|
|
@ -56,11 +56,12 @@ void usb_core_control_complete(int status);
|
|||
void usb_core_legacy_control_request(struct usb_ctrlrequest* req);
|
||||
void usb_core_transfer_complete(int endpoint,int dir,int status,int length);
|
||||
void usb_core_bus_reset(void);
|
||||
bool usb_core_any_exclusive_storage(void);
|
||||
void usb_core_enable_driver(int driver,bool enabled);
|
||||
bool usb_core_driver_enabled(int driver);
|
||||
#ifdef HAVE_USBSTACK
|
||||
void usb_core_handle_transfer_completion(
|
||||
struct usb_transfer_completion_event_data* event);
|
||||
#endif
|
||||
void usb_core_handle_notify(long id, intptr_t data);
|
||||
/* For controllers which handle SET ADDR and/or SET CONFIG in hardware */
|
||||
void usb_core_notify_set_address(uint8_t addr);
|
||||
|
|
@ -71,4 +72,3 @@ void usb_core_hotswap_event(int volume,bool inserted);
|
|||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
50
firmware/include/elf-target.h
Normal file
50
firmware/include/elf-target.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2026 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef __ELF_TARGET_H__
|
||||
#define __ELF_TARGET_H__
|
||||
|
||||
#include "elf.h"
|
||||
#include "config.h"
|
||||
|
||||
#define TARGET_ELF_CLASS ELFCLASS32
|
||||
#define TARGET_ELF_OSABI ELFOSABI_SYSV
|
||||
#define TARGET_ELF_ABIVERSION 0
|
||||
#define elf_phdr elf32_phdr
|
||||
|
||||
#if defined(CPU_ARM)
|
||||
# define TARGET_ELF_MACHINE EM_ARM
|
||||
#elif defined(CPU_MIPS)
|
||||
# define TARGET_ELF_MACHINE EM_MIPS
|
||||
#elif defined(CPU_COLDFIRE)
|
||||
# define TARGET_ELF_MACHINE EM_68K
|
||||
#else
|
||||
# error "Unknown CPU architecture!"
|
||||
#endif
|
||||
|
||||
#if defined(ROCKBOX_LITTLE_ENDIAN)
|
||||
# define TARGET_ELF_DATA ELFDATA2LSB
|
||||
#elif defined(ROCKBOX_BIG_ENDIAN)
|
||||
# define TARGET_ELF_DATA ELFDATA2MSB
|
||||
#else
|
||||
# error "Unknown endianness!"
|
||||
#endif
|
||||
|
||||
#endif /* __ELF_TARGET_H__ */
|
||||
143
firmware/include/elf.h
Normal file
143
firmware/include/elf.h
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2026 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef __ELF_H__
|
||||
#define __ELF_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Field offsets in the e_ident array */
|
||||
#define EI_MAG0 0
|
||||
#define EI_MAG1 1
|
||||
#define EI_MAG2 2
|
||||
#define EI_MAG3 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define EI_VERSION 6
|
||||
#define EI_OSABI 7
|
||||
#define EI_ABIVERSION 8
|
||||
#define EI_PAD 9
|
||||
#define EI_NIDENT 16
|
||||
|
||||
/* Values for ei_magic */
|
||||
#define ELFMAG0 0x7f
|
||||
#define ELFMAG1 'E'
|
||||
#define ELFMAG2 'L'
|
||||
#define ELFMAG3 'F'
|
||||
|
||||
/* Values for ei_class */
|
||||
#define ELFCLASSNONE 0
|
||||
#define ELFCLASS32 1
|
||||
#define ELFCLASS64 2
|
||||
|
||||
/* Values for ei_data */
|
||||
#define ELFDATANONE 0
|
||||
#define ELFDATA2LSB 1
|
||||
#define ELFDATA2MSB 2
|
||||
|
||||
/* Values for ei_version and e_version */
|
||||
#define EV_NONE 0
|
||||
#define EV_CURRENT 1
|
||||
|
||||
/* Values for ei_osabi */
|
||||
#define ELFOSABI_NONE ELFOSABI_SYSV
|
||||
#define ELFOSABI_SYSV 0
|
||||
|
||||
/* Values for e_type */
|
||||
#define ET_NONE 0
|
||||
#define ET_REL 1
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
#define ET_CORE 4
|
||||
|
||||
/* Values for e_machine */
|
||||
#define EM_NONE 0
|
||||
#define EM_68K 4
|
||||
#define EM_MIPS 8
|
||||
#define EM_ARM 40
|
||||
|
||||
/*
|
||||
* Special value for e_phnum when the real number of
|
||||
* program headers is too large.
|
||||
*/
|
||||
#define PN_XNUM 0xFFFFu
|
||||
|
||||
/* ELF basic types */
|
||||
typedef uint32_t elf_addr_t;
|
||||
typedef uint32_t elf_off_t;
|
||||
|
||||
/* ELF file header */
|
||||
struct elf_header
|
||||
{
|
||||
union {
|
||||
uint8_t e_ident[EI_NIDENT];
|
||||
struct {
|
||||
uint8_t ei_magic[4];
|
||||
uint8_t ei_class;
|
||||
uint8_t ei_data;
|
||||
uint8_t ei_version;
|
||||
uint8_t ei_osabi;
|
||||
uint8_t ei_abiversion;
|
||||
};
|
||||
};
|
||||
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
elf_addr_t e_entry;
|
||||
elf_off_t e_phoff;
|
||||
elf_off_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
};
|
||||
|
||||
/* Values for p_type */
|
||||
#define PT_NULL 0
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define PT_NOTE 4
|
||||
#define PT_SHLIB 5
|
||||
#define PT_PHDR 6
|
||||
|
||||
/* Values for p_flags */
|
||||
#define PF_X (1 << 0) /* Segment is executable */
|
||||
#define PF_W (1 << 1) /* Segment is writable */
|
||||
#define PF_R (1 << 2) /* Segment is readable */
|
||||
|
||||
/* ELF 32-bit program header */
|
||||
struct elf32_phdr
|
||||
{
|
||||
uint32_t p_type;
|
||||
elf_off_t p_offset;
|
||||
elf_addr_t p_vaddr;
|
||||
elf_addr_t p_paddr;
|
||||
uint32_t p_filesz;
|
||||
uint32_t p_memsz;
|
||||
uint32_t p_flags;
|
||||
uint32_t p_align;
|
||||
};
|
||||
|
||||
#endif /* __ELF_H__ */
|
||||
115
firmware/include/elf_loader.h
Normal file
115
firmware/include/elf_loader.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2026 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef __ELF_LOADER_H__
|
||||
#define __ELF_LOADER_H__
|
||||
|
||||
/*
|
||||
* Primitive ELF loader -- allows loading an ELF binary from
|
||||
* a file descriptor into RAM. Only static binaries linked at
|
||||
* a fixed address are supported.
|
||||
*
|
||||
* The caller supplies a memory map which limits where the
|
||||
* ELF file can be loaded; if a program header requests any
|
||||
* memory outside of this mapping, loading will fail. There
|
||||
* is no support for relocation, PIC code, or any form of
|
||||
* dynamic linking.
|
||||
*
|
||||
* The loader can return the entry point of the ELF binary.
|
||||
* It does not support arbitrary symbol lookups.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
enum elf_error
|
||||
{
|
||||
ELF_OK,
|
||||
ELF_ERR_FILE_NOT_FOUND,
|
||||
ELF_ERR_IO,
|
||||
ELF_ERR_EMPTY,
|
||||
ELF_ERR_BADMAGIC,
|
||||
ELF_ERR_UNSUPP_ARCH,
|
||||
ELF_ERR_UNSUPP_OS,
|
||||
ELF_ERR_UNSUPP_VERSION,
|
||||
ELF_ERR_UNSUPP_TYPE,
|
||||
ELF_ERR_UNSUPP_FORMAT,
|
||||
ELF_ERR_UNSUPP_PHSIZE,
|
||||
ELF_ERR_TOO_MANY_PHDRS,
|
||||
ELF_ERR_UNSUPP_PHDR,
|
||||
ELF_ERR_INVALID_PHDR,
|
||||
ELF_ERR_MEM_INCOMPAT_FLAGS,
|
||||
ELF_ERR_MEM_UNMAPPED,
|
||||
};
|
||||
|
||||
/*
|
||||
* Describes an entry in the virtual memory map specified
|
||||
* when loading an ELF file.
|
||||
*
|
||||
* ELF segments must fit completely within a single entry
|
||||
* in the memory map. Segments crossing multiple mappings
|
||||
* are rejected even if the mappings are contiguous.
|
||||
*
|
||||
* A segment may also be rejected if it has flags (R/W/X)
|
||||
* not present in the corresponding memory map entry.
|
||||
*/
|
||||
struct elf_memory_map
|
||||
{
|
||||
uintptr_t addr;
|
||||
size_t size;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct elf_load_context
|
||||
{
|
||||
const struct elf_memory_map *mmap;
|
||||
size_t num_mmap;
|
||||
};
|
||||
|
||||
typedef int (*elf_read_callback_t) (intptr_t arg, off_t pos, void *buf, size_t size);
|
||||
|
||||
int elf_load(elf_read_callback_t read_cb,
|
||||
intptr_t read_arg,
|
||||
const struct elf_load_context *ctx,
|
||||
void **entrypoint);
|
||||
|
||||
int elf_loadfd(int fd,
|
||||
const struct elf_load_context *ctx,
|
||||
void **entrypoint);
|
||||
int elf_read_fd_callback(intptr_t fd, off_t pos, void *buf, size_t size);
|
||||
|
||||
int elf_loadpath(const char *filename,
|
||||
const struct elf_load_context *ctx,
|
||||
void **entrypoint);
|
||||
|
||||
struct elf_loadmem_state
|
||||
{
|
||||
const void *buffer;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
int elf_loadmem(const void *elf_buffer,
|
||||
size_t elf_size,
|
||||
const struct elf_load_context *ctx,
|
||||
void **entrypoint);
|
||||
int elf_read_mem_callback(intptr_t loadmem_state, off_t pos, void *buf, size_t size);
|
||||
|
||||
#endif /* __ELF_LOADER_H__ */
|
||||
|
|
@ -32,7 +32,36 @@ CM_NVIC @ 0xe000e000 : block {
|
|||
|
||||
// System control block
|
||||
CM_SCB @ 0xe000ed00 : block {
|
||||
ICSR @ 0x04 : reg {
|
||||
-- 31 NMIPENDSET
|
||||
-- 28 PENDSVSET
|
||||
-- 27 PENDSVCLR
|
||||
-- 26 PENDSTSET
|
||||
-- 25 PENDSTCLR
|
||||
-- 23 ISRPREEMPT
|
||||
-- 22 ISRPENDING
|
||||
20 12 VECTPENDING
|
||||
-- 11 RETTOBASE
|
||||
08 00 VECTACTIVE
|
||||
}
|
||||
|
||||
VTOR @ 0x08 : reg
|
||||
|
||||
AIRCR @ 0x0c : reg {
|
||||
31 16 VECTKEY : { 0x05FA = KEY }
|
||||
-- 15 ENDIANNESS : { 0 = LITTLE; 1 = BIG }
|
||||
10 08 PRIGROUP
|
||||
-- 02 SYSRESETREQ
|
||||
-- 01 VECTCLRACTIVE
|
||||
-- 00 VECTRESET
|
||||
}
|
||||
|
||||
SCR @ 0x10 : reg {
|
||||
4 SEVONPEND
|
||||
2 SLEEPDEEP
|
||||
1 SLEEPONEXIT
|
||||
}
|
||||
|
||||
CCR @ 0x14 : reg {
|
||||
18 BP
|
||||
17 IC
|
||||
|
|
@ -41,9 +70,79 @@ CM_SCB @ 0xe000ed00 : block {
|
|||
08 BFHFNMIGN
|
||||
04 DIV_0_TRP
|
||||
03 UNALIGN_TRP
|
||||
01 USERETMPEND
|
||||
01 USERSETMPEND
|
||||
00 NONBASETHRDENA
|
||||
}
|
||||
|
||||
SHPR1 @ 0x18 : reg {
|
||||
23 16 PRI_USAGEFAULT
|
||||
15 08 PRI_BUSFAULT
|
||||
07 00 PRI_MEMMANAGE
|
||||
}
|
||||
|
||||
SHPR2 @ 0x1c : reg {
|
||||
31 24 PRI_SVCALL
|
||||
}
|
||||
|
||||
SHPR3 @ 0x20 : reg {
|
||||
31 24 PRI_SYSTICK
|
||||
23 16 PRI_PENDSV
|
||||
07 00 PRI_DEBUGMONITOR
|
||||
}
|
||||
|
||||
SHCSR @ 0x24 : reg {
|
||||
18 USGFAULTENA
|
||||
17 BUSFAULTENA
|
||||
16 MEMFAULTENA
|
||||
15 SVCALLPENDED
|
||||
14 BUSFAULTPENDED
|
||||
13 MEMFAULTPENDED
|
||||
12 USGFAULTPENDED
|
||||
11 SYSTICKACT
|
||||
10 PENDSVACT
|
||||
08 MONITORACT
|
||||
07 SVCALLACT
|
||||
03 USGFAULTACT
|
||||
01 BUSFAULTACT
|
||||
00 MEMFAULTACT
|
||||
}
|
||||
|
||||
CFSR @ 0x28 : reg {
|
||||
// UFSR bits
|
||||
25 DIVBYZERO
|
||||
24 UNALIGNED
|
||||
19 NOCP
|
||||
18 INVPC
|
||||
17 INVSTATE
|
||||
16 UNDEFINSTR
|
||||
|
||||
// BFSR bits
|
||||
15 BFARVALID
|
||||
13 LSPERR
|
||||
12 STKERR
|
||||
11 UNSTKERR
|
||||
10 IMPRECISERR
|
||||
09 PRECISERR
|
||||
08 IBUSERR
|
||||
|
||||
// MMSR bits
|
||||
07 MMARVALID
|
||||
05 MLSPERR
|
||||
04 MSTKERR
|
||||
03 MUNSTKERR
|
||||
01 DACCVIOL
|
||||
00 IACCVIOL
|
||||
}
|
||||
|
||||
HFSR @ 0x2c : reg {
|
||||
31 DEBUGEVT
|
||||
30 FORCED
|
||||
01 VECTTBL
|
||||
}
|
||||
|
||||
MMFAR @ 0x34 : reg
|
||||
BFAR @ 0x38 : reg
|
||||
CPACR @ 0x88 : reg
|
||||
}
|
||||
|
||||
// System timer
|
||||
|
|
|
|||
|
|
@ -254,6 +254,20 @@ RCC @ 0x58024400 : block {
|
|||
0 LSION
|
||||
}
|
||||
|
||||
RSR @ 0xd0 : reg {
|
||||
30 LPWRRSTF
|
||||
28 WWDG1RSTF
|
||||
26 IWDGRSTF
|
||||
24 SFTRSTF
|
||||
23 PORRSTF
|
||||
22 PINRSTF
|
||||
21 BORRSTF
|
||||
20 D2RSTF
|
||||
19 D1RSTF
|
||||
17 CPURSTF
|
||||
16 RMVF
|
||||
}
|
||||
|
||||
AHB1ENR @ 0xd8 : reg {
|
||||
28 USB2OTGHSULPIEN
|
||||
27 USB2OTGHSEN
|
||||
|
|
@ -587,6 +601,10 @@ RTC @ 0x58004000 : block {
|
|||
14 00 PREDIV_S
|
||||
}
|
||||
|
||||
WUTR @ 0x14 : reg {
|
||||
15 00 VALUE
|
||||
}
|
||||
|
||||
WPR @ 0x24 : reg {
|
||||
07 00 KEY : { 0xCA = KEY1; 0x53 = KEY2 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ static bool scroll_process_message(int delay)
|
|||
case SYS_TIMEOUT:
|
||||
return false;
|
||||
case SYS_USB_CONNECTED:
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
usb_wait_for_disconnect(&scroll_queue);
|
||||
sync_display_ticks();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ static void NORETURN_ATTR storage_thread(void)
|
|||
storage_event_send(CONFIG_STORAGE, ev.id, (intptr_t)&bdcast);
|
||||
usb_mode = ev.id == SYS_USB_CONNECTED;
|
||||
if (usb_mode) {
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
}
|
||||
else {
|
||||
bdcast = CONFIG_STORAGE;
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ static void piezo_thread(void)
|
|||
/*logf("USB: Piezo core");*/
|
||||
piezo_hw_stop();
|
||||
queue_clear(&piezo_queue);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
usb_wait_for_disconnect(&piezo_queue);
|
||||
break ;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -197,11 +197,6 @@ void usb_enable(bool on)
|
|||
|
||||
void usb_attach(void)
|
||||
{
|
||||
#if defined(IPOD_VIDEO)
|
||||
/* FIXME: Some iPod Video's need this 2nd call of usb_drv_init() to establish
|
||||
* an USB connection. */
|
||||
usb_drv_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool usb_plugged(void)
|
||||
|
|
|
|||
|
|
@ -34,13 +34,13 @@ static int dma_used = 0;
|
|||
/* Status flags */
|
||||
#define STATUS_CHANNEL_ACTIVE (1<<0)
|
||||
|
||||
static struct dma_channel_state
|
||||
static struct dma_channel_state
|
||||
{
|
||||
volatile unsigned status;
|
||||
void (*callback)(void);
|
||||
} dma_state [NUM_CHANNELS];
|
||||
|
||||
struct dma_channel_regs
|
||||
struct dma_channel_regs
|
||||
{
|
||||
volatile unsigned long disrc;
|
||||
volatile unsigned long disrcc;
|
||||
|
|
@ -51,7 +51,7 @@ struct dma_channel_regs
|
|||
volatile unsigned long dcsrc;
|
||||
volatile unsigned long dcdst;
|
||||
volatile unsigned long dmasktrig;
|
||||
volatile unsigned long reserved [7]; /* pad to 0x40 bytes */
|
||||
volatile unsigned long reserved [7]; /* pad to 0x40 bytes */
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ struct dma_channel_regs *dma_regs [4] =
|
|||
(struct dma_channel_regs *) &DISRC1,
|
||||
(struct dma_channel_regs *) &DISRC2,
|
||||
(struct dma_channel_regs *) &DISRC3
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ void dma_init(void)
|
|||
/* Clear pending source */
|
||||
SRCPND = DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK;
|
||||
INTPND = DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK;
|
||||
|
||||
|
||||
/* Enable interrupt in controller */
|
||||
bitclr32(&INTMOD, DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK);
|
||||
bitclr32(&INTMSK, DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK);
|
||||
|
|
@ -101,15 +101,15 @@ void dma_release(void)
|
|||
}
|
||||
|
||||
|
||||
inline void dma_disable_channel(int channel)
|
||||
void dma_disable_channel(int channel)
|
||||
{
|
||||
struct dma_channel_regs *regs = dma_regs [channel];
|
||||
|
||||
struct dma_channel_regs *regs = dma_regs [channel];
|
||||
|
||||
/* disable the specified channel */
|
||||
|
||||
|
||||
/* Reset the channel */
|
||||
regs->dmasktrig |= DMASKTRIG_STOP;
|
||||
|
||||
|
||||
/* Wait for DMA controller to be ready */
|
||||
while(regs->dmasktrig & DMASKTRIG_ON)
|
||||
;
|
||||
|
|
@ -120,35 +120,35 @@ inline void dma_disable_channel(int channel)
|
|||
void dma_enable_channel(int channel, struct dma_request *request)
|
||||
{
|
||||
struct dma_channel_regs *regs = dma_regs [channel];
|
||||
|
||||
|
||||
/* TODO - transfer sizes (assumes word) */
|
||||
|
||||
|
||||
if (DMA_GET_SRC(request->source_map, channel) == DMA_INVALID)
|
||||
panicf ("DMA: invalid channel");
|
||||
|
||||
|
||||
/* setup a transfer on specified channel */
|
||||
dma_disable_channel (channel);
|
||||
|
||||
dma_disable_channel(channel);
|
||||
|
||||
if((unsigned long)request->source_addr < UNCACHED_BASE_ADDR)
|
||||
regs->disrc = (unsigned long)request->source_addr + UNCACHED_BASE_ADDR;
|
||||
else
|
||||
regs->disrc = (unsigned long)request->source_addr;
|
||||
regs->disrcc = request->source_control;
|
||||
|
||||
|
||||
if((unsigned long)request->dest_addr < UNCACHED_BASE_ADDR)
|
||||
regs->didst = (unsigned long)request->dest_addr + UNCACHED_BASE_ADDR;
|
||||
else
|
||||
regs->didst = (unsigned long)request->dest_addr;
|
||||
regs->didstc = request->dest_control;
|
||||
|
||||
regs->dcon = request->control | request->count |
|
||||
|
||||
regs->dcon = request->control | request->count |
|
||||
DMA_GET_SRC(request->source_map, channel) * DCON_HWSRCSEL;
|
||||
|
||||
dma_state [channel].callback = request->callback;
|
||||
|
||||
|
||||
/* Activate the channel */
|
||||
commit_discard_dcache_range((void *)request->dest_addr, request->count * 4);
|
||||
|
||||
|
||||
dma_state [channel].status |= STATUS_CHANNEL_ACTIVE;
|
||||
regs->dmasktrig = DMASKTRIG_ON;
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ void dma_enable_channel(int channel, struct dma_request *request)
|
|||
/* Start DMA */
|
||||
regs->dmasktrig |= DMASKTRIG_SW_TRIG;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* ISRs */
|
||||
|
|
@ -168,7 +168,7 @@ static inline void generic_isr (unsigned channel)
|
|||
if (dma_state [channel].callback)
|
||||
/* call callback for relevant channel */
|
||||
dma_state [channel].callback();
|
||||
|
||||
|
||||
dma_state [channel].status &= ~STATUS_CHANNEL_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
#error Unsupported target
|
||||
#endif
|
||||
|
||||
struct dma_request
|
||||
struct dma_request
|
||||
{
|
||||
volatile void *source_addr;
|
||||
volatile void *dest_addr;
|
||||
|
|
@ -51,7 +51,7 @@ struct dma_request
|
|||
void dma_init(void);
|
||||
void dma_enable_channel(int channel, struct dma_request *request);
|
||||
|
||||
inline void dma_disable_channel(int channel);
|
||||
void dma_disable_channel(int channel);
|
||||
|
||||
void dma_retain(void);
|
||||
void dma_release(void);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___void
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___void
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
#include "system.h"
|
||||
#include "stdlib.h"
|
||||
#include "button.h"
|
||||
#include "tick.h"
|
||||
#include "touchscreen.h"
|
||||
|
||||
#define NO_OF_TOUCH_DATA 5
|
||||
|
|
@ -99,9 +100,9 @@ void touchscreen_scan_device()
|
|||
static int touch_data_index = 0;
|
||||
|
||||
int saveADCDLY;
|
||||
|
||||
/* check touch state */
|
||||
if(ADCDAT1 & (1<<15))
|
||||
|
||||
/* check touch state */
|
||||
if(ADCDAT1 & (1<<15))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -111,23 +112,23 @@ void touchscreen_scan_device()
|
|||
/* resets the index if the last touch could not be read 5 times */
|
||||
touch_data_index = 0;
|
||||
}
|
||||
|
||||
/* read touch data */
|
||||
|
||||
/* read touch data */
|
||||
saveADCDLY = ADCDLY;
|
||||
ADCDLY = 40000; /*delay ~0.8ms (1/50M)*4000 */
|
||||
ADCDLY = 40000; /*delay ~0.8ms (1/50M)*4000 */
|
||||
ADCTSC = (1<<3)|(1<<2); /* pullup disable, seq x,y pos measure */
|
||||
/* start adc */
|
||||
ADCCON|= 0x1;
|
||||
ADCCON|= 0x1;
|
||||
/* wait for start and end */
|
||||
while(ADCCON & 0x1);
|
||||
while(!(ADCCON & 0x8000));
|
||||
|
||||
x[touch_data_index] = ADCDAT0&0x3ff;
|
||||
y[touch_data_index] = ADCDAT1&0x3ff;
|
||||
|
||||
|
||||
ADCTSC = 0xd3; /* back to interrupt mode */
|
||||
ADCDLY = saveADCDLY;
|
||||
|
||||
|
||||
touch_data_index++;
|
||||
|
||||
if (touch_data_index > NO_OF_TOUCH_DATA - 1)
|
||||
|
|
@ -161,18 +162,18 @@ int touchscreen_read_device(int *data, int *old_data)
|
|||
/* sort the 5 data taken and use the median value */
|
||||
qsort(x, NO_OF_TOUCH_DATA, sizeof(short), short_cmp);
|
||||
qsort(y, NO_OF_TOUCH_DATA, sizeof(short), short_cmp);
|
||||
|
||||
|
||||
x_touch = last_x = x[(NO_OF_TOUCH_DATA - 1)/2];
|
||||
y_touch = last_y = y[(NO_OF_TOUCH_DATA - 1)/2];
|
||||
|
||||
|
||||
last_touch = current_tick;
|
||||
|
||||
|
||||
touch_hold = true;
|
||||
touch_available = false;
|
||||
}
|
||||
|
||||
|
||||
*old_data = *data = touch_to_pixels(x_touch, y_touch);
|
||||
|
||||
|
||||
btn |= touchscreen_to_pixels((*data&0xffff0000) >> 16,
|
||||
(*data&0x0000ffff),
|
||||
data);
|
||||
|
|
@ -183,8 +184,6 @@ int touchscreen_read_device(int *data, int *old_data)
|
|||
/* put the touchscreen back into interrupt mode */
|
||||
touch_hold = false;
|
||||
}
|
||||
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -799,7 +799,7 @@ int sd_read_sectors(IF_MD(int card_no,) sector_t start, int incount,
|
|||
ret = 0; /* assume success */
|
||||
else
|
||||
#endif
|
||||
ret = sd_transfer_sectors(card_no, start, incount, inbuf, false);
|
||||
ret = sd_transfer_sectors(IF_MD_DRV(card_no), start, incount, inbuf, false);
|
||||
dbgprintf ("sd_read, ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -827,7 +827,7 @@ int sd_write_sectors(IF_MD(int drive,) sector_t start, int count,
|
|||
return 0; /* assume success */
|
||||
else
|
||||
#endif
|
||||
return sd_transfer_sectors(drive, start, count, (void*)outbuf, true);
|
||||
return sd_transfer_sectors(IF_MD_DRV(drive), start, count, (void*)outbuf, true);
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -1,70 +1,34 @@
|
|||
#include "cpu.h"
|
||||
|
||||
/*
|
||||
* TODO: this is temporary and has not been tested
|
||||
*/
|
||||
|
||||
ENTRY(main)
|
||||
ENTRY(crt0_start)
|
||||
OUTPUT_FORMAT(elf32-littlearm)
|
||||
OUTPUT_ARCH(arm)
|
||||
STARTUP(target/arm/stm32/crt0-stm32h7.o)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
SRAM_AXI (rwx) : ORIGIN = STM32_SRAM_AXI_BASE, LENGTH = STM32_SRAM_AXI_SIZE
|
||||
DTCM (rwx) : ORIGIN = STM32_DTCM_BASE, LENGTH = STM32_DTCM_SIZE
|
||||
ITCM (rwx) : ORIGIN = STM32_ITCM_BASE, LENGTH = STM32_ITCM_SIZE
|
||||
SDRAM (rwx) : ORIGIN = STM32_SDRAM1_BASE, LENGTH = MEMORYSIZE * 1024 * 1024
|
||||
DTCM (rw) : ORIGIN = STM32_DTCM_BASE, LENGTH = STM32_DTCM_SIZE
|
||||
ITCM (rx) : ORIGIN = STM32_ITCM_BASE, LENGTH = STM32_ITCM_SIZE
|
||||
SRAM_AXI (rw) : ORIGIN = STM32_SRAM_AXI_BASE, LENGTH = STM32_SRAM_AXI_SIZE
|
||||
SDRAM (rwx) : ORIGIN = STM32_SDRAM1_BASE, LENGTH = MEMORYSIZE * 1024 * 1024
|
||||
}
|
||||
|
||||
/*
|
||||
* to control section alignment (only affects on-disk alignment):
|
||||
* -Wl,-z,max-page-size=0x1
|
||||
*/
|
||||
|
||||
PHDRS
|
||||
{
|
||||
sram_rx PT_LOAD ;
|
||||
sram_ro PT_LOAD ;
|
||||
sram_rw PT_LOAD ;
|
||||
itcm PT_LOAD ;
|
||||
dtcm PT_LOAD ;
|
||||
sdram_rx PT_LOAD ;
|
||||
sdram_rw PT_LOAD ;
|
||||
itcm PT_LOAD;
|
||||
sdram PT_LOAD;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
loadaddress = .; /* only needed to keep ROLO happy */
|
||||
|
||||
KEEP(*(.bootdata))
|
||||
*(.init.text*)
|
||||
*(.text*)
|
||||
} > SRAM_AXI :sram_rx
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata*)
|
||||
} > SRAM_AXI :sram_ro
|
||||
|
||||
.data :
|
||||
{
|
||||
_databegin = .;
|
||||
*(.data*)
|
||||
_dataend = .;
|
||||
} > SRAM_AXI :sram_rw
|
||||
_datacopy = LOADADDR(.data);
|
||||
|
||||
.itext :
|
||||
{
|
||||
KEEP(*(.vectors.arm))
|
||||
KEEP(*(.vectors.platform))
|
||||
KEEP(*(.vectors.arm));
|
||||
KEEP(*(.vectors.platform));
|
||||
*(.icode*);
|
||||
} > ITCM :itcm
|
||||
|
||||
.stack (NOLOAD) :
|
||||
.stack (NOLOAD) : ALIGN(8)
|
||||
{
|
||||
irqstackbegin = .;
|
||||
. += 0x400;
|
||||
|
|
@ -73,9 +37,30 @@ SECTIONS
|
|||
stackbegin = .;
|
||||
. += 0x2000;
|
||||
stackend = .;
|
||||
} > DTCM :NONE
|
||||
|
||||
*(.stack);
|
||||
} > DTCM :dtcm
|
||||
.framebuffer (NOLOAD) :
|
||||
{
|
||||
*(.framebuffer);
|
||||
} > SRAM_AXI :NONE
|
||||
|
||||
.text :
|
||||
{
|
||||
loadaddress = .; /* only needed to keep ROLO happy */
|
||||
|
||||
*(.init*);
|
||||
*(.text*);
|
||||
} > SDRAM :sdram
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata*);
|
||||
} > SDRAM :sdram
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.data*);
|
||||
} > SDRAM :sdram
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
|
|
@ -83,7 +68,7 @@ SECTIONS
|
|||
*(.bss*);
|
||||
*(COMMON);
|
||||
_bssend = .;
|
||||
} > SDRAM :sdram_rw
|
||||
} > SDRAM :sdram
|
||||
|
||||
audiobuffer = ALIGN(32);
|
||||
audiobufend = ORIGIN(SDRAM) + LENGTH(SDRAM) - CODEC_SIZE - PLUGIN_BUFFER_SIZE;
|
||||
|
|
|
|||
|
|
@ -7,26 +7,29 @@ STARTUP(target/arm/stm32/crt0-stm32h7.o)
|
|||
|
||||
MEMORY
|
||||
{
|
||||
SRAM_AXI (rwx) : ORIGIN = STM32_SRAM_AXI_BASE, LENGTH = STM32_SRAM_AXI_SIZE
|
||||
DTCM (rwx) : ORIGIN = STM32_DTCM_BASE, LENGTH = STM32_DTCM_SIZE
|
||||
FLASH1 (rx) : ORIGIN = STM32_FLASH_BANK1_BASE, LENGTH = STM32_FLASH_BANK1_SIZE
|
||||
SRAM_AXI (rw) : ORIGIN = STM32_SRAM_AXI_BASE, LENGTH = STM32_SRAM_AXI_SIZE
|
||||
FLASH1 (rx) : ORIGIN = STM32_FLASH_BANK1_BASE, LENGTH = STM32_FLASH_BANK1_SIZE
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.vectors.arm))
|
||||
KEEP(*(.vectors.platform))
|
||||
*(.init.text*)
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
KEEP(*(.vectors.arm));
|
||||
KEEP(*(.vectors.platform));
|
||||
*(.init*);
|
||||
*(.text*);
|
||||
} > FLASH1
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata*);
|
||||
} > FLASH1
|
||||
|
||||
.data :
|
||||
{
|
||||
_databegin = .;
|
||||
*(.data*)
|
||||
*(.data*);
|
||||
_dataend = .;
|
||||
} > SRAM_AXI AT> FLASH1
|
||||
_datacopy = LOADADDR(.data);
|
||||
|
|
@ -39,7 +42,7 @@ SECTIONS
|
|||
_bssend = .;
|
||||
} > SRAM_AXI
|
||||
|
||||
.stack (NOLOAD) : ALIGN(4)
|
||||
.stack (NOLOAD) : ALIGN(8)
|
||||
{
|
||||
irqstackbegin = .;
|
||||
. += 0x400;
|
||||
|
|
@ -48,9 +51,12 @@ SECTIONS
|
|||
stackbegin = .;
|
||||
. += 0x2000;
|
||||
stackend = .;
|
||||
} > SRAM_AXI
|
||||
|
||||
*(.stack);
|
||||
} > DTCM
|
||||
.framebuffer (NOLOAD) :
|
||||
{
|
||||
*(.framebuffer);
|
||||
} > SRAM_AXI
|
||||
}
|
||||
|
||||
EXTERN(__vectors_arm);
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2025 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "clock-stm32h7.h"
|
||||
#include "mutex.h"
|
||||
#include "panic.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct stm_clock_state
|
||||
{
|
||||
struct mutex mutex;
|
||||
uint8_t refcount[STM_NUM_CLOCKS];
|
||||
};
|
||||
|
||||
static struct stm_clock_state stm_clocks;
|
||||
|
||||
void stm_clock_init(void)
|
||||
{
|
||||
mutex_init(&stm_clocks.mutex);
|
||||
|
||||
stm_target_clock_init();
|
||||
}
|
||||
|
||||
void stm_clock_enable(enum stm_clock clock)
|
||||
{
|
||||
mutex_lock(&stm_clocks.mutex);
|
||||
|
||||
if (stm_clocks.refcount[clock] == UINT8_MAX)
|
||||
panicf("%s: clock %d overflow", __func__, (int)clock);
|
||||
|
||||
if (stm_clocks.refcount[clock]++ == 0)
|
||||
stm_target_clock_enable(clock, true);
|
||||
|
||||
mutex_unlock(&stm_clocks.mutex);
|
||||
}
|
||||
|
||||
void stm_clock_disable(enum stm_clock clock)
|
||||
{
|
||||
mutex_lock(&stm_clocks.mutex);
|
||||
|
||||
if (stm_clocks.refcount[clock] == 0)
|
||||
panicf("%s: clock %d underflow", __func__, (int)clock);
|
||||
|
||||
if (--stm_clocks.refcount[clock] == 0)
|
||||
stm_target_clock_enable(clock, false);
|
||||
|
||||
mutex_unlock(&stm_clocks.mutex);
|
||||
}
|
||||
|
|
@ -25,65 +25,47 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum stm_clock
|
||||
struct stm32_clock
|
||||
{
|
||||
STM_CLOCK_SPI1_KER,
|
||||
STM_CLOCK_SPI2_KER,
|
||||
STM_CLOCK_SPI3_KER,
|
||||
STM_CLOCK_SPI4_KER,
|
||||
STM_CLOCK_SPI5_KER,
|
||||
STM_CLOCK_SPI6_KER,
|
||||
STM_CLOCK_LTDC_KER,
|
||||
STM_CLOCK_SDMMC1_KER,
|
||||
STM_CLOCK_SDMMC2_KER,
|
||||
STM_NUM_CLOCKS,
|
||||
uint32_t frequency;
|
||||
|
||||
uint32_t en_reg;
|
||||
uint32_t en_bit;
|
||||
|
||||
uint32_t lpen_reg;
|
||||
uint32_t lpen_bit;
|
||||
};
|
||||
|
||||
/*
|
||||
* Implemented by the target to initialize all oscillators,
|
||||
* system, CPU, and bus clocks that need to be enabled from
|
||||
* early boot.
|
||||
* Enables a clock by setting its enable bits in the RCC.
|
||||
*/
|
||||
void stm_target_clock_init(void) INIT_ATTR;
|
||||
static inline void stm32_clock_enable(const struct stm32_clock *clk)
|
||||
{
|
||||
if (clk->en_reg)
|
||||
*(volatile uint32_t *)clk->en_reg |= clk->en_bit;
|
||||
|
||||
if (clk->lpen_reg)
|
||||
*(volatile uint32_t *)clk->lpen_reg |= clk->lpen_bit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback to be implemented by the target when the hardware
|
||||
* clock needs to be turned on or off. Clocks are internally
|
||||
* reference counted so only the first / last user will change
|
||||
* the hardware state.
|
||||
*
|
||||
* Only clocks that are actually used need to be implemented,
|
||||
* and unless otherwise noted it is allowed for enable/disable
|
||||
* to be a no-op if the clock is always enabled.
|
||||
* Disables a clock in the RCC.
|
||||
*/
|
||||
void stm_target_clock_enable(enum stm_clock clock, bool enable);
|
||||
static inline void stm32_clock_disable(const struct stm32_clock *clk)
|
||||
{
|
||||
if (clk->en_reg)
|
||||
*(volatile uint32_t *)clk->en_reg &= ~clk->en_bit;
|
||||
|
||||
/*
|
||||
* Callback to return a specific clock's frequency. For most
|
||||
* peripherals the frequency must be known at initialization
|
||||
* and not change afterwards; see peripheral drivers for the
|
||||
* details, as their exact requirements may vary.
|
||||
*/
|
||||
size_t stm_target_clock_get_frequency(enum stm_clock clock);
|
||||
|
||||
/*
|
||||
* Called from system_init(). Sets up internal book-keeping
|
||||
* and then calls stm_target_clock_init().
|
||||
*/
|
||||
void stm_clock_init(void) INIT_ATTR;
|
||||
|
||||
/*
|
||||
* Enable or disable a clock. Not safe to call from an IRQ handler.
|
||||
*/
|
||||
void stm_clock_enable(enum stm_clock clock);
|
||||
void stm_clock_disable(enum stm_clock clock);
|
||||
if (clk->lpen_reg)
|
||||
*(volatile uint32_t *)clk->lpen_reg &= ~clk->lpen_bit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a clock's frequency in Hz.
|
||||
*/
|
||||
static inline size_t stm_clock_get_frequency(enum stm_clock clock)
|
||||
static inline uint32_t stm32_clock_get_frequency(const struct stm32_clock *clk)
|
||||
{
|
||||
return stm_target_clock_get_frequency(clock);
|
||||
return clk->frequency;
|
||||
}
|
||||
|
||||
#endif /* __CLOCK_STM32H7_H__ */
|
||||
|
|
|
|||
|
|
@ -19,19 +19,12 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
#include "config.h"
|
||||
#include "bootdata.h"
|
||||
#include "regs/stm32h743/pwr.h"
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
|
||||
#if defined(HAVE_BOOTDATA) && !defined(BOOTLOADER)
|
||||
.section .bootdata
|
||||
|
||||
put_boot_data_here
|
||||
#endif
|
||||
|
||||
.section .init.text,"ax",%progbits
|
||||
.section .init,"ax",%progbits
|
||||
|
||||
.global reset_handler
|
||||
.type reset_handler, function
|
||||
|
|
@ -59,9 +52,15 @@ reset_handler:
|
|||
b crt0_start
|
||||
|
||||
|
||||
.global start
|
||||
.type start, function
|
||||
.global crt0_start
|
||||
.type crt0_start, function
|
||||
crt0_start:
|
||||
#ifdef BOOTLOADER
|
||||
/*
|
||||
* Initialize data/bss for bootloader
|
||||
* (not needed on app since ELF loader takes care of it)
|
||||
*/
|
||||
|
||||
/* Zero out BSS */
|
||||
ldr a1, =_bssbegin
|
||||
ldr a2, =_bssend
|
||||
|
|
@ -73,6 +72,7 @@ crt0_start:
|
|||
ldr a2, =_dataend
|
||||
ldr a3, =_datacopy
|
||||
bl crt0_area_copy
|
||||
#endif
|
||||
|
||||
/* Clear the main thread stack */
|
||||
ldr a1, =stackbegin
|
||||
|
|
@ -103,6 +103,7 @@ crt0_start:
|
|||
b main
|
||||
|
||||
|
||||
#ifdef BOOTLOADER
|
||||
.local crt0_area_copy
|
||||
.type crt0_area_copy, function
|
||||
/* crt0_area_copy(uint32_t *dst, uint32_t *dst_end, const void *src) */
|
||||
|
|
@ -112,7 +113,7 @@ crt0_area_copy:
|
|||
strhi v1, [a1], #4
|
||||
bhi crt0_area_copy
|
||||
bx lr
|
||||
|
||||
#endif
|
||||
|
||||
.local crt0_area_clear
|
||||
.type crt0_area_clear, function
|
||||
|
|
|
|||
|
|
@ -32,14 +32,14 @@
|
|||
/* Flag to use VOS0 */
|
||||
#define STM32H743_USE_VOS0 (CPU_FREQ > 400000000)
|
||||
|
||||
static void init_hse(void)
|
||||
INIT_ATTR static void init_hse(void)
|
||||
{
|
||||
reg_writef(RCC_CR, HSEON(1));
|
||||
|
||||
while (!reg_readf(RCC_CR, HSERDY));
|
||||
}
|
||||
|
||||
static void init_pll(void)
|
||||
INIT_ATTR static void init_pll(void)
|
||||
{
|
||||
/* For simplicity, PLL parameters are hardcoded */
|
||||
_Static_assert(STM32_HSE_FREQ == 24000000,
|
||||
|
|
@ -97,7 +97,7 @@ static void init_pll(void)
|
|||
while (!reg_readf(RCC_CR, PLL3RDY));
|
||||
}
|
||||
|
||||
static void init_vos(void)
|
||||
INIT_ATTR static void init_vos(void)
|
||||
{
|
||||
reg_writef(PWR_D3CR, VOS_V(VOS1));
|
||||
while (!reg_readf(PWR_D3CR, VOSRDY));
|
||||
|
|
@ -114,7 +114,7 @@ static void init_vos(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void init_system_clock(void)
|
||||
INIT_ATTR static void init_system_clock(void)
|
||||
{
|
||||
/* Enable HCLK /2 divider (CPU is at 480 MHz, HCLK limit is 240 MHz) */
|
||||
reg_writef(RCC_D1CFGR, HPRE(8));
|
||||
|
|
@ -134,7 +134,7 @@ static void init_system_clock(void)
|
|||
while (reg_readf(FLASH_ACR, LATENCY) != 4);
|
||||
}
|
||||
|
||||
static void init_lse(void)
|
||||
INIT_ATTR static void init_lse(void)
|
||||
{
|
||||
/*
|
||||
* Skip if LSE and RTC are already enabled.
|
||||
|
|
@ -161,7 +161,7 @@ static void init_lse(void)
|
|||
reg_writef(PWR_CR1, DBP(0));
|
||||
}
|
||||
|
||||
static void init_periph_clock(void)
|
||||
INIT_ATTR static void init_periph_clock(void)
|
||||
{
|
||||
reg_writef(RCC_D1CCIPR, SDMMCSEL_V(PLL1Q));
|
||||
reg_writef(RCC_D2CCIP1R, SPI45SEL_V(HSE));
|
||||
|
|
@ -170,7 +170,7 @@ static void init_periph_clock(void)
|
|||
reg_writef(RCC_AHB3LPENR, AXISRAMEN(1));
|
||||
}
|
||||
|
||||
void stm_target_clock_init(void)
|
||||
void echoplayer_clock_init(void)
|
||||
{
|
||||
init_hse();
|
||||
init_pll();
|
||||
|
|
@ -180,43 +180,26 @@ void stm_target_clock_init(void)
|
|||
init_periph_clock();
|
||||
}
|
||||
|
||||
void stm_target_clock_enable(enum stm_clock clock, bool enable)
|
||||
{
|
||||
switch (clock)
|
||||
{
|
||||
case STM_CLOCK_SPI5_KER:
|
||||
reg_writef(RCC_APB2ENR, SPI5EN(enable));
|
||||
reg_writef(RCC_APB2LPENR, SPI5EN(enable));
|
||||
break;
|
||||
const struct stm32_clock sdmmc1_ker_clock = {
|
||||
.frequency = PLL1Q_FREQ,
|
||||
.en_reg = ITA_RCC_AHB3ENR,
|
||||
.en_bit = BM_RCC_AHB3ENR_SDMMC1EN,
|
||||
.lpen_reg = ITA_RCC_AHB3LPENR,
|
||||
.lpen_bit = BM_RCC_AHB3LPENR_SDMMC1EN,
|
||||
};
|
||||
|
||||
case STM_CLOCK_LTDC_KER:
|
||||
reg_writef(RCC_APB3ENR, LTDCEN(enable));
|
||||
reg_writef(RCC_APB3LPENR, LTDCEN(enable));
|
||||
break;
|
||||
const struct stm32_clock ltdc_ker_clock = {
|
||||
.frequency = LCD_DOTCLOCK_FREQ,
|
||||
.en_reg = ITA_RCC_APB3ENR,
|
||||
.en_bit = BM_RCC_APB3ENR_LTDCEN,
|
||||
.lpen_reg = ITA_RCC_APB3LPENR,
|
||||
.lpen_bit = BM_RCC_APB3ENR_LTDCEN,
|
||||
};
|
||||
|
||||
case STM_CLOCK_SDMMC1_KER:
|
||||
reg_writef(RCC_AHB3ENR, SDMMC1EN(enable));
|
||||
reg_writef(RCC_AHB3LPENR, SDMMC1EN(enable));
|
||||
break;
|
||||
|
||||
default:
|
||||
panicf("%s: unsupported clock %d", __func__, (int)clock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t stm_target_clock_get_frequency(enum stm_clock clock)
|
||||
{
|
||||
switch (clock)
|
||||
{
|
||||
case STM_CLOCK_SPI5_KER:
|
||||
return STM32_HSE_FREQ;
|
||||
|
||||
case STM_CLOCK_SDMMC1_KER:
|
||||
return PLL1Q_FREQ;
|
||||
|
||||
default:
|
||||
panicf("%s: unsupported clock %d", __func__, (int)clock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
const struct stm32_clock spi5_ker_clock = {
|
||||
.frequency = STM32_HSE_FREQ,
|
||||
.en_reg = ITA_RCC_APB2ENR,
|
||||
.en_bit = BM_RCC_APB2ENR_SPI5EN,
|
||||
.lpen_reg = ITA_RCC_APB2LPENR,
|
||||
.lpen_bit = BM_RCC_APB2ENR_SPI5EN,
|
||||
};
|
||||
|
|
|
|||
32
firmware/target/arm/stm32/echoplayer/clock-echoplayer.h
Normal file
32
firmware/target/arm/stm32/echoplayer/clock-echoplayer.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2026 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef __CLOCK_ECHOPLAYER_H__
|
||||
#define __CLOCK_ECHOPLAYER_H__
|
||||
|
||||
#include "clock-stm32h7.h"
|
||||
|
||||
void echoplayer_clock_init(void) INIT_ATTR;
|
||||
|
||||
extern struct stm32_clock sdmmc1_ker_clock;
|
||||
extern struct stm32_clock ltdc_ker_clock;
|
||||
extern struct stm32_clock spi5_ker_clock;
|
||||
|
||||
#endif /* __CLOCK_ECHOPLAYER_H__ */
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#include "kernel.h"
|
||||
#include "lcd.h"
|
||||
#include "lcd-echoplayer.h"
|
||||
#include "clock-echoplayer.h"
|
||||
#include "nvic-arm.h"
|
||||
#include "spi-stm32h7.h"
|
||||
#include "gpio-stm32h7.h"
|
||||
|
|
@ -30,6 +31,9 @@
|
|||
#include "regs/stm32h743/spi.h"
|
||||
#include "regs/stm32h743/ltdc.h"
|
||||
|
||||
#define MS_TO_TICKS(x) \
|
||||
(((x) + (1000 / HZ - 1)) / (1000 / HZ))
|
||||
|
||||
/*
|
||||
* ILI9342C specifies 10 MHz max
|
||||
*
|
||||
|
|
@ -38,9 +42,17 @@
|
|||
*/
|
||||
#define LCD_SPI_FREQ 12000000
|
||||
|
||||
#define ili_cmd(cmd, ...) \
|
||||
do { \
|
||||
uint16_t arr[] = {cmd, __VA_ARGS__}; \
|
||||
for (size_t i = 1; i < ARRAYLEN(arr); ++i) \
|
||||
arr[i] |= 0x100; \
|
||||
stm_spi_transmit(&spi, arr, sizeof(arr)); \
|
||||
} while (0)
|
||||
|
||||
struct stm_spi_config spi_cfg = {
|
||||
.instance = ITA_SPI5,
|
||||
.clock = STM_CLOCK_SPI5_KER,
|
||||
.clock = &spi5_ker_clock,
|
||||
.freq = LCD_SPI_FREQ,
|
||||
.mode = STM_SPIMODE_HALF_DUPLEX,
|
||||
.proto = STM_SPIPROTO_MOTOROLA,
|
||||
|
|
@ -50,18 +62,19 @@ struct stm_spi_config spi_cfg = {
|
|||
|
||||
struct stm_spi spi;
|
||||
|
||||
#define ili_cmd(cmd, ...) \
|
||||
do { \
|
||||
uint16_t arr[] = {cmd, __VA_ARGS__}; \
|
||||
for (size_t i = 1; i < ARRAYLEN(arr); ++i) \
|
||||
arr[i] |= 0x100; \
|
||||
stm_spi_transmit(&spi, arr, sizeof(arr)); \
|
||||
} while (0)
|
||||
enum lcd_controller_state
|
||||
{
|
||||
RESET, /* Controller in hardware reset, LTDC disabled */
|
||||
SLEEP, /* Controller in sleep-in mode, LTDC disabled */
|
||||
AWAKE, /* Controller in sleep-out mode, LTDC enabled */
|
||||
};
|
||||
|
||||
static void init_ltdc(void)
|
||||
static enum lcd_controller_state lcd_controller_state = RESET;
|
||||
|
||||
static void enable_ltdc(void)
|
||||
{
|
||||
/* Enable LTDC clock */
|
||||
stm_clock_enable(STM_CLOCK_LTDC_KER);
|
||||
stm32_clock_enable(<dc_ker_clock);
|
||||
|
||||
/* Set timing parameters */
|
||||
const uint32_t hsw = LCD_HSW - 1;
|
||||
|
|
@ -100,63 +113,145 @@ static void init_ltdc(void)
|
|||
reg_writef(LTDC_GCR, LTDCEN(1));
|
||||
}
|
||||
|
||||
static void disable_ltdc(void)
|
||||
{
|
||||
reg_writef(LTDC_GCR, LTDCEN(0));
|
||||
|
||||
stm32_clock_disable(<dc_ker_clock);
|
||||
}
|
||||
|
||||
/* TODO: thread safety, is a mutex needed here? */
|
||||
|
||||
static void reset_lcd(void)
|
||||
{
|
||||
if (lcd_controller_state != RESET)
|
||||
{
|
||||
if (lcd_controller_state == AWAKE)
|
||||
disable_ltdc();
|
||||
|
||||
/* Must be >= 10 us to take effect */
|
||||
gpio_set_level(GPIO_LCD_RESET, 0);
|
||||
udelay(10);
|
||||
|
||||
lcd_controller_state = RESET;
|
||||
}
|
||||
}
|
||||
|
||||
static void sleep_lcd(void)
|
||||
{
|
||||
if (lcd_controller_state == AWAKE)
|
||||
{
|
||||
/*
|
||||
* Send sleep in command -- empirically this seems to
|
||||
* require a delay of 10ms before disabling the LTDC.
|
||||
* The clock output appears to be necessary to fully
|
||||
* blank the screen before entering sleep mode.
|
||||
*
|
||||
* Sometimes there is an effect where the screen is
|
||||
* only partly blanked and only later fully blanked,
|
||||
* which goes away with a 20ms delay.
|
||||
*/
|
||||
ili_cmd(0x10);
|
||||
sleep(MS_TO_TICKS(20));
|
||||
|
||||
/* Disable LTDC */
|
||||
disable_ltdc();
|
||||
|
||||
lcd_controller_state = SLEEP;
|
||||
}
|
||||
}
|
||||
|
||||
static void wake_lcd(void)
|
||||
{
|
||||
if (lcd_controller_state == RESET)
|
||||
{
|
||||
/* Release reset line */
|
||||
gpio_set_level(GPIO_LCD_RESET, 1);
|
||||
sleep(MS_TO_TICKS(5));
|
||||
|
||||
/* Memory access control (X/Y invert, BGR panel) */
|
||||
ili_cmd(0x36, 0xc8);
|
||||
|
||||
/* Pixel format set (18bpp for RGB bus, 16bpp for SPI bus) */
|
||||
ili_cmd(0x3a, 0x65);
|
||||
|
||||
/* Send set EXTC command to allow configuring RGB interface */
|
||||
ili_cmd(0xc8, 0xff, 0x93, 0x42);
|
||||
|
||||
/*
|
||||
* Enable RGB interface transferring to internal GRAM.
|
||||
*
|
||||
* Direct to shift register mode doesn't work; for one, the
|
||||
* framebuffer doesn't get transferred properly which might
|
||||
* just be timing issues. Two, the display is horizontally
|
||||
* flipped and there doesn't seem to be a way to change it
|
||||
* in the shift register mode.
|
||||
*/
|
||||
ili_cmd(0xb0, 0xc0);
|
||||
ili_cmd(0xf6, 0x01, 0x00, 0x06);
|
||||
|
||||
/* Display ON */
|
||||
ili_cmd(0x29);
|
||||
}
|
||||
|
||||
if (lcd_controller_state != AWAKE)
|
||||
{
|
||||
/* Sync framebuffer & enable LTDC output */
|
||||
commit_dcache();
|
||||
enable_ltdc();
|
||||
|
||||
/* Sleep out command */
|
||||
ili_cmd(0x11);
|
||||
sleep(MS_TO_TICKS(5));
|
||||
|
||||
lcd_controller_state = AWAKE;
|
||||
send_event(LCD_EVENT_ACTIVATION, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_init_device(void)
|
||||
{
|
||||
/* Configure SPI bus */
|
||||
stm_spi_init(&spi, &spi_cfg);
|
||||
nvic_enable_irq(NVIC_IRQN_SPI5);
|
||||
|
||||
/* Enable LCD controller */
|
||||
init_ltdc();
|
||||
|
||||
/* Ensure controller is reset */
|
||||
gpio_set_level(GPIO_LCD_RESET, 0);
|
||||
sleep(12);
|
||||
|
||||
gpio_set_level(GPIO_LCD_RESET, 1);
|
||||
sleep(12);
|
||||
|
||||
/* Sleep out */
|
||||
ili_cmd(0x11);
|
||||
sleep(12);
|
||||
|
||||
/* memory access control (X/Y invert, BGR panel) */
|
||||
ili_cmd(0x36, 0xc8);
|
||||
|
||||
/* pixel format set (18bpp for RGB bus, 16bpp for SPI bus) */
|
||||
ili_cmd(0x3a, 0x65);
|
||||
|
||||
/* send set EXTC command to allow configuring RGB interface */
|
||||
ili_cmd(0xc8, 0xff, 0x93, 0x42);
|
||||
|
||||
/*
|
||||
* Enable RGB interface transferring to internal GRAM.
|
||||
*
|
||||
* Direct to shift register mode doesn't work; for one, the
|
||||
* framebuffer doesn't get transferred properly which might
|
||||
* just be timing issues. Two, the display is horizontally
|
||||
* flipped and there doesn't seem to be a way to change it
|
||||
* in the shift register mode.
|
||||
*/
|
||||
ili_cmd(0xb0, 0xc0);
|
||||
ili_cmd(0xf6, 0x01, 0x00, 0x06);
|
||||
|
||||
/* display ON */
|
||||
ili_cmd(0x29);
|
||||
#ifndef BOOTLOADER
|
||||
/* Enable LTDC and LCD controller */
|
||||
wake_lcd();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool lcd_active(void)
|
||||
{
|
||||
return true;
|
||||
return lcd_controller_state == AWAKE;
|
||||
}
|
||||
|
||||
void lcd_enable(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
wake_lcd();
|
||||
else
|
||||
sleep_lcd();
|
||||
}
|
||||
|
||||
void lcd_shutdown(void)
|
||||
{
|
||||
reset_lcd();
|
||||
}
|
||||
|
||||
void lcd_update(void)
|
||||
{
|
||||
if (!lcd_active())
|
||||
return;
|
||||
|
||||
commit_dcache();
|
||||
}
|
||||
|
||||
void lcd_update_rect(int x, int y, int width, int height)
|
||||
{
|
||||
if (!lcd_active())
|
||||
return;
|
||||
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
else if (x >= LCD_WIDTH)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
#include "power.h"
|
||||
#include "mutex.h"
|
||||
#include "gpio-stm32h7.h"
|
||||
#include "system-echoplayer.h"
|
||||
#include "regs/cortex-m/cm_scb.h"
|
||||
|
||||
static struct mutex power_1v8_lock;
|
||||
static int power_1v8_refcount;
|
||||
|
|
@ -68,23 +70,34 @@ void power_init(void)
|
|||
|
||||
void power_off(void)
|
||||
{
|
||||
/*
|
||||
* Disable power and reset to the bootloader immediately.
|
||||
* The system can't really be powered off as long as USB
|
||||
* is plugged or the power button is pressed -- it's the
|
||||
* bootloader's job to monitor those inputs and decide
|
||||
* when the system needs to "really" power on.
|
||||
*/
|
||||
gpio_set_level(GPIO_CPU_POWER_ON, 0);
|
||||
|
||||
/* TODO: reset to bootloader if USB is plugged in */
|
||||
while (1)
|
||||
core_idle();
|
||||
reg_writef(CM_SCB_AIRCR, VECTKEY_V(KEY), SYSRESETREQ(1));
|
||||
while (1);
|
||||
}
|
||||
|
||||
void system_reboot(void)
|
||||
{
|
||||
/*
|
||||
* TODO: support reboot
|
||||
*
|
||||
* For R1-Rev1 PCBs doing a CPU reset will cut power when
|
||||
* running on battery (because cpu_power_on is no longer
|
||||
* being driven high). The RTC alarm could be used to wake
|
||||
* the system instead.
|
||||
* Disable IRQs to ensure an errant panic can't disturb
|
||||
* the RTC reconfig.
|
||||
*/
|
||||
disable_irq();
|
||||
|
||||
/*
|
||||
* Configure RTC_OUT pin to keep power enabled during
|
||||
* reset and then do a normal power off. If this fails
|
||||
* to reset back to the bootloader then the RTC_OUT
|
||||
* pin will go low automatically after some timeout.
|
||||
*/
|
||||
echoplayer_set_rtcout_mode(ECHOPLAYER_RTCOUT_REBOOT);
|
||||
power_off();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
#include "sdmmc_host.h"
|
||||
#include "clock-echoplayer.h"
|
||||
#include "sdmmc-stm32h7.h"
|
||||
#include "gpio-stm32h7.h"
|
||||
#include "nvic-arm.h"
|
||||
|
|
@ -95,7 +96,7 @@ static struct sdmmc_poll sdcard_poll;
|
|||
void sdmmc_host_target_init(void)
|
||||
{
|
||||
/* Initialize controller */
|
||||
stm32h7_sdmmc_init(&sdmmc1_ctl, ITA_SDMMC1, STM_CLOCK_SDMMC1_KER,
|
||||
stm32h7_sdmmc_init(&sdmmc1_ctl, ITA_SDMMC1, &sdmmc1_ker_clock,
|
||||
stm32h7_reset_sdmmc1, NULL);
|
||||
nvic_enable_irq(NVIC_IRQN_SDMMC1);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,21 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
#include "system.h"
|
||||
#include "button.h"
|
||||
#include "gpio-stm32h7.h"
|
||||
#include "regs/stm32h743/rcc.h"
|
||||
#include "clock-echoplayer.h"
|
||||
#include "system-echoplayer.h"
|
||||
#include "regs/stm32h743/fmc.h"
|
||||
#include "regs/stm32h743/pwr.h"
|
||||
#include "regs/stm32h743/rcc.h"
|
||||
#include "regs/stm32h743/rtc.h"
|
||||
#include "regs/cortex-m/cm_scb.h"
|
||||
|
||||
#ifdef BOOTLOADER
|
||||
# define BOOTLOADER_INIT 1
|
||||
#else
|
||||
# define BOOTLOADER_INIT 0
|
||||
#endif
|
||||
|
||||
#define F_INPUT GPIOF_INPUT(GPIO_PULL_DISABLED)
|
||||
#define F_INPUT_PU GPIOF_INPUT(GPIO_PULL_UP)
|
||||
|
|
@ -48,6 +60,8 @@
|
|||
# define F_MCO1 GPIOF_ANALOG()
|
||||
#endif
|
||||
|
||||
enum echoplayer_boot_reason echoplayer_boot_reason = ECHOPLAYER_BOOT_REASON_NORMAL;
|
||||
|
||||
static const struct gpio_setting gpios[] = {
|
||||
STM_DEFGPIO(GPIO_BUTTON_A, F_INPUT_PU),
|
||||
STM_DEFGPIO(GPIO_BUTTON_B, F_INPUT_PU),
|
||||
|
|
@ -63,7 +77,6 @@ static const struct gpio_setting gpios[] = {
|
|||
STM_DEFGPIO(GPIO_BUTTON_VOL_DOWN, F_INPUT_PU),
|
||||
STM_DEFGPIO(GPIO_BUTTON_POWER, F_INPUT_PD),
|
||||
STM_DEFGPIO(GPIO_BUTTON_HOLD, F_INPUT_PU),
|
||||
STM_DEFGPIO(GPIO_CPU_POWER_ON, F_OUT_LS(1)), /* active high */
|
||||
STM_DEFGPIO(GPIO_POWER_1V8, F_OUT_LS(0)), /* active high */
|
||||
STM_DEFGPIO(GPIO_CODEC_AVDD_EN, F_OUT_LS(1)), /* active low */
|
||||
STM_DEFGPIO(GPIO_CODEC_DVDD_EN, F_OUT_LS(1)), /* active low */
|
||||
|
|
@ -117,25 +130,7 @@ static const struct pingroup_setting pingroups[] = {
|
|||
STM_DEFPINS(GPIO_I, 0x06e7, F_LCD_AF14),
|
||||
};
|
||||
|
||||
void gpio_init(void)
|
||||
{
|
||||
/* Enable clocks for all used GPIO banks */
|
||||
reg_writef(RCC_AHB4ENR,
|
||||
GPIOAEN(1), GPIOBEN(1), GPIOCEN(1), GPIODEN(1),
|
||||
GPIOEEN(1), GPIOFEN(1), GPIOGEN(1), GPIOHEN(1), GPIOIEN(1));
|
||||
|
||||
/*
|
||||
* NOTE: I think it's possible to disable clocks for the banks which
|
||||
* we don't need to access at runtime because these are only clocking
|
||||
* register access. Probably a micro-optimization but it supposedly
|
||||
* does save a few uA/MHz.
|
||||
*/
|
||||
|
||||
gpio_configure_all(gpios, ARRAYLEN(gpios),
|
||||
pingroups, ARRAYLEN(pingroups));
|
||||
}
|
||||
|
||||
void fmc_init(void)
|
||||
INIT_ATTR static void fmc_init(void)
|
||||
{
|
||||
/* configure clock */
|
||||
reg_writef(RCC_D1CCIPR, FMCSEL_V(AHB));
|
||||
|
|
@ -181,3 +176,117 @@ void fmc_init(void)
|
|||
*/
|
||||
reg_writef(FMC_SDRTR, REIE(0), COUNT(917), CRE(0));
|
||||
}
|
||||
|
||||
void system_init(void)
|
||||
{
|
||||
if (BOOTLOADER_INIT)
|
||||
{
|
||||
/* Enable clocks for all used GPIO banks */
|
||||
reg_writef(RCC_AHB4ENR,
|
||||
GPIOAEN(1), GPIOBEN(1), GPIOCEN(1), GPIODEN(1),
|
||||
GPIOEEN(1), GPIOFEN(1), GPIOGEN(1), GPIOHEN(1), GPIOIEN(1));
|
||||
|
||||
/*
|
||||
* NOTE: I think it's possible to disable clocks for the banks which
|
||||
* we don't need to access at runtime because these are only clocking
|
||||
* register access. Probably a micro-optimization but it supposedly
|
||||
* does save a few uA/MHz.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Set cpu_power_on high as early as possible to
|
||||
* ensure we won't brown out if the power button
|
||||
* isn't pressed.
|
||||
*/
|
||||
gpio_configure_single(GPIO_CPU_POWER_ON, F_OUT_LS(1));
|
||||
|
||||
/* Set vector table address */
|
||||
extern char __vectors_arm[];
|
||||
reg_var(CM_SCB_VTOR) = (uint32_t)__vectors_arm;
|
||||
|
||||
#if defined(DEBUG)
|
||||
system_debug_enable(true);
|
||||
#endif
|
||||
|
||||
if (BOOTLOADER_INIT)
|
||||
{
|
||||
/* Enable CPU cache */
|
||||
stm32_enable_caches();
|
||||
|
||||
/* Initialize system clocks */
|
||||
echoplayer_clock_init();
|
||||
}
|
||||
|
||||
/* Enable systick early due to udelay() needed for FMC init */
|
||||
stm32_systick_enable();
|
||||
|
||||
if (BOOTLOADER_INIT)
|
||||
{
|
||||
/* Configure GPIOs and start FMC */
|
||||
gpio_configure_all(gpios, ARRAYLEN(gpios),
|
||||
pingroups, ARRAYLEN(pingroups));
|
||||
fmc_init();
|
||||
|
||||
/* Read & clear reset source */
|
||||
uint32_t rsr = reg_var(RCC_RSR);
|
||||
reg_assignf(RCC_RSR, RMVF(1));
|
||||
|
||||
/*
|
||||
* Determine boot reason -- SFTRST means a software reset
|
||||
* occurred, which may be a reboot or a power off
|
||||
*/
|
||||
if (reg_vreadf(rsr, RCC_RSR, SFTRSTF))
|
||||
{
|
||||
reg_writef(RCC_APB4ENR, RTCAPBEN(1));
|
||||
|
||||
if (reg_readf(RTC_CR, WUTE))
|
||||
echoplayer_boot_reason = ECHOPLAYER_BOOT_REASON_SW_REBOOT;
|
||||
else
|
||||
echoplayer_boot_reason = ECHOPLAYER_BOOT_REASON_SW_POWEROFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable RTC_OUT pin */
|
||||
echoplayer_set_rtcout_mode(ECHOPLAYER_RTCOUT_DISABLED);
|
||||
}
|
||||
|
||||
void system_exception_wait(void)
|
||||
{
|
||||
while (button_read_device() != (BUTTON_POWER | BUTTON_START));
|
||||
}
|
||||
|
||||
void echoplayer_set_rtcout_mode(enum echoplayer_rtcout_mode mode)
|
||||
{
|
||||
reg_writef(RCC_APB4ENR, RTCAPBEN(1));
|
||||
reg_writef(PWR_CR1, DBP(1));
|
||||
|
||||
reg_writef(RTC_WPR, KEY_V(KEY1));
|
||||
reg_writef(RTC_WPR, KEY_V(KEY2));
|
||||
|
||||
reg_writef(RTC_OR, OUT_RMP(0), ALARM_TYPE_V(PUSH_PULL));
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case ECHOPLAYER_RTCOUT_REBOOT:
|
||||
/*
|
||||
* Use the inverted wakeup timer output to keep power
|
||||
* enabled during reset. If, somehow, the system does
|
||||
* not reset properly then the wakeup timer will drive
|
||||
* the RTC_OUT pin low after 1 second and cut power.
|
||||
*/
|
||||
while (!reg_readf(RTC_ISR, WUTWF));
|
||||
reg_writef(RTC_ISR, WUTF(0));
|
||||
reg_writef(RTC_WUTR, VALUE(STM32_LSE_FREQ / 8));
|
||||
reg_writef(RTC_CR, OSEL_V(WAKEUP), POL(1), WUCKSEL(0), WUTE(1));
|
||||
break;
|
||||
|
||||
case ECHOPLAYER_RTCOUT_DISABLED:
|
||||
default:
|
||||
reg_writef(RTC_CR, OSEL_V(DISABLED), POL(0), WUTE(0));
|
||||
break;
|
||||
}
|
||||
|
||||
reg_writef(RTC_WPR, KEY(0));
|
||||
reg_writef(PWR_CR1, DBP(0));
|
||||
}
|
||||
|
|
|
|||
41
firmware/target/arm/stm32/echoplayer/system-echoplayer.h
Normal file
41
firmware/target/arm/stm32/echoplayer/system-echoplayer.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2026 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef __SYSTEM_ECHOPLAYER_H__
|
||||
#define __SYSTEM_ECHOPLAYER_H__
|
||||
|
||||
enum echoplayer_rtcout_mode
|
||||
{
|
||||
ECHOPLAYER_RTCOUT_DISABLED,
|
||||
ECHOPLAYER_RTCOUT_REBOOT,
|
||||
};
|
||||
|
||||
enum echoplayer_boot_reason
|
||||
{
|
||||
ECHOPLAYER_BOOT_REASON_NORMAL,
|
||||
ECHOPLAYER_BOOT_REASON_SW_POWEROFF,
|
||||
ECHOPLAYER_BOOT_REASON_SW_REBOOT,
|
||||
};
|
||||
|
||||
void echoplayer_set_rtcout_mode(enum echoplayer_rtcout_mode mode);
|
||||
|
||||
extern enum echoplayer_boot_reason echoplayer_boot_reason;
|
||||
|
||||
#endif /* __SYSTEM_ECHOPLAYER_H__ */
|
||||
|
|
@ -80,7 +80,7 @@ void stm32h7_reset_sdmmc1(void)
|
|||
|
||||
void stm32h7_sdmmc_init(struct stm32h7_sdmmc_controller *ctl,
|
||||
uint32_t instance,
|
||||
enum stm_clock clock,
|
||||
const struct stm32_clock *clock,
|
||||
void (*reset_sdmmc)(void),
|
||||
void (*vcc_enable)(bool))
|
||||
{
|
||||
|
|
@ -109,7 +109,7 @@ void stm32h7_sdmmc_set_power_enabled(void *controller, bool enabled)
|
|||
sleep(1);
|
||||
|
||||
/* Bus clock is now needed, so enable kernel clock */
|
||||
stm_clock_enable(ctl->clock);
|
||||
stm32_clock_enable(ctl->clock);
|
||||
|
||||
/* Configure bus parameters */
|
||||
stm32h7_sdmmc_set_bus_width(ctl, SDMMC_BUS_WIDTH_1BIT);
|
||||
|
|
@ -121,7 +121,7 @@ void stm32h7_sdmmc_set_power_enabled(void *controller, bool enabled)
|
|||
udelay(200);
|
||||
|
||||
/* Automatically stop clock when bus is not in use */
|
||||
reg_writelf(ctl->regs, SDMMC_CLKCR, PWRSAV(1));
|
||||
reg_writelf(ctl->regs, SDMMC_CLKCR, PWRSAV(1), HWFC_EN(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -136,7 +136,7 @@ void stm32h7_sdmmc_set_power_enabled(void *controller, bool enabled)
|
|||
* and the bus is powered down; some quick testing shows this
|
||||
* seems to be true.
|
||||
*/
|
||||
stm_clock_disable(ctl->clock);
|
||||
stm32_clock_disable(ctl->clock);
|
||||
|
||||
/* Disable VCC */
|
||||
if (ctl->vcc_enable)
|
||||
|
|
@ -174,7 +174,7 @@ void stm32h7_sdmmc_set_bus_clock(void *controller, uint32_t clock)
|
|||
if (stm32h7_sdmmc_is_powered_off(ctl))
|
||||
return;
|
||||
|
||||
size_t ker_freq = stm_clock_get_frequency(ctl->clock);
|
||||
size_t ker_freq = stm32_clock_get_frequency(ctl->clock);
|
||||
size_t bus_freq = get_sdmmc_bus_freq(clock);
|
||||
if (!bus_freq)
|
||||
panicf("%s", __func__);
|
||||
|
|
@ -273,27 +273,6 @@ int stm32h7_sdmmc_submit_command(void *controller,
|
|||
if (buff_size > MAX_DATA_LEN)
|
||||
panicf("%s: buffer too big", __func__);
|
||||
|
||||
/*
|
||||
* IDMA on the SDMMC controller can't access the DTCM.
|
||||
* This is only possible by bounce-buffering in one of
|
||||
* the other memories accessible to IDMA, then using
|
||||
* another DMA process to copy the resulting buffer to
|
||||
* DTCM, which seems unnecessarily convoluted.
|
||||
*/
|
||||
if ((uintptr_t)buff_addr >= STM32_DTCM_BASE &&
|
||||
(uintptr_t)buff_addr < STM32_DTCM_BASE + STM32_DTCM_SIZE)
|
||||
panicf("%s: buffer in DTCM not supported", __func__);
|
||||
|
||||
/*
|
||||
* Must assign to a variable to prevent GCC from whining
|
||||
* about 'limited range of data type', because the ITCM
|
||||
* is mapped at address 0.
|
||||
*/
|
||||
static const uintptr_t itcm_base = STM32_ITCM_BASE;
|
||||
if ((uintptr_t)buff_addr >= itcm_base &&
|
||||
(uintptr_t)buff_addr < itcm_base + STM32_ITCM_SIZE)
|
||||
panicf("%s: buffer in ITCM not supported", __func__);
|
||||
|
||||
/* Set block size */
|
||||
uint32_t dctrl = 0;
|
||||
uint32_t dblocksize = find_first_set_bit(cmd->block_len);
|
||||
|
|
@ -481,8 +460,12 @@ void stm32h7_sdmmc_irq_handler(struct stm32h7_sdmmc_controller *ctl)
|
|||
ctl->cmd_error = SDMMC_STATUS_TIMEOUT;
|
||||
else if (reg_vreadf(star, SDMMC_STAR, DCRCFAIL))
|
||||
ctl->cmd_error = SDMMC_STATUS_INVALID_CRC;
|
||||
else if (star & DATA_ERROR_BITS)
|
||||
else if (reg_vreadf(star, SDMMC_STAR, DABORT))
|
||||
ctl->cmd_error = SDMMC_STATUS_ERROR;
|
||||
else if (reg_vreadf(star, SDMMC_STAR, IDMATE))
|
||||
panicf("sdmmc dma err: %08lx", reg_readl(ctl->regs, SDMMC_IDMABASE0R));
|
||||
else if (star & DATA_ERROR_BITS)
|
||||
panicf("sdmmc data error: %08lx", star);
|
||||
}
|
||||
|
||||
ctl->cmd_wait &= ~WAIT_DATA;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ struct stm32h7_sdmmc_controller
|
|||
uint32_t regs;
|
||||
|
||||
/* SDMMC kernel clock */
|
||||
enum stm_clock clock;
|
||||
const struct stm32_clock *clock;
|
||||
|
||||
/* Callback to reset SDMMC instance in RCC */
|
||||
void (*reset_sdmmc)(void);
|
||||
|
|
@ -59,7 +59,7 @@ void stm32h7_reset_sdmmc1(void);
|
|||
|
||||
void stm32h7_sdmmc_init(struct stm32h7_sdmmc_controller *controller,
|
||||
uint32_t instance,
|
||||
enum stm_clock clock,
|
||||
const struct stm32_clock *clock,
|
||||
void (*reset_sdmmc)(void),
|
||||
void (*vcc_enable)(bool));
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ static void stm_spi_enable(struct stm_spi *spi, bool hd_tx, size_t size)
|
|||
if (tsize > TSIZE_MAX)
|
||||
panicf("%s: tsize > TSIZE_MAX", __func__);
|
||||
|
||||
stm_clock_enable(spi->clock);
|
||||
stm32_clock_enable(spi->clock);
|
||||
|
||||
if (spi->set_cs)
|
||||
spi->set_cs(spi, true);
|
||||
|
|
@ -59,7 +59,7 @@ static void stm_spi_disable(struct stm_spi *spi)
|
|||
if (spi->set_cs)
|
||||
spi->set_cs(spi, false);
|
||||
|
||||
stm_clock_disable(spi->clock);
|
||||
stm32_clock_disable(spi->clock);
|
||||
}
|
||||
|
||||
static uint32_t stm_spi_pack(const void **bufp, size_t *sizep)
|
||||
|
|
@ -110,7 +110,7 @@ static void stm_spi_unpack(void **bufp, size_t *sizep, uint32_t data)
|
|||
|
||||
static uint32_t stm_spi_calc_mbr(const struct stm_spi_config *config)
|
||||
{
|
||||
size_t ker_freq = stm_clock_get_frequency(config->clock);
|
||||
size_t ker_freq = stm32_clock_get_frequency(config->clock);
|
||||
for (uint32_t mbr = 0; mbr <= 7; mbr++)
|
||||
{
|
||||
if (ker_freq / (2 << mbr) <= config->freq)
|
||||
|
|
@ -162,7 +162,7 @@ void stm_spi_init(struct stm_spi *spi,
|
|||
ftlevel *= 2;
|
||||
}
|
||||
|
||||
stm_clock_enable(spi->clock);
|
||||
stm32_clock_enable(spi->clock);
|
||||
|
||||
/* TODO: allow setting MBR here */
|
||||
reg_writelf(spi->regs, SPI_CFG1,
|
||||
|
|
@ -191,7 +191,7 @@ void stm_spi_init(struct stm_spi *spi,
|
|||
MIDI(0),
|
||||
MSSI(0));
|
||||
|
||||
stm_clock_disable(spi->clock);
|
||||
stm32_clock_disable(spi->clock);
|
||||
}
|
||||
|
||||
int stm_spi_xfer(struct stm_spi *spi, size_t size,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ struct stm_spi_config
|
|||
* such the kernel clock should not be changed after
|
||||
* the SPI peripheral is initialized.
|
||||
*/
|
||||
enum stm_clock clock;
|
||||
const struct stm32_clock *clock;
|
||||
size_t freq;
|
||||
|
||||
enum stm_spi_mode mode;
|
||||
|
|
@ -77,7 +77,7 @@ struct stm_spi_config
|
|||
struct stm_spi
|
||||
{
|
||||
uint32_t regs;
|
||||
enum stm_clock clock;
|
||||
const struct stm32_clock *clock;
|
||||
enum stm_spi_mode mode;
|
||||
stm_spi_set_cs_t set_cs;
|
||||
uint32_t frame_size;
|
||||
|
|
|
|||
|
|
@ -27,26 +27,29 @@
|
|||
#include "regs/cortex-m/cm_systick.h"
|
||||
#include "regs/stm32h743/dbgmcu.h"
|
||||
|
||||
/* EXT timer is 1/8th of CPU clock */
|
||||
#define SYSTICK_FREQ (CPU_FREQ / 8)
|
||||
#define SYSTICK_PER_MS (SYSTICK_FREQ / 1000)
|
||||
#define SYSTICK_PER_US (SYSTICK_FREQ / 1000000)
|
||||
/* Assumed initial CPU frequency for calculating systick */
|
||||
#ifndef CPUFREQ_INITIAL
|
||||
# define CPUFREQ_INITIAL CPU_FREQ
|
||||
#endif
|
||||
|
||||
/* Max delay is limited by kernel tick interval + safety margin */
|
||||
#define SYSTICK_DELAY_MAX_US (1000000 / HZ / 2)
|
||||
#define SYSTICK_DELAY_MAX_MS (SYSTICK_DELAY_MAX_US / 1000)
|
||||
/* Tick interval in milliseconds */
|
||||
#ifndef SYSTICK_INTERVAL_INITIAL
|
||||
# define SYSTICK_INTERVAL_INITIAL (1000 / HZ)
|
||||
#endif
|
||||
|
||||
/* Base address of vector table */
|
||||
extern char __vectors_arm[];
|
||||
/* Use EXT source which is equal to CPU frequency divided by 8 */
|
||||
#define SYSTICK_SOURCE BV_CM_SYSTICK_CSR_CLKSOURCE_EXT
|
||||
#define SYSTICK_PRESCALER 8
|
||||
|
||||
static void systick_init(unsigned int interval_in_ms)
|
||||
{
|
||||
reg_writef(CM_SYSTICK_RVR, VALUE(SYSTICK_PER_MS * interval_in_ms - 1));
|
||||
reg_writef(CM_SYSTICK_CVR, VALUE(0));
|
||||
reg_writef(CM_SYSTICK_CSR, CLKSOURCE_V(EXT), ENABLE(1));
|
||||
}
|
||||
/* Convert CPU frequency to number of systick ticks in 1 ms */
|
||||
#define CPUFREQ_TO_SYSTICK_PER_MS(f) \
|
||||
((f) / (SYSTICK_PRESCALER * 1000))
|
||||
|
||||
static void stm_enable_caches(void)
|
||||
/* SysTick related state */
|
||||
static uint32_t systick_per_ms = CPUFREQ_TO_SYSTICK_PER_MS(CPUFREQ_INITIAL);
|
||||
static uint32_t systick_interval_in_ms = SYSTICK_INTERVAL_INITIAL;
|
||||
|
||||
void stm32_enable_caches(void)
|
||||
{
|
||||
__discard_idcache();
|
||||
|
||||
|
|
@ -56,28 +59,43 @@ static void stm_enable_caches(void)
|
|||
arm_isb();
|
||||
}
|
||||
|
||||
void system_init(void)
|
||||
static void stm32_recalc_systick_rvr(void)
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
system_debug_enable(true);
|
||||
#endif
|
||||
uint32_t ticks = systick_per_ms * systick_interval_in_ms;
|
||||
|
||||
/* Ensure IRQs are disabled and set vector table address */
|
||||
disable_irq();
|
||||
reg_var(CM_SCB_VTOR) = (uint32_t)__vectors_arm;
|
||||
reg_writef(CM_SYSTICK_RVR, VALUE(ticks - 1));
|
||||
}
|
||||
|
||||
/* Enable CPU caches */
|
||||
stm_enable_caches();
|
||||
static void stm32_set_systick_interval(uint32_t interval_in_ms)
|
||||
{
|
||||
if (interval_in_ms != systick_interval_in_ms)
|
||||
{
|
||||
systick_interval_in_ms = interval_in_ms;
|
||||
stm32_recalc_systick_rvr();
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize system clocks */
|
||||
stm_clock_init();
|
||||
void stm32_systick_set_cpu_freq(uint32_t freq)
|
||||
{
|
||||
uint32_t ticks_per_ms = CPUFREQ_TO_SYSTICK_PER_MS(freq);
|
||||
|
||||
/* TODO: move this */
|
||||
systick_init(1000/HZ);
|
||||
if (ticks_per_ms != systick_per_ms)
|
||||
{
|
||||
systick_per_ms = ticks_per_ms;
|
||||
stm32_recalc_systick_rvr();
|
||||
}
|
||||
}
|
||||
|
||||
/* Call target-specific initialization */
|
||||
gpio_init();
|
||||
fmc_init();
|
||||
void stm32_systick_enable(void)
|
||||
{
|
||||
stm32_recalc_systick_rvr();
|
||||
reg_writef(CM_SYSTICK_CVR, VALUE(0));
|
||||
reg_writef(CM_SYSTICK_CSR, CLKSOURCE(SYSTICK_SOURCE), ENABLE(1));
|
||||
}
|
||||
|
||||
void stm32_systick_disable(void)
|
||||
{
|
||||
reg_writef(CM_SYSTICK_CSR, ENABLE(0), TICKINT(0));
|
||||
}
|
||||
|
||||
void system_debug_enable(bool enable)
|
||||
|
|
@ -99,7 +117,8 @@ void system_debug_enable(bool enable)
|
|||
|
||||
void tick_start(unsigned int interval_in_ms)
|
||||
{
|
||||
(void)interval_in_ms;
|
||||
stm32_set_systick_interval(interval_in_ms);
|
||||
stm32_systick_enable();
|
||||
|
||||
reg_writef(CM_SYSTICK_CSR, TICKINT(1));
|
||||
}
|
||||
|
|
@ -110,58 +129,35 @@ void systick_handler(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* NOTE: This assumes that the CPU cannot be reclocked during an interrupt.
|
||||
* If that happens, the systick interval and reload value would be modified
|
||||
* to maintain the kernel tick interval and the code here will break.
|
||||
* This makes two assumptions:
|
||||
*
|
||||
* 1. the CPU frequency must not change while udelay() is running;
|
||||
* otherwise the delay time will be wrong.
|
||||
* 2. interrupt handlers should not block execution for more than
|
||||
* one systick interval; if this happens the delay may be much
|
||||
* longer than necessary.
|
||||
*/
|
||||
static void __udelay(uint32_t us)
|
||||
void udelay(uint32_t us)
|
||||
{
|
||||
uint32_t delay_ticks = (us * systick_per_ms / 1000);
|
||||
uint32_t start = reg_readf(CM_SYSTICK_CVR, VALUE);
|
||||
uint32_t max = reg_readf(CM_SYSTICK_RVR, VALUE);
|
||||
uint32_t delay = us * SYSTICK_PER_US;
|
||||
|
||||
for (;;)
|
||||
while (delay_ticks > 0)
|
||||
{
|
||||
uint32_t value = reg_readf(CM_SYSTICK_CVR, VALUE);
|
||||
uint32_t diff = start - value;
|
||||
if (value > start)
|
||||
diff += max;
|
||||
if (diff >= delay)
|
||||
|
||||
if (diff >= delay_ticks)
|
||||
break;
|
||||
|
||||
delay_ticks -= diff;
|
||||
start = value;
|
||||
}
|
||||
}
|
||||
|
||||
void udelay(uint32_t us)
|
||||
{
|
||||
while (us > SYSTICK_DELAY_MAX_US)
|
||||
{
|
||||
__udelay(SYSTICK_DELAY_MAX_US);
|
||||
us -= SYSTICK_DELAY_MAX_US;
|
||||
}
|
||||
|
||||
__udelay(us);
|
||||
}
|
||||
|
||||
void mdelay(uint32_t ms)
|
||||
{
|
||||
while (ms > SYSTICK_DELAY_MAX_MS)
|
||||
{
|
||||
__udelay(SYSTICK_DELAY_MAX_MS * 1000);
|
||||
ms -= SYSTICK_DELAY_MAX_MS;
|
||||
}
|
||||
|
||||
__udelay(ms * 1000);
|
||||
}
|
||||
|
||||
void system_exception_wait(void)
|
||||
{
|
||||
#if defined(ECHO_R1)
|
||||
while (button_read_device() != (BUTTON_POWER | BUTTON_START));
|
||||
#else
|
||||
while (1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int system_memory_guard(int newmode)
|
||||
{
|
||||
/* TODO -- maybe use MPU here to give some basic protection */
|
||||
|
|
|
|||
|
|
@ -25,14 +25,22 @@
|
|||
#include "cpucache-armv7m.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Enable CPU caches. Must be called after a reset. */
|
||||
void stm32_enable_caches(void) INIT_ATTR;
|
||||
|
||||
/* Enables the SysTick timer -- SysTick interrupt won't be enabled */
|
||||
void stm32_systick_enable(void);
|
||||
|
||||
/* Disables the SysTick timer -- also disables SysTick interrupt */
|
||||
void stm32_systick_disable(void);
|
||||
|
||||
/* Update the CPU frequency to recalibrate SysTick timer */
|
||||
void stm32_systick_set_cpu_freq(uint32_t freq);
|
||||
|
||||
/* Enable/disable debug clock domain during sleep mode. */
|
||||
void system_debug_enable(bool enable);
|
||||
|
||||
/* Implemented by the target -- can be a no-op if not needed */
|
||||
void gpio_init(void) INIT_ATTR;
|
||||
void fmc_init(void) INIT_ATTR;
|
||||
|
||||
/* Busy loop delay based on systick */
|
||||
void udelay(uint32_t us);
|
||||
void mdelay(uint32_t ms);
|
||||
|
||||
#endif /* __STM32_SYSTEM_TARGET_H__ */
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ static inline int set_interrupt_status(int status, int mask)
|
|||
unsigned long cpsr;
|
||||
int oldstatus;
|
||||
/* Read the old levels and set the new ones */
|
||||
#if (defined(CREATIVE_ZVM) || defined(CREATIVE_ZV)) && defined(BOOTLOADER)
|
||||
#if defined(CREATIVE_ZVx) && defined(BOOTLOADER)
|
||||
// FIXME: This workaround is for a problem with inlining;
|
||||
// for some reason 'mask' gets treated as a variable/non-immediate constant
|
||||
// but only on this build. All others (including the nearly-identical mrobe500boot) are fine
|
||||
|
|
|
|||
|
|
@ -26,9 +26,6 @@
|
|||
#define IRQ_STATUS 0x01
|
||||
#define HIGHEST_IRQ_LEVEL IRQ_DISABLED
|
||||
|
||||
#define disable_irq_save() \
|
||||
set_irq_level(IRQ_DISABLED)
|
||||
|
||||
/* For compatibility with ARM classic */
|
||||
#define CPU_MODE_THREAD_CONTEXT 0
|
||||
|
||||
|
|
@ -47,39 +44,51 @@
|
|||
__func__, __mproc, __massert); })
|
||||
|
||||
/* Core-level interrupt masking */
|
||||
|
||||
static inline int set_irq_level(int primask)
|
||||
{
|
||||
int oldvalue;
|
||||
|
||||
asm volatile ("mrs %0, primask\n"
|
||||
"msr primask, %1\n"
|
||||
: "=r"(oldvalue) : "r"(primask));
|
||||
|
||||
return oldvalue;
|
||||
}
|
||||
|
||||
static inline void restore_irq(int primask)
|
||||
{
|
||||
asm volatile ("msr primask, %0" :: "r"(primask));
|
||||
}
|
||||
|
||||
static inline void enable_irq(void)
|
||||
{
|
||||
asm volatile ("cpsie i");
|
||||
asm volatile ("cpsie i" ::: "memory");
|
||||
}
|
||||
|
||||
static inline void disable_irq(void)
|
||||
{
|
||||
asm volatile ("cpsid i");
|
||||
asm volatile ("cpsid i" ::: "memory");
|
||||
}
|
||||
|
||||
static inline void restore_irq(int primask)
|
||||
{
|
||||
asm volatile ("msr primask, %0" :: "r"(primask) : "memory");
|
||||
}
|
||||
|
||||
static inline int get_irq_level(void)
|
||||
{
|
||||
int primask;
|
||||
|
||||
asm volatile("mrs %0, primask" : "=r"(primask));
|
||||
|
||||
return primask;
|
||||
}
|
||||
|
||||
static inline int disable_irq_save(void)
|
||||
{
|
||||
int oldlevel = get_irq_level();
|
||||
|
||||
disable_irq();
|
||||
|
||||
return oldlevel;
|
||||
}
|
||||
|
||||
static inline int set_irq_level(int primask)
|
||||
{
|
||||
int oldvalue = get_irq_level();
|
||||
|
||||
restore_irq(primask);
|
||||
|
||||
return oldvalue;
|
||||
}
|
||||
|
||||
static inline bool irq_enabled(void)
|
||||
{
|
||||
int primask;
|
||||
asm volatile ("mrs %0, primask" : "=r"(primask));
|
||||
|
||||
return !(primask & 1);
|
||||
return get_irq_level() == IRQ_ENABLED;
|
||||
}
|
||||
|
||||
static inline unsigned long get_interrupt_number(void)
|
||||
|
|
|
|||
|
|
@ -838,7 +838,7 @@ void avr_thread(void)
|
|||
if (ev.id == SYS_USB_CONNECTED)
|
||||
{
|
||||
/* Allow USB to gain exclusive storage access */
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, ev.data);
|
||||
disk_access_available = false;
|
||||
}
|
||||
else if (ev.id == SYS_USB_DISCONNECTED)
|
||||
|
|
|
|||
|
|
@ -747,7 +747,7 @@ void usb_test(void)
|
|||
|
||||
usb_init();
|
||||
usb_start_monitoring();
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK, 0);
|
||||
|
||||
while (1) {
|
||||
sleep(HZ);
|
||||
|
|
|
|||
|
|
@ -93,6 +93,28 @@ static const struct nand_chip chip_gd5f1gq4xexx = {
|
|||
.cmd_program_load = NANDCMD_PROGRAM_LOAD_x4,
|
||||
};
|
||||
|
||||
static const struct nand_chip chip_xt26g01cwsiga = {
|
||||
.log2_ppb = 6, /* 64 pages */
|
||||
.page_size = 2048,
|
||||
.oob_size = 128,
|
||||
.nr_blocks = 1024,
|
||||
.bbm_pos = 2048,
|
||||
.clock_freq = 150000000,
|
||||
.dev_conf = jz_orf(SFC_DEV_CONF,
|
||||
CE_DL(1), HOLD_DL(1), WP_DL(1),
|
||||
CPHA(0), CPOL(0),
|
||||
TSH(7), TSETUP(0), THOLD(0),
|
||||
STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
|
||||
SMP_DELAY(1)),
|
||||
.flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT |
|
||||
NAND_CHIPFLAG_ON_DIE_ECC,
|
||||
.cmd_page_read = NANDCMD_PAGE_READ,
|
||||
.cmd_program_execute = NANDCMD_PROGRAM_EXECUTE,
|
||||
.cmd_block_erase = NANDCMD_BLOCK_ERASE,
|
||||
.cmd_read_cache = NANDCMD_READ_CACHE_x4,
|
||||
.cmd_program_load = NANDCMD_PROGRAM_LOAD_x4,
|
||||
};
|
||||
|
||||
#define chip_ds35x1gaxxx chip_gd5f1gq4xexx
|
||||
#define chip_gd5f1gq5xexxg chip_gd5f1gq4xexx
|
||||
|
||||
|
|
@ -105,6 +127,7 @@ const struct nand_chip_id supported_nand_chips[] = {
|
|||
NAND_CHIP_ID(&chip_ds35x1gaxxx, NAND_READID_ADDR, 0xe5, 0x21), /* 1.8 V */
|
||||
NAND_CHIP_ID(&chip_gd5f1gq5xexxg, NAND_READID_ADDR, 0xc8, 0x51), /* 3.3 V */
|
||||
NAND_CHIP_ID(&chip_gd5f1gq5xexxg, NAND_READID_ADDR, 0xc8, 0x41), /* 1.8 V */
|
||||
NAND_CHIP_ID(&chip_xt26g01cwsiga, NAND_READID_ADDR, 0x0b, 0x11),
|
||||
};
|
||||
|
||||
const size_t nr_supported_nand_chips = ARRAYLEN(supported_nand_chips);
|
||||
|
|
|
|||
269
firmware/usb.c
269
firmware/usb.c
|
|
@ -59,17 +59,7 @@
|
|||
#include "iap.h"
|
||||
#endif
|
||||
|
||||
/* Conditions under which we want the entire driver */
|
||||
#if !defined(BOOTLOADER) || \
|
||||
(defined(HAVE_USBSTACK) && defined(HAVE_BOOTLOADER_USB_MODE)) || \
|
||||
(defined(HAVE_USBSTACK) && defined(IPOD_NANO2G)) || \
|
||||
(defined(HAVE_USBSTACK) && (defined(CREATIVE_ZVx))) || \
|
||||
(defined(HAVE_USBSTACK) && (defined(OLYMPUS_MROBE_500))) || \
|
||||
defined(CPU_TCC780X) || \
|
||||
(CONFIG_USBOTG == USBOTG_JZ4740) || \
|
||||
(CONFIG_USBOTG == USBOTG_JZ4760)
|
||||
/* TODO: condition should be reset to be only the original
|
||||
(defined(HAVE_USBSTACK) && defined(HAVE_BOOTLOADER_USB_MODE)) */
|
||||
#if (!defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE))
|
||||
#define USB_FULL_INIT
|
||||
#endif
|
||||
|
||||
|
|
@ -91,8 +81,8 @@ static int usb_state = USB_EXTRACTED;
|
|||
static int usb_mmc_countdown = 0;
|
||||
#endif
|
||||
|
||||
/* Make sure there's enough stack space for screendump */
|
||||
#ifdef USB_FULL_INIT
|
||||
/* Make sure there's enough stack space for screendump */
|
||||
#ifndef USB_EXTRA_STACK
|
||||
# define USB_EXTRA_STACK 0x0 /*Define in firmware/export/config/[target].h*/
|
||||
#endif
|
||||
|
|
@ -100,27 +90,23 @@ static long usb_stack[(DEFAULT_STACK_SIZE*4 + DUMP_BMP_LINESIZE + USB_EXTRA_STAC
|
|||
static const char usb_thread_name[] = "usb";
|
||||
static unsigned int usb_thread_entry = 0;
|
||||
static bool usb_monitor_enabled = false;
|
||||
#endif /* USB_FULL_INIT */
|
||||
static bool exclusive_storage_enabled = false;
|
||||
static bool exclusive_storage_requested = false;
|
||||
static struct event_queue usb_queue SHAREDBSS_ATTR;
|
||||
static bool exclusive_storage_access = false;
|
||||
#ifdef USB_ENABLE_HID
|
||||
static bool usb_hid = true;
|
||||
#endif
|
||||
#ifdef USB_ENABLE_AUDIO
|
||||
static int usb_audio = 0;
|
||||
#endif
|
||||
|
||||
#ifdef USB_FULL_INIT
|
||||
static bool usb_host_present = false;
|
||||
static int usb_num_acks_to_expect = 0;
|
||||
static long usb_last_broadcast_tick = 0;
|
||||
static uint32_t usb_broadcast_seqnum = 0x80000000;
|
||||
#ifdef HAVE_USB_POWER
|
||||
static int usb_mode = USBMODE_DEFAULT;
|
||||
static int new_usbmode = USBMODE_DEFAULT;
|
||||
static bool usb_power_only = false;
|
||||
#endif
|
||||
|
||||
static int usb_release_exclusive_storage(void);
|
||||
|
||||
#if defined(USB_FIREWIRE_HANDLING)
|
||||
static void try_reboot(void)
|
||||
{
|
||||
|
|
@ -206,7 +192,7 @@ static inline void usb_handle_hotswap(long id)
|
|||
}
|
||||
#endif /* HAVE_HOTSWAP */
|
||||
|
||||
static inline bool usb_configure_drivers(int for_state)
|
||||
static inline void usb_configure_drivers(int for_state)
|
||||
{
|
||||
#ifdef USB_ENABLE_AUDIO
|
||||
// FIXME: doesn't seem to get set when loaded at boot...
|
||||
|
|
@ -232,9 +218,8 @@ static inline bool usb_configure_drivers(int for_state)
|
|||
#ifdef USB_ENABLE_CHARGING_ONLY
|
||||
usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true);
|
||||
#endif
|
||||
exclusive_storage_access = false;
|
||||
|
||||
usb_attach(); /* Powered only: attach now. */
|
||||
usb_attach();
|
||||
break;
|
||||
/* USB_POWERED: */
|
||||
|
||||
|
|
@ -251,25 +236,17 @@ static inline bool usb_configure_drivers(int for_state)
|
|||
#ifdef USB_ENABLE_CHARGING_ONLY
|
||||
usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false);
|
||||
#endif
|
||||
/* Check any drivers enabled at this point for exclusive storage
|
||||
* access requirements. */
|
||||
exclusive_storage_access = usb_core_any_exclusive_storage();
|
||||
|
||||
if(exclusive_storage_access)
|
||||
return true;
|
||||
|
||||
usb_attach(); /* Not exclusive: attach now. */
|
||||
usb_attach();
|
||||
break;
|
||||
/* USB_INSERTED: */
|
||||
|
||||
case USB_EXTRACTED:
|
||||
if(exclusive_storage_access)
|
||||
usb_release_exclusive_storage();
|
||||
/* do not call usb_release_exclusive_storage.
|
||||
* usb core handles it */
|
||||
break;
|
||||
/* USB_EXTRACTED: */
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void usb_slave_mode(bool on)
|
||||
|
|
@ -283,9 +260,8 @@ static inline void usb_slave_mode(bool on)
|
|||
thread_set_priority(thread_self(), PRIORITY_REALTIME);
|
||||
#endif
|
||||
disk_unmount_all();
|
||||
usb_attach();
|
||||
}
|
||||
else /* usb_state == USB_INSERTED (only!) */
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_PRIORITY_SCHEDULING
|
||||
thread_set_priority(thread_self(), PRIORITY_SYSTEM);
|
||||
|
|
@ -350,23 +326,20 @@ static inline void usb_handle_hotswap(long id)
|
|||
}
|
||||
#endif /* HAVE_HOTSWAP */
|
||||
|
||||
static inline bool usb_configure_drivers(int for_state)
|
||||
static inline void usb_configure_drivers(int for_state)
|
||||
{
|
||||
switch(for_state)
|
||||
{
|
||||
case USB_POWERED:
|
||||
exclusive_storage_access = false;
|
||||
exclusive_storage_requested = false;
|
||||
break;
|
||||
case USB_INSERTED:
|
||||
exclusive_storage_access = true;
|
||||
return true;
|
||||
usb_request_exclusive_storage();
|
||||
break;
|
||||
case USB_EXTRACTED:
|
||||
if(exclusive_storage_access)
|
||||
usb_release_exclusive_storage();
|
||||
usb_release_exclusive_storage();
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void usb_slave_mode(bool on)
|
||||
|
|
@ -420,7 +393,7 @@ static void usb_set_host_present(bool present)
|
|||
}
|
||||
|
||||
#ifdef HAVE_USB_POWER
|
||||
if (new_usbmode == USB_MODE_CHARGE || new_usbmode == USB_MODE_ADB)
|
||||
if (usb_power_only)
|
||||
{
|
||||
/* Only charging is desired */
|
||||
usb_configure_drivers(USB_POWERED);
|
||||
|
|
@ -428,44 +401,7 @@ static void usb_set_host_present(bool present)
|
|||
}
|
||||
#endif
|
||||
|
||||
if(!usb_configure_drivers(USB_INSERTED))
|
||||
return; /* Exclusive storage access not required */
|
||||
|
||||
/* Tell all threads that they have to back off the storage.
|
||||
We subtract one for our own thread. Expect an ACK for every
|
||||
listener for each broadcast they received. If it has been too
|
||||
long, the user might have entered a screen that didn't ACK
|
||||
when inserting the cable, such as a debugging screen. In that
|
||||
case, reset the count or else USB would be locked out until
|
||||
rebooting because it most likely won't ever come. Simply
|
||||
resetting to the most recent broadcast count is racy. */
|
||||
if(TIME_AFTER(current_tick, usb_last_broadcast_tick + HZ*5))
|
||||
{
|
||||
usb_num_acks_to_expect = 0;
|
||||
usb_last_broadcast_tick = current_tick;
|
||||
}
|
||||
|
||||
usb_num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
|
||||
DEBUGF("usb: waiting for %d acks...\n", usb_num_acks_to_expect);
|
||||
}
|
||||
|
||||
static bool usb_handle_connected_ack(void)
|
||||
{
|
||||
if(usb_num_acks_to_expect > 0 && --usb_num_acks_to_expect == 0)
|
||||
{
|
||||
DEBUGF("usb: all threads have acknowledged the connect.\n");
|
||||
if(usb_host_present)
|
||||
{
|
||||
usb_slave_mode(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGF("usb: got ack, %d to go...\n", usb_num_acks_to_expect);
|
||||
}
|
||||
|
||||
return false;
|
||||
usb_configure_drivers(USB_INSERTED);
|
||||
}
|
||||
|
||||
/*--- General driver code ---*/
|
||||
|
|
@ -487,6 +423,7 @@ static void NORETURN_ATTR usb_thread(void)
|
|||
case USB_NOTIFY_SET_ADDR:
|
||||
case USB_NOTIFY_SET_CONFIG:
|
||||
case USB_NOTIFY_BUS_RESET:
|
||||
case USB_NOTIFY_CLASS_DRIVER:
|
||||
if(usb_state <= USB_EXTRACTED)
|
||||
break;
|
||||
usb_core_handle_notify(ev.id, ev.data);
|
||||
|
|
@ -496,6 +433,7 @@ static void NORETURN_ATTR usb_thread(void)
|
|||
break;
|
||||
|
||||
#ifdef USB_DETECT_BY_REQUEST
|
||||
usb_state = USB_INSERTED;
|
||||
usb_set_host_present(true);
|
||||
#endif
|
||||
|
||||
|
|
@ -523,32 +461,40 @@ static void NORETURN_ATTR usb_thread(void)
|
|||
#endif
|
||||
send_event(SYS_EVENT_USB_INSERTED, &usb_mode);
|
||||
#endif
|
||||
/* Power (charging-only) button */
|
||||
#ifdef HAVE_USB_POWER
|
||||
new_usbmode = usb_mode;
|
||||
switch (usb_mode) {
|
||||
case USB_MODE_CHARGE:
|
||||
case USB_MODE_ADB:
|
||||
if (button_status() & ~USBPOWER_BTN_IGNORE)
|
||||
new_usbmode = USB_MODE_MASS_STORAGE;
|
||||
break;
|
||||
default:
|
||||
case USB_MODE_MASS_STORAGE:
|
||||
if (button_status() & ~USBPOWER_BTN_IGNORE)
|
||||
new_usbmode = USB_MODE_CHARGE;
|
||||
break;
|
||||
}
|
||||
/* Power (charging-only) button */
|
||||
usb_power_only = usb_mode != USB_MODE_MASS_STORAGE;
|
||||
if(button_status() & ~USBPOWER_BTN_IGNORE) {
|
||||
usb_power_only = !usb_power_only;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef USB_DETECT_BY_REQUEST
|
||||
usb_state = USB_INSERTED;
|
||||
usb_set_host_present(true);
|
||||
#endif
|
||||
break;
|
||||
/* USB_INSERTED */
|
||||
|
||||
case SYS_USB_CONNECTED_ACK:
|
||||
if(usb_handle_connected_ack())
|
||||
usb_state = USB_INSERTED;
|
||||
if((uint32_t)ev.data != usb_broadcast_seqnum) {
|
||||
DEBUGF("usb: late ack %lX < %lX", ev.data, usb_broadcast_seqnum);
|
||||
break;
|
||||
}
|
||||
if(usb_num_acks_to_expect == 0) {
|
||||
DEBUGF("usb: unexpected ack");
|
||||
break;
|
||||
}
|
||||
if(--usb_num_acks_to_expect > 0) {
|
||||
DEBUGF("usb: got ack, %d to go...\n", usb_num_acks_to_expect);
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUGF("usb: all threads have acknowledged the connect.\n");
|
||||
if(usb_host_present && exclusive_storage_requested) {
|
||||
usb_slave_mode(true);
|
||||
exclusive_storage_enabled = true;
|
||||
}
|
||||
break;
|
||||
/* SYS_USB_CONNECTED_ACK */
|
||||
|
||||
|
|
@ -563,15 +509,7 @@ static void NORETURN_ATTR usb_thread(void)
|
|||
iap_reset_state(IF_IAP_MP(0));
|
||||
#endif
|
||||
|
||||
/* Only disable the USB slave mode if we really have enabled
|
||||
it. Some expected acks may not have been received. */
|
||||
if(usb_state == USB_INSERTED)
|
||||
usb_slave_mode(false);
|
||||
|
||||
usb_state = USB_EXTRACTED;
|
||||
#ifdef HAVE_USB_POWER
|
||||
new_usbmode = usb_mode;
|
||||
#endif
|
||||
#ifndef BOOTLOADER
|
||||
send_event(SYS_EVENT_USB_EXTRACTED, NULL);
|
||||
#endif
|
||||
|
|
@ -757,18 +695,43 @@ static void usb_tick(void)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void usb_start_monitoring(void)
|
||||
{
|
||||
usb_monitor_enabled = true;
|
||||
}
|
||||
#endif /* USB_STATUS_BY_EVENT */
|
||||
#endif /* USB_FULL_INIT */
|
||||
|
||||
void usb_acknowledge(long id)
|
||||
void usb_acknowledge(long id, intptr_t seqnum)
|
||||
{
|
||||
queue_post(&usb_queue, id, 0);
|
||||
queue_post(&usb_queue, id, seqnum);
|
||||
}
|
||||
#else /* !USB_FULL_INIT */
|
||||
/* TODO: All of this can go away once usb_core.c is no longer built
|
||||
with BOOTLOADER && !HAVE_USB_BOOTLOADER_MODE */
|
||||
#ifdef HAVE_USBSTACK
|
||||
void usb_signal_transfer_completion(
|
||||
struct usb_transfer_completion_event_data* event_data)
|
||||
{
|
||||
(void)event_data;
|
||||
}
|
||||
#endif
|
||||
void usb_clear_pending_transfer_completion_events(void)
|
||||
{
|
||||
}
|
||||
void usb_release_exclusive_storage(void)
|
||||
{
|
||||
}
|
||||
void usb_signal_notify(long id, intptr_t data)
|
||||
{
|
||||
(void)id;
|
||||
(void)data;
|
||||
}
|
||||
void usb_acknowledge(long id, intptr_t seqnum)
|
||||
{
|
||||
(void)id;
|
||||
(void)seqnum;
|
||||
}
|
||||
#endif /* !USB_FULL_INIT */
|
||||
|
||||
void usb_init(void)
|
||||
{
|
||||
|
|
@ -853,22 +816,83 @@ bool usb_inserted(void)
|
|||
return usb_state == USB_INSERTED || usb_state == USB_POWERED;
|
||||
}
|
||||
|
||||
#ifdef HAVE_USBSTACK
|
||||
#if defined(USB_FULL_INIT)
|
||||
bool usb_exclusive_storage(void)
|
||||
{
|
||||
/* Storage isn't actually exclusive until slave mode has been entered */
|
||||
return exclusive_storage_access && usb_state == USB_INSERTED;
|
||||
return exclusive_storage_enabled;
|
||||
}
|
||||
#endif /* HAVE_USBSTACK */
|
||||
|
||||
int usb_release_exclusive_storage(void)
|
||||
/* exclusive storage mode transision
|
||||
* HAVE_USBSTACK:
|
||||
* (inserted)
|
||||
* usb_set_host_present(true)
|
||||
* usb_configure_drivers(USB_INSERTED)
|
||||
* ...
|
||||
* (SET_CONFIG(n) which requires exclusive storage)
|
||||
* usb_core_do_set_config(n)
|
||||
* usb_request_exclusive_storage()
|
||||
* exclusive_storage_requested = true
|
||||
* ...
|
||||
* (all threads acked)
|
||||
* usb_slave_mode(true)
|
||||
* disk_unmount_all()
|
||||
* exclusive_storage_enabled = true
|
||||
* (exclusive mode done)
|
||||
* ...
|
||||
* (extracted, or SET_CONFIG(m) which does not require exclusive storage)
|
||||
* usb_core_do_set_config(m)
|
||||
* usb_release_exclusive_storage()
|
||||
* exclusive_storage_requested = false
|
||||
* exclusive_storage_enabled = false
|
||||
* usb_slave_mode(false)
|
||||
* disk_mount_all()
|
||||
*
|
||||
* !HAVE_USBSTACK:
|
||||
* (inserted)
|
||||
* usb_set_host_present(true)
|
||||
* usb_configure_drivers(USB_INSERTED)
|
||||
* usb_request_exclusive_storage()
|
||||
* exclusive_storage_requested = true
|
||||
* ...
|
||||
* (all threads acked)
|
||||
* usb_slave_mode(true)
|
||||
* disk_unmount_all()
|
||||
* exclusive_storage_enabled = true
|
||||
* ...
|
||||
* (extracted)
|
||||
* usb_set_host_present(false)
|
||||
* usb_configure_drivers(USB_EXTRACTED)
|
||||
* usb_release_exclusive_storage()
|
||||
* ..
|
||||
* */
|
||||
|
||||
void usb_request_exclusive_storage(void)
|
||||
{
|
||||
int bccount;
|
||||
exclusive_storage_access = false;
|
||||
exclusive_storage_requested = true;
|
||||
usb_broadcast_seqnum += 1;
|
||||
usb_num_acks_to_expect = queue_broadcast(SYS_USB_CONNECTED, usb_broadcast_seqnum) - 1;
|
||||
DEBUGF("usb: waiting for %d acks...\n", usb_num_acks_to_expect);
|
||||
}
|
||||
|
||||
void usb_release_exclusive_storage(void)
|
||||
{
|
||||
if(!exclusive_storage_requested) {
|
||||
return;
|
||||
}
|
||||
exclusive_storage_requested = false;
|
||||
|
||||
if(exclusive_storage_enabled) {
|
||||
usb_slave_mode(false);
|
||||
}
|
||||
exclusive_storage_enabled = false;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Tell all threads that we are back in business */
|
||||
bccount = queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
|
||||
int bccount = queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
|
||||
DEBUGF("USB extracted. Broadcast to %d threads...\n", bccount);
|
||||
return bccount;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USB_ENABLE_HID
|
||||
|
|
@ -889,10 +913,12 @@ void usb_set_audio(int value)
|
|||
#ifdef HAVE_USB_POWER
|
||||
bool usb_powered_only(void)
|
||||
{
|
||||
return usb_state == USB_POWERED;
|
||||
return usb_power_only;
|
||||
}
|
||||
#endif /* HAVE_USB_POWER */
|
||||
|
||||
#endif /* HAVE_USBSTACK && defined(USB_FULL_INIT) */
|
||||
|
||||
#elif defined(USB_NONE)
|
||||
/* Dummy functions for USB_NONE */
|
||||
|
||||
|
|
@ -901,9 +927,10 @@ bool usb_inserted(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
void usb_acknowledge(long id)
|
||||
void usb_acknowledge(long id, intptr_t seqnum)
|
||||
{
|
||||
(void)id;
|
||||
(void)seqnum;
|
||||
}
|
||||
|
||||
void usb_init(void)
|
||||
|
|
|
|||
|
|
@ -118,6 +118,10 @@ struct usb_class_driver {
|
|||
* Returns value on success and -1 on error.
|
||||
* Mandatory function if alternate interface support is needed */
|
||||
int (*get_interface)(int interface);
|
||||
|
||||
/* Invoked by USB_NOTIFY_CLASS_DRIVER
|
||||
Optional function */
|
||||
void (*notify_event)(intptr_t data);
|
||||
};
|
||||
|
||||
#define PACK_DATA(dest, data) pack_data(dest, &(data), sizeof(data))
|
||||
|
|
|
|||
|
|
@ -544,16 +544,6 @@ bool usb_core_driver_enabled(int driver)
|
|||
return drivers[driver].enabled;
|
||||
}
|
||||
|
||||
bool usb_core_any_exclusive_storage(void)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < USB_NUM_DRIVERS; i++)
|
||||
if(drivers[i].enabled && drivers[i].needs_exclusive_storage)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef HAVE_HOTSWAP
|
||||
void usb_core_hotswap_event(int volume, bool inserted)
|
||||
{
|
||||
|
|
@ -874,16 +864,28 @@ static int usb_core_do_set_config(uint8_t new_config)
|
|||
usb_config = new_config;
|
||||
usb_state = usb_config == 0 ? ADDRESS : CONFIGURED;
|
||||
|
||||
bool require_exclusive = false;
|
||||
|
||||
/* activate new config */
|
||||
if(usb_config != 0) {
|
||||
init_deinit_endpoints(usb_config - 1, true);
|
||||
for(int i = 0; i < USB_NUM_DRIVERS; i++) {
|
||||
if(is_active(drivers[i]) && drivers[i].init_connection != NULL) {
|
||||
drivers[i].init_connection();
|
||||
require_exclusive |= drivers[i].needs_exclusive_storage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(require_exclusive) {
|
||||
if(!usb_exclusive_storage()) {
|
||||
usb_release_exclusive_storage();
|
||||
usb_request_exclusive_storage();
|
||||
}
|
||||
} else {
|
||||
usb_release_exclusive_storage();
|
||||
}
|
||||
|
||||
#ifdef HAVE_USB_CHARGING_ENABLE
|
||||
usb_charging_maxcurrent_change(usb_charging_maxcurrent());
|
||||
#endif
|
||||
|
|
@ -1179,6 +1181,20 @@ void usb_core_handle_notify(long id, intptr_t data)
|
|||
usb_charging_maxcurrent_change(usb_charging_maxcurrent());
|
||||
#endif
|
||||
break;
|
||||
case USB_NOTIFY_CLASS_DRIVER: {
|
||||
/* HACK: index is uint8 but promoted to int to avoid a compiler
|
||||
warning when USB_NUM_DRIVERS is 0, mainly in bootloaders.
|
||||
This hack can be removed once usb_core is no longer built
|
||||
for BOOTLOADER && !HAVE_BOOTLOADER_USB_MODE */
|
||||
int index = data >> 24;
|
||||
if(index < 0 || index >= USB_NUM_DRIVERS) {
|
||||
logf("usb_core: invalid notification destination index=%u", index);
|
||||
return;
|
||||
}
|
||||
if(is_active(drivers[index]) && drivers[index].notify_event != NULL) {
|
||||
drivers[index].notify_event(data & 0x00ffffff);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue