aboutsummaryrefslogtreecommitdiffstats
path: root/console/fbtv.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2010-04-01 11:24:38 +0200
committerGerd Hoffmann <kraxel@redhat.com>2010-04-01 11:24:38 +0200
commita4a3e6b21da7d11e66364ab9ab67795a3f78020a (patch)
tree4ab98e8339361b8a4c89bedbe8888055292746b6 /console/fbtv.c
parentf53a049ec82b6e1d0877a93387ed4d15797749a2 (diff)
v3.74
Diffstat (limited to 'console/fbtv.c')
-rw-r--r--console/fbtv.c905
1 files changed, 905 insertions, 0 deletions
diff --git a/console/fbtv.c b/console/fbtv.c
new file mode 100644
index 0000000..95e8b6f
--- /dev/null
+++ b/console/fbtv.c
@@ -0,0 +1,905 @@
+/*
+ * console TV application. Uses a framebuffer device.
+ *
+ * (c) 1998-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <curses.h>
+#include <math.h>
+#include <pthread.h>
+
+#include <linux/kd.h>
+#include <linux/fb.h>
+
+#include "grab-ng.h"
+#include "writefile.h"
+#include "sound.h"
+#include "channel.h"
+#include "frequencies.h"
+#include "commands.h"
+#include "capture.h"
+#include "lirc.h"
+#include "joystick.h"
+#include "midictrl.h"
+#include "event.h"
+
+#include "fbtools.h"
+#include "fs.h"
+#include "matrox.h"
+
+#define MAX(x,y) ((x)>(y)?(x):(y))
+#define MIN(x,y) ((x)<(y)?(x):(y))
+
+/* ---------------------------------------------------------------------- */
+/* framebuffer */
+
+static char *fbdev = NULL;
+static char *fontfile = NULL;
+static char *mode = NULL;
+static char *joydev = NULL;
+static struct fs_font *f;
+#ifndef X_DISPLAY_MISSING
+static char *x11_font = "10x20";
+#endif
+
+static unsigned short red[256], green[256], blue[256];
+static struct fb_cmap cmap = { 0, 256, red, green, blue };
+
+static int switch_last,fb;
+static int keep_dma_on = 0;
+
+static int sig,quiet,matrox;
+static int ww,hh;
+static float fbgamma = 1.0;
+
+static struct ng_video_buf *buf;
+static struct ng_video_fmt fmt,gfmt;
+static struct ng_video_conv *conv;
+static struct ng_convert_handle *ch;
+static int dx,dy;
+
+int have_config;
+int x11_native_format,have_dga=1,debug;
+
+/*--- channels ------------------------------------------------------------*/
+
+struct event_entry kbd_events[] = {
+ {
+ event: "kbd-key-+",
+ action: "volume inc",
+ },{
+ event: "kbd-key--",
+ action: "volume dec",
+ },{
+ event: "kbd-key-enter",
+ action: "volume mute",
+ },{
+ event: "kbd-key-space",
+ action: "setstation next",
+ },{
+ event: "kbd-key-backspace",
+ action: "setstation back",
+ },{
+ event: "kbd-key-pgup",
+ action: "setstation prev",
+ },{
+ event: "kbd-key-pgdown",
+ action: "setstation next",
+ },{
+ event: "kbd-key-right",
+ action: "setchannel fine_up",
+ },{
+ event: "kbd-key-left",
+ action: "setchannel fine_down",
+ },{
+ event: "kbd-key-up",
+ action: "setchannel next",
+ },{
+ event: "kbd-key-down",
+ action: "setchannel prev",
+ },{
+ event: "kbd-key-g",
+ action: "snap ppm",
+ },{
+ event: "kbd-key-j",
+ action: "snap jpeg",
+ },{
+ event: "kbd-key-v",
+ action: "capture toggle",
+ },{
+ event: "kbd-key-f",
+ action: "fullscreen toggle",
+ },{
+ event: "kbd-key-0",
+ action: "keypad 0",
+ },{
+ event: "kbd-key-1",
+ action: "keypad 1",
+ },{
+ event: "kbd-key-2",
+ action: "keypad 2",
+ },{
+ event: "kbd-key-3",
+ action: "keypad 3",
+ },{
+ event: "kbd-key-4",
+ action: "keypad 4",
+ },{
+ event: "kbd-key-5",
+ action: "keypad 5",
+ },{
+ event: "kbd-key-6",
+ action: "keypad 6",
+ },{
+ event: "kbd-key-7",
+ action: "keypad 7",
+ },{
+ event: "kbd-key-8",
+ action: "keypad 8",
+ },{
+ event: "kbd-key-9",
+ action: "keypad 9",
+ },{
+
+ /* end of list */
+ }
+};
+struct KEYTAB {
+ int key;
+ char *name;
+};
+
+static struct KEYTAB keytab[] = {
+ { 9, "tab" },
+ { 10, "enter" },
+ { 13, "enter" },
+ { KEY_ENTER, "enter" },
+
+ { ' ', "space" },
+ { KEY_BACKSPACE, "backspace" },
+
+ { KEY_RIGHT, "right" },
+ { KEY_LEFT, "left" },
+ { KEY_UP, "up" },
+ { KEY_DOWN, "down" },
+ { KEY_PPAGE, "pgup" },
+ { KEY_NPAGE, "pgdown" },
+ { KEY_HOME, "home" },
+ { KEY_END, "end" },
+};
+
+#define NKEYTAB (sizeof(keytab)/sizeof(struct KEYTAB))
+
+static char *snapbase;
+static char default_title[128] = "???";
+static char message[128] = "";
+
+/* ---------------------------------------------------------------------- */
+/* framebuffer stuff */
+
+static void
+linear_palette(int bit)
+{
+ int i, size = 256 >> (8 - bit);
+
+ for (i = 0; i < size; i++)
+ red[i] = green[i] = blue[i] = (unsigned short)(65535.0
+ * pow(i/(size - 1.0), fbgamma));
+}
+
+static void
+dither_palette(int r, int g, int b)
+{
+ int rs, gs, bs, i;
+
+ rs = 256 / (r - 1);
+ gs = 256 / (g - 1);
+ bs = 256 / (b - 1);
+ for (i = 0; i < r*g*b; i++) {
+ green[i+16] = (gs * ((i / (r * b)) % g)) * 255;
+ red[i+16] = (rs * ((i / b) % r)) * 255;
+ blue[i+16] = (bs * ((i) % b)) * 255;
+ }
+}
+
+static void
+fb_initcolors(int fd, int gray)
+{
+ /* get colormap */
+ if (fb_var.bits_per_pixel == 8 ||
+ fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ if (-1 == ioctl(fd,FBIOGETCMAP,&cmap))
+ perror("ioctl FBIOGETCMAP");
+ }
+
+ switch (fb_var.bits_per_pixel) {
+ case 8:
+ if (gray) {
+ linear_palette(8);
+ x11_native_format = VIDEO_GRAY;
+ } else {
+ dither_palette(5,9,5);
+ x11_native_format = VIDEO_RGB08;
+ }
+ break;
+ case 15:
+ case 16:
+ if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
+ linear_palette(5);
+#if BYTE_ORDER == BIG_ENDIAN
+ x11_native_format = (fb_var.green.length == 6) ?
+ VIDEO_RGB16_BE : VIDEO_RGB15_BE;
+#else
+ x11_native_format = (fb_var.green.length == 6) ?
+ VIDEO_RGB16_LE : VIDEO_RGB15_LE;
+#endif
+ break;
+ case 24:
+ if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
+ linear_palette(8);
+#if BYTE_ORDER == BIG_ENDIAN
+ x11_native_format = VIDEO_RGB24;
+#else
+ x11_native_format = VIDEO_BGR24;
+#endif
+ break;
+ case 32:
+ if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
+ linear_palette(8);
+#if BYTE_ORDER == BIG_ENDIAN
+ x11_native_format = VIDEO_RGB32;
+#else
+ x11_native_format = VIDEO_BGR32;
+#endif
+ break;
+ default:
+ fprintf(stderr, "Oops: %i bit/pixel ???\n",
+ fb_var.bits_per_pixel);
+ exit(1);
+ }
+
+ /* set colormap */
+ if (fb_var.bits_per_pixel == 8 ||
+ fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ if (-1 == ioctl(fd,FBIOPUTCMAP,&cmap))
+ perror("ioctl FBIOPUTCMAP");
+ }
+}
+
+static void
+tty_init(void)
+{
+ /* we use curses just for kbd input */
+ initscr();
+ cbreak();
+ noecho();
+ keypad(stdscr,1);
+}
+
+static void
+tty_cleanup(void)
+{
+ clear();
+ refresh();
+ endwin();
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+static void
+text_init(char *font)
+{
+ char *fonts[2] = { font, NULL };
+
+ if (NULL == f)
+ f = fs_consolefont(font ? fonts : NULL);
+#ifndef X_DISPLAY_MISSING
+ if (NULL == f && 0 == fs_connect(NULL))
+ f = fs_open(font ? font : x11_font);
+#endif
+ if (NULL == f) {
+ fprintf(stderr,"no font available\n");
+ exit(1);
+ }
+}
+
+static void
+text_out(int x, int y, char *str)
+{
+ y *= f->height;
+ y -= f->fontHeader.max_bounds.descent;
+ fs_puts(f,x,y,str);
+}
+
+static int
+text_width(char *str)
+{
+ return fs_textwidth(f,str);
+}
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef HAVE_ALSA
+static struct midi_handle fb_midi;
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static void
+ctrlc(int signal)
+{
+ sig=1;
+}
+
+#if 0
+void
+change_audio(int mode)
+{
+ if (grabber->grab_audio)
+ grabber->grab_audio(-1,-1,&mode);
+}
+#endif
+
+static void do_capture(int from, int to, int tmp_switch)
+{
+ /* off */
+ switch (from) {
+ case CAPTURE_GRABDISPLAY:
+ if (f_drv & CAN_CAPTURE)
+ drv->stopvideo(h_drv);
+ break;
+ case CAPTURE_OVERLAY:
+ if (f_drv & CAN_CAPTURE)
+ drv->overlay(h_drv,NULL,0,0,NULL,0,0);
+ if (matrox && !tmp_switch)
+ gfx_scaler_off();
+ break;
+ }
+
+ /* on */
+ memset(&buf,0,sizeof(buf));
+ switch (to) {
+ case CAPTURE_GRABDISPLAY:
+ if (ww && hh) {
+ dx = fb_var.xres-fmt.width;
+ dy = 0;
+ fmt.fmtid = x11_native_format;
+ fmt.width = ww;
+ fmt.height = hh;
+ fmt.bytesperline = fb_fix.line_length;
+ } else {
+ if (quiet) {
+ dx = 0;
+ dy = 0;
+ } else {
+ dx = f->height*3/2;
+ dy = f->height;
+ }
+ fmt.fmtid = x11_native_format;
+ fmt.width = fb_var.xres-dx;
+ fmt.height = fb_var.yres-dy;
+ fmt.bytesperline = fb_fix.line_length;
+ }
+ if (0 != ng_grabber_setformat(&fmt,1)) {
+ gfmt = fmt;
+ if (NULL == (conv = ng_grabber_findconv(&gfmt,0))) {
+ fprintf(stderr,"can't fint useful capture format\n");
+ exit(1);
+ }
+ ch = ng_convert_alloc(conv,&gfmt,&fmt);
+ ng_convert_init(ch);
+ }
+ dx += (fb_var.xres-24-fmt.width)/2;
+ dy += (fb_var.yres-16-fmt.height)/2;
+
+ if (f_drv & CAN_CAPTURE)
+ drv->startvideo(h_drv,-1,2);
+ break;
+ case CAPTURE_OVERLAY:
+ fmt.fmtid = x11_native_format;
+ if (ww && hh) {
+ fmt.width = ww;
+ fmt.height = hh;
+ dx = fb_var.xres-fmt.width;
+ dy = 0;
+ } else if (quiet) {
+ fmt.width = fb_var.xres;
+ fmt.height = fb_var.yres;
+ dx = 0;
+ dy = 0;
+ } else {
+ fmt.width = fb_var.xres-24;
+ fmt.height = fb_var.yres-16;
+ dx = f->height*3/2;
+ dy = f->height;
+ }
+ if (matrox) {
+ struct ng_video_fmt off;
+ int starty;
+#if 1
+ /* FIXME: need some kind of size negotiation */
+ /* hardcoded: PAL, half height (want no interleace) */
+ off.width = 768;
+ off.height = 288;
+ starty = fb_var.yres;
+#else
+ /* settings for debugging */
+ off.width = 320;
+ off.height = 240;
+ starty = fb_var.yres-off.height;
+#endif
+ off.bytesperline = fb_fix.line_length;
+ if (off.width*2 > off.bytesperline)
+ off.width = off.bytesperline/2;
+ off.fmtid = VIDEO_YUV422;
+ drv->overlay(h_drv,&off,0,starty,NULL,0,0);
+ gfx_scaler_on(starty*off.bytesperline,off.bytesperline,
+ off.width,off.height,
+ dx,dx+fmt.width,
+ dy,dy+fmt.height);
+ } else {
+ drv->overlay(h_drv,&fmt,dx,dy,NULL,0,1);
+ }
+ break;
+ }
+}
+
+static void
+do_exit(void)
+{
+ sig = 1;
+}
+
+static void
+new_title(char *txt)
+{
+ strcpy(default_title,txt);
+}
+
+static void
+new_message(char *txt)
+{
+ strcpy(message,txt);
+}
+
+static void
+channel_menu(void)
+{
+ char key[32],ctrl[16],event[64],action[128];
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (channels[i]->key) {
+ if (2 != sscanf(channels[i]->key,"%15[A-Za-z0-9_]+%31[A-Za-z0-9_]",
+ ctrl,key))
+ strcpy(key,channels[i]->key);
+ sprintf(event,"kbd-key-%s",key);
+ sprintf(action,"setstation \"%s\"",channels[i]->name);
+ event_register(event,action);
+ }
+ }
+}
+
+static void
+do_fullscreen(void)
+{
+ do_va_cmd(2,"capture","off");
+ quiet = !quiet;
+ fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
+ do_va_cmd(2,"capture","on");
+}
+
+/*--- main ---------------------------------------------------------------*/
+
+static void
+grabber_init(void)
+{
+ struct ng_video_fmt screen;
+
+ memset(&screen,0,sizeof(screen));
+ screen.fmtid = x11_native_format,
+ screen.width = fb_var.xres_virtual;
+ screen.height = fb_var.yres_virtual;
+ screen.bytesperline = fb_fix.line_length;
+ drv = ng_vid_open(ng_dev.video,&screen,0,&h_drv);
+ if (NULL == drv) {
+ fprintf(stderr,"no grabber device available\n");
+ exit(1);
+ }
+ f_drv = drv->capabilities(h_drv);
+ add_attrs(drv->list_attrs(h_drv));
+}
+
+static void
+console_switch(void)
+{
+ switch (fb_switch_state) {
+ case FB_REL_REQ:
+ if (!keep_dma_on)
+ do_va_cmd(2,"capture","off");
+ switch_last = fb_switch_state;
+ fb_switch_release();
+ break;
+ case FB_ACQ_REQ:
+ switch_last = fb_switch_state;
+ fb_switch_acquire();
+ fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
+ ioctl(fb,FBIOPAN_DISPLAY,&fb_var);
+ do_va_cmd(2,"capture","on");
+ break;
+ case FB_ACTIVE:
+ case FB_INACTIVE:
+ default:
+ switch_last = fb_switch_state;
+ break;
+ }
+}
+
+#if 0
+/* just a hook for some test code */
+static void
+scaler_test(int off)
+{
+ if (!matrox) {
+ matrox=1;
+ if (-1 == gfx_init(fb))
+ matrox = 0;
+ }
+
+ if (matrox) {
+ gfx_scaler_on(0,fb_fix.line_length,320,240,
+ fb_var.xres-320,fb_var.xres,0,240);
+ sleep(2);
+ }
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ int key,i,c,gray=0,rc,vt=0,fps=0,t1,t2,lirc,js,err,mute=1,fdmax;
+ unsigned long freq;
+ struct timeval tv;
+ time_t t;
+ char text[80],event[64],*env,*dst;
+ fd_set set;
+
+ if (0 == geteuid() && 0 != getuid()) {
+ fprintf(stderr,"fbtv /must not/ be installed suid root\n");
+ exit(1);
+ }
+
+ if (NULL != (env = getenv("FBFONT")))
+ fontfile = env;
+ ng_init();
+ for (;;) {
+ double val;
+ c = getopt(argc, argv, "Mgvqxkd:o:s:c:f:m:z:t:j:");
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'z':
+ if(sscanf(optarg, "%lf", &val) == 1) {
+ if(val < 0.1 || val > 10)
+ fprintf(stderr, "gamma value is out of range. must be "
+ "0.1 < value < 10.0\n");
+ else
+ fbgamma = 1.0 / val;
+ }
+ break;
+ case 'f':
+ fontfile = optarg;
+ break;
+ case 'm':
+ mode = optarg;
+ break;
+ case 'g':
+ gray = 1;
+ break;
+ case 'M':
+ matrox = 1;
+ break;
+ case 'k':
+ keep_dma_on = 1;
+ break;
+ case 'v':
+ debug++;
+ ng_debug++;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'd':
+ fbdev = optarg;
+ break;
+ case 'o':
+ snapbase = strdup(optarg);
+ break;
+ case 's':
+ sscanf(optarg,"%dx%d",&ww,&hh);
+ break;
+ case 'c':
+ ng_dev.video = optarg;
+ /* v4l-conf needs this too */
+ strcat(ng_v4l_conf," -c ");
+ strcat(ng_v4l_conf,ng_dev.video);
+ break;
+ case 't':
+ if (optarg)
+ vt = strtoul(optarg, 0, 0);
+ else
+ vt = -1;
+ break;
+ case 'j':
+ joydev = optarg;
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ do_overlay = 1;
+ text_init(fontfile);
+ fb = fb_init(fbdev,mode,vt);
+ fb_cleanup_fork();
+ fb_initcolors(fb,gray);
+ fb_switch_init();
+ switch_last = fb_switch_state;
+ fs_init_fb(15);
+
+ if (matrox)
+ if (-1 == gfx_init(fb))
+ matrox = 0;
+ if (matrox)
+ strcat(ng_v4l_conf," -y ");
+
+ grabber_init();
+ read_config(NULL);
+ if (0 != strlen(mixerdev)) {
+ struct ng_attribute *attr;
+ if (NULL != (attr = ng_mix_init(mixerdev,mixerctl)))
+ add_attrs(attr);
+ }
+
+ /* set hooks (command.c) */
+ update_title = new_title;
+ display_message = new_message;
+ set_capture_hook = do_capture;
+ exit_hook = do_exit;
+ fullscreen_hook = do_fullscreen;
+
+ tty_init();
+ atexit(tty_cleanup);
+ signal(SIGINT,ctrlc);
+ signal(SIGTSTP,SIG_IGN);
+
+ /* init hardware */
+ attr_init();
+ audio_on();
+ audio_init();
+
+ /* build channel list */
+ parse_config();
+ channel_menu();
+
+ do_va_cmd(2,"setfreqtab",chanlist_names[chantab].str);
+ cur_capture = 0;
+ do_va_cmd(2,"capture","overlay");
+ if (optind+1 == argc) {
+ do_va_cmd(2,"setstation",argv[optind]);
+ } else {
+ if ((f_drv & CAN_TUNE) && 0 != (freq = drv->getfreq(h_drv))) {
+ for (i = 0; i < chancount; i++)
+ if (chanlist[i].freq == freq*1000/16) {
+ do_va_cmd(2,"setchannel",chanlist[i].name);
+ break;
+ }
+ }
+ if (-1 == cur_channel) {
+ if (count > 0)
+ do_va_cmd(2,"setstation","0");
+ else
+ set_defaults();
+ }
+ }
+
+ /* keyboard, lirc + midi + joystick input support */
+ event_register_list(kbd_events);
+ lirc = lirc_tv_init();
+ js = joystick_tv_init(joydev);
+#ifdef HAVE_ALSA
+ fb_midi.fd = -1;
+ if (midi) {
+ if (-1 != midi_open(&fb_midi, "fbtv"))
+ midi_connect(&fb_midi,midi);
+ }
+#endif
+
+ fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
+ for (;!sig;) {
+ if ((fb_switch_state == FB_ACTIVE || keep_dma_on) && !quiet) {
+ /* clear first lines */
+ fb_memset(fb_mem+fb_mem_offset,0,f->height*fb_fix.line_length);
+ if (message[0] != '\0') {
+ strcpy(text,message);
+ } else {
+ sprintf(text,"Framebuffer TV - %s",default_title);
+ }
+ /* debugging + preformance monitoring */
+ switch (cur_capture) {
+ case CAPTURE_GRABDISPLAY:
+ sprintf(text+strlen(text), " - grab %d.%d fps",fps/5,(fps*2)%10);
+ break;
+ }
+ text_out(0,0,text);
+
+ if (dy > 0) {
+ /* display time */
+ time(&t);
+ strftime(text,16,"%H:%M",localtime(&t));
+ text_out(fb_var.xres - text_width(text) - f->width, 0, text);
+ }
+ }
+ if (switch_last != fb_switch_state)
+ console_switch();
+
+ t1 = time(NULL);
+ fps = 0;
+ message[0] = '\0';
+ for (;;) {
+ FD_ZERO(&set);
+ FD_SET(0,&set);
+ fdmax = 1;
+ if (lirc != -1) {
+ FD_SET(lirc,&set);
+ fdmax = MAX(fdmax,lirc+1);
+ }
+ if (js != -1) {
+ FD_SET(js,&set);
+ fdmax = MAX(fdmax,js+1);
+ }
+#ifdef HAVE_ALSA
+ if (fb_midi.fd != -1) {
+ FD_SET(fb_midi.fd,&set);
+ fdmax = MAX(fdmax,fb_midi.fd+1);
+ }
+#endif
+ if (cur_capture == CAPTURE_GRABDISPLAY &&
+ (fb_switch_state == FB_ACTIVE || keep_dma_on)) {
+ fps++;
+ /* grab + convert frame */
+ if (NULL == (buf = ng_grabber_grab_image(0))) {
+ fprintf(stderr,"capturing image failed\n");
+ exit(1);
+ }
+ if (ch)
+ buf = ng_convert_frame(ch,NULL,buf);
+ /* blit frame */
+ dst = fb_mem +
+ dy * fb_fix.line_length +
+ dx * ((fb_var.bits_per_pixel+7)/8);
+ for (i = 0; i < buf->fmt.height; i++) {
+ memcpy(dst,buf->data + i*buf->fmt.bytesperline, buf->fmt.bytesperline);
+ dst += fb_fix.line_length;
+ }
+ ng_release_video_buf(buf);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ rc = select(fdmax,&set,NULL,NULL,&tv);
+ } else {
+ tv.tv_sec = 6;
+ tv.tv_usec = 0;
+ rc = select(fdmax,&set,NULL,NULL,&tv);
+ }
+ err = errno;
+ if (switch_last != fb_switch_state)
+ console_switch();
+ if (-1 == rc && EINTR == err)
+ continue;
+ if (rc > 0)
+ break;
+ t2 = time(NULL);
+ if (t2 - t1 >= 5) {
+ keypad_timeout();
+ break;
+ }
+ }
+
+ if (FD_ISSET(0,&set)) {
+ /* keyboard input */
+ switch (key = getch()) {
+ case 27: /* ESC */
+ case 'q':
+ case 'Q':
+ sig=1;
+ break;
+ case 'x':
+ case 'X':
+ sig=1;
+ mute=0;
+ break;
+ case -1:
+ break;
+
+#if 0 /* debug */
+ case 'y':
+ /* scaler_test(1); */
+ do_va_cmd(2,"capture","off");
+ do_va_cmd(2,"capture","grab");
+ break;
+#endif
+
+ default:
+ event[0] = 0;
+ if (key > ' ' && key < 127) {
+ /* as is */
+ sprintf(event,"kbd-key-%c",key);
+ } else if (key >= KEY_F(0) && key <= KEY_F(12)) {
+ /* function keys */
+ sprintf(event,"kbd-key-f%d",key - KEY_F(0));
+ } else {
+ /* other special keys */
+ for (i = 0; i < NKEYTAB; i++) {
+ if (keytab[i].key == key)
+ break;
+ }
+ if (i != NKEYTAB)
+ sprintf(event,"kbd-key-%s",keytab[i].name);
+ }
+ if (0 != event[0]) {
+ event_dispatch(event);
+ } else {
+ sprintf(message,"unknown key: %d 0x%x ",key,key);
+ }
+
+ }
+ } /* if (FD_ISSET(0,&set)) */
+
+ if (lirc != -1 && FD_ISSET(lirc,&set)) {
+ /* lirc input */
+ if (-1 == lirc_tv_havedata()) {
+ fprintf(stderr,"lirc: connection lost\n");
+ close(lirc);
+ lirc = -1;
+ }
+ }
+
+ if (js != -1 && FD_ISSET(js,&set)) {
+ /* joystick input */
+ joystick_tv_havedata(js);
+ }
+
+#ifdef HAVE_ALSA
+ if (fb_midi.fd != -1 && FD_ISSET(fb_midi.fd,&set)) {
+ /* midi input */
+ midi_read(&fb_midi);
+ midi_translate(&fb_midi);
+ }
+#endif
+ }
+ do_va_cmd(2,"capture","off");
+ if (mute)
+ audio_off();
+ drv->close(h_drv);
+ fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
+ /* parent will clean up */
+ exit(0);
+}

Privacy Policy