1/**
2 * \file
3 * \brief Framebuffer glue
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <barrelfish/barrelfish.h>
19#include <if/fb_defs.h>
20#include <if/keyboard_defs.h>
21#include <barrelfish/nameservice_client.h>
22#include <vfs/vfs.h>
23#include <vfs/vfs_path.h>
24
25#include "slideshow.h"
26
27static struct fb_binding *fb_client;
28static struct keyboard_binding *kb_client;
29
30static char *vidmem;    /// Pointer to video memory
31
32// original video mode
33static uint16_t origmode;
34static bool origlinear;
35static char fontbackup[65536];
36
37void wait_for_vsync(void)
38{
39    errval_t err = fb_client->rpc_tx_vtbl.vsync(fb_client);
40    assert(err_is_ok(err));
41}
42
43void quit(void)
44{
45    errval_t err, ret;
46
47    // Restore font backup
48    memcpy(vidmem, fontbackup, 65536);
49
50    err = fb_client->rpc_tx_vtbl.set_vesamode(fb_client, origmode, origlinear,
51                                      true, &ret);
52    assert(err_is_ok(err));
53    assert(err_is_ok(ret));
54    exit(0);
55}
56
57static struct keyboard_rx_vtbl keyboard_rx_vtbl = {
58    .key_event = keyboard_key_event,
59};
60
61static void keyboard_connected_callback(void *st, errval_t err,
62                                        struct keyboard_binding *cl)
63{
64    assert(err_is_ok(err));
65    cl->rx_vtbl = keyboard_rx_vtbl;
66    kb_client = cl;
67}
68
69static void fb_connected_callback(void *st, errval_t err, struct fb_binding *b)
70{
71    assert(err_is_ok(err));
72
73    fb_client = b;
74    fb_rpc_client_init(fb_client);
75}
76
77static void start_keyboard_client(void)
78{
79    iref_t iref;
80    errval_t err;
81
82    err = nameservice_blocking_lookup("keyboard", &iref);
83    if (err_is_fail(err)) {
84        fprintf(stderr, "slideshow: could not connect to the keyboard driver.\n");
85        abort();
86    }
87    assert(iref != 0);
88
89    err = keyboard_bind(iref, keyboard_connected_callback, NULL,
90                        get_default_waitset(), IDC_BIND_FLAGS_DEFAULT);
91    assert(err_is_ok(err));
92}
93
94static int fb_client_connect(void)
95{
96    iref_t iref;
97    errval_t err;
98
99    err = nameservice_blocking_lookup("framebuffer", &iref);
100    if (err_is_fail(err)) {
101        DEBUG_ERR(err, "could not lookup IREF for framebuffer driver");
102        abort();
103    }
104
105    err = fb_bind(iref, fb_connected_callback, NULL, get_default_waitset(),
106                  IDC_BIND_FLAG_RPC_CAP_TRANSFER);
107    if (err_is_fail(err)) {
108        DEBUG_ERR(err, "could not connect to framebuffer driver");
109        abort();
110    }
111
112    return 0;
113}
114
115static int keyboard_client_connect(void)
116{
117    start_keyboard_client();
118    while (kb_client == NULL) {
119        messages_wait_and_handle_next();
120    }
121    return 0;
122}
123
124static int cmpstringp(const void *p1, const void *p2)
125{
126    return strcmp(*(char * const *)p1, *(char * const *)p2);
127}
128
129static void load_slides(const char *indir)
130{
131    errval_t err;
132
133    // Make dir relative to '/'
134    char *dir = vfs_path_mkabsolute("/", indir);
135    assert(dir != NULL);
136
137    vfs_handle_t dh;
138    err = vfs_opendir(dir, &dh);
139    if (err_is_fail(err)) {
140        USER_PANIC_ERR(err, "error opening directory\n");
141    }
142
143    char *paths[MAX_SLIDES] = { NULL };
144    for(;;) {
145        struct vfs_fileinfo info;
146        char *name;
147
148        err = vfs_dir_read_next(dh, &name, &info);
149        if (err_is_fail(err)) {
150            if (err_no(err) == FS_ERR_INDEX_BOUNDS) {
151                break;
152            } else {
153                USER_PANIC_ERR(err, "error reading directory\n");
154            }
155        }
156
157        if (info.type == VFS_DIRECTORY) {
158            printf("Skipped %s", name);
159            free(name);
160            continue;
161        }
162
163        paths[nslides] = vfs_path_mkabsolute(dir, name);
164        assert(paths[nslides] != NULL);
165        free(name);
166
167        if (++nslides == MAX_SLIDES) {
168            printf("slideshow: reached MAX_SLIDES (%d)\n", MAX_SLIDES);
169            break;
170        }
171    }
172
173    // Sort filenames
174    qsort(paths, nslides, sizeof(char *), cmpstringp);
175
176    for(int i = 0; i < nslides; i++) {
177        printf("Opening %s\n", paths[i]);
178
179        vfs_handle_t fh;
180        err = vfs_open(paths[i], &fh);
181        if (err_is_fail(err)) {
182            USER_PANIC_ERR(err, "failed to open '%s'\n", paths[i]);
183        }
184
185        struct vfs_fileinfo info;
186        err = vfs_stat(fh, &info);
187        if (err_is_fail(err)) {
188            USER_PANIC_ERR(err, "failed to stat '%s'\n", paths[i]);
189        }
190
191        void *buf = malloc(info.size);
192        assert(buf != NULL);
193
194        size_t len;
195        err = vfs_read(fh, buf, info.size, &len);
196        if (err_is_fail(err)) {
197            USER_PANIC_ERR(err, "vfs_read '%s' failed\n", paths[i]);
198        } else if (len != info.size) {
199            USER_PANIC("short read %lu != %lu\n", len, info.size);
200        }
201
202        vfs_close(fh);
203        free(paths[i]);
204
205        slide[i] = buf;
206        slide_length[i] = info.size;
207    }
208
209    vfs_closedir(dh);
210    free(dir);
211}
212
213int main(int argc, char *argv[])
214{
215    int xres, yres, bpp;
216    errval_t err, ret;
217
218    // Parse commandline
219    if(argc < 5) {
220        fprintf(stderr, "Usage: %s <xres> <yres> <bpp> <slides path>\n",
221                argv[0]);
222        return EXIT_FAILURE;
223    }
224
225    xres = atoi(argv[1]);
226    yres = atoi(argv[2]);
227    bpp = atoi(argv[3]);
228
229    vfs_init();
230
231    // Connect to framebuffer driver
232    fb_client_connect();
233
234    // Connect to keyboard driver
235    keyboard_client_connect();
236
237    // Load the slides off multiboot
238    load_slides(argv[4]);
239
240    // Get current video mode
241    err = fb_client->rpc_tx_vtbl.get_vesamode(fb_client, &origmode, &origlinear, &ret);
242    assert(err_is_ok(err));
243    assert(err_is_ok(ret));
244
245    // Set videomode
246    err = fb_client->rpc_tx_vtbl.set_videomode(fb_client, xres, yres, bpp, &ret);
247    assert(err_is_ok(err));
248    assert(err_is_ok(ret));
249
250    // Get and map framebuffer
251    struct capref fbcap;
252    uint32_t fboffset;
253    err = fb_client->rpc_tx_vtbl.get_framebuffer(fb_client, &ret, &fbcap, &fboffset);
254    assert(err_is_ok(err));
255    assert(err_is_ok(ret));
256
257    struct frame_identity fbid = { .base = 0, .bytes = 0 };
258    err = invoke_frame_identify(fbcap, &fbid);
259    assert(err_is_ok(err));
260    err = vspace_map_one_frame((void**)&vidmem, fbid.bytes, fbcap,
261                               NULL, NULL);
262    assert(err_is_ok(err));
263
264    vidmem += fboffset;
265
266    // Save textmode bit of framebuffer and hopefully capture the font
267    memcpy(fontbackup, vidmem, 65536);
268
269    // Start the show
270    slideshow(vidmem, xres, yres, bpp);
271    messages_handler_loop();
272}
273