1 /*
2 * console TV application. Uses a framebuffer device.
3 *
4 * (c) 1998-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
5 *
6 */
7
8 #include "config.h"
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <time.h>
15 #include <fcntl.h>
16 #include <termios.h>
17 #include <signal.h>
18 #include <ctype.h>
19 #include <errno.h>
20 #include <sys/time.h>
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <sys/mman.h>
24 #include <curses.h>
25 #include <math.h>
26 #include <pthread.h>
27
28 #include <linux/kd.h>
29 #include <linux/fb.h>
30
31 #include "grab-ng.h"
32 #include "writefile.h"
33 #include "sound.h"
34 #include "channel.h"
35 #include "frequencies.h"
36 #include "commands.h"
37 #include "capture.h"
38 #include "lirc.h"
39 #include "joystick.h"
40 #include "midictrl.h"
41 #include "event.h"
42
43 #include "fbtools.h"
44 #include "fs.h"
45 #include "matrox.h"
46
47 #define MAX(x,y) ((x)>(y)?(x):(y))
48 #define MIN(x,y) ((x)<(y)?(x):(y))
49
50 /* ---------------------------------------------------------------------- */
51 /* framebuffer */
52
53 static char *fbdev = NULL;
54 static char *fontfile = NULL;
55 static char *mode = NULL;
56 static char *joydev = NULL;
57 static struct fs_font *f;
58 #ifndef X_DISPLAY_MISSING
59 static char *x11_font = "10x20";
60 #endif
61
62 static unsigned short red[256], green[256], blue[256];
63 static struct fb_cmap cmap = { 0, 256, red, green, blue };
64
65 static int switch_last,fb;
66 static int keep_dma_on = 0;
67
68 static int sig,quiet,matrox;
69 static int ww,hh;
70 static float fbgamma = 1.0;
71
72 static struct ng_video_buf *buf;
73 static struct ng_video_fmt fmt,gfmt;
74 static struct ng_video_conv *conv;
75 static struct ng_convert_handle *ch;
76 static int dx,dy;
77
78 int have_config;
79 int x11_native_format,have_dga=1,debug;
80
81 /*--- channels ------------------------------------------------------------*/
82
83 struct event_entry kbd_events[] = {
84 {
85 .event = "kbd-key-+",
86 .action = "volume inc",
87 },{
88 .event = "kbd-key--",
89 .action = "volume dec",
90 },{
91 .event = "kbd-key-enter",
92 .action = "volume mute",
93 },{
94 .event = "kbd-key-space",
95 .action = "setstation next",
96 },{
97 .event = "kbd-key-backspace",
98 .action = "setstation back",
99 },{
100 .event = "kbd-key-pgup",
101 .action = "setstation next",
102 },{
103 .event = "kbd-key-pgdown",
104 .action = "setstation prev",
105 },{
106 .event = "kbd-key-right",
107 .action = "setchannel fine_up",
108 },{
109 .event = "kbd-key-left",
110 .action = "setchannel fine_down",
111 },{
112 .event = "kbd-key-up",
113 .action = "setchannel next",
114 },{
115 .event = "kbd-key-down",
116 .action = "setchannel prev",
117 },{
118 .event = "kbd-key-g",
119 .action = "snap ppm",
120 },{
121 .event = "kbd-key-j",
122 .action = "snap jpeg",
123 },{
124 .event = "kbd-key-v",
125 .action = "capture toggle",
126 },{
127 .event = "kbd-key-f",
128 .action = "fullscreen toggle",
129 },{
130 .event = "kbd-key-0",
131 .action = "keypad 0",
132 },{
133 .event = "kbd-key-1",
134 .action = "keypad 1",
135 },{
136 .event = "kbd-key-2",
137 .action = "keypad 2",
138 },{
139 .event = "kbd-key-3",
140 .action = "keypad 3",
141 },{
142 .event = "kbd-key-4",
143 .action = "keypad 4",
144 },{
145 .event = "kbd-key-5",
146 .action = "keypad 5",
147 },{
148 .event = "kbd-key-6",
149 .action = "keypad 6",
150 },{
151 .event = "kbd-key-7",
152 .action = "keypad 7",
153 },{
154 .event = "kbd-key-8",
155 .action = "keypad 8",
156 },{
157 .event = "kbd-key-9",
158 .action = "keypad 9",
159 },{
160
161 /* end of list */
162 }
163 };
164 struct KEYTAB {
165 int key;
166 char *name;
167 };
168
169 static struct KEYTAB keytab[] = {
170 { 9, "tab" },
171 { 10, "enter" },
172 { 13, "enter" },
173 { KEY_ENTER, "enter" },
174
175 { ' ', "space" },
176 { KEY_BACKSPACE, "backspace" },
177
178 { KEY_RIGHT, "right" },
179 { KEY_LEFT, "left" },
180 { KEY_UP, "up" },
181 { KEY_DOWN, "down" },
182 { KEY_PPAGE, "pgup" },
183 { KEY_NPAGE, "pgdown" },
184 { KEY_HOME, "home" },
185 { KEY_END, "end" },
186 };
187
188 #define NKEYTAB (sizeof(keytab)/sizeof(struct KEYTAB))
189
190 static char default_title[128] = "???";
191 static char message[128] = "";
192
193 /* ---------------------------------------------------------------------- */
194 /* framebuffer stuff */
195
196 static void
197 linear_palette(int r, int g, int b)
198 {
199 int i, size;
200
201 size = 256 >> (8 - r);
202 for (i = 0; i < size; i++)
203 red[i] = (unsigned short)(65535.0
204 * pow(i/(size - 1.0), fbgamma));
205
206 size = 256 >> (8 - g);
207 for (i = 0; i < size; i++)
208 green[i] = (unsigned short)(65535.0
209 * pow(i/(size - 1.0), fbgamma));
210
211 size = 256 >> (8 - b);
212 for (i = 0; i < size; i++)
213 blue[i] = (unsigned short)(65535.0
214 * pow(i/(size - 1.0), fbgamma));
215 }
216
217 static void
218 dither_palette(int r, int g, int b)
219 {
220 int rs, gs, bs, i;
221
222 rs = 256 / (r - 1);
223 gs = 256 / (g - 1);
224 bs = 256 / (b - 1);
225 for (i = 0; i < r*g*b; i++) {
226 green[i+16] = (gs * ((i / (r * b)) % g)) * 255;
227 red[i+16] = (rs * ((i / b) % r)) * 255;
228 blue[i+16] = (bs * ((i) % b)) * 255;
229 }
230 }
231
232 static void
233 fb_initcolors(int fd, int gray)
234 {
235 /* get colormap */
236 if (fb_var.bits_per_pixel == 8 ||
237 fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
238 if (-1 == ioctl(fd,FBIOGETCMAP,&cmap))
239 perror("ioctl FBIOGETCMAP");
240 }
241
242 switch (fb_var.bits_per_pixel) {
243 case 8:
244 if (gray) {
245 linear_palette(8,8,8);
246 x11_native_format = VIDEO_GRAY;
247 } else {
248 dither_palette(5,9,5);
249 x11_native_format = VIDEO_RGB08;
250 }
251 break;
252 case 15:
253 case 16:
254 if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
255 linear_palette(fb_var.red.length,
256 fb_var.green.length,
257 fb_var.blue.length);
258 #if BYTE_ORDER == BIG_ENDIAN
259 x11_native_format = (fb_var.green.length == 6) ?
260 VIDEO_RGB16_BE : VIDEO_RGB15_BE;
261 #else
262 x11_native_format = (fb_var.green.length == 6) ?
263 VIDEO_RGB16_LE : VIDEO_RGB15_LE;
264 #endif
265 break;
266 case 24:
267 if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
268 linear_palette(8,8,8);
269 #if BYTE_ORDER == BIG_ENDIAN
270 x11_native_format = VIDEO_RGB24;
271 #else
272 x11_native_format = VIDEO_BGR24;
273 #endif
274 break;
275 case 32:
276 if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
277 linear_palette(8,8,8);
278 #if BYTE_ORDER == BIG_ENDIAN
279 x11_native_format = VIDEO_RGB32;
280 #else
281 x11_native_format = VIDEO_BGR32;
282 #endif
283 break;
284 default:
285 fprintf(stderr, "Oops: %i bit/pixel ???\n",
286 fb_var.bits_per_pixel);
287 exit(1);
288 }
289
290 /* set colormap */
291 if (fb_var.bits_per_pixel == 8 ||
292 fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
293 if (-1 == ioctl(fd,FBIOPUTCMAP,&cmap))
294 perror("ioctl FBIOPUTCMAP");
295 }
296 }
297
298 static void
299 tty_init(void)
300 {
301 /* we use curses just for kbd input */
302 initscr();
303 cbreak();
304 noecho();
305 keypad(stdscr,1);
306 }
307
308 static void
309 tty_cleanup(void)
310 {
311 clear();
312 refresh();
313 endwin();
314 }
315
316
317 /* ---------------------------------------------------------------------- */
318
319 static void
320 text_init(char *font)
321 {
322 char *fonts[2] = { font, NULL };
323
324 if (NULL == f)
325 f = fs_consolefont(font ? fonts : NULL);
326 #ifndef X_DISPLAY_MISSING
327 if (NULL == f && 0 == fs_connect(NULL))
328 f = fs_open(font ? font : x11_font);
329 #endif
330 if (NULL == f) {
331 fprintf(stderr,"no font available\n");
332 exit(1);
333 }
334 }
335
336 static void
337 text_out(int x, int y, char *str)
338 {
339 y *= f->height;
340 y -= f->fontHeader.max_bounds.descent;
341 fs_puts(f,x,y,str);
342 }
343
344 static int
345 text_width(char *str)
346 {
347 return fs_textwidth(f,str);
348 }
349
350 /* ---------------------------------------------------------------------- */
351
352 #ifdef HAVE_ALSA
353 static struct midi_handle fb_midi;
354 #endif
355
356 /* ---------------------------------------------------------------------- */
357
358 static void
359 ctrlc(int signal)
360 {
361 sig=1;
362 }
363
364 #if 0
365 void
366 change_audio(int mode)
367 {
368 if (grabber->grab_audio)
369 grabber->grab_audio(-1,-1,&mode);
370 }
371 #endif
372
373 static void do_capture(int from, int to, int tmp_switch)
374 {
375 /* off */
376 switch (from) {
377 case CAPTURE_GRABDISPLAY:
378 if (f_drv & CAN_CAPTURE)
379 drv->stopvideo(h_drv);
380 break;
381 case CAPTURE_OVERLAY:
382 if (f_drv & CAN_CAPTURE)
383 drv->overlay(h_drv,NULL,0,0,NULL,0,0);
384 if (matrox && !tmp_switch)
385 gfx_scaler_off();
386 break;
387 }
388
389 /* on */
390 memset(&buf,0,sizeof(buf));
391 switch (to) {
392 case CAPTURE_GRABDISPLAY:
393 if (ww && hh) {
394 dx = fb_var.xres-fmt.width;
395 dy = 0;
396 fmt.fmtid = x11_native_format;
397 fmt.width = ww;
398 fmt.height = hh;
399 fmt.bytesperline = fb_fix.line_length;
400 } else {
401 if (quiet) {
402 dx = 0;
403 dy = 0;
404 } else {
405 dx = f->height*3/2;
406 dy = f->height;
407 }
408 fmt.fmtid = x11_native_format;
409 fmt.width = fb_var.xres-dx;
410 fmt.height = fb_var.yres-dy;
411 fmt.bytesperline = fb_fix.line_length;
412 }
413 if (0 != ng_grabber_setformat(&fmt,1)) {
414 gfmt = fmt;
415 if (NULL == (conv = ng_grabber_findconv(&gfmt,0))) {
416 fprintf(stderr,"can't fint useful capture format\n");
417 exit(1);
418 }
419 ch = ng_convert_alloc(conv,&gfmt,&fmt);
420 ng_convert_init(ch);
421 }
422 dx += (fb_var.xres-24-fmt.width)/2;
423 dy += (fb_var.yres-16-fmt.height)/2;
424
425 if (f_drv & CAN_CAPTURE)
426 drv->startvideo(h_drv,-1,2);
427 break;
428 case CAPTURE_OVERLAY:
429 fmt.fmtid = x11_native_format;
430 if (ww && hh) {
431 fmt.width = ww;
432 fmt.height = hh;
433 dx = fb_var.xres-fmt.width;
434 dy = 0;
435 } else if (quiet) {
436 fmt.width = fb_var.xres;
437 fmt.height = fb_var.yres;
438 dx = 0;
439 dy = 0;
440 } else {
441 fmt.width = fb_var.xres-24;
442 fmt.height = fb_var.yres-16;
443 dx = f->height*3/2;
444 dy = f->height;
445 }
446 if (matrox) {
447 struct ng_video_fmt off;
448 int starty;
449 #if 1
450 /* FIXME: need some kind of size negotiation */
451 /* hardcoded: PAL, half height (want no interleace) */
452 off.width = 768;
453 off.height = 288;
454 starty = fb_var.yres;
455 #else
456 /* settings for debugging */
457 off.width = 320;
458 off.height = 240;
459 starty = fb_var.yres-off.height;
460 #endif
461 off.bytesperline = fb_fix.line_length;
462 if (off.width*2 > off.bytesperline)
463 off.width = off.bytesperline/2;
464 off.fmtid = VIDEO_YUYV;
465 drv->overlay(h_drv,&off,0,starty,NULL,0,0);
466 gfx_scaler_on(starty*off.bytesperline,off.bytesperline,
467 off.width,off.height,
468 dx,dx+fmt.width,
469 dy,dy+fmt.height);
470 } else {
471 drv->overlay(h_drv,&fmt,dx,dy,NULL,0,1);
472 }
473 break;
474 }
475 }
476
477 static void
478 do_exit(void)
479 {
480 sig = 1;
481 }
482
483 static void
484 new_title(char *txt)
485 {
486 strcpy(default_title,txt);
487 }
488
489 static void
490 new_message(char *txt)
491 {
492 strcpy(message,txt);
493 }
494
495 static void
496 channel_menu(void)
497 {
498 char key[32],ctrl[16],event[64],action[128];
499 int i;
500
501 for (i = 0; i < count; i++) {
502 if (channels[i]->key) {
503 if (2 != sscanf(channels[i]->key,"%15[A-Za-z0-9_]+%31[A-Za-z0-9_]",
504 ctrl,key))
505 strcpy(key,channels[i]->key);
506 sprintf(event,"kbd-key-%s",key);
507 sprintf(action,"setstation \"%s\"",channels[i]->name);
508 event_register(event,action);
509 }
510 }
511 }
512
513 static void
514 do_fullscreen(void)
515 {
516 do_va_cmd(2,"capture","off");
517 quiet = !quiet;
518 fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
519 do_va_cmd(2,"capture","on");
520 }
521
522 /*--- main ---------------------------------------------------------------*/
523
524 static void
525 grabber_init(void)
526 {
527 struct ng_video_fmt screen;
528
529 memset(&screen,0,sizeof(screen));
530 screen.fmtid = x11_native_format,
531 screen.width = fb_var.xres_virtual;
532 screen.height = fb_var.yres_virtual;
533 screen.bytesperline = fb_fix.line_length;
534 drv = ng_vid_open(ng_dev.video,NULL,&screen,0,&h_drv);
535 if (NULL == drv) {
536 fprintf(stderr,"no grabber device available\n");
537 exit(1);
538 }
539 f_drv = drv->capabilities(h_drv);
540 add_attrs(drv->list_attrs(h_drv));
541 }
542
543 static void
544 console_switch(void)
545 {
546 switch (fb_switch_state) {
547 case FB_REL_REQ:
548 if (!keep_dma_on)
549 do_va_cmd(2,"capture","off");
550 switch_last = fb_switch_state;
551 fb_switch_release();
552 break;
553 case FB_ACQ_REQ:
554 switch_last = fb_switch_state;
555 fb_switch_acquire();
556 fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
557 ioctl(fb,FBIOPAN_DISPLAY,&fb_var);
558 do_va_cmd(2,"capture","on");
559 break;
560 case FB_ACTIVE:
561 case FB_INACTIVE:
562 default:
563 switch_last = fb_switch_state;
564 break;
565 }
566 }
567
568 #if 0
569 /* just a hook for some test code */
570 static void
571 scaler_test(int off)
572 {
573 if (!matrox) {
574 matrox=1;
575 if (-1 == gfx_init(fb))
576 matrox = 0;
577 }
578
579 if (matrox) {
580 gfx_scaler_on(0,fb_fix.line_length,320,240,
581 fb_var.xres-320,fb_var.xres,0,240);
582 sleep(2);
583 }
584 }
585 #endif
586
587 int
588 main(int argc, char *argv[])
589 {
590 int i,key,c,gray=0,rc,vt=0,fps=0,t1,t2,lirc,js,err,mute=1,fdmax;
591 unsigned int ui;
592 unsigned long freq;
593 struct timeval tv;
594 time_t t;
595 char text[80],event[64],*env,*dst;
596 fd_set set;
597 struct sigaction act,old;
598
599
600 if (0 == geteuid() && 0 != getuid()) {
601 fprintf(stderr,"fbtv /must not/ be installed suid root\n");
602 exit(1);
603 }
604
605 if (NULL != (env = getenv("FBFONT")))
606 fontfile = env;
607 ng_init();
608 for (;;) {
609 double val;
610 c = getopt(argc, argv, "Mgvqxkd:o:s:c:f:m:z:t:j:");
611 if (c == -1)
612 break;
613 switch (c) {
614 case 'z':
615 if(sscanf(optarg, "%lf", &val) == 1) {
616 if(val < 0.1 || val > 10)
617 fprintf(stderr, "gamma value is out of range. must be "
618 "0.1 < value < 10.0\n");
619 else
620 fbgamma = 1.0 / val;
621 }
622 break;
623 case 'f':
624 fontfile = optarg;
625 break;
626 case 'm':
627 mode = optarg;
628 break;
629 case 'g':
630 gray = 1;
631 break;
632 case 'M':
633 matrox = 1;
634 break;
635 case 'k':
636 keep_dma_on = 1;
637 break;
638 case 'v':
639 debug++;
640 ng_debug++;
641 break;
642 case 'q':
643 quiet = 1;
644 break;
645 case 'd':
646 fbdev = optarg;
647 break;
648 case 'o':
649 snapbase = strdup(optarg);
650 break;
651 case 's':
652 sscanf(optarg,"%dx%d",&ww,&hh);
653 break;
654 case 'c':
655 ng_dev.video = optarg;
656 /* v4l-conf needs this too */
657 strcat(ng_v4l_conf," -c ");
658 strcat(ng_v4l_conf,ng_dev.video);
659 break;
660 case 't':
661 if (optarg)
662 vt = strtoul(optarg, 0, 0);
663 else
664 vt = 0;
665 break;
666 case 'j':
667 joydev = optarg;
668 break;
669 default:
670 exit(1);
671 }
672 }
673
674 do_overlay = 1;
675 text_init(fontfile);
676 fb = fb_init(fbdev,mode,vt);
677 fb_catch_exit_signals();
678 fb_initcolors(fb,gray);
679 fb_switch_init();
680 switch_last = fb_switch_state;
681 fs_init_fb(15);
682
683 if (matrox)
684 if (-1 == gfx_init(fb))
685 matrox = 0;
686 if (matrox)
687 strcat(ng_v4l_conf," -y ");
688
689 grabber_init();
690 freq_init();
691 read_config(NULL,NULL,NULL);
692 if (0 != strlen(mixerdev)) {
693 struct ng_attribute *attr;
694 if (NULL != (attr = ng_mix_init(mixerdev,mixerctl)))
695 add_attrs(attr);
696 }
697
698 /* set hooks (command.c) */
699 update_title = new_title;
700 display_message = new_message;
701 set_capture_hook = do_capture;
702 exit_hook = do_exit;
703 fullscreen_hook = do_fullscreen;
704
705 tty_init();
706 memset(&act,0,sizeof(act));
707 act.sa_handler = ctrlc;
708 sigemptyset(&act.sa_mask);
709 sigaction(SIGINT,&act,&old);
710
711 /* init hardware */
712 attr_init();
713 audio_on();
714 audio_init();
715
716 /* build channel list */
717 parse_config();
718 channel_menu();
719
720 init_overlay();
721 if (optind+1 == argc) {
722 do_va_cmd(2,"setstation",argv[optind]);
723 } else {
724 if ((f_drv & CAN_TUNE) && 0 != (freq = drv->getfreq(h_drv))) {
725 for (i = 0; i < chancount; i++)
726 if (chanlist[i].freq == freq*1000/16) {
727 do_va_cmd(2,"setchannel",chanlist[i].name);
728 break;
729 }
730 }
731 if (-1 == cur_channel) {
732 if (count > 0)
733 do_va_cmd(2,"setstation","");
734 else
735 set_defaults();
736 }
737 }
738
739 /* keyboard, lirc + midi + joystick input support */
740 event_register_list(kbd_events);
741 lirc = lirc_tv_init();
742 js = joystick_tv_init(joydev);
743 #ifdef HAVE_ALSA
744 fb_midi.fd = -1;
745 if (midi) {
746 if (-1 != midi_open(&fb_midi, "fbtv"))
747 midi_connect(&fb_midi,midi);
748 }
749 #endif
750
751 fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
752 for (;!sig;) {
753 if ((fb_switch_state == FB_ACTIVE || keep_dma_on) && !quiet) {
754 /* clear first lines */
755 fb_memset(fb_mem+fb_mem_offset,0,f->height*fb_fix.line_length);
756 if (message[0] != '\0') {
757 strcpy(text,message);
758 } else {
759 sprintf(text,"Framebuffer TV - %s",default_title);
760 }
761 /* debugging + preformance monitoring */
762 switch (cur_capture) {
763 case CAPTURE_GRABDISPLAY:
764 sprintf(text+strlen(text), " - grab %d.%d fps",fps/5,(fps*2)%10);
765 break;
766 }
767 text_out(0,0,text);
768
769 if (dy > 0) {
770 /* display time */
771 time(&t);
772 strftime(text,16,"%H:%M",localtime(&t));
773 text_out(fb_var.xres - text_width(text) - f->width, 0, text);
774 }
775 }
776 if (switch_last != fb_switch_state)
777 console_switch();
778
779 t1 = time(NULL);
780 fps = 0;
781 message[0] = '\0';
782 for (;!sig;) {
783 FD_ZERO(&set);
784 FD_SET(0,&set);
785 fdmax = 1;
786 if (lirc != -1) {
787 FD_SET(lirc,&set);
788 fdmax = MAX(fdmax,lirc+1);
789 }
790 if (js != -1) {
791 FD_SET(js,&set);
792 fdmax = MAX(fdmax,js+1);
793 }
794 #ifdef HAVE_ALSA
795 if (fb_midi.fd != -1) {
796 FD_SET(fb_midi.fd,&set);
797 fdmax = MAX(fdmax,fb_midi.fd+1);
798 }
799 #endif
800 if (cur_capture == CAPTURE_GRABDISPLAY &&
801 (fb_switch_state == FB_ACTIVE || keep_dma_on)) {
802 fps++;
803 /* grab + convert frame */
804 if (NULL == (buf = ng_grabber_grab_image(0))) {
805 fprintf(stderr,"capturing image failed\n");
806 exit(1);
807 }
808 if (ch)
809 buf = ng_convert_frame(ch,NULL,buf);
810 /* blit frame */
811 dst = fb_mem +
812 dy * fb_fix.line_length +
813 dx * ((fb_var.bits_per_pixel+7)/8);
814 for (ui = 0; ui < buf->fmt.height; ui++) {
815 memcpy(dst, buf->data + ui*buf->fmt.bytesperline,
816 buf->fmt.bytesperline);
817 dst += fb_fix.line_length;
818 }
819 ng_release_video_buf(buf);
820 tv.tv_sec = 0;
821 tv.tv_usec = 0;
822 rc = select(fdmax,&set,NULL,NULL,&tv);
823 } else {
824 tv.tv_sec = 6;
825 tv.tv_usec = 0;
826 rc = select(fdmax,&set,NULL,NULL,&tv);
827 }
828 err = errno;
829 if (switch_last != fb_switch_state)
830 console_switch();
831 if (-1 == rc && EINTR == err) {
832 FD_ZERO(&set);
833 continue;
834 }
835 if (rc > 0)
836 break;
837 t2 = time(NULL);
838 if (t2 - t1 >= 5) {
839 keypad_timeout();
840 break;
841 }
842 }
843
844 if (FD_ISSET(0,&set)) {
845 /* keyboard input */
846 switch (key = getch()) {
847 case 27: /* ESC */
848 case 'q':
849 case 'Q':
850 sig=1;
851 break;
852 case 'x':
853 case 'X':
854 sig=1;
855 mute=0;
856 break;
857 case -1:
858 break;
859
860 #if 0 /* debug */
861 case 'y':
862 /* scaler_test(1); */
863 do_va_cmd(2,"capture","off");
864 do_va_cmd(2,"capture","grab");
865 break;
866 #endif
867
868 default:
869 event[0] = 0;
870 if (key > ' ' && key < 127) {
871 /* as is */
872 sprintf(event,"kbd-key-%c",key);
873 } else if (key >= KEY_F(0) && key <= KEY_F(12)) {
874 /* function keys */
875 sprintf(event,"kbd-key-f%d",key - KEY_F(0));
876 } else {
877 /* other special keys */
878 for (ui = 0; ui < NKEYTAB; ui++) {
879 if (keytab[ui].key == key)
880 break;
881 }
882 if (ui != NKEYTAB)
883 sprintf(event,"kbd-key-%s",keytab[ui].name);
884 }
885 if (0 != event[0]) {
886 event_dispatch(event);
887 } else {
888 sprintf(message,"unknown key: %d 0x%x ",key,key);
889 }
890
891 }
892 } /* if (FD_ISSET(0,&set)) */
893
894 if (lirc != -1 && FD_ISSET(lirc,&set)) {
895 /* lirc input */
896 if (-1 == lirc_tv_havedata()) {
897 fprintf(stderr,"lirc: connection lost\n");
898 close(lirc);
899 lirc = -1;
900 }
901 }
902
903 if (js != -1 && FD_ISSET(js,&set)) {
904 /* joystick input */
905 joystick_tv_havedata(js);
906 }
907
908 #ifdef HAVE_ALSA
909 if (fb_midi.fd != -1 && FD_ISSET(fb_midi.fd,&set)) {
910 /* midi input */
911 midi_read(&fb_midi);
912 midi_translate(&fb_midi);
913 }
914 #endif
915 }
916 do_va_cmd(2,"capture","off");
917 if (mute)
918 audio_off();
919 drv->close(h_drv);
920 if (fb_switch_state == FB_ACTIVE)
921 fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
922 tty_cleanup();
923 fb_cleanup();
924 exit(0);
925 }
926
|
This page was automatically generated by the
LXR engine.
|