fb.c 22.8 KB
Newer Older
1 2 3
/*****************************************************************************
 * fb.c : framebuffer plugin for vlc
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2000-2009 VLC authors and VideoLAN
5
 * $Id$
6 7
 *
 * Authors: Samuel Hocevar <sam@zoy.org>
8
 *          Jean-Paul Saman
9
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
10 11 12
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
13
 * (at your option) any later version.
14
 *
15 16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
19
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
20 21 22
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 24 25 26 27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
28 29 30 31 32

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33 34 35
#include <signal.h>                                      /* SIGUSR1, SIGUSR2 */
#include <fcntl.h>                                                 /* open() */
#include <unistd.h>                                               /* close() */
36
#include <errno.h>
37 38 39 40 41 42 43 44
#include <termios.h>                                       /* struct termios */
#include <sys/ioctl.h>
#include <sys/mman.h>                                              /* mmap() */

#include <linux/fb.h>
#include <linux/vt.h>                                                /* VT_* */
#include <linux/kd.h>                                                 /* KD* */

45
#include <vlc_common.h>
46
#include <vlc_plugin.h>
47 48
#include <vlc_vout_display.h>
#include <vlc_picture_pool.h>
49
#include <vlc_fs.h>
50 51 52 53 54 55

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
#define FB_DEV_VAR "fbdev"

Clément Stenac's avatar
Clément Stenac committed
56
#define DEVICE_TEXT N_("Framebuffer device")
57
#define DEVICE_LONGTEXT N_(\
58
    "Framebuffer device to use for rendering (usually /dev/fb0).")
Clément Stenac's avatar
Clément Stenac committed
59

60
#define TTY_TEXT N_("Run fb on current tty")
61
#define TTY_LONGTEXT N_(\
62
    "Run framebuffer on current TTY device (default enabled). " \
63
    "(disable tty handling with caution)")
64

65
#define FB_MODE_TEXT N_("Framebuffer resolution to use")
66
#define FB_MODE_LONGTEXT N_(\
67
    "Select the resolution for the framebuffer. Currently it supports " \
68
    "the values 0=QCIF 1=CIF 2=NTSC 3=PAL, 4=auto (default 4=auto)")
69

70
#define HW_ACCEL_TEXT N_("Framebuffer uses hw acceleration")
71
#define HW_ACCEL_LONGTEXT N_("Disable for double buffering in software.")
72

73
#define CHROMA_TEXT N_("Image format (default RGB)")
Rafaël Carré's avatar
Rafaël Carré committed
74
#define CHROMA_LONGTEXT N_("Chroma fourcc used by the framebuffer. Default is RGB since the fb device has no way to report its chroma.")
75

76 77
static int  Open (vlc_object_t *);
static void Close(vlc_object_t *);
Laurent Aimar's avatar
Laurent Aimar committed
78

79
vlc_module_begin ()
80 81 82
    set_shortname("Framebuffer")
    set_category(CAT_VIDEO)
    set_subcategory(SUBCAT_VIDEO_VOUT)
83
    add_loadfile(FB_DEV_VAR, "/dev/fb0", DEVICE_TEXT, DEVICE_LONGTEXT,
84
                 false)
85
    add_bool("fb-tty", true, TTY_TEXT, TTY_LONGTEXT, true)
86
    add_string( "fb-chroma", NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true )
87
    add_obsolete_string("fb-aspect-ratio")
88
    add_integer("fb-mode", 4, FB_MODE_TEXT, FB_MODE_LONGTEXT,
89
                 true)
90
    add_bool("fb-hw-accel", true, HW_ACCEL_TEXT, HW_ACCEL_LONGTEXT,
91 92 93 94
              true)
    set_description(N_("GNU/Linux framebuffer video output"))
    set_capability("vout display", 30)
    set_callbacks(Open, Close)
95
vlc_module_end ()
96

Laurent Aimar's avatar
Laurent Aimar committed
97 98 99
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
100
static picture_pool_t *Pool  (vout_display_t *, unsigned);
101
static void           Display(vout_display_t *, picture_t *, subpicture_t *);
102
static int            Control(vout_display_t *, int, va_list);
103 104 105 106

/* */
static int  OpenDisplay  (vout_display_t *, bool force_resolution);
static void CloseDisplay (vout_display_t *);
107
#if 0
108
static void SwitchDisplay(int i_signal);
109
#endif
110 111 112 113 114 115 116 117
static void TextMode     (int tty);
static void GfxMode      (int tty);

static int  TtyInit(vout_display_t *);
static void TtyExit(vout_display_t *);

/* */
struct vout_display_sys_t {
118
    /* System information */
119 120
    int                 tty;                          /* tty device handle */
    bool                is_tty;
121 122
    struct termios      old_termios;

123
    /* Original configuration information */
124
#if 0
125 126
    struct sigaction            sig_usr1;           /* USR1 previous handler */
    struct sigaction            sig_usr2;           /* USR2 previous handler */
127
#endif
128 129 130
    struct vt_mode              vt_mode;                 /* previous VT mode */

    /* Framebuffer information */
131
    int                         fd;                       /* device handle */
132 133
    struct fb_var_screeninfo    old_info;       /* original mode information */
    struct fb_var_screeninfo    var_info;        /* current mode information */
134
    bool                        has_pan;   /* does device supports panning ? */
135
    struct fb_cmap              fb_cmap;                /* original colormap */
136 137
    uint16_t                    *palette;                /* original palette */
    bool                        is_hw_accel;         /* has hardware support */
138 139

    /* Video information */
140 141
    uint32_t width;
    uint32_t height;
142
    uint32_t line_length;
143
    vlc_fourcc_t chroma;
144
    int      bytes_per_pixel;
145 146

    /* Video memory */
Rémi Denis-Courmont's avatar
Typos  
Rémi Denis-Courmont committed
147
    uint8_t     *video_ptr;                                 /* base address */
148
    size_t      video_size;                                    /* page size */
149

150 151
    picture_t       *picture;
    picture_pool_t  *pool;
152 153
};

154

155
static void ClearScreen(vout_display_sys_t *sys)
156
{
157
    switch (sys->chroma) {
158
    /* XXX: add other chromas */
159
    case VLC_CODEC_UYVY: {
160 161 162 163 164 165 166 167 168 169 170
        unsigned int j, size = sys->video_size / 4;
        uint32_t *ptr = (uint32_t*)((uintptr_t)(sys->video_ptr + 3) & ~3);
        for(j=0; j < size; j++)
            ptr[j] = 0x10801080;    /* U = V = 16, Y = 128 */
        break;
    }
    default:    /* RGB */
        memset(sys->video_ptr, 0, sys->video_size);
    }
}

Laurent Aimar's avatar
Laurent Aimar committed
171
/**
172
 * This function allocates and initializes a FB vout method.
Laurent Aimar's avatar
Laurent Aimar committed
173
 */
174
static int Open(vlc_object_t *object)
175
{
176 177
    vout_display_t     *vd = (vout_display_t *)object;
    vout_display_sys_t *sys;
178

179 180 181
    if (vout_display_IsWindowed(vd))
        return VLC_EGENERIC;

182
    /* Allocate instance and initialize some members */
183 184
    vd->sys = sys = calloc(1, sizeof(*sys));
    if (!sys)
185
        return VLC_ENOMEM;
186

187
    /* Does the framebuffer uses hw acceleration? */
188
    sys->is_hw_accel = var_InheritBool(vd, "fb-hw-accel");
189

190
    /* Set tty and fb devices */
191
    sys->tty = 0; /* 0 == /dev/tty0 == current console */
192
    sys->is_tty = var_InheritBool(vd, "fb-tty");
193
#if !defined(_WIN32) &&  defined(HAVE_ISATTY)
194
    /* Check that stdin is a TTY */
195
    if (sys->is_tty && !isatty(0)) {
196
        msg_Warn(vd, "standard input is not a TTY");
197
        free(sys);
198
        return VLC_EGENERIC;
199
    }
200 201
    msg_Warn(vd, "disabling TTY handling, use with caution because "
                 "there is no way to return to the TTY");
202
#endif
203

204
    const int mode = var_InheritInteger(vd, "fb-mode");
205 206
    bool force_resolution = true;
    switch (mode) {
Laurent Aimar's avatar
Laurent Aimar committed
207
    case 0: /* QCIF */
208 209
        sys->width  = 176;
        sys->height = 144;
Laurent Aimar's avatar
Laurent Aimar committed
210 211
        break;
    case 1: /* CIF */
212 213
        sys->width  = 352;
        sys->height = 288;
Laurent Aimar's avatar
Laurent Aimar committed
214 215
        break;
    case 2: /* NTSC */
216 217
        sys->width  = 640;
        sys->height = 480;
Laurent Aimar's avatar
Laurent Aimar committed
218 219
        break;
    case 3: /* PAL */
220 221
        sys->width  = 704;
        sys->height = 576;
Laurent Aimar's avatar
Laurent Aimar committed
222 223 224
        break;
    case 4:
    default:
225
        force_resolution = false;
Laurent Aimar's avatar
Laurent Aimar committed
226 227
        break;
    }
228

229
    char *chroma = var_InheritString(vd, "fb-chroma");
230 231
    if (chroma) {
        sys->chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma);
232 233

        if (sys->chroma)
234
            msg_Dbg(vd, "forcing chroma '%s'", chroma);
235
        else
236
            msg_Warn(vd, "chroma %s invalid, using default", chroma);
237

238
        free(chroma);
239
    } else
240 241
        sys->chroma = 0;

242
    /* tty handling */
243 244
    if (sys->is_tty && TtyInit(vd)) {
        free(sys);
Laurent Aimar's avatar
Laurent Aimar committed
245
        return VLC_EGENERIC;
246 247
    }

248 249 250 251 252 253 254 255 256 257 258
    /* */
    sys->video_ptr = MAP_FAILED;
    sys->picture = NULL;
    sys->pool = NULL;

    if (OpenDisplay(vd, force_resolution)) {
        Close(VLC_OBJECT(vd));
        return VLC_EGENERIC;
    }

    /* */
259 260
    video_format_t fmt;
    video_format_ApplyRotation(&fmt, &vd->fmt);
261

262
    if (sys->chroma) {
263
        fmt.i_chroma = sys->chroma;
264
    } else {
265 266
        /* Assume RGB */

267
        msg_Dbg(vd, "%d bppd", sys->var_info.bits_per_pixel);
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
        switch (sys->var_info.bits_per_pixel) {
        case 8: /* FIXME: set the palette */
            fmt.i_chroma = VLC_CODEC_RGB8;
            break;
        case 15:
            fmt.i_chroma = VLC_CODEC_RGB15;
            break;
        case 16:
            fmt.i_chroma = VLC_CODEC_RGB16;
            break;
        case 24:
            fmt.i_chroma = VLC_CODEC_RGB24;
            break;
        case 32:
            fmt.i_chroma = VLC_CODEC_RGB32;
            break;
        default:
            msg_Err(vd, "unknown screendepth %i", sys->var_info.bits_per_pixel);
            Close(VLC_OBJECT(vd));
            return VLC_EGENERIC;
        }
        if (sys->var_info.bits_per_pixel != 8) {
            fmt.i_rmask = ((1 << sys->var_info.red.length) - 1)
                                 << sys->var_info.red.offset;
            fmt.i_gmask = ((1 << sys->var_info.green.length) - 1)
                                 << sys->var_info.green.offset;
            fmt.i_bmask = ((1 << sys->var_info.blue.length) - 1)
                                 << sys->var_info.blue.offset;
        }
297
    }
298

Rafaël Carré's avatar
Rafaël Carré committed
299 300
    fmt.i_visible_width  = sys->width;
    fmt.i_visible_height = sys->height;
301

302 303
    /* */
    vd->fmt     = fmt;
304
    vd->pool    = Pool;
305 306 307 308 309
    vd->prepare = NULL;
    vd->display = Display;
    vd->control = Control;

    /* */
310
    vout_display_SendEventDisplaySize(vd, fmt.i_visible_width, fmt.i_visible_height);
311
    return VLC_SUCCESS;
312 313
}

Laurent Aimar's avatar
Laurent Aimar committed
314 315 316
/**
 * Terminate an output method created by Open
 */
317
static void Close(vlc_object_t *object)
318
{
319 320
    vout_display_t *vd = (vout_display_t *)object;
    vout_display_sys_t *sys = vd->sys;
321

322
    if (sys->pool)
323
        picture_pool_Release(sys->pool);
324 325
    if (!sys->is_hw_accel && sys->picture)
        picture_Release(sys->picture);
326

327
    CloseDisplay(vd);
Laurent Aimar's avatar
Laurent Aimar committed
328

329 330 331 332
    if (sys->is_tty)
        TtyExit(vd);

    free(sys);
Laurent Aimar's avatar
Laurent Aimar committed
333 334
}

335
/* */
336
static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
Laurent Aimar's avatar
Laurent Aimar committed
337
{
338 339 340 341 342 343 344 345 346
    vout_display_sys_t *sys = vd->sys;

    if (!sys->pool) {
        if (!sys->picture) {
            picture_resource_t rsc;

            memset(&rsc, 0, sizeof(rsc));
            rsc.p[0].p_pixels = sys->video_ptr;
            rsc.p[0].i_lines  = sys->var_info.yres;
347
            rsc.p[0].i_pitch = sys->line_length;
348 349 350 351 352

            sys->picture = picture_NewFromResource(&vd->fmt, &rsc);
            if (!sys->picture)
                return NULL;
        }
353

354 355 356
        if (sys->is_hw_accel)
            sys->pool = picture_pool_New(1, &sys->picture);
        else
357
            sys->pool = picture_pool_NewFromFormat(&vd->fmt, count);
Laurent Aimar's avatar
Laurent Aimar committed
358
    }
359
    return sys->pool;
360
}
361
static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
362 363
{
    vout_display_sys_t *sys = vd->sys;
364

365 366 367 368
    /* swap the two Y offsets if the drivers supports panning */
    if (sys->has_pan) {
        sys->var_info.yoffset = 0;
        /*vd->sys->var_info.yoffset = vd->sys->var_info.yres; */
369

370 371 372
        /* the X offset should be 0, but who knows ...
         * some other app might have played with the framebuffer */
        sys->var_info.xoffset = 0;
Laurent Aimar's avatar
Laurent Aimar committed
373

374 375 376 377 378 379
        /* FIXME 'static' is damn wrong and it's dead code ... */
        static int panned = 0;
        if (panned < 0) {
            ioctl(sys->fd, FBIOPAN_DISPLAY, &sys->var_info);
            panned++;
        }
Laurent Aimar's avatar
Laurent Aimar committed
380 381
    }

382 383
    if (!sys->is_hw_accel)
        picture_Copy(sys->picture, picture);
Laurent Aimar's avatar
Laurent Aimar committed
384

385
    picture_Release(picture);
386
    VLC_UNUSED(subpicture);
Laurent Aimar's avatar
Laurent Aimar committed
387
}
Laurent Aimar's avatar
Laurent Aimar committed
388
static int Control(vout_display_t *vd, int query, va_list args)
Laurent Aimar's avatar
Laurent Aimar committed
389
{
390 391
    (void) vd; (void) query; (void) args;
    return VLC_EGENERIC;
392
}
393

394 395
/* following functions are local */
static int TtyInit(vout_display_t *vd)
396
{
397
    vout_display_sys_t *sys = vd->sys;
398

399
    struct termios new_termios;
400

401
    GfxMode(sys->tty);
402

403 404 405
    /* Set keyboard settings */
    if (tcgetattr(0, &sys->old_termios) == -1) {
        msg_Err(vd, "tcgetattr failed");
406
    }
407

408 409
    if (tcgetattr(0, &new_termios) == -1) {
        msg_Err(vd, "tcgetattr failed");
410 411
    }

412 413 414 415 416 417 418
    /* new_termios.c_lflag &= ~ (ICANON | ISIG);
    new_termios.c_lflag |= (ECHO | ECHOCTL); */
    new_termios.c_lflag &= ~ (ICANON);
    new_termios.c_lflag &= ~(ECHO | ECHOCTL);
    new_termios.c_iflag = 0;
    new_termios.c_cc[VMIN] = 1;
    new_termios.c_cc[VTIME] = 0;
419

420 421
    if (tcsetattr(0, TCSAFLUSH, &new_termios) == -1) {
        msg_Err(vd, "tcsetattr failed");
422
    }
423

424
    ioctl(sys->tty, VT_RELDISP, VT_ACKACQ);
425

426
#if 0
427 428 429 430 431 432 433
    /* Set-up tty signal handler to be aware of tty changes */
    struct sigaction sig_tty;
    memset(&sig_tty, 0, sizeof(sig_tty));
    sig_tty.sa_handler = SwitchDisplay;
    sigemptyset(&sig_tty.sa_mask);
    if (sigaction(SIGUSR1, &sig_tty, &sys->sig_usr1) ||
        sigaction(SIGUSR2, &sig_tty, &sys->sig_usr2)) {
434
        msg_Err(vd, "cannot set signal handler (%s)", vlc_strerror_c(errno));
435 436
        /* FIXME SIGUSR1 could have succeed */
        goto error_signal;
437
    }
438
#endif
439

440 441
    /* Set-up tty according to new signal handler */
    if (-1 == ioctl(sys->tty, VT_GETMODE, &sys->vt_mode)) {
442
        msg_Err(vd, "cannot get terminal mode (%s)", vlc_strerror_c(errno));
443
        goto error;
444
    }
445 446 447 448 449
    struct vt_mode vt_mode = sys->vt_mode;
    vt_mode.mode   = VT_PROCESS;
    vt_mode.waitv  = 0;
    vt_mode.relsig = SIGUSR1;
    vt_mode.acqsig = SIGUSR2;
450

451
    if (-1 == ioctl(sys->tty, VT_SETMODE, &vt_mode)) {
452
        msg_Err(vd, "cannot set terminal mode (%s)", vlc_strerror_c(errno));
453
        goto error;
454
    }
455
    return VLC_SUCCESS;
456

457
error:
458
#if 0
459 460 461
    sigaction(SIGUSR1, &sys->sig_usr1, NULL);
    sigaction(SIGUSR2, &sys->sig_usr2, NULL);
error_signal:
462
#endif
463 464 465 466 467
    tcsetattr(0, 0, &sys->old_termios);
    TextMode(sys->tty);
    return VLC_EGENERIC;
}
static void TtyExit(vout_display_t *vd)
468
{
469
    vout_display_sys_t *sys = vd->sys;
Sam Hocevar's avatar
Sam Hocevar committed
470

471 472
    /* Reset the terminal */
    ioctl(sys->tty, VT_SETMODE, &sys->vt_mode);
473

474
#if 0
475 476 477
    /* Remove signal handlers */
    sigaction(SIGUSR1, &sys->sig_usr1, NULL);
    sigaction(SIGUSR2, &sys->sig_usr2, NULL);
478
#endif
479

480 481
    /* Reset the keyboard state */
    tcsetattr(0, 0, &sys->old_termios);
482

483 484
    /* Return to text mode */
    TextMode(sys->tty);
485 486 487 488 489
}

/*****************************************************************************
 * OpenDisplay: initialize framebuffer
 *****************************************************************************/
490
static int OpenDisplay(vout_display_t *vd, bool force_resolution)
491
{
492
    vout_display_sys_t *sys = vd->sys;
493 494 495
    char *psz_device;                             /* framebuffer device path */

    /* Open framebuffer device */
Rafaël Carré's avatar
Rafaël Carré committed
496
    if (!(psz_device = var_InheritString(vd, FB_DEV_VAR))) {
497
        msg_Err(vd, "don't know which fb device to open");
498
        return VLC_EGENERIC;
499 500
    }

501
    sys->fd = vlc_open(psz_device, O_RDWR);
502
    if (sys->fd == -1) {
503
        msg_Err(vd, "cannot open %s (%s)", psz_device, vlc_strerror_c(errno));
504
        free(psz_device);
505
        return VLC_EGENERIC;
506
    }
507
    free(psz_device);
508

509
    /* Get framebuffer device information */
510
    if (ioctl(sys->fd, FBIOGET_VSCREENINFO, &sys->var_info)) {
511
        msg_Err(vd, "cannot get fb info (%s)", vlc_strerror_c(errno));
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
512
        vlc_close(sys->fd);
513
        return VLC_EGENERIC;
514
    }
515
    sys->old_info = sys->var_info;
516

517
    /* Get some info on the framebuffer itself */
518 519 520
    if (force_resolution) {
        sys->var_info.xres = sys->var_info.xres_virtual = sys->width;
        sys->var_info.yres = sys->var_info.yres_virtual = sys->height;
521 522
    }

523
    /* Set some attributes */
524 525 526 527 528 529
    sys->var_info.activate = sys->is_tty ? FB_ACTIVATE_NXTOPEN :
                                           FB_ACTIVATE_NOW;
    sys->var_info.xoffset  =  0;
    sys->var_info.yoffset  =  0;

    if (ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->var_info)) {
530
        msg_Err(vd, "cannot set fb info (%s)", vlc_strerror_c(errno));
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
531
        vlc_close(sys->fd);
532
        return VLC_EGENERIC;
533 534
    }

535
    struct fb_fix_screeninfo fix_info;
536
    /* Get some information again, in the definitive configuration */
537
    if (ioctl(sys->fd, FBIOGET_FSCREENINFO, &fix_info) ||
538
        ioctl(sys->fd, FBIOGET_VSCREENINFO, &sys->var_info)) {
539 540
        msg_Err(vd, "cannot get additional fb info (%s)",
                vlc_strerror_c(errno));
541 542

        /* Restore fb config */
543
        ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->old_info);
544

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
545
        vlc_close(sys->fd);
546
        return VLC_EGENERIC;
547 548
    }

549 550
    /* If the fb has limitations on mode change,
     * then keep the resolution of the fb */
551 552 553 554 555
    if ((sys->height != sys->var_info.yres) ||
        (sys->width != sys->var_info.xres)) {
        msg_Warn(vd,
                 "using framebuffer native resolution instead of requested (%ix%i)",
                 sys->width, sys->height);
556
    }
557 558 559
    sys->height = sys->var_info.yres;
    sys->width  = sys->var_info.xres_virtual ? sys->var_info.xres_virtual :
                                               sys->var_info.xres;
560
    sys->line_length = fix_info.line_length;
561

562 563
    /* FIXME: if the image is full-size, it gets cropped on the left
     * because of the xres / xres_virtual slight difference */
564 565 566 567 568
    msg_Dbg(vd, "%ix%i (virtual %ix%i) (request %ix%i)",
            sys->var_info.xres, sys->var_info.yres,
            sys->var_info.xres_virtual,
            sys->var_info.yres_virtual,
            sys->width, sys->height);
569

570
    sys->palette = NULL;
571
    sys->has_pan = (fix_info.ypanstep || fix_info.ywrapstep);
572

573
    switch (sys->var_info.bits_per_pixel) {
574
    case 8:
575
        sys->palette = malloc(4 * 256 * sizeof(uint16_t));
576
        if (!sys->palette) {
577
            /* Restore fb config */
578
            ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->old_info);
579

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
580
            vlc_close(sys->fd);
581 582
            return VLC_ENOMEM;
        }
583 584 585
        sys->fb_cmap.start = 0;
        sys->fb_cmap.len = 256;
        sys->fb_cmap.red = sys->palette;
586 587 588
        sys->fb_cmap.green = sys->palette + 256;
        sys->fb_cmap.blue = sys->palette + 2 * 256;
        sys->fb_cmap.transp = sys->palette + 3 * 256;
589 590

        /* Save the colormap */
591
        ioctl(sys->fd, FBIOGETCMAP, &sys->fb_cmap);
592

593
        sys->bytes_per_pixel = 1;
594 595 596 597
        break;

    case 15:
    case 16:
598
        sys->bytes_per_pixel = 2;
599 600 601
        break;

    case 24:
602
        sys->bytes_per_pixel = 3;
603 604 605
        break;

    case 32:
606
        sys->bytes_per_pixel = 4;
607 608 609
        break;

    default:
610 611
        msg_Err(vd, "screen depth %d is not supported",
                sys->var_info.bits_per_pixel);
612 613

        /* Restore fb config */
614
        ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->old_info);
615

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
616
        vlc_close(sys->fd);
617
        return VLC_EGENERIC;
618 619
    }

620
    sys->video_size = sys->line_length * sys->var_info.yres_virtual;
621 622

    /* Map a framebuffer at the beginning */
623 624
    sys->video_ptr = mmap(NULL, sys->video_size,
                          PROT_READ | PROT_WRITE, MAP_SHARED, sys->fd, 0);
625

626
    if (sys->video_ptr == MAP_FAILED) {
627
        msg_Err(vd, "cannot map video memory (%s)", vlc_strerror_c(errno));
628

629 630 631
        if (sys->var_info.bits_per_pixel == 8) {
            free(sys->palette);
            sys->palette = NULL;
632 633 634
        }

        /* Restore fb config */
635
        ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->old_info);
636

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
637
        vlc_close(sys->fd);
638
        return VLC_EGENERIC;
639
    }
640

641
    ClearScreen(sys);
642

643 644
    msg_Dbg(vd,
            "framebuffer type=%d, visual=%d, ypanstep=%d, ywrap=%d, accel=%d",
645 646
            fix_info.type, fix_info.visual,
            fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel);
647
    return VLC_SUCCESS;
648 649 650 651 652
}

/*****************************************************************************
 * CloseDisplay: terminate FB video thread output method
 *****************************************************************************/
653
static void CloseDisplay(vout_display_t *vd)
654
{
655 656 657
    vout_display_sys_t *sys = vd->sys;

    if (sys->video_ptr != MAP_FAILED) {
658
        ClearScreen(sys);
659
        munmap(sys->video_ptr, sys->video_size);
660
    }
661

662
    if (sys->fd >= 0) {
663
        /* Restore palette */
664 665 666 667
        if (sys->var_info.bits_per_pixel == 8) {
            ioctl(sys->fd, FBIOPUTCMAP, &sys->fb_cmap);
            free(sys->palette);
            sys->palette = NULL;
668
        }
669

670
        /* Restore fb config */
671
        ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->old_info);
672

673
        /* Close fb */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
674
        vlc_close(sys->fd);
675
    }
676 677
}

678
#if 0
679 680 681 682 683 684
/*****************************************************************************
 * SwitchDisplay: VT change signal handler
 *****************************************************************************
 * This function activates or deactivates the output of the thread. It is
 * called by the VT driver, on terminal change.
 *****************************************************************************/
685
static void SwitchDisplay(int i_signal)
686
{
687
    vout_display_t *vd;
688

689
    vlc_mutex_lock(&p_vout_bank->lock);
690 691

    /* XXX: only test the first video output */
692
    if (p_vout_bank->i_count)
693
    {
694
        vd = p_vout_bank->pp_vout[0];
695

696
        switch (i_signal)
697 698
        {
        case SIGUSR1:                                /* vt has been released */
699 700
            vd->b_active = 0;
            ioctl(sys->tty, VT_RELDISP, 1);
701 702
            break;
        case SIGUSR2:                                /* vt has been acquired */
703 704
            vd->b_active = 1;
            ioctl(sys->tty, VT_RELDISP, VT_ACTIVATE);
705
            /* handle blanking */
706 707 708
            vlc_mutex_lock(&vd->change_lock);
            vd->i_changes |= VOUT_SIZE_CHANGE;
            vlc_mutex_unlock(&vd->change_lock);
709 710 711 712
            break;
        }
    }

713
    vlc_mutex_unlock(&p_vout_bank->lock);
714
}
715
#endif
716 717 718 719 720 721

/*****************************************************************************
 * TextMode and GfxMode : switch tty to text/graphic mode
 *****************************************************************************
 * These functions toggle the tty mode.
 *****************************************************************************/
722
static void TextMode(int tty)
723 724
{
    /* return to text mode */
725 726
    if (-1 == ioctl(tty, KDSETMODE, KD_TEXT)) {
        /*msg_Err(vd, "failed ioctl KDSETMODE KD_TEXT");*/
727 728 729
    }
}

730
static void GfxMode(int tty)
731 732
{
    /* switch to graphic mode */
733 734
    if (-1 == ioctl(tty, KDSETMODE, KD_GRAPHICS)) {
        /*msg_Err(vd, "failed ioctl KDSETMODE KD_GRAPHICS");*/
735 736
    }
}