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 #define _GNU_SOURCE
  2 
  3 #include "config.h"
  4 
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <unistd.h>
  8 #include <string.h>
  9 #include <ctype.h>
 10 #include <errno.h>
 11 #include <math.h>
 12 #include <stdarg.h>
 13 #include <fcntl.h>
 14 #include <pthread.h>
 15 #include <sys/time.h>
 16 
 17 #include <sys/socket.h>
 18 #include <netinet/in.h>
 19 #include <arpa/inet.h>
 20 #include <netdb.h>
 21 
 22 #include "grab-ng.h"
 23 
 24 #include "capture.h"
 25 #include "commands.h"
 26 #include "writefile.h"
 27 #include "channel.h"
 28 #include "webcam.h"
 29 #include "frequencies.h"
 30 #include "sound.h"
 31 
 32 /* ----------------------------------------------------------------------- */
 33 
 34 /* feedback for the user */
 35 void (*update_title)(char *message);
 36 void (*display_message)(char *message);
 37 void (*rec_status)(char *message);
 38 #if TT
 39 void (*vtx_message)(struct TEXTELEM *tt);
 40 #endif
 41 #ifdef HAVE_ZVBI
 42 void (*vtx_subtitle)(struct vbi_page *pg, struct vbi_rect *rect);
 43 #endif
 44 
 45 /* for updating GUI elements / whatever */
 46 void (*attr_notify)(struct ng_attribute *attr, int val);
 47 void (*volume_notify)(void);
 48 void (*freqtab_notify)(void);
 49 void (*setfreqtab_notify)(void);
 50 void (*setstation_notify)(void);
 51 
 52 /* gets called _before_ channel switches */
 53 void (*channel_switch_hook)(void);
 54 
 55 /* capture overlay/grab/off */
 56 void (*set_capture_hook)(int old, int new, int tmp_switch);
 57 
 58 /* toggle fullscreen */
 59 void (*fullscreen_hook)(void);
 60 void (*exit_hook)(void);
 61 void (*capture_get_hook)(void);
 62 void (*capture_rel_hook)(void);
 63 void (*movie_hook)(int argc, char **argv);
 64 
 65 int debug;
 66 int do_overlay;
 67 char *snapbase = "snap";
 68 int have_shmem;
 69 
 70 unsigned int cur_tv_width,cur_tv_height;
 71 int cur_movie,cur_attrs[256];
 72 
 73 /* current hardware driver */
 74 const struct ng_vid_driver  *drv;
 75 void                        *h_drv;
 76 int                          f_drv;
 77 
 78 struct ng_attribute         *attrs = NULL;
 79 
 80 
 81 /* ----------------------------------------------------------------------- */
 82 
 83 static int setfreqtab_handler(char *name, int argc, char **argv);
 84 static int setstation_handler(char *name, int argc, char **argv);
 85 static int setchannel_handler(char *name, int argc, char **argv);
 86 
 87 static int capture_handler(char *name, int argc, char **argv);
 88 static int volume_handler(char *name, int argc, char **argv);
 89 static int attr_handler(char *name, int argc, char **argv);
 90 static int show_handler(char *name, int argc, char **argv);
 91 static int list_handler(char *name, int argc, char **argv);
 92 static int dattr_handler(char *name, int argc, char **argv);
 93 
 94 static int snap_handler(char *name, int argc, char **argv);
 95 static int webcam_handler(char *name, int argc, char **argv);
 96 static int movie_handler(char *name, int argc, char **argv);
 97 static int fullscreen_handler(char *name, int argc, char **argv);
 98 static int msg_handler(char *name, int argc, char **argv);
 99 static int showtime_handler(char *name, int argc, char **argv);
100 static int vdr_handler(char *name, int argc, char **argv);
101 #if TT
102 static int vtx_handler(char *name, int argc, char **argv);
103 #endif
104 static int exit_handler(char *name, int argc, char **argv);
105 
106 static int keypad_handler(char *name, int argc, char **argv);
107 
108 static struct COMMANDS {
109     char  *name;
110     int    min_args;
111     int   (*handler)(char *name, int argc, char **argv);
112 } commands[] = {
113     { "setstation", 0, setstation_handler },
114     { "setchannel", 0, setchannel_handler },
115     { "setfreq",    1, setchannel_handler },
116     { "setfreqtab", 1, setfreqtab_handler },
117 
118     { "capture",    1, capture_handler    },
119 
120     { "setnorm",    1, attr_handler       },
121     { "setinput",   1, attr_handler       },
122     { "setattr",    1, attr_handler       },
123     { "color",      0, attr_handler       },
124     { "hue",        0, attr_handler       },
125     { "bright",     0, attr_handler       },
126     { "contrast",   0, attr_handler       },
127     { "show",       0, show_handler       },
128     { "list",       0, list_handler       },
129 
130     { "volume",     0, volume_handler     },
131     { "attr",       0, dattr_handler      },
132 
133     { "snap",       0, snap_handler       },
134     { "webcam",     1, webcam_handler     },
135     { "movie",      1, movie_handler      },
136     { "fullscreen", 0, fullscreen_handler },
137     { "msg",        1, msg_handler        },
138 #if 0
139     { "vtx",        0, vtx_handler        },
140 #endif
141     { "message",    0, msg_handler        },
142     { "exit",       0, exit_handler       },
143     { "quit",       0, exit_handler       },
144     { "bye",        0, exit_handler       },
145 
146     { "keypad",     1, keypad_handler     },
147     { "showtime",   0, showtime_handler   },
148     { "vdr",        1, vdr_handler        },
149 
150     { NULL, 0, NULL }
151 };
152 
153 static int cur_dattr = 0;
154 static int dattr[] = {
155     ATTR_ID_VOLUME,
156     ATTR_ID_BRIGHT,
157     ATTR_ID_CONTRAST,
158     ATTR_ID_COLOR,
159     ATTR_ID_HUE
160 };
161 #define NUM_DATTR (sizeof(dattr)/sizeof(char*))
162 
163 static int keypad_state = -1;
164 
165 /* ----------------------------------------------------------------------- */
166 
167 void add_attrs(struct ng_attribute *new)
168 {
169     struct ng_attribute *all;
170     int nold,nnew;
171 
172     if (attrs)
173         for (nold = 0; attrs[nold].name != NULL; nold++)
174             ;
175     else
176         nold = 0;
177     for (nnew = 0; new[nnew].name != NULL; nnew++)
178         ;
179     all = malloc(sizeof(struct ng_attribute) * (nold + nnew + 1));
180     memset(all,0,sizeof(struct ng_attribute) * (nold + nnew + 1));
181     memcpy(all,new,sizeof(struct ng_attribute)*nnew);
182     if (attrs) {
183         memcpy(all+nnew,attrs,sizeof(struct ng_attribute)*nold);
184         free(attrs);
185     }
186     attrs = all;
187 
188 #if 0
189     {
190         int i;
191         fprintf(stderr,"  <attr>\n");
192         for (i = 0; attrs[i].name != NULL; i++) {
193             fprintf(stderr,"  attr[%p]: %s \n",
194                     attrs[i].handle,attrs[i].name);
195         }
196         fprintf(stderr,"  </attr>\n");
197     }
198 #endif
199 }
200 
201 void init_overlay(void)
202 {
203     do_va_cmd(2,"setfreqtab",(-1 != chantab)
204               ? chanlist_names[chantab].str : "europe-west");
205 
206     cur_capture = -1;
207     switch (defaults.capture) {
208     case CAPTURE_ON:
209     case CAPTURE_OVERLAY:
210         do_va_cmd(2,"capture","overlay");
211         break;
212     case CAPTURE_GRABDISPLAY:
213         do_va_cmd(2,"capture","grabdisplay");
214         break;
215     default:
216         do_va_cmd(2,"capture","off");
217         break;
218     }
219 }
220 
221 /* ----------------------------------------------------------------------- */
222 
223 int
224 do_va_cmd(int argc, ...)
225 {
226     va_list ap;
227     int  i;
228     char *argv[32];
229     
230     va_start(ap,argc);
231     for (i = 0; i < argc; i++)
232         argv[i] = va_arg(ap,char*);
233     argv[i] = NULL;
234     va_end (ap);
235     return do_command(argc,argv);
236 }
237 
238 int
239 do_command(int argc, char **argv)
240 {
241     int i;
242     
243     if (argc == 0) {
244         fprintf(stderr,"do_command: no argument\n");
245         return -1;
246     }
247     if (debug) {
248         fprintf(stderr,"cmd:");
249         for (i = 0; i < argc; i++) {
250             fprintf(stderr," \"%s\"",argv[i]);
251         }
252         fprintf(stderr,"\n");
253     }
254 
255     for (i = 0; commands[i].name != NULL; i++)
256         if (0 == strcasecmp(commands[i].name,argv[0]))
257             break;
258     if (commands[i].name == NULL) {
259         fprintf(stderr,"no handler for %s\n",argv[0]);
260         return -1;
261     }
262     if (argc-1 < commands[i].min_args) {
263         fprintf(stderr,"no enough args for %s\n",argv[0]);
264         return -1;
265     } else {
266         return commands[i].handler(argv[0],argc-1,argv+1);
267     }
268 }
269 
270 char**
271 split_cmdline(char *line, int *count)
272 {
273     static char cmdline[1024];
274     static char *argv[32];
275     int  argc,i;
276 
277     strcpy(cmdline,line);
278     for (argc=0, i=0; argc<31;) {
279         argv[argc++] = cmdline+i;
280         while (cmdline[i] != ' ' &&
281                cmdline[i] != '\t' &&
282                cmdline[i] != '\0')
283             i++;
284         if (cmdline[i] == '\0')
285             break;
286         cmdline[i++] = '\0';
287         while (cmdline[i] == ' ' ||
288                cmdline[i] == '\t')
289             i++;
290         if (cmdline[i] == '\0')
291             break;
292     }
293     argv[argc] = NULL;
294 
295     *count = argc;
296     return argv;
297 }
298 
299 /* ----------------------------------------------------------------------- */
300 
301 /* sharing code does'nt work well for this one ... */
302 static void
303 set_capture(int capture, int tmp_switch)
304 {
305     static int last_on = CAPTURE_OVERLAY;
306 
307     if (set_capture_hook) {
308         if (capture == CAPTURE_ON)
309             capture = last_on;
310         
311         if (capture == CAPTURE_OVERLAY) {
312             /* can we do overlay ?? */
313             if (!(f_drv & CAN_OVERLAY))
314                 capture = CAPTURE_GRABDISPLAY;
315             if (!do_overlay)
316                 capture = CAPTURE_GRABDISPLAY;
317         }
318 
319         if (cur_capture != capture) {
320             set_capture_hook(cur_capture,capture,tmp_switch);
321             cur_capture = capture;
322         }
323         
324         if (cur_capture != CAPTURE_OFF)
325             last_on = cur_capture;
326     }
327 }
328 
329 static void
330 set_attr(struct ng_attribute *attr, int val)
331 {
332     if (NULL == attr)
333         return;
334 
335     attr->write(attr,val);
336     cur_attrs[attr->id] = val;
337     if (attr_notify)
338         attr_notify(attr,val);
339 }
340 
341 static void
342 set_volume(void)
343 {
344     struct ng_attribute *attr;
345     
346     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_VOLUME)))
347         attr->write(attr,cur_attrs[ATTR_ID_VOLUME]);
348     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_MUTE)))
349         attr->write(attr,cur_attrs[ATTR_ID_MUTE]);
350 
351     if (volume_notify)
352         volume_notify();
353 }
354 
355 static void
356 set_freqtab(int j)
357 {
358     freq_newtab(j);
359     
360     /* cur_channel might be invalid (>chancount) right now */
361     cur_channel = -1;
362     /* this is valid for (struct CHANNEL*)->channel too    */
363     calc_frequencies();
364 
365     if (freqtab_notify)
366         freqtab_notify();
367 }
368 
369 static void
370 set_title(void)
371 {
372     static char  title[256];
373     const char *norm;
374 
375     keypad_state = -1;
376     if (update_title) {
377         if (-1 != cur_sender) {
378             sprintf(title,"%s",channels[cur_sender]->name);
379         } else if (-1 != cur_channel) {
380             sprintf(title,"channel %s",chanlist[cur_channel].name);
381             if (cur_fine != 0)
382                 sprintf(title+strlen(title)," (%d)",cur_fine);
383             norm = ng_attr_getstr(ng_attr_byid(attrs,ATTR_ID_NORM),
384                                   cur_attrs[ATTR_ID_NORM]);
385             sprintf(title+strlen(title)," (%s/%s)",
386                     norm ? norm : "???", chanlists[chantab].name);
387         } else {
388             sprintf(title,"%.3f MHz",cur_freq/16.0);
389         }
390         update_title(title);
391     }
392 }
393 
394 static void
395 set_msg_int(struct ng_attribute *attr, int val)
396 {
397     static char  title[256];
398     
399     if (display_message) {
400         sprintf(title,"%s: %d%%",attr->name,
401                 ng_attr_int2percent(attr,val));
402         display_message(title);
403     }
404 }
405 
406 static void
407 set_msg_bool(const char *name, int val)
408 {
409     static char  title[256];
410     
411     if (display_message) {
412         sprintf(title,"%s: %s",name, val ? "on" : "off");
413         display_message(title);
414     }
415 }
416 
417 static void
418 set_msg_str(char *name, char *val)
419 {
420     static char  title[256];
421     
422     if (display_message) {
423         sprintf(title,"%s: %s",name,val);
424         display_message(title);
425     }
426 }
427 
428 /* ----------------------------------------------------------------------- */
429 
430 static int update_int(struct ng_attribute *attr, int old, char *new)
431 {
432     int value = old;
433     int step;
434 
435     step = (attr->max - attr->min) * 3 / 100;
436     if (step == 0)
437         step = 1;
438     
439     if (0 == strcasecmp(new,"inc"))
440         value += step;
441     else if (0 == strcasecmp(new,"dec"))
442         value -= step;
443     else if (0 == strncasecmp(new,"+=",2))
444         value += ng_attr_parse_int(attr,new+2);
445     else if (0 == strncasecmp(new,"-=",2))
446         value -= ng_attr_parse_int(attr,new+2);
447     else if (isdigit(new[0]) || '+' == new[0] || '-' == new[0])
448         value = ng_attr_parse_int(attr,new);
449     else
450         fprintf(stderr,"update_int: can't parse %s\n",new);
451 
452     if (value < attr->min)
453         value = attr->min;
454     if (value > attr->max)
455         value = attr->max;
456     return value;
457 }
458 
459 /* ----------------------------------------------------------------------- */
460 
461 void
462 attr_init(void)
463 {
464     struct ng_attribute *attr;
465     int val;
466     
467     for (attr = attrs; attr != NULL && attr->name != NULL; attr++) {
468         if (attr->id == ATTR_ID_VOLUME ||
469             attr->id == ATTR_ID_MUTE)
470             continue;
471         val = attr->read(attr);
472         if (attr_notify)
473             attr_notify(attr,val);
474         cur_attrs[attr->id] = val;
475     }
476     if (-1 == defaults.color &&
477         NULL != ng_attr_byid(attrs,ATTR_ID_COLOR))
478         defaults.color = cur_attrs[ATTR_ID_COLOR];
479     if (-1 == defaults.bright &&
480         NULL != ng_attr_byid(attrs,ATTR_ID_BRIGHT))
481         defaults.bright = cur_attrs[ATTR_ID_BRIGHT];
482     if (-1 == defaults.hue &&
483         NULL != ng_attr_byid(attrs,ATTR_ID_HUE))
484         defaults.hue = cur_attrs[ATTR_ID_HUE];
485     if (-1 == defaults.contrast &&
486         NULL != ng_attr_byid(attrs,ATTR_ID_CONTRAST))
487         defaults.contrast = cur_attrs[ATTR_ID_CONTRAST];
488 }
489 
490 void
491 audio_init(void)
492 {
493     struct ng_attribute *attr;
494 
495     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_VOLUME)))
496         cur_attrs[ATTR_ID_VOLUME] = attr->read(attr);
497     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_MUTE)))
498         cur_attrs[ATTR_ID_MUTE] = attr->read(attr);
499     if (volume_notify)
500         volume_notify();
501 }
502 
503 void
504 audio_on(void)
505 {
506     struct ng_attribute *attr,*list;
507 
508     list = drv->list_attrs(h_drv);
509     attr = ng_attr_byid(list,ATTR_ID_MUTE);
510     if (NULL != attr)
511         attr->write(attr,0);
512 }
513 
514 void
515 audio_off(void)
516 {
517     struct ng_attribute *attr,*list;
518 
519     list = drv->list_attrs(h_drv);
520     attr = ng_attr_byid(list,ATTR_ID_MUTE);
521     if (NULL != attr)
522         attr->write(attr,1);
523 }
524 
525 void
526 set_defaults(void)
527 {
528     struct ng_attribute *attr;
529 
530     /* image parameters */
531     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_COLOR)))
532         set_attr(attr,defaults.color);
533     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_BRIGHT)))
534         set_attr(attr,defaults.bright);
535     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_HUE)))
536         set_attr(attr,defaults.hue);
537     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_CONTRAST)))
538         set_attr(attr,defaults.contrast);
539     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_INPUT)))
540         set_attr(attr,defaults.input);
541     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_NORM)))
542         set_attr(attr,defaults.norm);
543     set_capture(defaults.capture,0);
544 
545     cur_channel  = defaults.channel;
546     cur_fine     = defaults.fine;
547     cur_freq     = defaults.freq;
548     if (f_drv & CAN_TUNE)
549         drv->setfreq(h_drv,defaults.freq);
550 }
551 
552 /* ----------------------------------------------------------------------- */
553 
554 #ifndef HAVE_STRCASESTR
555 static char* strcasestr(char *haystack, char *needle)
556 {
557     int hlen = strlen(haystack);
558     int nlen = strlen(needle);
559     int offset;
560 
561     for (offset = 0; offset <= hlen - nlen; offset++)
562         if (0 == strncasecmp(haystack+offset,needle,nlen))
563             return haystack+offset;
564     return NULL;
565 }
566 #endif
567 
568 static int setstation_handler(char *name, int argc, char **argv)
569 {
570     struct ng_attribute *attr,*mute;
571     int i;
572 
573     if (0 == argc) {
574         set_title();
575         return 0;
576     }
577     
578     if (cur_movie) {
579         if (display_message)
580             display_message("grabber busy");
581         return -1;
582     }
583 
584     if (count && 0 == strcasecmp(argv[0],"next")) {
585         i = (cur_sender+1) % count;
586     } else if (count && 0 == strcasecmp(argv[0],"prev")) {
587         i = (cur_sender+count-1) % count;
588     } else if (count && 0 == strcasecmp(argv[0],"back")) {
589         if (-1 == last_sender)
590             return -1;
591         i = last_sender;
592     } else {
593         /* search the configured channels first... */
594         for (i = 0; i < count; i++)
595             if (0 == strcasecmp(channels[i]->name,argv[0]))
596                 break;
597         /* ... next try substring matches ... */
598         if (i == count)
599             for (i = 0; i < count; i++)
600                 if (NULL != strcasestr(channels[i]->name,argv[0]))
601                     break;
602         /* ... next try using the argument as index ... */
603         if (i == count)
604             if (isdigit(argv[0][0]))
605                 i = atoi(argv[0]);
606         if (i == count) {
607             /* ... sorry folks */
608             fprintf(stderr,"station \"%s\" not found\n",argv[0]);
609             return -1;
610         }
611     }
612 
613     /* ok ?? */
614     if (i < 0 || i >= count)
615         return -1;
616     
617     /* switch ... */
618     if (channel_switch_hook)
619         channel_switch_hook();
620     set_capture(CAPTURE_OFF,1);
621 
622     last_sender = cur_sender;
623     cur_sender = i;
624 
625     mute = ng_attr_byid(attrs,ATTR_ID_MUTE);
626     if (mute && !cur_attrs[ATTR_ID_MUTE])
627         mute->write(mute,1);
628 
629     /* image parameters */
630     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_COLOR)))
631         set_attr(attr,channels[i]->color);
632     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_BRIGHT)))
633         set_attr(attr,channels[i]->bright);
634     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_HUE)))
635         set_attr(attr,channels[i]->hue);
636     if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_CONTRAST)))
637         set_attr(attr,channels[i]->contrast);
638 
639     /* input / norm */
640     if (cur_attrs[ATTR_ID_INPUT] != channels[i]->input)
641         if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_INPUT)))
642             set_attr(attr,channels[i]->input);
643     if (cur_attrs[ATTR_ID_NORM] != channels[i]->norm)
644         if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_NORM)))
645             set_attr(attr,channels[i]->norm);
646     
647     /* station */
648     cur_channel  = channels[i]->channel;
649     cur_fine     = channels[i]->fine;
650     cur_freq     = channels[i]->freq;
651     if (f_drv & CAN_TUNE)
652         drv->setfreq(h_drv,channels[i]->freq);
653     set_capture(channels[i]->capture,0);
654     
655     set_title();
656     if (setstation_notify)
657         setstation_notify();
658 
659     if (mute && !cur_attrs[ATTR_ID_MUTE]) {
660         usleep(20000);
661         mute->write(mute,0);
662     }
663     return 0;
664 }
665 
666 static int setchannel_handler(char *name, int argc, char **argv)
667 {
668     struct ng_attribute *mute;
669     int c,i;
670     
671     if (0 == argc) {
672         set_title();
673         return 0;
674     }
675 
676     if (cur_movie) {
677         if (display_message)
678             display_message("grabber busy");
679         return -1;
680     }
681 
682     if (0 == strcasecmp("setfreq",name)) {
683         cur_freq = (unsigned long)(atof(argv[0])*16);
684         cur_sender = -1;
685         cur_channel = -1;
686         cur_fine = 0;
687     } else {
688         if (0 == strcasecmp(argv[0],"next")) {
689             cur_channel = (cur_channel+1) % chancount;
690             cur_fine = defaults.fine;
691         } else if (0 == strcasecmp(argv[0],"prev")) {
692             cur_channel = (cur_channel+chancount-1) % chancount;
693             cur_fine = defaults.fine;
694         } else if (0 == strcasecmp(argv[0],"fine_up")) {
695             cur_fine++;
696         } else if (0 == strcasecmp(argv[0],"fine_down")) {
697             cur_fine--;
698         } else {
699             if (-1 != (c = lookup_channel(argv[0]))) {
700                 cur_channel = c;
701                 cur_fine = defaults.fine;
702             }
703         }
704         
705         if (0 != strncmp(argv[0],"fine",4)) {
706             /* look if there is a known station on that channel */
707             for (i = 0; i < count; i++) {
708                 if (cur_channel == channels[i]->channel) {
709                     char *argv[2];
710                     argv[0] = channels[i]->name;
711                     argv[1] = NULL;
712                     return setstation_handler("", argc, argv);
713                 }
714             }
715         }
716         cur_sender  = -1;
717         if (-1 != cur_channel)
718             cur_freq = get_freq(cur_channel)+cur_fine;
719         else {
720             cur_freq += cur_fine;
721             cur_fine = 0;
722         }
723     }
724     
725     if (channel_switch_hook)
726         channel_switch_hook();
727     set_capture(CAPTURE_OFF,1);
728 
729     mute = ng_attr_byid(attrs,ATTR_ID_MUTE);
730     if (mute && !cur_attrs[ATTR_ID_MUTE])
731         mute->write(mute,1);
732 
733     if (f_drv & CAN_TUNE)
734         drv->setfreq(h_drv,cur_freq);
735     set_capture(defaults.capture,0);
736 
737     set_title();
738     if (setstation_notify)
739         setstation_notify();
740 
741     if (mute && !cur_attrs[ATTR_ID_MUTE]) {
742         usleep(20000);
743         mute->write(mute,0);
744     }
745     return 0;
746 }
747 
748 /* ----------------------------------------------------------------------- */
749 
750 static void
751 print_choices(char *name, char *value, struct STRTAB *tab)
752 {
753     int i;
754     
755     fprintf(stderr,"unknown %s: '%s' (available: ",name,value);
756     for (i = 0; tab[i].str != NULL; i++)
757         fprintf(stderr,"%s'%s'", (0 == i) ? "" : ", ", tab[i].str);
758     fprintf(stderr,")\n");
759 }
760 
761 static int setfreqtab_handler(char *name, int argc, char **argv)
762 {
763     int i;
764 
765     i = str_to_int(argv[0],chanlist_names);
766     if (i != -1)
767         set_freqtab(i);
768     else
769         print_choices("freqtab",argv[0],chanlist_names);
770     return 0;
771 }
772 
773 static int capture_handler(char *name, int argc, char **argv)
774 {
775     int i;
776 
777     if (0 == strcasecmp(argv[0],"toggle")) {
778         i = (cur_capture == CAPTURE_OFF) ? CAPTURE_ON : CAPTURE_OFF;
779     } else {
780         i = str_to_int(argv[0],captab);
781     }
782     if (i != -1)
783         set_capture(i,0);
784     return 0;
785 }
786 
787 /* ----------------------------------------------------------------------- */
788 
789 static int volume_handler(char *name, int argc, char **argv)
790 {
791     struct ng_attribute *vol = ng_attr_byid(attrs,ATTR_ID_VOLUME);
792 
793     if (0 == argc)
794         goto display;
795     
796     if (0 == strcasecmp(argv[0],"mute")) {
797         /* mute on/off/toggle */
798         if (argc > 1) {
799             switch (str_to_int(argv[1],booltab)) {
800             case 0:  cur_attrs[ATTR_ID_MUTE] = 0; break;
801             case 1:  cur_attrs[ATTR_ID_MUTE] = 1; break;
802             default: cur_attrs[ATTR_ID_MUTE] = !cur_attrs[ATTR_ID_MUTE]; break;
803             }
804         } else {
805             cur_attrs[ATTR_ID_MUTE] = !cur_attrs[ATTR_ID_MUTE];
806         }
807     } else {
808         /* volume */
809         if (NULL != vol) {
810             cur_attrs[ATTR_ID_VOLUME] = vol->read(vol);
811             cur_attrs[ATTR_ID_VOLUME] =
812                 update_int(vol,cur_attrs[ATTR_ID_VOLUME],argv[0]);
813         }
814     }
815     set_volume();
816 
817  display:
818     if (cur_attrs[ATTR_ID_MUTE])
819         set_msg_str("volume","muted");
820     else {
821         if (vol)
822             set_msg_int(vol,cur_attrs[ATTR_ID_VOLUME]);
823         else
824             set_msg_str("volume","unmuted");
825     }
826     return 0;
827 }
828 
829 static int attr_handler(char *name, int argc, char **argv)
830 {
831     struct ng_attribute *attr;
832     int val,arg=0;
833 
834     if (0 == strcasecmp(name,"setnorm")) {
835         attr = ng_attr_byname(attrs,"norm");
836 
837     } else if (0 == strcasecmp(name,"setinput")) {
838         attr = ng_attr_byname(attrs,"input");
839 
840     } else if (0 == strcasecmp(name,"setattr") &&
841                argc > 0) {
842         attr = ng_attr_byname(attrs,argv[arg++]);
843 
844     } else {
845         attr = ng_attr_byname(attrs,name);
846     }
847 
848     if (NULL == attr) {
849         fprintf(stderr,"cmd: %s: attribute not found\nvalid choices are:",
850                 (arg > 0) ? argv[0] : name);
851         for (attr = attrs; attr->name != NULL; attr++)
852             fprintf(stderr,"%s \"%s\"",
853                     (attr != attrs) ? "," : "", attr->name);
854         fprintf(stderr,"\n");
855         return -1;
856     }
857 
858     if (!cur_movie && capture_get_hook)
859         capture_get_hook();
860     switch (attr->type) {
861     case ATTR_TYPE_CHOICE:
862         if (argc > arg) {
863             if (0 == strcasecmp("next", argv[arg])) {
864                 val = cur_attrs[attr->id];
865                 val++;
866                 if (NULL == attr->choices[val].str)
867                     val = 0;
868             } else {
869                 val = ng_attr_getint(attr, argv[arg]);
870             }
871             if (-1 == val) {
872                 fprintf(stderr,"invalid value for %s: %s\n",attr->name,argv[arg]);
873                 ng_attr_listchoices(attr);
874             } else {
875                 set_attr(attr,val);
876             }
877         }
878         break;
879     case ATTR_TYPE_INTEGER:
880         if (argc > arg) {
881             cur_attrs[attr->id] = attr->read(attr);
882             val = update_int(attr,cur_attrs[attr->id],argv[arg]);
883             set_attr(attr,val);
884         }
885         set_msg_int(attr,cur_attrs[attr->id]);
886         break;
887     case ATTR_TYPE_BOOL:
888         if (argc > arg) {
889             val = str_to_int(argv[arg],booltab);
890             if (-1 == val) {
891                 if (0 == strcasecmp(argv[arg],"toggle"))
892                     val = !cur_attrs[attr->id];
893             }
894             set_attr(attr,val);
895         }
896         set_msg_bool(attr->name,cur_attrs[attr->id]);
897         break;
898     }
899     if (!cur_movie && capture_rel_hook)
900         capture_rel_hook();
901     return 0;
902 }
903 
904 static int show_handler(char *name, int argc, char **argv)
905 {
906     struct ng_attribute *attr;
907     char *n[2] = { NULL, NULL };
908     int val;
909 
910     if (0 == argc) {
911         for (attr = attrs; attr->name != NULL; attr++) {
912             n[0] = (char*)attr->name;
913             show_handler("show", 1, n);
914         }
915         return 0;
916     }
917 
918     attr = ng_attr_byname(attrs,argv[0]);
919     if (NULL == attr) {
920         fprintf(stderr,"fixme: 404 %s\n",argv[0]);
921         return 0;
922     }
923     val = cur_attrs[attr->id];
924     switch (attr->type) {
925     case ATTR_TYPE_CHOICE:
926         printf("%s: %s\n", attr->name, ng_attr_getstr(attr,val));
927         break;
928     case ATTR_TYPE_INTEGER:
929         printf("%s: %d\n", attr->name, val);
930         break;
931     case ATTR_TYPE_BOOL:
932         printf("%s: %s\n", attr->name, val ? "on" : "off");
933         break;
934     }
935     return 0;
936 }
937 
938 static int list_handler(char *name, int argc, char **argv)
939 {
940     struct ng_attribute *attr;
941     int val,i;
942 
943     printf("%-10.10s | type   | %-7.7s | %-7.7s | %s\n",
944            "attribute","current","default","comment");
945     printf("-----------+--------+---------+--------"
946            "-+-------------------------------------\n");
947     for (attr = attrs; attr->name != NULL; attr++) {
948         val = cur_attrs[attr->id];
949         switch (attr->type) {
950         case ATTR_TYPE_CHOICE:
951             printf("%-10.10s | choice | %-7.7s | %-7.7s |",
952                    attr->name,
953                    ng_attr_getstr(attr,val),
954                    ng_attr_getstr(attr,attr->defval));
955             for (i = 0; attr->choices[i].str != NULL; i++)
956                 printf(" %s",attr->choices[i].str);
957             printf("\n");
958             break;
959         case ATTR_TYPE_INTEGER:
960             printf("%-10.10s | int    | %7d | %7d | range is %d => %d\n",
961                    attr->name, val, attr->defval,
962                    attr->min, attr->max);
963             break;
964         case ATTR_TYPE_BOOL:
965             printf("%-10.10s | bool   | %-7.7s | %-7.7s |\n",
966                    attr->name,
967                    val ? "on" : "off",
968                    attr->defval ? "on" : "off");
969             break;
970         }
971     }
972     return 0;
973 }
974 
975 static int dattr_handler(char *name, int argc, char **argv)
976 {
977     struct ng_attribute *attr = NULL;
978     unsigned int i;
979     
980     if (argc > 0 && 0 == strcasecmp(argv[0],"next")) {
981         for (i = 0; i < NUM_DATTR; i++) {
982             cur_dattr++;
983             cur_dattr %= NUM_DATTR;
984             attr = ng_attr_byid(attrs,dattr[cur_dattr]);
985             if (NULL != attr)
986                 break;
987         }
988         if (NULL == attr)
989             return 0;
990         argc = 0;
991     }
992     if (NULL == attr)
993         attr = ng_attr_byid(attrs,dattr[cur_dattr]);
994     if (NULL == attr)
995         return 0;
996     return attr_handler((char*)attr->name,argc,argv);
997 }
998 
999 /* ----------------------------------------------------------------------- */
1000 
1001 static int snap_handler(char *hname, int argc, char **argv)
1002 {
1003     char message[512];
1004     char *tmpfilename = NULL;
1005     char *filename = NULL;
1006     char *name;
1007     int   jpeg = 0;
1008     int   ret = 0;
1009     struct ng_video_fmt fmt;
1010     struct ng_video_buf *buf = NULL;
1011 
1012     if (!(f_drv & CAN_CAPTURE)) {
1013         fprintf(stderr,"grabbing: not supported [try -noxv switch?]\n");
1014         return -1;
1015     }
1016 
1017     if (cur_movie) {
1018         if (display_message)
1019             display_message("grabber busy");
1020         return -1;
1021     }
1022 
1023     if (capture_get_hook)
1024         capture_get_hook();
1025 
1026     /* format */
1027     if (argc > 0) {
1028         if (0 == strcasecmp(argv[0],"jpeg"))
1029             jpeg = 1;
1030         if (0 == strcasecmp(argv[0],"ppm"))
1031             jpeg = 0;
1032     }
1033 
1034     /* size */
1035     memset(&fmt,0,sizeof(fmt));
1036     fmt.fmtid  = VIDEO_RGB24;
1037     fmt.width  = 2048;
1038     fmt.height = 1572;
1039     if (argc > 1) {
1040         if (0 == strcasecmp(argv[1],"full")) {
1041             /* nothing */
1042         } else if (0 == strcasecmp(argv[1],"win")) {
1043             fmt.width  = cur_tv_width;
1044             fmt.height = cur_tv_height;
1045         } else if (2 == sscanf(argv[1],"%dx%d",&fmt.width,&fmt.height)) {
1046             /* nothing */
1047         } else {
1048             return -1;
1049         }
1050     }
1051 
1052     /* filename */
1053     if (argc > 2)
1054         filename = argv[2];
1055     
1056     if (NULL == (buf = ng_grabber_get_image(&fmt))) {
1057         if (display_message)
1058             display_message("grabbing failed");
1059         ret = -1;
1060         goto done;
1061     }
1062     buf = ng_filter_single(cur_filter,buf);
1063 
1064     if (NULL == filename) {
1065         if (-1 != cur_sender) {
1066             name = channels[cur_sender]->name;
1067         } else if (-1 != cur_channel) {
1068             name = chanlist[cur_channel].name;
1069         } else {
1070             name = "unknown";
1071         }
1072         filename = snap_filename(snapbase, name, jpeg ? "jpeg" : "ppm");
1073     }
1074     tmpfilename = malloc(strlen(filename)+8);
1075     sprintf(tmpfilename,"%s.$$$",filename);
1076 
1077     if (jpeg) {
1078         if (-1 == write_jpeg(tmpfilename, buf, ng_jpeg_quality, 0)) {
1079             sprintf(message,"open %s: %s\n",tmpfilename,strerror(errno));
1080         } else {
1081             sprintf(message,"saved jpeg: %s",filename);
1082         }
1083     } else {
1084         if (-1 == write_ppm(tmpfilename, buf)) {
1085             sprintf(message,"open %s: %s\n",tmpfilename,strerror(errno));
1086         } else {
1087             sprintf(message,"saved ppm: %s",filename);
1088         }
1089     }
1090     unlink(filename);
1091     if (-1 == link(tmpfilename,filename)) {
1092         fprintf(stderr,"link(%s,%s): %s\n",
1093                 tmpfilename,filename,strerror(errno));
1094         goto done;
1095     }
1096     unlink(tmpfilename);
1097     if (display_message)
1098         display_message(message);
1099 
1100 done:
1101     if (tmpfilename)
1102         free(tmpfilename);
1103     if (NULL != buf)
1104         ng_release_video_buf(buf);
1105     if (capture_rel_hook)
1106         capture_rel_hook();
1107     return ret;
1108 }
1109 
1110 static int webcam_handler(char *hname, int argc, char **argv)
1111 {
1112     struct ng_video_fmt fmt;
1113     struct ng_video_buf *buf;
1114 
1115     if (webcam)
1116         free(webcam);
1117     webcam = strdup(argv[0]);
1118 
1119     /* if either avi recording or grabdisplay is active, we do
1120        /not/ stop capture and switch the video format.  The next
1121        capture will send a copy of the frame to the webcam thread
1122        and it has to deal with it as-is */
1123     if (cur_movie)
1124         return 0;
1125     if (cur_capture == CAPTURE_GRABDISPLAY)
1126         return 0;
1127 
1128     /* if no capture is running we can switch to RGB first to make
1129        the webcam happy */
1130     if (capture_get_hook)
1131         capture_get_hook();
1132     memset(&fmt,0,sizeof(fmt));
1133     fmt.fmtid  = VIDEO_RGB24;
1134     fmt.width  = cur_tv_width;
1135     fmt.height = cur_tv_height;
1136     buf = ng_grabber_get_image(&fmt);
1137     if (buf)
1138         ng_release_video_buf(buf);
1139     if (capture_rel_hook)
1140         capture_rel_hook();
1141     return 0;
1142 }
1143 
1144 static int movie_handler(char *name, int argc, char **argv)
1145 {
1146     if (!movie_hook)
1147         return 0;
1148     movie_hook(argc,argv);
1149     return 0;
1150 }
1151 
1152 static int
1153 fullscreen_handler(char *name, int argc, char **argv)
1154 {
1155     if (fullscreen_hook)
1156         fullscreen_hook();
1157     return 0;
1158 }
1159 
1160 static int
1161 msg_handler(char *name, int argc, char **argv)
1162 {
1163     if (display_message)
1164         display_message(argv[0]);
1165     return 0;
1166 }
1167 
1168 static int
1169 showtime_handler(char *name, int argc, char **argv)
1170 {
1171     char timestr[6];
1172     struct tm *times;
1173     time_t timet;
1174 
1175     timet = time(NULL);
1176     times = localtime(&timet);
1177     strftime(timestr, 6, "%k:%M", times);
1178     if (display_message)
1179         display_message(timestr);
1180     return 0;
1181 }
1182 
1183 static int
1184 exit_handler(char *name, int argc, char **argv)
1185 {
1186     if (exit_hook)
1187         exit_hook();
1188     return 0;
1189 }
1190 
1191 /* ----------------------------------------------------------------------- */
1192 
1193 static char *strfamily(int family)
1194 {
1195     switch (family) {
1196     case PF_INET6: return "ipv6";
1197     case PF_INET:  return "ipv4";
1198     case PF_UNIX:  return "unix";
1199     }
1200     return "????";
1201 }
1202 
1203 static int
1204 tcp_connect(struct addrinfo *ai, char *host, char *serv)
1205 {
1206     struct addrinfo *res,*e;
1207     char uhost[INET6_ADDRSTRLEN+1];
1208     char userv[33];
1209     int sock,rc,opt=1;
1210 
1211     ai->ai_flags = AI_CANONNAME;
1212     if (debug)
1213         fprintf(stderr,"tcp: lookup %s:%s ... ",host,serv);
1214     if (0 != (rc = getaddrinfo(host, serv, ai, &res))) {
1215         fprintf(stderr,"tcp: getaddrinfo (%s:%s): %s\n",
1216                 host,serv,gai_strerror(rc));
1217         return -1;
1218     }
1219     if (debug)
1220         fprintf(stderr,"ok\n");
1221     for (e = res; e != NULL; e = e->ai_next) {
1222         if (0 != getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
1223                              uhost,INET6_ADDRSTRLEN,userv,32,
1224                              NI_NUMERICHOST | NI_NUMERICSERV)) {
1225             fprintf(stderr,"tcp: getnameinfo (peer): oops\n");
1226             continue;
1227         }
1228         if (debug)
1229             fprintf(stderr,"tcp: trying %s (%s:%s) ... ",
1230                     strfamily(e->ai_family),uhost,userv);
1231         if (-1 == (sock = socket(e->ai_family, e->ai_socktype,
1232                                  e->ai_protocol))) {
1233             fprintf(stderr,"tcp: socket: %s\n",strerror(errno));
1234             continue;
1235         }
1236         setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
1237         if (-1 == connect(sock,e->ai_addr,e->ai_addrlen)) {
1238             fprintf(stderr,"tcp: connect: %s\n",strerror(errno));
1239             close(sock);
1240             continue;
1241         }
1242         if (debug)
1243             fprintf(stderr,"ok\n");
1244         fcntl(sock,F_SETFL,O_NONBLOCK);
1245         fcntl(sock,F_SETFD,FD_CLOEXEC);
1246         return sock;
1247     }
1248     return -1;
1249 }
1250 
1251 static int tcp_readbuf(int sock, int timeout, char *dest, char dlen)
1252 {
1253     struct timeval tv;
1254     fd_set set;
1255     int rc;
1256 
1257  again:
1258     FD_ZERO(&set);
1259     FD_SET(sock,&set);
1260     tv.tv_sec  = timeout;
1261     tv.tv_usec = 0;
1262     rc = select(sock+1,&set,NULL,NULL,&tv);
1263     if (-1 == rc && EINTR == errno)
1264         goto again;
1265     if (-1 == rc) {
1266         if (debug)
1267             perror("tcp: select");
1268         return -1;
1269     }
1270     if (0 == rc) {
1271         if (debug)
1272             fprintf(stderr,"tcp: select timeout\n");
1273         return -1;
1274     }
1275     rc = read(sock,dest,dlen-1);
1276     if (-1 == rc) {
1277         if (debug)
1278             perror("tcp: read");
1279         return -1;
1280     }
1281     dest[rc] = 0;
1282     return rc;
1283 }
1284 
1285 static int vdr_sock = -1;
1286 
1287 static int
1288 vdr_handler(char *name, int argc, char **argv)
1289 {
1290     char line[80];
1291     struct addrinfo ask;
1292     int i,rc;
1293     unsigned int l,len;
1294 
1295  reconnect:
1296     if (-1 == vdr_sock) {
1297         memset(&ask,0,sizeof(ask));
1298         ask.ai_family = PF_UNSPEC;
1299         ask.ai_socktype = SOCK_STREAM;
1300         vdr_sock = tcp_connect(&ask,"localhost","2001");
1301         if (-1 == vdr_sock)
1302             return -1;
1303         if (debug)
1304             fprintf(stderr,"vdr: connected\n");
1305 
1306         /* skip greeting line */
1307         if (-1 == tcp_readbuf(vdr_sock,3,line,sizeof(line)))
1308             goto oops;
1309         if (debug)
1310             fprintf(stderr,"vdr: << %s",line);
1311     }
1312 
1313     /* send command */
1314     line[0] = 0;
1315     for (i = 0, len = 0; i < argc; i++) {
1316         l = strlen(argv[i]);
1317         if (len+l+4 > sizeof(line))
1318             break;
1319         if (len) {
1320             strcpy(line+len," ");
1321             len++;
1322         }
1323         strcpy(line+len,argv[i]);
1324         len += l;
1325     }
1326     strcpy(line+len,"\r\n");
1327     len += 2;
1328     if (len != (rc = write(vdr_sock,line,len))) {
1329         if (-1 == rc  &&  EPIPE == errno) {
1330             if (debug)
1331                 fprintf(stderr,"tcp: write: broken pipe, trying reconnect\n");
1332             close(vdr_sock);
1333             vdr_sock = -1;
1334             goto reconnect;
1335         }
1336         if (debug)
1337             perror("tcp: write");
1338         goto oops;
1339     }
1340     if (debug)
1341         fprintf(stderr,"vdr: >> %s",line);
1342     
1343     /* skip answer */
1344     if (-1 == tcp_readbuf(vdr_sock,3,line,sizeof(line)))
1345         goto oops;
1346     if (debug)
1347         fprintf(stderr,"vdr: << %s",line);
1348 
1349 #if 0
1350     /* play nicely and close the handle -- vdr can handle only one
1351      * connection at the same time.  Drawback is that it increases
1352      * latencies ... */
1353     close(vdr_sock);
1354     vdr_sock = -1;
1355 #endif
1356     return 0;
1357 
1358 oops:
1359     close(vdr_sock);
1360     vdr_sock = -1;
1361     return -1;
1362 }
1363 
1364 /* ----------------------------------------------------------------------- */
1365 
1366 #if TT
1367 static struct TEXTELEM*
1368 parse_vtx(int lines, char **text)
1369 {
1370     static char *names[8] = { "black", "red", "green", "yellow",
1371                               "blue", "magenta", "cyan", "white" };
1372     static struct TEXTELEM tt[VTX_COUNT];
1373     int i,n,t,ansi;
1374     char *ansi_fg,*ansi_bg;
1375 
1376     /* parse */
1377     t = 0;
1378     memset(tt,0,sizeof(tt));
1379     for (i = 0; i < lines; i++) {
1380         tt[t].line = i;
1381         ansi_fg = NULL; ansi_bg = NULL;
1382         for (n = 0; text[i][n] != 0;) {
1383             if (text[i][n] == '\033') {
1384                 if (tt[t].len) {
1385                     t++;
1386                     if (VTX_COUNT == t)
1387                         return tt;
1388                 }
1389                 n++;
1390                 if (text[i][n] == '[') {
1391                     /* ANSI color tty sequences */
1392                     n++;
1393                     for (ansi=1;ansi;) {
1394                         switch (text[i][n]) {
1395                         case '3':
1396                             n++;
1397                             if (text[i][n] >= '' && text[i][n] < '8') {
1398                                 ansi_fg  = names[text[i][n]-''];
1399                                 n++;
1400                             }
1401                             break;
1402                         case '4':
1403                             n++;
1404                             if (text[i][n] >= '' && text[i][n] < '8') {
1405                                 ansi_bg  = names[text[i][n]-''];
1406                                 n++;
1407                             }
1408                             break;
1409                         case '1':
1410                         case ';':
1411                             n++;
1412                             break;
1413                         case 'm':
1414                             n++;
1415                             /* ok, commit */
1416                             ansi=0;
1417                             tt[t].fg = ansi_fg;
1418                             tt[t].bg = ansi_bg;
1419                             break;
1420                         default:
1421                             /* error */
1422                             ansi=0;
1423                         }
1424                     }
1425                 } else {
1426                     /* old way: ESC fg bg */
1427                     if (text[i][n] >= '' && text[i][n] < '8') {
1428                         tt[t].fg  = names[text[i][n]-''];
1429                         n++;
1430                     }
1431                     if (text[i][n] >= '' && text[i][n] < '8') {
1432                         tt[t].bg  = names[text[i][n]-''];
1433                         n++;
1434                     }
1435                 }
1436                 tt[t].line = i;
1437             } else {
1438                 tt[t].str[tt[t].len++] = text[i][n];
1439                 n++;
1440                 if (tt[t].len >= VTX_LEN-1) {
1441                     t++;
1442                     if (VTX_COUNT == t)
1443                         return tt;
1444                     tt[t].line = i;
1445                 }
1446             }
1447         }
1448         if (tt[t].len) {
1449             t++;
1450             if (VTX_COUNT == t)
1451                 break;
1452         }
1453     }
1454     return tt;
1455 }
1456 
1457 static int
1458 vtx_handler(char *name, int argc, char **argv)
1459 {
1460     struct TEXTELEM *tt;
1461 
1462     if (vtx_message) {
1463         if (argc) {
1464             tt = parse_vtx(argc,argv);
1465             vtx_message(tt);
1466         } else {
1467             vtx_message(NULL);
1468         }
1469     }
1470     return 0;
1471 }
1472 #endif
1473 
1474 /* ----------------------------------------------------------------------- */
1475 
1476 #define CH_MAX (keypad_ntsc ? 99 : count)
1477 
1478 static int
1479 keypad_handler(char *name, int argc, char **argv)
1480 {
1481     int n = atoi(argv[0])%10;
1482     char msg[8],ch[8];
1483 
1484     if (debug)
1485         fprintf(stderr,"keypad: key %d\n",n);
1486     if (-1 == keypad_state) {
1487         if ((keypad_partial   &&  n > 0 && n <= CH_MAX) ||
1488             (!keypad_partial  &&  n > 0 && n <= CH_MAX && 10*n > CH_MAX)) {
1489             if (keypad_ntsc) {
1490                 sprintf(ch,"%d",n);
1491                 do_va_cmd(2,"setchannel",ch,NULL);
1492             } else
1493                 do_va_cmd(2,"setstation",channels[n-1]->name,NULL);
1494         }
1495         if (n >= 0 && 10*n <= CH_MAX) {
1496             if (debug)
1497                 fprintf(stderr,"keypad: hang: %d\n",n);
1498             keypad_state = n;
1499             if (display_message) {
1500                 sprintf(msg,"%d_",n);
1501                 display_message(msg);
1502             }
1503         }
1504     } else {
1505         if ((n+keypad_state*10) <= CH_MAX)
1506             n += keypad_state*10;
1507         keypad_state = -1;
1508         if (debug)
1509             fprintf(stderr,"keypad: ok: %d\n",n);
1510         if (n > 0 && n <= CH_MAX) {
1511             if (keypad_ntsc) {
1512                 sprintf(ch,"%d",n);
1513                 do_va_cmd(2,"setchannel",ch,NULL);
1514             } else
1515                 do_va_cmd(2,"setstation",channels[n-1]->name,NULL);
1516         }
1517     }
1518     return 0;
1519 }
1520 
1521 void
1522 keypad_timeout(void)
1523 {
1524     if (debug)
1525         fprintf(stderr,"keypad: timeout\n");
1526     if (keypad_state == cur_sender+1)
1527         set_title();
1528     keypad_state = -1;
1529 }
1530 
  This page was automatically generated by the LXR engine.