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