nwztools/plattools: fix black screen issue in dualboot, rework dualboot

Sony added extensions to the frambuffer interface. It is important to take them
into account since the OF uses them and might leave the framebuffer in an
unusual state which would make the dualboot not display anything. Also rework
the dualboot code so that it can boot rockbox (not doing anything at the moment),
display all tools or boot the OF.

Change-Id: Ia0f589c9ec8558f375270841503c0964aff07f0b
This commit is contained in:
Amaury Pouly 2016-11-06 00:12:04 +01:00
parent d492f25c54
commit 5017babb30
7 changed files with 180 additions and 76 deletions

View file

@ -6,7 +6,7 @@ INCLUDES=-I.
LIB_FILES=nwz_lib.c nwz_lib_devlist.c
TOOL_FILES=dest_tool.c test_adc.c test_adc.c test_bl.c test_display.c \
test_keys.c test_power.c test_ts.c
test_keys.c test_power.c test_ts.c test_fb.c
ALL_ELF=$(patsubst %.c,%.elf,$(TOOL_FILES)) all_tools.elf dualboot.elf
all: $(ALL_ELF)

View file

@ -31,7 +31,8 @@
TOOL(test_display) \
TOOL(test_keys) \
TOOL(test_power) \
TOOL(test_ts)
TOOL(test_ts) \
TOOL(test_fb) \
typedef int (*nwz_tool_main_t)(int argc, char **argv);
@ -60,7 +61,7 @@ static void hello(void)
{
/* clear screen and display welcome message */
nwz_lcdmsg(true, 0, 0, "all_tools");
nwz_lcdmsg(false, 0, 2, "BACK: quit");
nwz_lcdmsg(false, 0, 1, "BACK: quit");
nwz_lcdmsg(false, 0, 2, "LEFT/RIGHT: change tool");
nwz_lcdmsg(false, 0, 3, "PLAY: run tool");
}

View file

@ -29,7 +29,14 @@
* error, the OF is run. This seems like the safest option since the OF is
* always there and might do magic things. */
bool boot_rockbox(void)
enum boot_mode
{
BOOT_ROCKBOX,
BOOT_TOOLS,
BOOT_OF
};
enum boot_mode get_boot_mode(void)
{
/* get time */
struct timeval deadline;
@ -37,7 +44,7 @@ bool boot_rockbox(void)
{
nwz_lcdmsg(false, 0, 2, "Cannot get time");
sleep(2);
return false;
return BOOT_OF;
}
/* open input device */
int input_fd = nwz_key_open();
@ -45,11 +52,11 @@ bool boot_rockbox(void)
{
nwz_lcdmsg(false, 0, 2, "Cannot open input device");
sleep(2);
return false;
return BOOT_OF;
}
deadline.tv_sec += 5;
/* wait for user action */
bool boot_rb = false;
enum boot_mode mode = BOOT_OF;
while(true)
{
/* get time */
@ -69,7 +76,8 @@ bool boot_rockbox(void)
int sec_left = deadline.tv_sec - cur_time.tv_sec;
sec_left += (deadline.tv_usec - cur_time.tv_usec + 999999) / 1000000; /* round up */
nwz_lcdmsgf(false, 0, 2, "Booting OF in %d seconds ", sec_left);
nwz_lcdmsg(false, 0, 3, "Press BACK to boot RB");
nwz_lcdmsg(false, 0, 3, "Press BACK to run tools");
nwz_lcdmsg(false, 0, 3, "Press PLAY to boot RB");
/* wait for a key (1s) */
int ret = nwz_key_wait_event(input_fd, 1000000);
if(ret != 1)
@ -77,14 +85,21 @@ bool boot_rockbox(void)
struct input_event evt;
if(nwz_key_read_event(input_fd, &evt) != 1)
continue;
if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt))
if(nwz_key_event_is_press(&evt))
continue;
if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_PLAY)
{
boot_rb = true;
mode = BOOT_ROCKBOX;
break;
}
else if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK)
{
mode = BOOT_TOOLS;
break;
}
}
nwz_key_close(input_fd);
return boot_rb;
return mode;
}
static char *boot_rb_argv[] =
@ -97,41 +112,40 @@ static char *boot_rb_argv[] =
NULL
};
static void wait_key(void)
{
int input_fd = nwz_key_open();
/* display input state in a loop */
while(1)
{
/* wait for event (10ms) */
int ret = nwz_key_wait_event(input_fd, 10000);
if(ret != 1)
continue;
struct input_event evt;
if(nwz_key_read_event(input_fd, &evt) != 1)
continue;
if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt))
break;
}
/* finish nicely */
nwz_key_close(input_fd);
}
int NWZ_TOOL_MAIN(all_tools)(int argc, char **argv);
int main(int argc, char **argv)
{
#if 0
/* make sure backlight is on and we are running the standard lcd mode */
int fb_fd = nwz_fb_open(true);
if(fb_fd >= 0)
{
struct nwz_fb_brightness bl;
nwz_fb_get_brightness(fb_fd, &bl);
bl.level = NWZ_FB_BL_MAX_LEVEL;
nwz_fb_set_brightness(fb_fd, &bl);
nwz_fb_set_standard_mode(fb_fd);
nwz_fb_close(fb_fd);
}
nwz_lcdmsg(true, 0, 0, "dualboot");
if(boot_rockbox())
/* run all tools menu */
enum boot_mode mode = get_boot_mode();
if(mode == BOOT_TOOLS)
{
/* run tools and then run OF */
NWZ_TOOL_MAIN(all_tools)(argc, argv);
}
else if(mode == BOOT_ROCKBOX)
{
/* boot rockox */
nwz_lcdmsg(true, 0, 3, "Booting rockbox...");
/* in the future, we will run rockbox here, for now we just print a
* message */
execvp("/usr/local/bin/lcdmsg", boot_rb_argv);
/* fallback to OF in case of failure */
nwz_lcdmsg(false, 0, 4, "failed.");
sleep(5);
}
/* if for some reason, running rockbox failed, then try to run the OF */
/* boot OF */
nwz_lcdmsg(true, 0, 3, "Booting OF...");
execvp("/usr/local/bin/SpiderApp.of", argv);
@ -140,42 +154,4 @@ int main(int argc, char **argv)
/* if we reach this point, everything failed, so return an error so that
* sysmgrd knows something is wrong */
return 1;
#elif 0
const char *args_mount[] = {"mount", NULL};
int status;
char *output = nwz_run_pipe("mount", args_mount, &status);
nwz_lcdmsgf(true, 0, 0, "%d\n%s", status, output);
free(output);
wait_key();
const char *args_ls[] = {"ls", "/var", NULL};
output = nwz_run_pipe("ls", args_ls, &status);
nwz_lcdmsgf(true, 0, 0, "%d\n%s", status, output);
free(output);
wait_key();
const char *args_glogctl[] = {"glogctl", "flush", NULL};
output = nwz_run_pipe("/usr/local/bin/glogctl", args_glogctl, &status);
nwz_lcdmsgf(true, 0, 0, "%d\n%s", status, output);
free(output);
wait_key();
system("cp /var/GEMINILOG* /contents/");
sync();
execvp("/usr/local/bin/SpiderApp.of", argv);
return 0;
#else
/* make sure backlight is on */
int fb_fd = nwz_fb_open(true);
if(fb_fd >= 0)
{
struct nwz_fb_brightness bl;
nwz_fb_get_brightness(fb_fd, &bl);
bl.level = NWZ_FB_BL_MAX_LEVEL;
nwz_fb_set_brightness(fb_fd, &bl);
nwz_fb_close(fb_fd);
}
/* run all tools menu */
NWZ_TOOL_MAIN(all_tools)(argc, argv);
/* run OF */
execvp("/usr/local/bin/SpiderApp.of", argv);
return 0;
#endif
}

View file

@ -50,7 +50,90 @@ struct nwz_fb_brightness
int period; /* period in ms between steps when changing: >=10 */
};
#define NWZ_FB_SET_BRIGHTNESS _IOW(NWZ_FB_TYPE, 0x07, struct nwz_fb_brightness)
#define NWZ_FB_GET_BRIGHTNESS _IOR(NWZ_FB_TYPE, 0x08, struct nwz_fb_brightness)
/* FB extensions:
*
* Sony added relatively complicated extensions to the framebuffer. They allow
* better control of framebuffer refresh, double-buffering and mixing with DSP
* (v4l2). Each outout (LCD and TV) has two buffers, called page 0 and 1 (or A
* and B). Each page has its own attributes (image info) that control
* transparency, rotation and updates. At any point in time, the LCD is drawing
* a page and one can select the next page to draw. Unless an UPDATE ioctl()
* is made to change it, the next page will be the same as the one being drawn.
*
* FIXME I don't know what the timer is, it seems irrelevant for the LCD but
* the OF uses it for TV, maybe this controls the refresh rate of the TV output?
*
* On a side note, this information only applies to a subset of LCD types (the
* LCD type can be gathered from icx_sysinfo):
* - BB(0): AQUILA BB LCD
* - SW(1): SWAN or FIJI LCD
* - FC(2): FALCON OLED
* - GM(3): GUAM and ROTA LCD
* - FR(5): FURANO LCD ---> /!\ DOES NOT APPLY /!\
* - SD(6): SPICA_D LCD
* - AQ(7): AQUILA LCD
*/
/* Image infomation:
* SET_MODE will change the attributes of the requested page (ie .page)
* GET_MODE will return the attributes of the currently being displayed page
* UPDATE will do the same thing as SET_MODE but immediately refreshes the screen */
struct nwz_fb_image_info
{
int tc_enable; /* enable(1)/disable(0) transparent color */
int t_color; /* transparent color (16bpp RGB565) */
int alpha; /* alpha ratio (0 - 255) */
int page; /* 2D framebuffer page(0/1) */
int rot; /* LCD image rotation(0/1=180deg.) */
int update; /* only use with NWZ_FB_UPDATE, ignored for others */
};
/* update type */
#define NWZ_FB_ONLY_2D_MODE 0
#define NWZ_FB_DSP_AND_2D_MODE 1
/* frame buffer page infomation: when NWZ_FB_WAIT_REFREHS is called, the driver
* will wait until the next refresh or the timeout, whichever comes first. It
* will then fill this structure with the page status. */
struct nwz_fb_status
{
int timeout; /* waiting time for any frame ready (in units of 10 ms) */
int page0; /* page 0 is out of display or waiting to be displayed */
int page1; /* page 0 is out of display or waiting to be displayed */
};
/* frame buffer page status */
#define NWZ_FB_OUT_OF_DISPLAY 0
#define NWZ_FB_WAITING_FOR_ON_DISPLAY 1
/* frame buffer update timer infomation (use I/F fb <-> 2D API) */
struct nwz_fb_update_timer
{
int timerflag; /* auto update off(0) / auto update on(1) */
int timeout; /* timeout timer value (ms) */
};
/* timer flags */
#define NWZ_FB_TIMER_ON 1
#define NWZ_FB_TIMER_OFF 0
/* default and minimum timeout value */
#define NWZ_FB_DEFAULT_TIMEOUT 60
#define NWZ_FB_MIN_TIMEOUT 33
/* mmap offsets for page 1 (page 0 is always at address 0) */
#define NWZ_FB_LCD_PAGE_OFFSET 0x2f000
/* NOTE: I renamed those from Sony's header, because their original names were
* pure crap */
/* FIXME: Sony uses _IOR for NWZ_FB_WAIT_REFRESH but it should be _IORW */
#define NWZ_FB_WAIT_REFRESH _IORW(NWZ_FB_TYPE, 0x00, struct nwz_fb_status)
#define NWZ_FB_UPDATE _IOW(NWZ_FB_TYPE, 0x01, struct nwz_fb_image_info)
#define NWZ_FB_SET_MODE _IOW(NWZ_FB_TYPE, 0x02, struct nwz_fb_image_info)
#define NWZ_FB_GET_MODE _IOR(NWZ_FB_TYPE, 0x03, struct nwz_fb_image_info)
#define NWZ_FB_UPDATE_TIMER _IOR(NWZ_FB_TYPE, 0x04, struct nwz_fb_update_timer)
#define NWZ_FB_SET_BRIGHTNESS _IOW(NWZ_FB_TYPE, 0x07, struct nwz_fb_brightness)
#define NWZ_FB_GET_BRIGHTNESS _IOR(NWZ_FB_TYPE, 0x08, struct nwz_fb_brightness)
#endif /* __NWZ_FB_H__ */

View file

@ -238,6 +238,27 @@ int nwz_fb_set_brightness(int fd, struct nwz_fb_brightness *bl)
return 1;
}
int nwz_fb_set_standard_mode(int fd)
{
/* disable timer (apparently useless with LCD) */
struct nwz_fb_update_timer update_timer;
update_timer.timerflag = NWZ_FB_TIMER_OFF;
update_timer.timeout = NWZ_FB_DEFAULT_TIMEOUT;
if(ioctl(fd, NWZ_FB_UPDATE_TIMER, &update_timer) < 0)
return -1;
/* set page 0 mode to no transparency and no rotation */
struct nwz_fb_image_info mode_info;
mode_info.tc_enable = 0;
mode_info.t_color = 0;
mode_info.alpha = 0;
mode_info.rot = 0;
mode_info.page = 0;
mode_info.update = NWZ_FB_ONLY_2D_MODE;
if(ioctl(fd, NWZ_FB_UPDATE, &mode_info) < 0)
return -2;
return 0;
}
int nwz_adc_open(void)
{
return open(NWZ_ADC_DEV, O_RDONLY);

View file

@ -85,6 +85,9 @@ void nwz_fb_close(int fb);
int nwz_fb_get_brightness(int fd, struct nwz_fb_brightness *bl);
/* set backlight brightness (return -1 on error, 1 on success) */
int nwz_fb_set_brightness(int fd, struct nwz_fb_brightness *bl);
/* setup framebuffer to its standard mode: LCD output, page 0, no transparency
* and no rotation, 2D only updates */
int nwz_fb_set_standard_mode(int fd);
/* open adc device */
int nwz_adc_open(void);

View file

@ -25,7 +25,27 @@ int NWZ_TOOL_MAIN(test_display)(int argc, char **argv)
{
/* clear screen and display welcome message */
nwz_lcdmsg(true, 0, 0, "test_display");
nwz_lcdmsg(false, 3, 10, "This program will stop in 5 seconds");
sleep(5);
nwz_lcdmsg(false, 0, 1, "BACK: quit");
/* wait for key */
int input_fd = nwz_key_open();
if(input_fd < 0)
{
sleep(2);
return 1;
}
while(1)
{
/* wait for event */
int ret = nwz_key_wait_event(input_fd, 1000000);
if(ret != 1)
continue;
struct input_event evt;
if(nwz_key_read_event(input_fd, &evt) != 1)
continue;
/* handle quit */
if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt))
break;
}
nwz_key_close(input_fd);
return 0;
}