Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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.