Log to stderr, allow --log=-
[petitboot] / ui / twin / main-ps3.c
1 /*
2  * Petitboot twin bootloader for the PS3 game console
3  *
4  *  Copyright Geoff Levand <geoff@infradead.org>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; version 2 of the License.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #if defined(HAVE_CONFIG_H)
21 #include "config.h"
22 #endif
23
24 #define _GNU_SOURCE
25 #include <assert.h>
26 #include <errno.h>
27 #include <getopt.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <linux/input.h>
32 #include <sys/time.h>
33
34 #include "log/log.h"
35 #include "talloc/talloc.h"
36 #include "waiter/waiter.h"
37 #include "ui/common/timer.h"
38 #include "ui/common/ps3.h"
39
40 #include "pbt-client.h"
41 #include "pbt-main.h"
42
43 /* control to keyboard mappings for the sixaxis controller */
44
45 static const uint8_t ps3_sixaxis_map[] = {
46         0,              /*   0  Select          */
47         0,              /*   1  L3              */
48         0,              /*   2  R3              */
49         0,              /*   3  Start           */
50         KEY_UP,         /*   4  Dpad Up         */
51         KEY_RIGHT,      /*   5  Dpad Right      */
52         KEY_DOWN,       /*   6  Dpad Down       */
53         KEY_LEFT,       /*   7  Dpad Left       */
54         0,              /*   8  L2              */
55         0,              /*   9  R2              */
56         0,              /*  10  L1              */
57         0,              /*  11  R1              */
58         0,              /*  12  Triangle        */
59         KEY_ENTER,      /*  13  Circle          */
60         0,              /*  14  Cross           */
61         KEY_DELETE,     /*  15  Square          */
62         0,              /*  16  PS Button       */
63         0,              /*  17  nothing      */
64         0,              /*  18  nothing      */
65 };
66
67 static struct pbt_item *ps3_setup_system_item(struct pbt_menu *menu,
68         const struct pbt_menu_layout *layout)
69 {
70 #if 0
71         struct _twin_rect r;
72         struct pbt_item *main_item;
73         struct pbt_item *sub_item;
74         twin_pixmap_t *icon;
75
76         icon = pbt_icon_load(NULL);
77
78         /* Main item */
79
80         pbt_view_get_item_rect(menu->main, layout, icon, 0, &r);
81         main_item = pbt_item_create(menu->main, menu->main, &r);
82
83         if (!main_item)
84                 goto fail;
85
86         main_item->image = icon;
87
88         list_add_tail(menu->main->items_list, &main_item->list);
89
90         /* Sub items */
91
92         main_item->sub_items_list = talloc(main_item, struct list);
93         list_init(main_item->sub_items_list);
94
95         pbt_view_get_item_rect(menu->sub, layout, icon, 0, &r);
96         sub_item = pbt_item_create(main_item, menu->sub, &r);
97
98         if (!sub_item)
99                 goto fail;
100
101         sub_item->image = pbt_item_create_text_image(layout, pbt_rect_width(&r),
102                 pbt_rect_height(&r), icon, "Boot GameOS",
103                 "Reboot the PS3 into the GameOS");
104
105         list_add_tail(main_item->sub_items_list, &sub_item->list);
106
107         pbt_view_get_item_rect(menu->sub, layout, icon, 1, &r);
108         sub_item = pbt_item_create(main_item, menu->sub, &r);
109
110         if (!sub_item)
111                 goto fail;
112
113         sub_item->image = pbt_item_create_text_image(layout, pbt_rect_width(&r),
114                 pbt_rect_height(&r), icon, "Set Video Mode",
115                 "Set the current video mode");
116
117         list_add_tail(main_item->sub_items_list, &sub_item->list);
118
119         pbt_view_get_item_rect(menu->sub, layout, icon, 2, &r);
120         sub_item = pbt_item_create(main_item, menu->sub, &r);
121
122         if (!sub_item)
123                 goto fail;
124
125         sub_item->image = pbt_item_create_text_image(layout, pbt_rect_width(&r),
126                 pbt_rect_height(&r), icon, "Exit to Shell",
127                 "Exit to a system shell prompt");
128
129         list_add_tail(main_item->sub_items_list, &sub_item->list);
130
131         menu->sub->selected = sub_item;
132         menu->sub->items_list = main_item->sub_items_list;
133
134         return main_item;
135 fail:
136 #endif
137         // FIXME: need cleanup
138         assert(0);
139         return NULL;
140 }
141
142 static int ps3_setup_test_item(struct pbt_menu *menu,
143         const struct pbt_menu_layout *layout)
144 {
145 #if 0
146         struct _twin_rect r;
147         struct pbt_item *main_item;
148         struct pbt_item *sub_item;
149         twin_pixmap_t *icon;
150
151         icon = pbt_icon_load(PB_ARTWORK_PATH "/drive-harddisk.png");
152
153         /* Main item */
154
155         pbt_view_get_item_rect(menu->main, layout, icon, 1, &r);
156         main_item = pbt_item_create(menu->main, menu->main, &r);
157
158         if (!main_item)
159                 goto fail;
160
161         main_item->image = icon;
162
163         list_add_tail(menu->main->items_list, &main_item->list);
164
165         /* Sub items */
166
167         main_item->sub_items_list = talloc(main_item, struct list);
168         list_init(main_item->sub_items_list);
169
170         pbt_view_get_item_rect(menu->sub, layout, icon, 0, &r);
171         sub_item = pbt_item_create(main_item, menu->sub, &r);
172
173         if (!sub_item)
174                 goto fail;
175
176         sub_item->active = 0;
177         sub_item->image = pbt_item_create_text_image(layout, pbt_rect_width(&r),
178                 pbt_rect_height(&r), icon, "test 1",
179                 "text for test 1");
180
181         list_add_tail(main_item->sub_items_list, &sub_item->list);
182
183         pbt_view_get_item_rect(menu->sub, layout, icon, 1, &r);
184         sub_item = pbt_item_create(main_item, menu->sub, &r);
185
186         if (!sub_item)
187                 goto fail;
188
189         sub_item->active = 0;
190         sub_item->image = pbt_item_create_text_image(layout, pbt_rect_width(&r),
191                 pbt_rect_height(&r), icon, "test 2",
192                 "text for test 2");
193
194         list_add_tail(main_item->sub_items_list, &sub_item->list);
195
196         menu->sub->selected = sub_item;
197         menu->sub->items_list = main_item->sub_items_list;
198
199         return 0;
200
201 fail:
202 #endif
203         // FIXME: need cleanup
204         assert(0);
205         return -1;
206 }
207
208 static struct pbt_menu *ps3_menu_create(void *ctx, struct pbt_scr *scr)
209 {
210 #if 0
211         struct pbt_menu *menu;
212         struct _twin_rect r;
213         twin_pixmap_t *icon;
214         const struct pbt_border *border;
215         static const struct pbt_menu_layout layout = {
216                 .item_space = 10,
217                 .icon_space = 6,
218                 .title_font_size = 30,
219                 .title_font_color = 0xff000000,
220                 .text_font_size = 18,
221                 .text_font_color = 0xff400000,
222         };
223
224         assert(scr && scr->sig == pbt_scr_sig);
225
226         menu = talloc_zero(ctx, struct pbt_menu);
227
228         if (!menu)
229                 return NULL;
230
231         menu->sig = pbt_menu_sig;
232         menu->scr = scr;
233
234         icon = pbt_icon_load(NULL);
235
236         if (!icon)
237                 return NULL;
238
239         /* Setup main view */
240
241         border = &pbt_right_border;
242         r.left = 0;
243         r.top = 0;
244         r.right = icon->width + 2 * layout.item_space + 2 * layout.icon_space
245                 + border->left + border->right;
246         r.bottom = menu->scr->tscreen->height;
247
248         menu->main = pbt_view_create(menu, &r);
249
250         if (!menu->main)
251                 goto fail_main;
252
253         menu->main->background_color = 0x80000000;
254         menu->main->border = *border;
255         menu->main->items_list = talloc(menu->main, struct list);
256         list_init(menu->main->items_list);
257
258         /* Setup sub view */
259
260         r.left = r.right;
261         r.top = 0;
262         r.right = menu->scr->tscreen->width;
263         r.bottom = menu->scr->tscreen->height;
264
265         menu->sub = pbt_view_create(menu, &r);
266
267         if (!menu->sub)
268                 goto fail_sub;
269
270         menu->sub->background_color = 0x40000000;
271
272         /* Setup system item */
273
274         menu->main->selected = ps3_setup_system_item(menu, &layout);
275
276         if (!menu->main->selected)
277                 goto fail_main_item;
278
279         //ps3_setup_test_item(menu, &layout);
280
281         return menu;
282
283 fail_main_item:
284         // FIXME: need cleanup
285 fail_sub:
286         // FIXME: need cleanup
287 fail_main:
288         talloc_free(menu);
289 #endif
290         assert(0);
291         return NULL;
292 }
293
294 /**
295  * struct ps3_gui - Main gui program instance.
296  */
297
298
299 struct ps3_gui {
300         struct ui_timer timer;
301         struct ps3_flash_values values;
302         int dirty_values;
303
304         struct pbt_scr scr;
305         struct pbt_frame frame;
306         struct pbt_menu *menu;
307 };
308
309 static struct ps3_gui ps3;
310
311 static struct pbt_scr *ps3_scr_from_tscreen(twin_screen_t *tscreen)
312 {
313         assert(ps3.scr.tscreen == tscreen);
314         return &ps3.scr;
315 }
316
317 static twin_bool_t ps3_scr_event_cb(twin_screen_t *tscreen, twin_event_t *event)
318 {
319         struct pbt_scr *scr = ps3_scr_from_tscreen(tscreen);
320
321         pbt_dump_event("scr", NULL, event);
322
323         switch(event->kind) {
324         case TwinEventJoyButton:
325                 /* convert joystick events to key events */
326                 // FIXME: need to test
327                 if (event->u.js.control < sizeof(ps3_sixaxis_map)) {
328                         event->u.key.key = ps3_sixaxis_map[event->u.js.control];
329                         event->kind = event->u.js.value ? TwinEventKeyUp
330                                 : TwinEventKeyDown;
331                 }
332                 break;
333         default:
334                 break;
335         }
336         return TWIN_FALSE;
337 }
338
339 static void sig_handler(int signum)
340 {
341         DBGS("%d\n", signum);
342
343         switch (signum) {
344         case SIGALRM:
345                 ui_timer_sigalrm(&ps3.timer);
346                 break;
347         case SIGWINCH:
348 //              if (ps3.gui)
349 //                      gui_resize(ps3.gui);
350                 break;
351         default:
352                 assert(0 && "unknown sig");
353                 /* fall through */
354         case SIGINT:
355         case SIGHUP:
356         case SIGTERM:
357                 exit(EXIT_FAILURE);
358 //              if (ps3.gui)
359 //                      gui_abort(ps3.gui);
360                 break;
361         }
362 }
363
364 /**
365  * main - twin bootloader main routine.
366  */
367
368 int main(int argc, char *argv[])
369 {
370         static struct sigaction sa;
371         static struct pbt_opts opts;
372         int result;
373         int ui_result = -1;
374         unsigned int mode;
375
376         result = pbt_opts_parse(&opts, argc, argv);
377
378         if (result) {
379                 pbt_print_usage();
380                 return EXIT_FAILURE;
381         }
382
383         if (opts.show_help == pbt_opt_yes) {
384                 pbt_print_usage();
385                 return EXIT_SUCCESS;
386         }
387
388         if (opts.show_version == pbt_opt_yes) {
389                 pbt_print_version();
390                 return EXIT_SUCCESS;
391         }
392
393         if (strcmp(opts.log_file, "-")) {
394                 FILE *log = fopen(opts.log_file, "a");
395
396                 assert(log);
397                 pb_log_set_stream(log);
398         } else
399                 pb_log_set_stream(stderr);
400
401 #if defined(DEBUG)
402         pb_log_always_flush(1);
403 #endif
404
405         pb_log("--- pb-twin ---\n");
406
407         sa.sa_handler = sig_handler;
408         result = sigaction(SIGALRM, &sa, NULL);
409         result += sigaction(SIGHUP, &sa, NULL);
410         result += sigaction(SIGINT, &sa, NULL);
411         result += sigaction(SIGTERM, &sa, NULL);
412         result += sigaction(SIGWINCH, &sa, NULL);
413
414         if (result) {
415                 pb_log("%s sigaction failed.\n", __func__);
416                 return EXIT_FAILURE;
417         }
418
419         ps3.values = ps3_flash_defaults;
420
421         if (opts.reset_defaults != pbt_opt_yes)
422                 ps3.dirty_values = ps3_flash_get_values(&ps3.values);
423
424 #if 0
425         twin_feature_init(); // need it???
426
427         /* Setup screen. */
428
429 #if defined(HAVE_LIBTWIN_TWIN_X11_H)
430 # if defined(USE_X11)
431         if (1) {
432 # else
433         if (0) {
434 # endif
435                 //ps3.scr.x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
436                 ps3.scr.x11 = twin_x11_create(XOpenDisplay(0), 512, 384);
437
438                 if (!ps3.scr.x11) {
439                         perror("failed to create x11 screen !\n");
440                         return EXIT_FAILURE;
441                 }
442
443                 ps3.scr.tscreen = ps3.scr.x11->screen;
444         } else {
445 #else
446         if (1) {
447 #endif
448                 result = ps3_get_video_mode(&mode);
449
450                 /* Current becomes default if ps3_flash_get_values() failed. */
451
452                 if (ps3.dirty_values && !result)
453                         ps3.values.video_mode = mode;
454
455                 /* Set mode if not at default. */
456
457                 if (!result && (ps3.values.video_mode != (uint16_t)mode))
458                         ps3_set_video_mode(ps3.values.video_mode);
459
460                 ps3.scr.fbdev = twin_fbdev_create(-1, SIGUSR1);
461
462                 if (!ps3.scr.fbdev) {
463                         perror("failed to create fbdev screen !\n");
464                         return EXIT_FAILURE;
465                 }
466
467                 ps3.scr.tscreen = ps3.scr.fbdev->screen;
468         }
469
470         ps3.scr.tscreen->event_filter = pbt_scr_event;
471
472         twin_screen_set_background(ps3.scr.tscreen,
473                 pbt_background_load(ps3.scr.tscreen, NULL));
474
475         /* setup menu */
476
477         ps3.menu = ps3_menu_create(NULL, &ps3.scr);
478
479         if (!ps3.menu)
480                 return EXIT_FAILURE;
481
482         /* Console switch */
483
484         if (ps3.scr.fbdev)
485                 twin_fbdev_activate(ps3.scr.fbdev);
486
487         /* run twin */
488
489         // need to hookup pb waiters to twin...
490         twin_dispatch();
491
492 #endif
493
494         pb_log("--- end ---\n");
495
496         return ui_result ? EXIT_FAILURE : EXIT_SUCCESS;
497 }