aboutsummaryrefslogtreecommitdiffstats
path: root/console
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2010-04-01 09:24:38 (GMT)
committerGerd Hoffmann <kraxel@redhat.com>2010-04-01 09:24:38 (GMT)
commita4a3e6b21da7d11e66364ab9ab67795a3f78020a (patch)
tree4ab98e8339361b8a4c89bedbe8888055292746b6 /console
parentf53a049ec82b6e1d0877a93387ed4d15797749a2 (diff)
v3.74
Diffstat (limited to 'console')
-rw-r--r--console/Makefile2
-rw-r--r--console/Subdir.mk103
-rw-r--r--console/aa.c352
-rw-r--r--console/dump-mixers.c86
-rw-r--r--console/fbtools.c488
-rw-r--r--console/fbtools.h22
-rw-r--r--console/fbtv.c905
-rw-r--r--console/font-6x11.h3337
-rw-r--r--console/fs.c501
-rw-r--r--console/fs.h68
-rw-r--r--console/ftp.c268
-rw-r--r--console/ftp.h8
-rw-r--r--console/matrox.c232
-rw-r--r--console/matrox.h4
-rw-r--r--console/radio.c654
-rw-r--r--console/record.c806
-rw-r--r--console/scantv.c395
-rw-r--r--console/showriff.c575
-rw-r--r--console/streamer.c486
-rw-r--r--console/v4l-conf.c601
-rw-r--r--console/webcam.c599
21 files changed, 10492 insertions, 0 deletions
diff --git a/console/Makefile b/console/Makefile
new file mode 100644
index 0000000..4e33e30
--- /dev/null
+++ b/console/Makefile
@@ -0,0 +1,2 @@
+default:
+ cd ..; $(MAKE)
diff --git a/console/Subdir.mk b/console/Subdir.mk
new file mode 100644
index 0000000..016ef0f
--- /dev/null
+++ b/console/Subdir.mk
@@ -0,0 +1,103 @@
+
+# variables
+TARGETS-console := \
+ console/dump-mixers \
+ console/record \
+ console/scantv \
+ console/showriff \
+ console/streamer \
+ console/webcam
+TARGETS-v4l-conf :=
+
+ifeq ($(FOUND_AALIB),yes)
+TARGETS-console += \
+ console/ttv
+endif
+ifeq ($(FOUND_OS),linux)
+TARGETS-console += \
+ console/radio \
+ console/fbtv
+TARGETS-v4l-conf += \
+ console/v4l-conf
+endif
+
+OBJS-fbtv := \
+ console/fbtv.o \
+ console/fbtools.o \
+ console/fs.o \
+ console/matrox.o \
+ common/channel-no-x11.o \
+ $(OBJS-common-input) \
+ $(OBJS-common-capture)
+LIBS-fbtv := \
+ $(THREAD_LIBS) $(CURSES_LIBS) $(LIRC_LIBS) $(ALSA_LIBS) \
+ $(FS_LIBS) -ljpeg -lm
+
+OBJS-ttv := \
+ console/aa.o \
+ common/channel-no-x11.o \
+ $(OBJS-common-capture)
+LIBS-ttv := \
+ $(THREAD_LIBS) $(AA_LIBS) -ljpeg -lm
+
+OBJS-scantv := \
+ console/scantv.o \
+ common/channel-no-x11.o \
+ $(OBJS-common-capture) \
+ libvbi/libvbi.a
+OBJS-streamer := \
+ console/streamer.o \
+ common/channel-no-x11.o \
+ $(OBJS-common-capture)
+LIBS-capture := \
+ $(THREAD_LIBS) -ljpeg -lm
+
+OBJS-webcam := \
+ console/webcam.o \
+ console/ftp.o \
+ common/parseconfig.o \
+ libng/libng.a
+LIBS-webcam := \
+ $(THREAD_LIBS) -ljpeg
+
+# local targets
+console/dump-mixers: console/dump-mixers.o
+console/showriff: console/showriff.o
+
+console/radio: console/radio.o
+ $(CC) $(CFLAGS) -o $@ $< $(CURSES_LIBS)
+
+console/record: console/record.o
+ $(CC) $(CFLAGS) -o $@ $< $(CURSES_LIBS)
+
+console/v4l-conf: console/v4l-conf.o
+ $(CC) $(CFLAGS) -o $@ $< $(ATHENA_LIBS)
+
+console/fbtv: $(OBJS-fbtv)
+ $(CC) $(CFLAGS) -o $@ $(OBJS-fbtv) $(LIBS-fbtv) $(DLFLAGS)
+
+console/scantv: $(OBJS-scantv)
+ $(CC) $(CFLAGS) -o $@ $(OBJS-scantv) $(LIBS-capture) $(DLFLAGS)
+
+console/streamer: $(OBJS-streamer)
+ $(CC) $(CFLAGS) -o $@ $(OBJS-streamer) $(LIBS-capture) $(DLFLAGS)
+
+console/webcam: $(OBJS-webcam)
+ $(CC) $(CFLAGS) -o $@ $(OBJS-webcam) $(LIBS-webcam) $(DLFLAGS)
+
+console/ttv: $(OBJS-ttv)
+ $(CC) $(CFLAGS) -o $@ $(OBJS-ttv) $(LIBS-ttv) $(DLFLAGS)
+
+
+# global targets
+all:: $(TARGETS-console) $(TARGETS-v4l-conf)
+
+install::
+ $(INSTALL_PROGRAM) $(TARGETS-console) $(bindir)
+ifeq ($(FOUND_OS),linux)
+ $(INSTALL_PROGRAM) $(SUID_ROOT) $(TARGETS-v4l-conf) $(bindir)
+endif
+
+distclean::
+ rm -f $(TARGETS-console) $(TARGETS-v4l-conf)
+
diff --git a/console/aa.c b/console/aa.c
new file mode 100644
index 0000000..4c1e86f
--- /dev/null
+++ b/console/aa.c
@@ -0,0 +1,352 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <pthread.h>
+#include <X11/Intrinsic.h>
+#include <aalib.h>
+
+#include "grab-ng.h"
+#include "capture.h"
+#include "channel.h"
+#include "commands.h"
+#include "frequencies.h"
+#include "parseconfig.h"
+#include "sound.h"
+
+/* ---------------------------------------------------------------------- */
+/* capture stuff */
+
+static struct aa_hardware_params params;
+static aa_renderparams render;
+static aa_context *context;
+char *framebuffer;
+static int signaled;
+
+static char title[256];
+static char message[256];
+static time_t mtime;
+static struct ng_video_fmt fmt,gfmt;
+static struct ng_video_conv *conv;
+static struct ng_convert_handle *ch;
+static int fast;
+
+static void
+grabber_init(void)
+{
+ drv = ng_vid_open(ng_dev.video,NULL,0,&h_drv);
+ if (NULL == drv) {
+ fprintf(stderr,"no grabber device available\n");
+ exit(1);
+ }
+ f_drv = drv->capabilities(h_drv);
+ add_attrs(drv->list_attrs(h_drv));
+}
+
+static void
+new_title(char *txt)
+{
+ strcpy(title,txt);
+}
+
+static void
+new_message(char *txt)
+{
+ mtime = time(NULL);
+ strcpy(message,txt);
+}
+
+static void do_capture(int from, int to, int tmp_switch)
+{
+ /* off */
+ switch (from) {
+ case CAPTURE_GRABDISPLAY:
+ if (f_drv & CAN_CAPTURE)
+ drv->stopvideo(h_drv);
+ break;
+ }
+
+ /* on */
+ switch (to) {
+ case CAPTURE_GRABDISPLAY:
+ /* try native */
+ fmt.fmtid = VIDEO_GRAY;
+ fmt.width = aa_imgwidth(context);
+ fmt.height = aa_imgheight(context);
+ if (0 != ng_grabber_setformat(&fmt,1)) {
+ gfmt = fmt;
+ if (NULL == (conv = ng_grabber_findconv(&gfmt,0))) {
+ fprintf(stderr,"can't capture gray data\n");
+ exit(1);
+ }
+ ch = ng_convert_alloc(conv,&gfmt,&fmt);
+ ng_convert_init(ch);
+ }
+ if (f_drv & CAN_CAPTURE)
+ drv->startvideo(h_drv,-1,2);
+ break;
+ }
+}
+
+static void blitframe(struct ng_video_buf *buf)
+{
+ int w,h,y;
+ char *s,*d;
+
+#if 0
+ /* debug */
+ fprintf(stdout,"P5\n%d %d\n255\n",buf->fmt.width,buf->fmt.height);
+ fwrite(buf->data,buf->fmt.width,buf->fmt.height,stdout);
+ exit(1);
+#endif
+ if (buf->fmt.width == aa_imgwidth(context) &&
+ buf->fmt.height == aa_imgheight(context)) {
+ memcpy(framebuffer,buf->data,buf->fmt.width*buf->fmt.height);
+ } else {
+ s = buf->data;
+ d = framebuffer;
+ if (buf->fmt.height < aa_imgheight(context)) {
+ h = buf->fmt.height;
+ d += (aa_imgheight(context)-buf->fmt.height)/2 *
+ aa_imgwidth(context);
+ } else {
+ h = aa_imgheight(context);
+ s += (buf->fmt.height-aa_imgheight(context))/2 *
+ buf->fmt.width;
+ }
+ if (buf->fmt.width < aa_imgwidth(context)) {
+ w = buf->fmt.width;
+ d += (aa_imgwidth(context)-buf->fmt.width)/2;
+ } else {
+ w = aa_imgwidth(context);
+ s += (buf->fmt.width-aa_imgwidth(context))/2;
+ }
+ for (y = 0; y < h; y++) {
+ memcpy(d,s,w);
+ s += buf->fmt.width;
+ d += aa_imgwidth(context);
+ }
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void aa_cleanup(void)
+{
+ aa_uninitkbd(context);
+ aa_close(context);
+}
+
+static void
+ctrlc(int signal)
+{
+ signaled++;
+}
+
+static void
+usage(void)
+{
+ printf("ttv -- watch tv on a ascii terminal using aalib\n"
+ "\n"
+ "ttv options:\n"
+ " -h print this text\n"
+ " -f use fast aalib render function\n"
+ " -c <device> video device [%s]\n"
+ "\n"
+ "aalib options:\n"
+ "%s",
+ ng_dev.video,aa_help);
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct ng_video_buf *buf;
+ unsigned long freq;
+ int c,i,key,frames,fps;
+ time_t now,last;
+ struct tm *t;
+
+ ng_init();
+ params = aa_defparams;
+ render = aa_defrenderparams;
+ if (!aa_parseoptions (&params, &render, &argc, argv))
+ usage();
+ for (;;) {
+ c = getopt(argc, argv, "vfhc:");
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'v':
+ debug++;
+ ng_debug++;
+ break;
+ case 'f':
+ fast++;
+ break;
+ case 'c':
+ ng_dev.video = optarg;
+ break;
+ case 'h':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ /* init aalib */
+ context = aa_autoinit(&params);
+ if (context == NULL) {
+ printf("Failed to initialize aalib\n");
+ exit (1);
+ }
+ aa_autoinitkbd(context,0);
+ atexit(aa_cleanup);
+ framebuffer = aa_image(context);
+
+ /* init v4l */
+ grabber_init();
+ read_config(NULL);
+ ng_ratio_x = 0;
+ ng_ratio_y = 0;
+
+ /* init mixer */
+ if (0 != strlen(mixerdev)) {
+ struct ng_attribute *attr;
+ if (NULL != (attr = ng_mix_init(mixerdev,mixerctl)))
+ add_attrs(attr);
+ }
+
+ /* set hooks (command.c) */
+ update_title = new_title;
+ display_message = new_message;
+ set_capture_hook = do_capture;
+
+ /* init hardware */
+ attr_init();
+ audio_on();
+ audio_init();
+
+ /* build channel list */
+ parse_config();
+
+ do_va_cmd(2,"setfreqtab",chanlist_names[chantab].str);
+ cur_capture = 0;
+ do_va_cmd(2,"capture","grabdisplay");
+ if (optind+1 == argc) {
+ do_va_cmd(2,"setstation",argv[optind]);
+ } else {
+ if ((f_drv & CAN_TUNE) && 0 != (freq = drv->getfreq(h_drv))) {
+ for (i = 0; i < chancount; i++)
+ if (chanlist[i].freq == freq*1000/16) {
+ do_va_cmd(2,"setchannel",chanlist[i].name);
+ break;
+ }
+ }
+ if (-1 == cur_channel) {
+ if (count > 0)
+ do_va_cmd(2,"setstation","0");
+ else
+ set_defaults();
+ }
+ }
+
+ /* catch ^C */
+ signal(SIGINT,ctrlc);
+ signal(SIGTERM,ctrlc);
+ signal(SIGQUIT,ctrlc);
+
+ /* main loop */
+ last = now = time(NULL);
+ frames = fps = 0;
+ for (;!signaled;) {
+ /* time + performance */
+ now = time(NULL);
+ t = localtime(&now);
+ frames++;
+ if (now - last >= 5) {
+ fps = frames * 10 / (now-last);
+ last = now;
+ frames = 0;
+ }
+
+ /* grab + convert frame */
+ if (NULL == (buf = ng_grabber_grab_image(0))) {
+ fprintf(stderr,"capturing image failed\n");
+ exit(1);
+ }
+ if (ch)
+ buf = ng_convert_frame(ch,NULL,buf);
+
+ /* blit frame */
+ blitframe(buf);
+ ng_release_video_buf(buf);
+ if (fast)
+ aa_fastrender(context, 0, 0,
+ aa_scrwidth (context), aa_scrheight (context));
+ else
+ aa_render(context, &render, 0, 0,
+ aa_scrwidth (context), aa_scrheight (context));
+ if (now - mtime < 6) {
+ aa_printf(context,0,0,AA_NORMAL,"[ %s ] ",
+ message);
+ } else {
+ aa_printf(context,0,0,AA_NORMAL,"[ %s - %d.%d fps - %02d:%02d ] ",
+ title,fps/10,fps%10,t->tm_hour,t->tm_min);
+ }
+ aa_flush(context);
+
+ /* check for keys */
+ key = aa_getkey(context,0);
+ switch (key) {
+ case 'q':
+ case 'Q':
+ case 'e':
+ case 'E':
+ case 'x':
+ case 'X':
+ audio_off();
+ signaled++;
+ break;
+ case 'd':
+ case 'D':
+ mtime = time(NULL);
+ sprintf(message,"debug: scr=%dx%d / img=%dx%d / cap=%dx%d",
+ aa_scrwidth(context),aa_scrheight(context),
+ aa_imgwidth(context),aa_imgheight(context),
+ fmt.width,fmt.height);
+ break;
+ case '+':
+ do_va_cmd(2,"volume","inc");
+ break;
+ case '-':
+ do_va_cmd(2,"volume","dec");
+ break;
+ case 10:
+ case 13:
+ do_va_cmd(2,"volume","mute");
+ break;
+ case AA_UP:
+ do_va_cmd(2,"setchannel","next");
+ break;
+ case AA_DOWN:
+ do_va_cmd(2,"setchannel","prev");
+ break;
+ case AA_RIGHT:
+ do_va_cmd(2,"setchannel","fine_up");
+ break;
+ case AA_LEFT:
+ do_va_cmd(2,"setchannel","fine_down");
+ break;
+ case ' ':
+ do_va_cmd(2,"setstation","next");
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+ }
+ exit(0);
+}
diff --git a/console/dump-mixers.c b/console/dump-mixers.c
new file mode 100644
index 0000000..b28dc38
--- /dev/null
+++ b/console/dump-mixers.c
@@ -0,0 +1,86 @@
+/*
+ * dump current mixer settings
+ *
+ * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SOUNDCARD_H
+# include <soundcard.h>
+#endif
+#ifdef HAVE_SYS_SOUNDCARD_H
+# include <sys/soundcard.h>
+#endif
+
+char *labels[] = SOUND_DEVICE_LABELS;
+char *names[] = SOUND_DEVICE_NAMES;
+
+static int
+dump_mixer(char *devname)
+{
+#ifdef SOUND_MIXER_INFO
+ struct mixer_info info;
+#endif
+ int mix,i,devmask,recmask,recsrc,stereomask,volume;
+
+ if (-1 == (mix = open(devname,O_RDONLY)))
+ return -1;
+
+ printf("%s",devname);
+#ifdef SOUND_MIXER_INFO
+ if (-1 != ioctl(mix,SOUND_MIXER_INFO,&info))
+ printf(" = %s (%s)",info.id,info.name);
+#endif
+ printf("\n");
+
+ if (-1 == ioctl(mix,MIXER_READ(SOUND_MIXER_DEVMASK),&devmask) ||
+ -1 == ioctl(mix,MIXER_READ(SOUND_MIXER_STEREODEVS),&stereomask) ||
+ -1 == ioctl(mix,MIXER_READ(SOUND_MIXER_RECMASK),&recmask) ||
+ -1 == ioctl(mix,MIXER_READ(SOUND_MIXER_RECSRC),&recsrc)) {
+ perror("mixer ioctl");
+ return -1;
+ }
+
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+ if ((1<<i) & devmask) {
+ if (-1 == ioctl(mix,MIXER_READ(i),&volume)) {
+ perror("mixer read volume");
+ return -1;
+ }
+ printf(" %-10s (%2d) : %s %s%s",
+ names[i],i,
+ (1<<i) & stereomask ? "stereo" : "mono ",
+ (1<<i) & recmask ? "rec" : " ",
+ (1<<i) & recsrc ? "*" : " ");
+ if ((1<<i) & stereomask)
+ printf(" %d/%d\n",volume & 0xff,(volume >> 8) & 0xff);
+ else
+ printf(" %d\n",volume & 0xff);
+ }
+ }
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char devname[32];
+ int i;
+
+ /* first mixer device. If "mixer0" does'nt work, try "mixer" */
+ if (-1 == dump_mixer("/dev/mixer0"))
+ dump_mixer("/dev/mixer");
+ /* other more devices */
+ for (i = 1; i < 8; i++) {
+ sprintf(devname,"/dev/mixer%d",i);
+ dump_mixer(devname);
+ }
+ return 0;
+}
diff --git a/console/fbtools.c b/console/fbtools.c
new file mode 100644
index 0000000..b6a53a8
--- /dev/null
+++ b/console/fbtools.c
@@ -0,0 +1,488 @@
+/*
+ * some generic framebuffer device stuff
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <signal.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/fb.h>
+#include <linux/major.h>
+
+#include <asm/page.h>
+
+#include "fbtools.h"
+
+/* -------------------------------------------------------------------- */
+/* exported stuff */
+
+struct fb_fix_screeninfo fb_fix;
+struct fb_var_screeninfo fb_var;
+unsigned char *fb_mem;
+int fb_mem_offset = 0;
+int fb_switch_state = FB_ACTIVE;
+
+/* -------------------------------------------------------------------- */
+/* internal variables */
+
+static int fb,tty;
+#if 0
+static int bpp,black,white;
+#endif
+
+static int orig_vt_no = 0;
+static struct vt_mode vt_mode;
+
+static int kd_mode;
+static struct vt_mode vt_omode;
+static struct termios term;
+static struct fb_var_screeninfo fb_ovar;
+static unsigned short ored[256], ogreen[256], oblue[256];
+static struct fb_cmap ocmap = { 0, 256, ored, ogreen, oblue };
+
+/* -------------------------------------------------------------------- */
+/* devices */
+
+struct DEVS {
+ char *fb0;
+ char *fbnr;
+ char *ttynr;
+};
+
+struct DEVS devs_default = {
+ fb0: "/dev/fb0",
+ fbnr: "/dev/fb%d",
+ ttynr: "/dev/tty%d",
+};
+struct DEVS devs_devfs = {
+ fb0: "/dev/fb/0",
+ fbnr: "/dev/fb/%d",
+ ttynr: "/dev/vc/%d",
+};
+struct DEVS *devices;
+
+
+/* -------------------------------------------------------------------- */
+/* console switching */
+
+extern int debug;
+
+static void
+fb_switch_signal(int signal)
+{
+ if (signal == SIGUSR1) {
+ /* release */
+ fb_switch_state = FB_REL_REQ;
+ if (debug)
+ write(2,"vt: SIGUSR1\n",12);
+ }
+ if (signal == SIGUSR2) {
+ /* acquisition */
+ fb_switch_state = FB_ACQ_REQ;
+ if (debug)
+ write(2,"vt: SIGUSR2\n",12);
+ }
+}
+
+void
+fb_switch_release()
+{
+ ioctl(tty, VT_RELDISP, 1);
+ fb_switch_state = FB_INACTIVE;
+ if (debug)
+ write(2,"vt: release\n",12);
+}
+
+void
+fb_switch_acquire()
+{
+ ioctl(tty, VT_RELDISP, VT_ACKACQ);
+ fb_switch_state = FB_ACTIVE;
+ if (debug)
+ write(2,"vt: acquire\n",12);
+}
+
+int
+fb_switch_init()
+{
+ struct sigaction act,old;
+
+ memset(&act,0,sizeof(act));
+ act.sa_handler = fb_switch_signal;
+ sigemptyset(&act.sa_mask);
+ sigaction(SIGUSR1,&act,&old);
+ sigaction(SIGUSR2,&act,&old);
+
+ if (-1 == ioctl(tty,VT_GETMODE, &vt_mode)) {
+ perror("ioctl VT_GETMODE");
+ exit(1);
+ }
+ vt_mode.mode = VT_PROCESS;
+ vt_mode.waitv = 0;
+ vt_mode.relsig = SIGUSR1;
+ vt_mode.acqsig = SIGUSR2;
+
+ if (-1 == ioctl(tty,VT_SETMODE, &vt_mode)) {
+ perror("ioctl VT_SETMODE");
+ exit(1);
+ }
+ return 0;
+}
+
+/* -------------------------------------------------------------------- */
+/* initialisation & cleanup */
+
+void
+fb_memset (void *addr, int c, size_t len)
+{
+#if 1 /* defined(__powerpc__) */
+ unsigned int i, *p;
+
+ i = (c & 0xff) << 8;
+ i |= i << 16;
+ len >>= 2;
+ for (p = addr; len--; p++)
+ *p = i;
+#else
+ memset(addr, c, len);
+#endif
+}
+
+static int
+fb_setmode(char *name)
+{
+ FILE *fp;
+ char line[80],label[32],value[16];
+ int geometry=0, timings=0;
+
+ /* load current values */
+ if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_var)) {
+ perror("ioctl FBIOGET_VSCREENINFO");
+ exit(1);
+ }
+
+ if (NULL == name)
+ return -1;
+ if (NULL == (fp = fopen("/etc/fb.modes","r")))
+ return -1;
+ while (NULL != fgets(line,79,fp)) {
+ if (1 == sscanf(line, "mode \"%31[^\"]\"",label) &&
+ 0 == strcmp(label,name)) {
+ /* fill in new values */
+ fb_var.sync = 0;
+ fb_var.vmode = 0;
+ while (NULL != fgets(line,79,fp) &&
+ NULL == strstr(line,"endmode")) {
+ if (5 == sscanf(line," geometry %d %d %d %d %d",
+ &fb_var.xres,&fb_var.yres,
+ &fb_var.xres_virtual,&fb_var.yres_virtual,
+ &fb_var.bits_per_pixel))
+ geometry = 1;
+ if (7 == sscanf(line," timings %d %d %d %d %d %d %d",
+ &fb_var.pixclock,
+ &fb_var.left_margin, &fb_var.right_margin,
+ &fb_var.upper_margin, &fb_var.lower_margin,
+ &fb_var.hsync_len, &fb_var.vsync_len))
+ timings = 1;
+ if (1 == sscanf(line, " hsync %15s",value) &&
+ 0 == strcasecmp(value,"high"))
+ fb_var.sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (1 == sscanf(line, " vsync %15s",value) &&
+ 0 == strcasecmp(value,"high"))
+ fb_var.sync |= FB_SYNC_VERT_HIGH_ACT;
+ if (1 == sscanf(line, " csync %15s",value) &&
+ 0 == strcasecmp(value,"high"))
+ fb_var.sync |= FB_SYNC_COMP_HIGH_ACT;
+ if (1 == sscanf(line, " extsync %15s",value) &&
+ 0 == strcasecmp(value,"true"))
+ fb_var.sync |= FB_SYNC_EXT;
+ if (1 == sscanf(line, " laced %15s",value) &&
+ 0 == strcasecmp(value,"true"))
+ fb_var.vmode |= FB_VMODE_INTERLACED;
+ if (1 == sscanf(line, " double %15s",value) &&
+ 0 == strcasecmp(value,"true"))
+ fb_var.vmode |= FB_VMODE_DOUBLE;
+ }
+ /* ok ? */
+ if (!geometry || !timings)
+ return -1;
+ /* set */
+ fb_var.xoffset = 0;
+ fb_var.yoffset = 0;
+ if (-1 == ioctl(fb,FBIOPUT_VSCREENINFO,&fb_var))
+ perror("ioctl FBIOPUT_VSCREENINFO");
+ /* look what we have now ... */
+ if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_var)) {
+ perror("ioctl FBIOGET_VSCREENINFO");
+ exit(1);
+ }
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static void
+fb_setvt(int vtno)
+{
+ struct vt_stat vts;
+ char vtname[12];
+
+ if (vtno < 0) {
+ if (-1 == ioctl(tty,VT_OPENQRY, &vtno) || vtno == -1) {
+ perror("ioctl VT_OPENQRY");
+ exit(1);
+ }
+ }
+
+ vtno &= 0xff;
+ sprintf(vtname, devices->ttynr, vtno);
+ chown(vtname, getuid(), getgid());
+ if (-1 == access(vtname,R_OK | W_OK)) {
+ fprintf(stderr,"access %s: %s\n",vtname,strerror(errno));
+ exit(1);
+ }
+ switch (fork()) {
+ case 0:
+ break;
+ case -1:
+ perror("fork");
+ exit(1);
+ default:
+ exit(0);
+ }
+ close(tty);
+ close(0);
+ close(1);
+ close(2);
+ setsid();
+ open(vtname,O_RDWR);
+ dup(0);
+ dup(0);
+
+ if (-1 == ioctl(tty,VT_GETSTATE, &vts)) {
+ perror("ioctl VT_GETSTATE");
+ exit(1);
+ }
+ orig_vt_no = vts.v_active;
+ if (-1 == ioctl(tty,VT_ACTIVATE, vtno)) {
+ perror("ioctl VT_ACTIVATE");
+ exit(1);
+ }
+ if (-1 == ioctl(tty,VT_WAITACTIVE, vtno)) {
+ perror("ioctl VT_WAITACTIVE");
+ exit(1);
+ }
+}
+
+int
+fb_init(char *device, char *mode, int vt)
+{
+ struct stat st;
+ char fbdev[16];
+
+ tty = 0;
+ if (vt != 0)
+ fb_setvt(vt);
+
+ /* FIXME: where are MAJOR() / MINOR() ??? */
+ fstat(tty,&st);
+ if (((st.st_rdev >> 8) & 0xff) != TTY_MAJOR) {
+ /* catch that here, give a more user friendly error message that just
+ * throw a error about a failed ioctl later on ... */
+ fprintf(stderr,
+ "ERROR: tty is not a linux console. You can not start this\n"
+ " tool from a pseudo tty (xterm/ssh/screen/...).\n");
+ exit(1);
+ }
+ if (NULL == devices) {
+ struct stat dummy;
+ if (0 == stat("/dev/.devfsd",&dummy))
+ devices = &devs_devfs;
+ else
+ devices = &devs_default;
+ }
+
+ if (NULL == device) {
+ device = getenv("FRAMEBUFFER");
+ if (NULL == device) {
+ struct fb_con2fbmap c2m;
+ if (-1 == (fb = open(devices->fb0,O_WRONLY,0))) {
+ fprintf(stderr,"open %s: %s\n",devices->fb0,strerror(errno));
+ exit(1);
+ }
+ c2m.console = st.st_rdev & 0xff;
+ if (-1 == ioctl(fb, FBIOGET_CON2FBMAP, &c2m)) {
+ perror("ioctl FBIOGET_CON2FBMAP");
+ exit(1);
+ }
+ close(fb);
+ fprintf(stderr,"map: vt%02d => fb%d\n",
+ c2m.console,c2m.framebuffer);
+ sprintf(fbdev,devices->fbnr,c2m.framebuffer);
+ device = fbdev;
+ }
+ }
+
+ /* get current settings (which we have to restore) */
+ if (-1 == (fb = open(device,O_RDWR /* O_WRONLY */))) {
+ fprintf(stderr,"open %s: %s\n",device,strerror(errno));
+ exit(1);
+ }
+ if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_ovar)) {
+ perror("ioctl FBIOGET_VSCREENINFO");
+ exit(1);
+ }
+ if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) {
+ perror("ioctl FBIOGET_FSCREENINFO");
+ exit(1);
+ }
+ if (fb_ovar.bits_per_pixel == 8 ||
+ fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ if (-1 == ioctl(fb,FBIOGETCMAP,&ocmap)) {
+ perror("ioctl FBIOGETCMAP");
+ exit(1);
+ }
+ }
+ if (-1 == ioctl(tty,KDGETMODE, &kd_mode)) {
+ perror("ioctl KDGETMODE");
+ exit(1);
+ }
+ if (-1 == ioctl(tty,VT_GETMODE, &vt_omode)) {
+ perror("ioctl VT_GETMODE");
+ exit(1);
+ }
+ tcgetattr(tty, &term);
+
+ /* switch mode */
+ fb_setmode(mode);
+
+ /* checks & initialisation */
+ if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) {
+ perror("ioctl FBIOGET_FSCREENINFO");
+ exit(1);
+ }
+ if (fb_fix.type != FB_TYPE_PACKED_PIXELS) {
+ fprintf(stderr,"can handle only packed pixel frame buffers\n");
+ goto err;
+ }
+#if 0
+ switch (fb_var.bits_per_pixel) {
+ case 8:
+ white = 255; black = 0; bpp = 1;
+ break;
+ case 15:
+ case 16:
+ if (fb_var.green.length == 6)
+ white = 0xffff;
+ else
+ white = 0x7fff;
+ black = 0; bpp = 2;
+ break;
+ case 24:
+ white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8;
+ break;
+ case 32:
+ white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8;
+ fb_setpixels = fb_setpixels4;
+ break;
+ default:
+ fprintf(stderr, "Oops: %i bit/pixel ???\n",
+ fb_var.bits_per_pixel);
+ goto err;
+ }
+#endif
+ fb_mem_offset = (unsigned long)(fb_fix.smem_start) & (~PAGE_MASK);
+ fb_mem = mmap(NULL,fb_fix.smem_len+fb_mem_offset,
+ PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
+ if (-1L == (long)fb_mem) {
+ perror("mmap");
+ goto err;
+ }
+ /* move viewport to upper left corner */
+ if (fb_var.xoffset != 0 || fb_var.yoffset != 0) {
+ fb_var.xoffset = 0;
+ fb_var.yoffset = 0;
+ if (-1 == ioctl(fb,FBIOPAN_DISPLAY,&fb_var)) {
+ perror("ioctl FBIOPAN_DISPLAY");
+ goto err;
+ }
+ }
+ if (-1 == ioctl(tty,KDSETMODE, KD_GRAPHICS)) {
+ perror("ioctl KDSETMODE");
+ goto err;
+ }
+
+ /* cls */
+ fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
+ return fb;
+
+ err:
+ fb_cleanup();
+ exit(1);
+}
+
+void
+fb_cleanup(void)
+{
+ /* restore console */
+ if (-1 == ioctl(fb,FBIOPUT_VSCREENINFO,&fb_ovar))
+ perror("ioctl FBIOPUT_VSCREENINFO");
+ if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix))
+ perror("ioctl FBIOGET_FSCREENINFO");
+ if (fb_ovar.bits_per_pixel == 8 ||
+ fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ if (-1 == ioctl(fb,FBIOPUTCMAP,&ocmap))
+ perror("ioctl FBIOPUTCMAP");
+ }
+ close(fb);
+
+ if (-1 == ioctl(tty,KDSETMODE, kd_mode))
+ perror("ioctl KDSETMODE");
+ if (-1 == ioctl(tty,VT_SETMODE, &vt_omode))
+ perror("ioctl VT_SETMODE");
+ if (orig_vt_no && -1 == ioctl(tty,VT_ACTIVATE, orig_vt_no))
+ perror("ioctl VT_ACTIVATE");
+ tcsetattr(tty, TCSANOW, &term);
+ close(tty);
+}
+
+void
+fb_cleanup_fork()
+{
+ int status;
+
+ switch (fork()) {
+ case -1:
+ fb_cleanup();
+ perror("fork");
+ exit(1);
+ case 0:
+ return;
+ }
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTSTP,SIG_IGN);
+ signal(SIGTERM,SIG_IGN);
+ signal(SIGUSR1,SIG_IGN);
+ signal(SIGUSR2,SIG_IGN);
+
+ wait(&status);
+ fb_cleanup();
+ if (WIFSIGNALED(status))
+ fprintf(stderr,"Oops: %s\n",sys_siglist[WTERMSIG(status)]);
+ exit(status);
+}
diff --git a/console/fbtools.h b/console/fbtools.h
new file mode 100644
index 0000000..090fa01
--- /dev/null
+++ b/console/fbtools.h
@@ -0,0 +1,22 @@
+#define FB_ACTIVE 0
+#define FB_REL_REQ 1
+#define FB_INACTIVE 2
+#define FB_ACQ_REQ 3
+
+/* info about videomode - yes I know, quick & dirty... */
+extern struct fb_fix_screeninfo fb_fix;
+extern struct fb_var_screeninfo fb_var;
+extern unsigned char *fb_mem;
+extern int fb_mem_offset;
+extern int fb_switch_state;
+
+/* init + cleanup */
+int fb_init(char *device, char *mode, int vt);
+void fb_cleanup(void);
+void fb_cleanup_fork(void);
+void fb_memset(void *addr, int c, size_t len);
+
+/* console switching */
+int fb_switch_init(void);
+void fb_switch_release(void);
+void fb_switch_acquire(void);
diff --git a/console/fbtv.c b/console/fbtv.c
new file mode 100644
index 0000000..95e8b6f
--- /dev/null
+++ b/console/fbtv.c
@@ -0,0 +1,905 @@
+/*
+ * console TV application. Uses a framebuffer device.
+ *
+ * (c) 1998-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <curses.h>
+#include <math.h>
+#include <pthread.h>
+
+#include <linux/kd.h>
+#include <linux/fb.h>
+
+#include "grab-ng.h"
+#include "writefile.h"
+#include "sound.h"
+#include "channel.h"
+#include "frequencies.h"
+#include "commands.h"
+#include "capture.h"
+#include "lirc.h"
+#include "joystick.h"
+#include "midictrl.h"
+#include "event.h"
+
+#include "fbtools.h"
+#include "fs.h"
+#include "matrox.h"
+
+#define MAX(x,y) ((x)>(y)?(x):(y))
+#define MIN(x,y) ((x)<(y)?(x):(y))
+
+/* ---------------------------------------------------------------------- */
+/* framebuffer */
+
+static char *fbdev = NULL;
+static char *fontfile = NULL;
+static char *mode = NULL;
+static char *joydev = NULL;
+static struct fs_font *f;
+#ifndef X_DISPLAY_MISSING
+static char *x11_font = "10x20";
+#endif
+
+static unsigned short red[256], green[256], blue[256];
+static struct fb_cmap cmap = { 0, 256, red, green, blue };
+
+static int switch_last,fb;
+static int keep_dma_on = 0;
+
+static int sig,quiet,matrox;
+static int ww,hh;
+static float fbgamma = 1.0;
+
+static struct ng_video_buf *buf;
+static struct ng_video_fmt fmt,gfmt;
+static struct ng_video_conv *conv;
+static struct ng_convert_handle *ch;
+static int dx,dy;
+
+int have_config;
+int x11_native_format,have_dga=1,debug;
+
+/*--- channels ------------------------------------------------------------*/
+
+struct event_entry kbd_events[] = {
+ {
+ event: "kbd-key-+",
+ action: "volume inc",
+ },{
+ event: "kbd-key--",
+ action: "volume dec",
+ },{
+ event: "kbd-key-enter",
+ action: "volume mute",
+ },{
+ event: "kbd-key-space",
+ action: "setstation next",
+ },{
+ event: "kbd-key-backspace",
+ action: "setstation back",
+ },{
+ event: "kbd-key-pgup",
+ action: "setstation prev",
+ },{
+ event: "kbd-key-pgdown",
+ action: "setstation next",
+ },{
+ event: "kbd-key-right",
+ action: "setchannel fine_up",
+ },{
+ event: "kbd-key-left",
+ action: "setchannel fine_down",
+ },{
+ event: "kbd-key-up",
+ action: "setchannel next",
+ },{
+ event: "kbd-key-down",
+ action: "setchannel prev",
+ },{
+ event: "kbd-key-g",
+ action: "snap ppm",
+ },{
+ event: "kbd-key-j",
+ action: "snap jpeg",
+ },{
+ event: "kbd-key-v",
+ action: "capture toggle",
+ },{
+ event: "kbd-key-f",
+ action: "fullscreen toggle",
+ },{
+ event: "kbd-key-0",
+ action: "keypad 0",
+ },{
+ event: "kbd-key-1",
+ action: "keypad 1",
+ },{
+ event: "kbd-key-2",
+ action: "keypad 2",
+ },{
+ event: "kbd-key-3",
+ action: "keypad 3",
+ },{
+ event: "kbd-key-4",
+ action: "keypad 4",
+ },{
+ event: "kbd-key-5",
+ action: "keypad 5",
+ },{
+ event: "kbd-key-6",
+ action: "keypad 6",
+ },{
+ event: "kbd-key-7",
+ action: "keypad 7",
+ },{
+ event: "kbd-key-8",
+ action: "keypad 8",
+ },{
+ event: "kbd-key-9",
+ action: "keypad 9",
+ },{
+
+ /* end of list */
+ }
+};
+struct KEYTAB {
+ int key;
+ char *name;
+};
+
+static struct KEYTAB keytab[] = {
+ { 9, "tab" },
+ { 10, "enter" },
+ { 13, "enter" },
+ { KEY_ENTER, "enter" },
+
+ { ' ', "space" },
+ { KEY_BACKSPACE, "backspace" },
+
+ { KEY_RIGHT, "right" },
+ { KEY_LEFT, "left" },
+ { KEY_UP, "up" },
+ { KEY_DOWN, "down" },
+ { KEY_PPAGE, "pgup" },
+ { KEY_NPAGE, "pgdown" },
+ { KEY_HOME, "home" },
+ { KEY_END, "end" },
+};
+
+#define NKEYTAB (sizeof(keytab)/sizeof(struct KEYTAB))
+
+static char *snapbase;
+static char default_title[128] = "???";
+static char message[128] = "";
+
+/* ---------------------------------------------------------------------- */
+/* framebuffer stuff */
+
+static void
+linear_palette(int bit)
+{
+ int i, size = 256 >> (8 - bit);
+
+ for (i = 0; i < size; i++)
+ red[i] = green[i] = blue[i] = (unsigned short)(65535.0
+ * pow(i/(size - 1.0), fbgamma));
+}
+
+static void
+dither_palette(int r, int g, int b)
+{
+ int rs, gs, bs, i;
+
+ rs = 256 / (r - 1);
+ gs = 256 / (g - 1);
+ bs = 256 / (b - 1);
+ for (i = 0; i < r*g*b; i++) {
+ green[i+16] = (gs * ((i / (r * b)) % g)) * 255;
+ red[i+16] = (rs * ((i / b) % r)) * 255;
+ blue[i+16] = (bs * ((i) % b)) * 255;
+ }
+}
+
+static void
+fb_initcolors(int fd, int gray)
+{
+ /* get colormap */
+ if (fb_var.bits_per_pixel == 8 ||
+ fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ if (-1 == ioctl(fd,FBIOGETCMAP,&cmap))
+ perror("ioctl FBIOGETCMAP");
+ }
+
+ switch (fb_var.bits_per_pixel) {
+ case 8:
+ if (gray) {
+ linear_palette(8);
+ x11_native_format = VIDEO_GRAY;
+ } else {
+ dither_palette(5,9,5);
+ x11_native_format = VIDEO_RGB08;
+ }
+ break;
+ case 15:
+ case 16:
+ if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
+ linear_palette(5);
+#if BYTE_ORDER == BIG_ENDIAN
+ x11_native_format = (fb_var.green.length == 6) ?
+ VIDEO_RGB16_BE : VIDEO_RGB15_BE;
+#else
+ x11_native_format = (fb_var.green.length == 6) ?
+ VIDEO_RGB16_LE : VIDEO_RGB15_LE;
+#endif
+ break;
+ case 24:
+ if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
+ linear_palette(8);
+#if BYTE_ORDER == BIG_ENDIAN
+ x11_native_format = VIDEO_RGB24;
+#else
+ x11_native_format = VIDEO_BGR24;
+#endif
+ break;
+ case 32:
+ if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
+ linear_palette(8);
+#if BYTE_ORDER == BIG_ENDIAN
+ x11_native_format = VIDEO_RGB32;
+#else
+ x11_native_format = VIDEO_BGR32;
+#endif
+ break;
+ default:
+ fprintf(stderr, "Oops: %i bit/pixel ???\n",
+ fb_var.bits_per_pixel);
+ exit(1);
+ }
+
+ /* set colormap */
+ if (fb_var.bits_per_pixel == 8 ||
+ fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ if (-1 == ioctl(fd,FBIOPUTCMAP,&cmap))
+ perror("ioctl FBIOPUTCMAP");
+ }
+}
+
+static void
+tty_init(void)
+{
+ /* we use curses just for kbd input */
+ initscr();
+ cbreak();
+ noecho();
+ keypad(stdscr,1);
+}
+
+static void
+tty_cleanup(void)
+{
+ clear();
+ refresh();
+ endwin();
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+static void
+text_init(char *font)
+{
+ char *fonts[2] = { font, NULL };
+
+ if (NULL == f)
+ f = fs_consolefont(font ? fonts : NULL);
+#ifndef X_DISPLAY_MISSING
+ if (NULL == f && 0 == fs_connect(NULL))
+ f = fs_open(font ? font : x11_font);
+#endif
+ if (NULL == f) {
+ fprintf(stderr,"no font available\n");
+ exit(1);
+ }
+}
+
+static void
+text_out(int x, int y, char *str)
+{
+ y *= f->height;
+ y -= f->fontHeader.max_bounds.descent;
+ fs_puts(f,x,y,str);
+}
+
+static int
+text_width(char *str)
+{
+ return fs_textwidth(f,str);
+}
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef HAVE_ALSA
+static struct midi_handle fb_midi;
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static void
+ctrlc(int signal)
+{
+ sig=1;
+}
+
+#if 0
+void
+change_audio(int mode)
+{
+ if (grabber->grab_audio)
+ grabber->grab_audio(-1,-1,&mode);
+}
+#endif
+
+static void do_capture(int from, int to, int tmp_switch)
+{
+ /* off */
+ switch (from) {
+ case CAPTURE_GRABDISPLAY:
+ if (f_drv & CAN_CAPTURE)
+ drv->stopvideo(h_drv);
+ break;
+ case CAPTURE_OVERLAY:
+ if (f_drv & CAN_CAPTURE)
+ drv->overlay(h_drv,NULL,0,0,NULL,0,0);
+ if (matrox && !tmp_switch)
+ gfx_scaler_off();
+ break;
+ }
+
+ /* on */
+ memset(&buf,0,sizeof(buf));
+ switch (to) {
+ case CAPTURE_GRABDISPLAY:
+ if (ww && hh) {
+ dx = fb_var.xres-fmt.width;
+ dy = 0;
+ fmt.fmtid = x11_native_format;
+ fmt.width = ww;
+ fmt.height = hh;
+ fmt.bytesperline = fb_fix.line_length;
+ } else {
+ if (quiet) {
+ dx = 0;
+ dy = 0;
+ } else {
+ dx = f->height*3/2;
+ dy = f->height;
+ }
+ fmt.fmtid = x11_native_format;
+ fmt.width = fb_var.xres-dx;
+ fmt.height = fb_var.yres-dy;
+ fmt.bytesperline = fb_fix.line_length;
+ }
+ if (0 != ng_grabber_setformat(&fmt,1)) {
+ gfmt = fmt;
+ if (NULL == (conv = ng_grabber_findconv(&gfmt,0))) {
+ fprintf(stderr,"can't fint useful capture format\n");
+ exit(1);
+ }
+ ch = ng_convert_alloc(conv,&gfmt,&fmt);
+ ng_convert_init(ch);
+ }
+ dx += (fb_var.xres-24-fmt.width)/2;
+ dy += (fb_var.yres-16-fmt.height)/2;
+
+ if (f_drv & CAN_CAPTURE)
+ drv->startvideo(h_drv,-1,2);
+ break;
+ case CAPTURE_OVERLAY:
+ fmt.fmtid = x11_native_format;
+ if (ww && hh) {
+ fmt.width = ww;
+ fmt.height = hh;
+ dx = fb_var.xres-fmt.width;
+ dy = 0;
+ } else if (quiet) {
+ fmt.width = fb_var.xres;
+ fmt.height = fb_var.yres;
+ dx = 0;
+ dy = 0;
+ } else {
+ fmt.width = fb_var.xres-24;
+ fmt.height = fb_var.yres-16;
+ dx = f->height*3/2;
+ dy = f->height;
+ }
+ if (matrox) {
+ struct ng_video_fmt off;
+ int starty;
+#if 1
+ /* FIXME: need some kind of size negotiation */
+ /* hardcoded: PAL, half height (want no interleace) */
+ off.width = 768;
+ off.height = 288;
+ starty = fb_var.yres;
+#else
+ /* settings for debugging */
+ off.width = 320;
+ off.height = 240;
+ starty = fb_var.yres-off.height;
+#endif
+ off.bytesperline = fb_fix.line_length;
+ if (off.width*2 > off.bytesperline)
+ off.width = off.bytesperline/2;
+ off.fmtid = VIDEO_YUV422;
+ drv->overlay(h_drv,&off,0,starty,NULL,0,0);
+ gfx_scaler_on(starty*off.bytesperline,off.bytesperline,
+ off.width,off.height,
+ dx,dx+fmt.width,
+ dy,dy+fmt.height);
+ } else {
+ drv->overlay(h_drv,&fmt,dx,dy,NULL,0,1);
+ }
+ break;
+ }
+}
+
+static void
+do_exit(void)
+{
+ sig = 1;
+}
+
+static void
+new_title(char *txt)
+{
+ strcpy(default_title,txt);
+}
+
+static void
+new_message(char *txt)
+{
+ strcpy(message,txt);
+}
+
+static void
+channel_menu(void)
+{
+ char key[32],ctrl[16],event[64],action[128];
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (channels[i]->key) {
+ if (2 != sscanf(channels[i]->key,"%15[A-Za-z0-9_]+%31[A-Za-z0-9_]",
+ ctrl,key))
+ strcpy(key,channels[i]->key);
+ sprintf(event,"kbd-key-%s",key);
+ sprintf(action,"setstation \"%s\"",channels[i]->name);
+ event_register(event,action);
+ }
+ }
+}
+
+static void
+do_fullscreen(void)
+{
+ do_va_cmd(2,"capture","off");
+ quiet = !quiet;
+ fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
+ do_va_cmd(2,"capture","on");
+}
+
+/*--- main ---------------------------------------------------------------*/
+
+static void
+grabber_init(void)
+{
+ struct ng_video_fmt screen;
+
+ memset(&screen,0,sizeof(screen));
+ screen.fmtid = x11_native_format,
+ screen.width = fb_var.xres_virtual;
+ screen.height = fb_var.yres_virtual;
+ screen.bytesperline = fb_fix.line_length;
+ drv = ng_vid_open(ng_dev.video,&screen,0,&h_drv);
+ if (NULL == drv) {
+ fprintf(stderr,"no grabber device available\n");
+ exit(1);
+ }
+ f_drv = drv->capabilities(h_drv);
+ add_attrs(drv->list_attrs(h_drv));
+}
+
+static void
+console_switch(void)
+{
+ switch (fb_switch_state) {
+ case FB_REL_REQ:
+ if (!keep_dma_on)
+ do_va_cmd(2,"capture","off");
+ switch_last = fb_switch_state;
+ fb_switch_release();
+ break;
+ case FB_ACQ_REQ:
+ switch_last = fb_switch_state;
+ fb_switch_acquire();
+ fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
+ ioctl(fb,FBIOPAN_DISPLAY,&fb_var);
+ do_va_cmd(2,"capture","on");
+ break;
+ case FB_ACTIVE:
+ case FB_INACTIVE:
+ default:
+ switch_last = fb_switch_state;
+ break;
+ }
+}
+
+#if 0
+/* just a hook for some test code */
+static void
+scaler_test(int off)
+{
+ if (!matrox) {
+ matrox=1;
+ if (-1 == gfx_init(fb))
+ matrox = 0;
+ }
+
+ if (matrox) {
+ gfx_scaler_on(0,fb_fix.line_length,320,240,
+ fb_var.xres-320,fb_var.xres,0,240);
+ sleep(2);
+ }
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ int key,i,c,gray=0,rc,vt=0,fps=0,t1,t2,lirc,js,err,mute=1,fdmax;
+ unsigned long freq;
+ struct timeval tv;
+ time_t t;
+ char text[80],event[64],*env,*dst;
+ fd_set set;
+
+ if (0 == geteuid() && 0 != getuid()) {
+ fprintf(stderr,"fbtv /must not/ be installed suid root\n");
+ exit(1);
+ }
+
+ if (NULL != (env = getenv("FBFONT")))
+ fontfile = env;
+ ng_init();
+ for (;;) {
+ double val;
+ c = getopt(argc, argv, "Mgvqxkd:o:s:c:f:m:z:t:j:");
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'z':
+ if(sscanf(optarg, "%lf", &val) == 1) {
+ if(val < 0.1 || val > 10)
+ fprintf(stderr, "gamma value is out of range. must be "
+ "0.1 < value < 10.0\n");
+ else
+ fbgamma = 1.0 / val;
+ }
+ break;
+ case 'f':
+ fontfile = optarg;
+ break;
+ case 'm':
+ mode = optarg;
+ break;
+ case 'g':
+ gray = 1;
+ break;
+ case 'M':
+ matrox = 1;
+ break;
+ case 'k':
+ keep_dma_on = 1;
+ break;
+ case 'v':
+ debug++;
+ ng_debug++;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'd':
+ fbdev = optarg;
+ break;
+ case 'o':
+ snapbase = strdup(optarg);
+ break;
+ case 's':
+ sscanf(optarg,"%dx%d",&ww,&hh);
+ break;
+ case 'c':
+ ng_dev.video = optarg;
+ /* v4l-conf needs this too */
+ strcat(ng_v4l_conf," -c ");
+ strcat(ng_v4l_conf,ng_dev.video);
+ break;
+ case 't':
+ if (optarg)
+ vt = strtoul(optarg, 0, 0);
+ else
+ vt = -1;
+ break;
+ case 'j':
+ joydev = optarg;
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ do_overlay = 1;
+ text_init(fontfile);
+ fb = fb_init(fbdev,mode,vt);
+ fb_cleanup_fork();
+ fb_initcolors(fb,gray);
+ fb_switch_init();
+ switch_last = fb_switch_state;
+ fs_init_fb(15);
+
+ if (matrox)
+ if (-1 == gfx_init(fb))
+ matrox = 0;
+ if (matrox)
+ strcat(ng_v4l_conf," -y ");
+
+ grabber_init();
+ read_config(NULL);
+ if (0 != strlen(mixerdev)) {
+ struct ng_attribute *attr;
+ if (NULL != (attr = ng_mix_init(mixerdev,mixerctl)))
+ add_attrs(attr);
+ }
+
+ /* set hooks (command.c) */
+ update_title = new_title;
+ display_message = new_message;
+ set_capture_hook = do_capture;
+ exit_hook = do_exit;
+ fullscreen_hook = do_fullscreen;
+
+ tty_init();
+ atexit(tty_cleanup);
+ signal(SIGINT,ctrlc);
+ signal(SIGTSTP,SIG_IGN);
+
+ /* init hardware */
+ attr_init();
+ audio_on();
+ audio_init();
+
+ /* build channel list */
+ parse_config();
+ channel_menu();
+
+ do_va_cmd(2,"setfreqtab",chanlist_names[chantab].str);
+ cur_capture = 0;
+ do_va_cmd(2,"capture","overlay");
+ if (optind+1 == argc) {
+ do_va_cmd(2,"setstation",argv[optind]);
+ } else {
+ if ((f_drv & CAN_TUNE) && 0 != (freq = drv->getfreq(h_drv))) {
+ for (i = 0; i < chancount; i++)
+ if (chanlist[i].freq == freq*1000/16) {
+ do_va_cmd(2,"setchannel",chanlist[i].name);
+ break;
+ }
+ }
+ if (-1 == cur_channel) {
+ if (count > 0)
+ do_va_cmd(2,"setstation","0");
+ else
+ set_defaults();
+ }
+ }
+
+ /* keyboard, lirc + midi + joystick input support */
+ event_register_list(kbd_events);
+ lirc = lirc_tv_init();
+ js = joystick_tv_init(joydev);
+#ifdef HAVE_ALSA
+ fb_midi.fd = -1;
+ if (midi) {
+ if (-1 != midi_open(&fb_midi, "fbtv"))
+ midi_connect(&fb_midi,midi);
+ }
+#endif
+
+ fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
+ for (;!sig;) {
+ if ((fb_switch_state == FB_ACTIVE || keep_dma_on) && !quiet) {
+ /* clear first lines */
+ fb_memset(fb_mem+fb_mem_offset,0,f->height*fb_fix.line_length);
+ if (message[0] != '\0') {
+ strcpy(text,message);
+ } else {
+ sprintf(text,"Framebuffer TV - %s",default_title);
+ }
+ /* debugging + preformance monitoring */
+ switch (cur_capture) {
+ case CAPTURE_GRABDISPLAY:
+ sprintf(text+strlen(text), " - grab %d.%d fps",fps/5,(fps*2)%10);
+ break;
+ }
+ text_out(0,0,text);
+
+ if (dy > 0) {
+ /* display time */
+ time(&t);
+ strftime(text,16,"%H:%M",localtime(&t));
+ text_out(fb_var.xres - text_width(text) - f->width, 0, text);
+ }
+ }
+ if (switch_last != fb_switch_state)
+ console_switch();
+
+ t1 = time(NULL);
+ fps = 0;
+ message[0] = '\0';
+ for (;;) {
+ FD_ZERO(&set);
+ FD_SET(0,&set);
+ fdmax = 1;
+ if (lirc != -1) {
+ FD_SET(lirc,&set);
+ fdmax = MAX(fdmax,lirc+1);
+ }
+ if (js != -1) {
+ FD_SET(js,&set);
+ fdmax = MAX(fdmax,js+1);
+ }
+#ifdef HAVE_ALSA
+ if (fb_midi.fd != -1) {
+ FD_SET(fb_midi.fd,&set);
+ fdmax = MAX(fdmax,fb_midi.fd+1);
+ }
+#endif
+ if (cur_capture == CAPTURE_GRABDISPLAY &&
+ (fb_switch_state == FB_ACTIVE || keep_dma_on)) {
+ fps++;
+ /* grab + convert frame */
+ if (NULL == (buf = ng_grabber_grab_image(0))) {
+ fprintf(stderr,"capturing image failed\n");
+ exit(1);
+ }
+ if (ch)
+ buf = ng_convert_frame(ch,NULL,buf);
+ /* blit frame */
+ dst = fb_mem +
+ dy * fb_fix.line_length +
+ dx * ((fb_var.bits_per_pixel+7)/8);
+ for (i = 0; i < buf->fmt.height; i++) {
+ memcpy(dst,buf->data + i*buf->fmt.bytesperline, buf->fmt.bytesperline);
+ dst += fb_fix.line_length;
+ }
+ ng_release_video_buf(buf);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ rc = select(fdmax,&set,NULL,NULL,&tv);
+ } else {
+ tv.tv_sec = 6;
+ tv.tv_usec = 0;
+ rc = select(fdmax,&set,NULL,NULL,&tv);
+ }
+ err = errno;
+ if (switch_last != fb_switch_state)
+ console_switch();
+ if (-1 == rc && EINTR == err)
+ continue;
+ if (rc > 0)
+ break;
+ t2 = time(NULL);
+ if (t2 - t1 >= 5) {
+ keypad_timeout();
+ break;
+ }
+ }
+
+ if (FD_ISSET(0,&set)) {
+ /* keyboard input */
+ switch (key = getch()) {
+ case 27: /* ESC */
+ case 'q':
+ case 'Q':
+ sig=1;
+ break;
+ case 'x':
+ case 'X':
+ sig=1;
+ mute=0;
+ break;
+ case -1:
+ break;
+
+#if 0 /* debug */
+ case 'y':
+ /* scaler_test(1); */
+ do_va_cmd(2,"capture","off");
+ do_va_cmd(2,"capture","grab");
+ break;
+#endif
+
+ default:
+ event[0] = 0;
+ if (key > ' ' && key < 127) {
+ /* as is */
+ sprintf(event,"kbd-key-%c",key);
+ } else if (key >= KEY_F(0) && key <= KEY_F(12)) {
+ /* function keys */
+ sprintf(event,"kbd-key-f%d",key - KEY_F(0));
+ } else {
+ /* other special keys */
+ for (i = 0; i < NKEYTAB; i++) {
+ if (keytab[i].key == key)
+ break;
+ }
+ if (i != NKEYTAB)
+ sprintf(event,"kbd-key-%s",keytab[i].name);
+ }
+ if (0 != event[0]) {
+ event_dispatch(event);
+ } else {
+ sprintf(message,"unknown key: %d 0x%x ",key,key);
+ }
+
+ }
+ } /* if (FD_ISSET(0,&set)) */
+
+ if (lirc != -1 && FD_ISSET(lirc,&set)) {
+ /* lirc input */
+ if (-1 == lirc_tv_havedata()) {
+ fprintf(stderr,"lirc: connection lost\n");
+ close(lirc);
+ lirc = -1;
+ }
+ }
+
+ if (js != -1 && FD_ISSET(js,&set)) {
+ /* joystick input */
+ joystick_tv_havedata(js);
+ }
+
+#ifdef HAVE_ALSA
+ if (fb_midi.fd != -1 && FD_ISSET(fb_midi.fd,&set)) {
+ /* midi input */
+ midi_read(&fb_midi);
+ midi_translate(&fb_midi);
+ }
+#endif
+ }
+ do_va_cmd(2,"capture","off");
+ if (mute)
+ audio_off();
+ drv->close(h_drv);
+ fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
+ /* parent will clean up */
+ exit(0);
+}
diff --git a/console/font-6x11.h b/console/font-6x11.h
new file mode 100644
index 0000000..844ff4f
--- /dev/null
+++ b/console/font-6x11.h
@@ -0,0 +1,3337 @@
+/**********************************************/
+/* */
+/* Font file generated by rthelen */
+/* */
+/**********************************************/
+
+static unsigned char fontdata[] = {
+
+ /* 0 0x00 '^A' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 1 0x01 '^B' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 2 0x02 '^C' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 3 0x03 '^D' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 4 0x04 '^E' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 5 0x05 '^F' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 6 0x06 '^G' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 7 0x07 '^H' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 8 0x08 '^I' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 9 0x09 '^J' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 10 0x0a '^K' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 11 0x0b '^L' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 12 0x0c '^M' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 13 0x0d '^N' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 14 0x0e '^O' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 15 0x0f '^P' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 16 0x10 '^Q' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 17 0x11 '^R' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x38, /* 00 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 18 0x12 '^S' */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x50, /* 0 0 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x20, /* 00 00000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 19 0x13 '^T' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x7c, /* 0 00 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 20 0x14 '^U' */
+ 0x18, /* 000 000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x7c, /* 0 00 */
+ 0x78, /* 0 000 */
+ 0x78, /* 0 000 */
+ 0x7c, /* 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 21 0x15 '^V' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 22 0x16 '^W' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 23 0x17 '^X' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 24 0x18 '^Y' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 25 0x19 '^Z' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 26 0x1a '^[' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 27 0x1b '^\' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 28 0x1c '^]' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 29 0x1d '^^' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 30 0x1e '^_' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 31 0x1f '^`' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 32 0x20 ' ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 33 0x21 '!' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 34 0x22 '"' */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 35 0x23 '#' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x7c, /* 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x7c, /* 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 36 0x24 '$' */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x50, /* 0 0 0000 */
+ 0x38, /* 00 000 */
+ 0x14, /* 000 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 37 0x25 '%' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x58, /* 0 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x34, /* 00 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x48, /* 0 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 38 0x26 '&' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x48, /* 0 00 000 */
+ 0x50, /* 0 0 0000 */
+ 0x20, /* 00 00000 */
+ 0x54, /* 0 0 0 00 */
+ 0x48, /* 0 00 000 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 39 0x27 ''' */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 40 0x28 '(' */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 41 0x29 ')' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 42 0x2a '*' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x54, /* 0 0 0 00 */
+ 0x38, /* 00 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 43 0x2b '+' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 44 0x2c ',' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+
+ /* 45 0x2d '-' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 46 0x2e '.' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 000 000 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 47 0x2f '/' */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x20, /* 00 00000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+
+ /* 48 0x30 '0' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x64, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 49 0x31 '1' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x18, /* 000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x1c, /* 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 50 0x32 '2' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 51 0x33 '3' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x04, /* 00000 00 */
+ 0x18, /* 000 000 */
+ 0x04, /* 00000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 52 0x34 '4' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x18, /* 000 000 */
+ 0x28, /* 00 0 000 */
+ 0x48, /* 0 00 000 */
+ 0x7c, /* 0 00 */
+ 0x08, /* 0000 000 */
+ 0x1c, /* 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 53 0x35 '5' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 54 0x36 '6' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 55 0x37 '7' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 56 0x38 '8' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 57 0x39 '9' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x04, /* 00000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 58 0x3a ':' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 000 000 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 000 000 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 59 0x3b ';' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x30, /* 00 0000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+
+ /* 60 0x3c '<' */
+ 0x00, /* 00000000 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 61 0x3d '=' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 62 0x3e '>' */
+ 0x00, /* 00000000 */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 63 0x3f '?' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 64 0x40 '@' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x74, /* 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 65 0x41 'A' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 66 0x42 'B' */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 67 0x43 'C' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 68 0x44 'D' */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 69 0x45 'E' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 70 0x46 'F' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 71 0x47 'G' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x4c, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 72 0x48 'H' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 73 0x49 'I' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 74 0x4a 'J' */
+ 0x00, /* 00000000 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 75 0x4b 'K' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x48, /* 0 00 000 */
+ 0x50, /* 0 0 0000 */
+ 0x60, /* 0 00000 */
+ 0x50, /* 0 0 0000 */
+ 0x48, /* 0 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 76 0x4c 'L' */
+ 0x00, /* 00000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 77 0x4d 'M' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x6c, /* 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 78 0x4e 'N' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x64, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x4c, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 79 0x4f 'O' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 80 0x50 'P' */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 81 0x51 'Q' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x38, /* 00 000 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 82 0x52 'R' */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 83 0x53 'S' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x38, /* 00 000 */
+ 0x04, /* 00000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 84 0x54 'T' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 85 0x55 'U' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 86 0x56 'V' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 87 0x57 'W' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x6c, /* 0 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 88 0x58 'X' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 89 0x59 'Y' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 90 0x5a 'Z' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x40, /* 0 000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 91 0x5b '[' */
+ 0x0c, /* 0000 00 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x0c, /* 0000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 92 0x5c '\' */
+ 0x20, /* 00 00000 */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x02, /* 000000 0 */
+ 0x02, /* 000000 0 */
+ 0x00, /* 00000000 */
+
+ /* 93 0x5d ']' */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x30, /* 00 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 94 0x5e '^' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 95 0x5f '_' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 0 0 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 96 0x60 '`' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 97 0x61 'a' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 98 0x62 'b' */
+ 0x00, /* 00000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 99 0x63 'c' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 100 0x64 'd' */
+ 0x00, /* 00000000 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 101 0x65 'e' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 102 0x66 'f' */
+ 0x00, /* 00000000 */
+ 0x0c, /* 0000 00 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 103 0x67 'g' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x04, /* 00000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+
+ /* 104 0x68 'h' */
+ 0x00, /* 00000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 105 0x69 'i' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 106 0x6a 'j' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x60, /* 0 00000 */
+ 0x00, /* 00000000 */
+
+ /* 107 0x6b 'k' */
+ 0x00, /* 00000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x48, /* 0 00 000 */
+ 0x50, /* 0 0 0000 */
+ 0x70, /* 0 0000 */
+ 0x48, /* 0 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 108 0x6c 'l' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 109 0x6d 'm' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 110 0x6e 'n' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x58, /* 0 0 000 */
+ 0x64, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 111 0x6f 'o' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 112 0x70 'p' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+
+ /* 113 0x71 'q' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+
+ /* 114 0x72 'r' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x58, /* 0 0 000 */
+ 0x64, /* 0 00 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 115 0x73 's' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x40, /* 0 000000 */
+ 0x38, /* 00 000 */
+ 0x04, /* 00000 00 */
+ 0x78, /* 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 116 0x74 't' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x0c, /* 0000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 117 0x75 'u' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 118 0x76 'v' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 119 0x77 'w' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 120 0x78 'x' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 121 0x79 'y' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x04, /* 00000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+
+ /* 122 0x7a 'z' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 123 0x7b '{' */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+
+ /* 124 0x7c '|' */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 125 0x7d '}' */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+
+ /* 126 0x7e '~' */
+ 0x00, /* 00000000 */
+ 0x34, /* 00 0 00 */
+ 0x58, /* 0 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 127 0x7f '^?' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 128 0x80 '\200' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 129 0x81 '\201' */
+ 0x28, /* 00 0 000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 130 0x82 '\202' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 131 0x83 '\203' */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 132 0x84 '\204' */
+ 0x58, /* 0 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x64, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x4c, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 133 0x85 '\205' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 134 0x86 '\206' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 135 0x87 '\207' */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 136 0x88 '\210' */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 137 0x89 '\211' */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 138 0x8a '\212' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 139 0x8b '\213' */
+ 0x34, /* 00 0 00 */
+ 0x58, /* 0 0 000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 140 0x8c '\214' */
+ 0x18, /* 000 000 */
+ 0x24, /* 00 00 00 */
+ 0x18, /* 000 000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 141 0x8d '\215' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+
+ /* 142 0x8e '\216' */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 143 0x8f '\217' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 144 0x90 '\220' */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 145 0x91 '\221' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 146 0x92 '\222' */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 147 0x93 '\223' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 148 0x94 '\224' */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 149 0x95 '\225' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 150 0x96 '\226' */
+ 0x34, /* 00 0 00 */
+ 0x58, /* 0 0 000 */
+ 0x00, /* 00000000 */
+ 0x58, /* 0 0 000 */
+ 0x64, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 151 0x97 '\227' */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 152 0x98 '\230' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 153 0x99 '\231' */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 154 0x9a '\232' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 155 0x9b '\233' */
+ 0x34, /* 00 0 00 */
+ 0x58, /* 0 0 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 156 0x9c '\234' */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 157 0x9d '\235' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 158 0x9e '\236' */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 159 0x9f '\237' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 160 0xa0 '\240' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 161 0xa1 '\241' */
+ 0x18, /* 000 000 */
+ 0x24, /* 00 00 00 */
+ 0x24, /* 00 00 00 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 162 0xa2 '\242' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x50, /* 0 0 0000 */
+ 0x54, /* 0 0 0 00 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 163 0xa3 '\243' */
+ 0x30, /* 00 0000 */
+ 0x48, /* 0 00 000 */
+ 0x40, /* 0 000000 */
+ 0x70, /* 0 0000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 164 0xa4 '\244' */
+ 0x44, /* 0 000 00 */
+ 0x24, /* 00 00 00 */
+ 0x50, /* 0 0 0000 */
+ 0x48, /* 0 00 000 */
+ 0x24, /* 00 00 00 */
+ 0x14, /* 000 0 00 */
+ 0x48, /* 0 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 165 0xa5 '\245' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x7c, /* 0 00 */
+ 0x7c, /* 0 00 */
+ 0x7c, /* 0 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 166 0xa6 '\246' */
+ 0x3c, /* 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x3c, /* 00 00 */
+ 0x14, /* 000 0 00 */
+ 0x14, /* 000 0 00 */
+ 0x14, /* 000 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 167 0xa7 '\247' */
+ 0x18, /* 000 000 */
+ 0x24, /* 00 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x48, /* 0 00 000 */
+ 0x48, /* 0 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x58, /* 0 0 000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 168 0xa8 '\250' */
+ 0x00, /* 00000000 */
+ 0x70, /* 0 0000 */
+ 0x08, /* 0000 000 */
+ 0x64, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x64, /* 0 00 00 */
+ 0x58, /* 0 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 169 0xa9 '\251' */
+ 0x00, /* 00000000 */
+ 0x70, /* 0 0000 */
+ 0x08, /* 0000 000 */
+ 0x34, /* 00 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x34, /* 00 0 00 */
+ 0x08, /* 0000 000 */
+ 0x70, /* 0 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 170 0xaa '\252' */
+ 0x00, /* 00000000 */
+ 0x7a, /* 0 0 0 */
+ 0x2e, /* 00 0 0 */
+ 0x2e, /* 00 0 0 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 171 0xab '\253' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 172 0xac '\254' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 173 0xad '\255' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 174 0xae '\256' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x50, /* 0 0 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x78, /* 0 000 */
+ 0x50, /* 0 0 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x5c, /* 0 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 175 0xaf '\257' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x64, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 176 0xb0 '\260' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x6c, /* 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x6c, /* 0 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 177 0xb1 '\261' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 178 0xb2 '\262' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 179 0xb3 '\263' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x1c, /* 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 180 0xb4 '\264' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 181 0xb5 '\265' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x48, /* 0 00 000 */
+ 0x48, /* 0 00 000 */
+ 0x48, /* 0 00 000 */
+ 0x48, /* 0 00 000 */
+ 0x74, /* 0 0 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+
+ /* 182 0xb6 '\266' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x0c, /* 0000 00 */
+ 0x14, /* 000 0 00 */
+ 0x24, /* 00 00 00 */
+ 0x24, /* 00 00 00 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 183 0xb7 '\267' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x24, /* 00 00 00 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x24, /* 00 00 00 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 184 0xb8 '\270' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 185 0xb9 '\271' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 186 0xba '\272' */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x60, /* 0 00000 */
+ 0x00, /* 00000000 */
+
+ /* 187 0xbb '\273' */
+ 0x00, /* 00000000 */
+ 0x1c, /* 000 00 */
+ 0x24, /* 00 00 00 */
+ 0x24, /* 00 00 00 */
+ 0x1c, /* 000 00 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 188 0xbc '\274' */
+ 0x00, /* 00000000 */
+ 0x18, /* 000 000 */
+ 0x24, /* 00 00 00 */
+ 0x24, /* 00 00 00 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 189 0xbd '\275' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x6c, /* 0 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 190 0xbe '\276' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x5c, /* 0 0 00 */
+ 0x50, /* 0 0 0000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 191 0xbf '\277' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x4c, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x64, /* 0 00 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 192 0xc0 '\300' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x40, /* 0 000000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 193 0xc1 '\301' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 194 0xc2 '\302' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 195 0xc3 '\303' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0c, /* 0000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x20, /* 00 00000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 196 0xc4 '\304' */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x60, /* 0 00000 */
+ 0x00, /* 00000000 */
+
+ /* 197 0xc5 '\305' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x04, /* 00000 00 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 198 0xc6 '\306' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 199 0xc7 '\307' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x24, /* 00 00 00 */
+ 0x48, /* 0 00 000 */
+ 0x48, /* 0 00 000 */
+ 0x24, /* 00 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 200 0xc8 '\310' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x48, /* 0 00 000 */
+ 0x24, /* 00 00 00 */
+ 0x24, /* 00 00 00 */
+ 0x48, /* 0 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 201 0xc9 '\311' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x54, /* 0 0 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 202 0xca '\312' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 203 0xcb '\313' */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 204 0xcc '\314' */
+ 0x58, /* 0 0 000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 205 0xcd '\315' */
+ 0x58, /* 0 0 000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 206 0xce '\316' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x50, /* 0 0 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x58, /* 0 0 000 */
+ 0x50, /* 0 0 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 207 0xcf '\317' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x5c, /* 0 0 00 */
+ 0x50, /* 0 0 0000 */
+ 0x2c, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 208 0xd0 '\320' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 209 0xd1 '\321' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 0 0 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 210 0xd2 '\322' */
+ 0x00, /* 00000000 */
+ 0x14, /* 000 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 211 0xd3 '\323' */
+ 0x00, /* 00000000 */
+ 0x14, /* 000 0 00 */
+ 0x14, /* 000 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 212 0xd4 '\324' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 213 0xd5 '\325' */
+ 0x00, /* 00000000 */
+ 0x18, /* 000 000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 214 0xd6 '\326' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 215 0xd7 '\327' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 216 0xd8 '\330' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x04, /* 00000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+
+ /* 217 0xd9 '\331' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 0 0 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 0 0 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 0 0 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 218 0xda '\332' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 219 0xdb '\333' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 220 0xdc '\334' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 221 0xdd '\335' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 222 0xde '\336' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 223 0xdf '\337' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 224 0xe0 '\340' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 225 0xe1 '\341' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 226 0xe2 '\342' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 227 0xe3 '\343' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 228 0xe4 '\344' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 229 0xe5 '\345' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 230 0xe6 '\346' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 231 0xe7 '\347' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 232 0xe8 '\350' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 233 0xe9 '\351' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 234 0xea '\352' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 235 0xeb '\353' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 236 0xec '\354' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 237 0xed '\355' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 238 0xee '\356' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 239 0xef '\357' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 240 0xf0 '\360' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 241 0xf1 '\361' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 242 0xf2 '\362' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 243 0xf3 '\363' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 244 0xf4 '\364' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 245 0xf5 '\365' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 246 0xf6 '\366' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 247 0xf7 '\367' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 248 0xf8 '\370' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 249 0xf9 '\371' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 250 0xfa '\372' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 251 0xfb '\373' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 252 0xfc '\374' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 253 0xfd '\375' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 254 0xfe '\376' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 255 0xff '\377' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+};
diff --git a/console/fs.c b/console/fs.c
new file mode 100644
index 0000000..c5008a2
--- /dev/null
+++ b/console/fs.c
@@ -0,0 +1,501 @@
+/*
+ * text rendering for the framebuffer console
+ * pick fonts from X11 font server or
+ * use linux consolefont psf files.
+ * (c) 2001 Gerd Knorr <kraxel@bytesex.org>
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/fb.h>
+
+#include "fbtools.h"
+#include "fs.h"
+
+/* ------------------------------------------------------------------ */
+
+#define BIT_ORDER BitmapFormatBitOrderMSB
+#ifdef BYTE_ORDER
+#undef BYTE_ORDER
+#endif
+#define BYTE_ORDER BitmapFormatByteOrderMSB
+#define SCANLINE_UNIT BitmapFormatScanlineUnit8
+#define SCANLINE_PAD BitmapFormatScanlinePad8
+#define EXTENTS BitmapFormatImageRectMin
+
+#define SCANLINE_PAD_BYTES 1
+#define GLWIDTHBYTESPADDED(bits, nBytes) \
+ ((nBytes) == 1 ? (((bits) + 7) >> 3) /* pad to 1 byte */\
+ :(nBytes) == 2 ? ((((bits) + 15) >> 3) & ~1) /* pad to 2 bytes */\
+ :(nBytes) == 4 ? ((((bits) + 31) >> 3) & ~3) /* pad to 4 bytes */\
+ :(nBytes) == 8 ? ((((bits) + 63) >> 3) & ~7) /* pad to 8 bytes */\
+ : 0)
+
+static const unsigned fs_masktab[] = {
+ (1 << 7), (1 << 6), (1 << 5), (1 << 4),
+ (1 << 3), (1 << 2), (1 << 1), (1 << 0),
+};
+
+/* ------------------------------------------------------------------ */
+
+#ifndef X_DISPLAY_MISSING
+static FSServer *svr;
+#endif
+static unsigned int bpp,black,white;
+
+static void (*setpixel)(void *ptr, unsigned int color);
+
+static void setpixel1(void *ptr, unsigned int color)
+{
+ unsigned char *p = ptr;
+ *p = color;
+}
+static void setpixel2(void *ptr, unsigned int color)
+{
+ unsigned short *p = ptr;
+ *p = color;
+}
+static void setpixel3(void *ptr, unsigned int color)
+{
+ unsigned char *p = ptr;
+ *(p++) = (color >> 16) & 0xff;
+ *(p++) = (color >> 8) & 0xff;
+ *(p++) = color & 0xff;
+}
+static void setpixel4(void *ptr, unsigned int color)
+{
+ unsigned long *p = ptr;
+ *p = color;
+}
+
+int fs_init_fb(int white8)
+{
+ switch (fb_var.bits_per_pixel) {
+ case 8:
+ white = white8; black = 0; bpp = 1;
+ setpixel = setpixel1;
+ break;
+ case 15:
+ case 16:
+ if (fb_var.green.length == 6)
+ white = 0xffff;
+ else
+ white = 0x7fff;
+ black = 0; bpp = 2;
+ setpixel = setpixel2;
+ break;
+ case 24:
+ white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8;
+ setpixel = setpixel3;
+ break;
+ case 32:
+ white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8;
+ setpixel = setpixel4;
+ break;
+ default:
+ fprintf(stderr, "Oops: %i bit/pixel ???\n",
+ fb_var.bits_per_pixel);
+ return -1;
+ }
+ return 0;
+}
+
+void fs_render_fb(unsigned char *ptr, int pitch,
+ FSXCharInfo *charInfo, unsigned char *data)
+{
+ int row,bit,bpr,x;
+
+ bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left),
+ SCANLINE_PAD_BYTES);
+ for (row = 0; row < (charInfo->ascent + charInfo->descent); row++) {
+ for (x = 0, bit = 0; bit < (charInfo->right - charInfo->left); bit++) {
+ if (data[bit>>3] & fs_masktab[bit&7])
+ setpixel(ptr+x,white);
+ x += bpp;
+ }
+ data += bpr;
+ ptr += pitch;
+ }
+}
+
+int fs_puts(struct fs_font *f, int x, int y, unsigned char *str)
+{
+ unsigned char *pos,*start;
+ int i,c,j,w;
+
+ pos = fb_mem+fb_mem_offset;
+ pos += fb_fix.line_length * y;
+ for (i = 0; str[i] != '\0'; i++) {
+ c = str[i];
+ if (NULL == f->eindex[c])
+ continue;
+ /* clear with bg color */
+ start = pos + x*bpp + f->fontHeader.max_bounds.descent * fb_fix.line_length;
+ w = (f->eindex[c]->width+1)*bpp;
+ for (j = 0; j < f->height; j++) {
+ memset(start,0,w);
+ start += fb_fix.line_length;
+ }
+ /* draw char */
+ start = pos + x*bpp + fb_fix.line_length * (f->height-f->eindex[c]->ascent);
+ fs_render_fb(start,fb_fix.line_length,f->eindex[c],f->gindex[c]);
+ x += f->eindex[c]->width;
+ if (x > fb_var.xres - f->width)
+ return -1;
+ }
+ return x;
+}
+
+int fs_textwidth(struct fs_font *f, unsigned char *str)
+{
+ int width = 0;
+ int i,c;
+
+ for (i = 0; str[i] != '\0'; i++) {
+ c = str[i];
+ if (NULL == f->eindex[c])
+ continue;
+ width += f->eindex[c]->width;
+ }
+ return width;
+}
+
+void fs_render_tty(FSXCharInfo *charInfo, unsigned char *data)
+{
+ int bpr,row,bit,on;
+
+ bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left),
+ SCANLINE_PAD_BYTES);
+ for (row = 0; row < (charInfo->ascent + charInfo->descent); row++) {
+ fprintf(stdout,"|");
+ for (bit = 0; bit < (charInfo->right - charInfo->left); bit++) {
+ on = data[bit>>3] & fs_masktab[bit&7];
+ fprintf(stdout,"%s",on ? "##" : " ");
+ }
+ fprintf(stdout,"|\n");
+ data += bpr;
+ }
+ fprintf(stdout,"--\n");
+}
+
+/* ------------------------------------------------------------------ */
+
+#ifndef X_DISPLAY_MISSING
+/* connect to font server */
+int fs_connect(char *servername)
+{
+ if (NULL == servername)
+ servername = getenv("FONTSERVER");
+ if (NULL == servername)
+ servername = "unix/:7100";
+ svr = FSOpenServer(servername);
+ if (NULL == svr) {
+ if (NULL == FSServerName(servername)) {
+ fprintf(stderr, "no font server defined\n");
+ } else {
+ fprintf(stderr, "unable to open server \"%s\"\n",
+ FSServerName(servername));
+ }
+ return -1;
+ }
+ return 0;
+}
+
+/* load font from font server */
+struct fs_font* fs_open(char *pattern)
+{
+ int nnames = 1;
+ int available,high,low,encoding,bpr;
+ char **fonts;
+ unsigned char *glyph;
+ Font dummy;
+ FSBitmapFormat format;
+ FSXCharInfo *charInfo;
+ struct fs_font *f = NULL;
+
+ if (NULL == svr) {
+ fprintf(stderr,"fs: not connected\n");
+ return NULL;
+ }
+
+ fonts = FSListFonts(svr, pattern, nnames, &available);
+ if (0 == available) {
+ fprintf(stderr,"fs: font not available [%s]\n",pattern);
+ goto out;
+ }
+ fprintf(stderr,"using x11 font \"%s\"\n",fonts[0]);
+
+ f = malloc(sizeof(*f));
+ memset(f,0,sizeof(*f));
+ f->font = FSOpenBitmapFont(svr, 0, 0, fonts[0], &dummy);
+ FSFreeFontNames(fonts);
+ if (0 == f->font)
+ goto out;
+
+ FSQueryXInfo(svr,f->font,&f->fontHeader, &f->propInfo,
+ &f->propOffsets, &f->propData);
+ format = BYTE_ORDER | BIT_ORDER | SCANLINE_UNIT | SCANLINE_PAD | EXTENTS;
+ FSQueryXExtents16(svr, f->font, True, (FSChar2b *) 0, 0, &f->extents);
+ FSQueryXBitmaps16(svr, f->font, format, True, (FSChar2b *) 0, 0,
+ &f->offsets, &f->glyphs);
+
+ f->maxenc = (f->fontHeader.char_range.max_char.high+1) << 8;
+ f->width = f->fontHeader.max_bounds.right - f->fontHeader.min_bounds.left;
+ f->height = f->fontHeader.max_bounds.ascent + f->fontHeader.max_bounds.descent;
+ f->eindex = malloc(f->maxenc * sizeof(FSXCharInfo*));
+ f->gindex = malloc(f->maxenc * sizeof(unsigned char*));
+ memset(f->eindex,0,f->maxenc * sizeof(FSXCharInfo*));
+ memset(f->gindex,0,f->maxenc * sizeof(unsigned char*));
+
+ glyph = f->glyphs;
+ charInfo = f->extents;
+ for (high = f->fontHeader.char_range.min_char.high;
+ high <= f->fontHeader.char_range.max_char.high;
+ high++) {
+ for (low = f->fontHeader.char_range.min_char.low;
+ low <= f->fontHeader.char_range.max_char.low;
+ low++) {
+ bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left),
+ SCANLINE_PAD_BYTES);
+ encoding = (high<<8) + low;
+#ifdef TTY
+ fprintf(stdout,"e=0x%x | w=%d l=%d r=%d | a=%d d=%d\n",
+ encoding,charInfo->width,charInfo->left,
+ charInfo->right,charInfo->ascent,charInfo->descent);
+#endif
+ if ((charInfo->width != 0) || (charInfo->right != charInfo->left)) {
+ f->gindex[encoding] = glyph;
+ f->eindex[encoding] = charInfo;
+#ifdef TTY
+ fs_render_tty(f->eindex[encoding],
+ f->gindex[encoding]);
+#endif
+ }
+ glyph += (charInfo->descent + charInfo->ascent) * bpr;
+ charInfo++;
+ }
+ }
+ return f;
+
+ out:
+ if (f)
+ fs_free(f);
+ return NULL;
+}
+#endif
+
+void fs_free(struct fs_font *f)
+{
+ if (f->gindex)
+ free(f->gindex);
+#if 0
+ if (f->extents)
+ FSFree((char *) f->extents);
+ if (f->offsets)
+ FSFree((char *) f->offsets);
+ if (f->propOffsets)
+ FSFree((char *) (f->propOffsets));
+ if (f->propData)
+ FSFree((char *) (f->propData));
+#endif
+#if 0 /* FIXME */
+ if (f->glyphs)
+ FSFree((char *) f->glyphs);
+#endif
+ free(f);
+}
+
+/* ------------------------------------------------------------------ */
+/* load console font file */
+
+static char *default_font[] = {
+ /* why the heck every f*cking distribution picks another
+ location for these fonts ??? */
+ "/usr/share/consolefonts/lat1-16.psf",
+ "/usr/share/consolefonts/lat1-16.psf.gz",
+ "/usr/share/consolefonts/lat1-16.psfu.gz",
+ "/usr/share/kbd/consolefonts/lat1-16.psf",
+ "/usr/share/kbd/consolefonts/lat1-16.psf.gz",
+ "/usr/share/kbd/consolefonts/lat1-16.psfu.gz",
+ "/usr/lib/kbd/consolefonts/lat1-16.psf",
+ "/usr/lib/kbd/consolefonts/lat1-16.psf.gz",
+ "/usr/lib/kbd/consolefonts/lat1-16.psfu.gz",
+ "/lib/kbd/consolefonts/lat1-16.psf",
+ "/lib/kbd/consolefonts/lat1-16.psf.gz",
+ "/lib/kbd/consolefonts/lat1-16.psfu.gz",
+ NULL
+};
+
+struct fs_font* fs_consolefont(char **filename)
+{
+ int i;
+ char *h,command[256];
+ struct fs_font *f = NULL;
+ FILE *fp;
+
+ if (NULL == filename)
+ filename = default_font;
+
+ for(i = 0; filename[i] != NULL; i++) {
+ if (-1 == access(filename[i],R_OK))
+ continue;
+ break;
+ }
+ if (NULL == filename[i]) {
+ fprintf(stderr,"can't find console font file\n");
+ return NULL;
+ }
+
+ h = filename[i]+strlen(filename[i])-3;
+ if (0 == strcmp(h,".gz")) {
+ sprintf(command,"zcat %s",filename[i]);
+ fp = popen(command,"r");
+ } else {
+ fp = fopen(filename[i], "r");
+ }
+ if (NULL == fp) {
+ fprintf(stderr,"can't open %s: %s\n",filename[i],strerror(errno));
+ return NULL;
+ }
+
+ if (fgetc(fp) != 0x36 ||
+ fgetc(fp) != 0x04) {
+ fprintf(stderr,"can't use font %s\n",filename[i]);
+ return NULL;
+ }
+ fprintf(stderr,"using linux console font \"%s\"\n",filename[i]);
+
+ f = malloc(sizeof(*f));
+ memset(f,0,sizeof(*f));
+
+ fgetc(fp);
+ f->maxenc = 256;
+ f->width = 8;
+ f->height = fgetc(fp);
+ f->fontHeader.min_bounds.left = 0;
+ f->fontHeader.max_bounds.right = f->width;
+ f->fontHeader.max_bounds.descent = 0;
+ f->fontHeader.max_bounds.ascent = f->height;
+
+ f->glyphs = malloc(f->height * 256);
+ f->extents = malloc(sizeof(FSXCharInfo)*256);
+ fread(f->glyphs, 256, f->height, fp);
+ fclose(fp);
+
+ f->eindex = malloc(sizeof(FSXCharInfo*) * 256);
+ f->gindex = malloc(sizeof(unsigned char*) * 256);
+ for (i = 0; i < 256; i++) {
+ f->eindex[i] = f->extents +i;
+ f->gindex[i] = f->glyphs +i * f->height;
+ f->eindex[i]->left = 0;
+ f->eindex[i]->right = 7;
+ f->eindex[i]->width = 8;
+ f->eindex[i]->descent = 0;
+ f->eindex[i]->ascent = f->height;
+ }
+ return f;
+}
+
+
+#ifdef TESTING
+/* ------------------------------------------------------------------ */
+/* for testing */
+
+int debug;
+
+/* list fonts */
+int fs_ls(char *pattern)
+{
+ int nnames = 16;
+ int available,i;
+ char **fonts;
+
+ if (NULL == svr) {
+ fprintf(stderr,"fs: not connected\n");
+ return -1;
+ }
+
+ fonts = FSListFonts(svr, pattern, nnames, &available);
+ while (nnames <= available) {
+ nnames *= 2;
+ FSFreeFontNames(fonts);
+ fonts = FSListFonts(svr, pattern, nnames, &available);
+ }
+ for (i = 0; i < available; i++) {
+ fprintf(stderr,"%s\n",fonts[i]);
+ }
+ FSFreeFontNames(fonts);
+ return 0;
+}
+
+void dump_charset(struct fs_font *f)
+{
+ unsigned char *pos;
+ int c,x,y;
+
+ x = 0, y = 0;
+ for (c = 0; c < f->maxenc; c++) {
+ if (NULL == f->eindex[c])
+ continue;
+ pos = fb_mem+fb_mem_offset;
+ pos += fb_fix.line_length * (y+f->height-f->eindex[c]->ascent);
+ pos += x*bpp;
+ fs_render_fb(pos,fb_fix.line_length,f->eindex[c],f->gindex[c]);
+ x += f->eindex[c]->right-f->eindex[c]->left+1;
+ if (x > fb_var.xres - f->width) {
+ x = 0;
+ y += f->height+1;
+ }
+ if (y > fb_var.yres - f->height)
+ break;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct fs_font *f = NULL;
+ unsigned char dummy[42];
+ int fd;
+
+ if (argc < 2) {
+ fprintf(stderr,"missing arg\n");
+ exit(1);
+ }
+
+ /* try font server */
+ if (-1 != fs_connect(NULL)) {
+ fs_ls(argv[1]);
+ f = fs_open(argv[1]);
+ if (NULL == f)
+ fprintf(stderr,"no such font\n");
+ }
+
+ /* try console font */
+ if (NULL == f)
+ f = fs_consolefont(NULL);
+ if (NULL == f)
+ exit(1);
+
+#ifdef TTY
+ exit(1);
+#endif
+
+ fd = fb_init(NULL, NULL, 0);
+ fb_cleanup_fork();
+ fb_switch_init();
+ fs_init_fb();
+
+ if (argc < 3) {
+ dump_charset(f);
+ } else {
+ fs_puts(f,0,0,argv[2]);
+ }
+ fgets(dummy,42,stdin);
+
+ return 0;
+}
+#endif
diff --git a/console/fs.h b/console/fs.h
new file mode 100644
index 0000000..2ac7228
--- /dev/null
+++ b/console/fs.h
@@ -0,0 +1,68 @@
+#ifndef X_DISPLAY_MISSING
+# include <FSlib.h>
+
+struct fs_font {
+ Font font;
+ FSXFontInfoHeader fontHeader;
+ FSPropInfo propInfo;
+ FSPropOffset *propOffsets;
+ unsigned char *propData;
+
+ FSXCharInfo *extents;
+ FSOffset *offsets;
+ unsigned char *glyphs;
+
+ int maxenc,width,height;
+ FSXCharInfo **eindex;
+ unsigned char **gindex;
+};
+
+#else
+
+typedef struct _FSXCharInfo {
+ short left;
+ short right;
+ short width;
+ short ascent;
+ short descent;
+ //unsigned short attributes;
+} FSXCharInfo;
+
+typedef struct _FSXFontInfoHeader {
+ //int flags;
+ //FSRange char_range;
+ //unsigned draw_direction;
+ //FSChar2b default_char;
+ FSXCharInfo min_bounds;
+ FSXCharInfo max_bounds;
+ short font_ascent;
+ short font_descent;
+} FSXFontInfoHeader;
+
+struct fs_font {
+ FSXFontInfoHeader fontHeader;
+ //unsigned char *propData;
+ FSXCharInfo *extents;
+ unsigned char *glyphs;
+ int maxenc,width,height;
+ FSXCharInfo **eindex;
+ unsigned char **gindex;
+};
+
+#endif
+
+/* ------------------------------------------------------------------ */
+
+int fs_init_fb(int white8);
+void fs_render_fb(unsigned char *ptr, int pitch,
+ FSXCharInfo *charInfo, unsigned char *data);
+int fs_puts(struct fs_font *f, int x, int y, unsigned char *str);
+int fs_textwidth(struct fs_font *f, unsigned char *str);
+void fs_render_tty(FSXCharInfo *charInfo, unsigned char *data);
+
+#ifndef X_DISPLAY_MISSING
+int fs_connect(char *servername);
+struct fs_font* fs_open(char *pattern);
+#endif
+struct fs_font* fs_consolefont(char **filename);
+void fs_free(struct fs_font *f);
diff --git a/console/ftp.c b/console/ftp.c
new file mode 100644
index 0000000..29c8f59
--- /dev/null
+++ b/console/ftp.c
@@ -0,0 +1,268 @@
+/*
+ * (c) 1998-2000 Gerd Knorr
+ *
+ * functions to handle ftp uploads using the ftp utility
+ *
+ */
+#include "config.h"
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include "ftp.h"
+
+/* ---------------------------------------------------------------------- */
+/* FTP stuff */
+
+int ftp_connected;
+int ftp_debug;
+
+static int ftp_pty, ftp_pid;
+static char tty_name[32];
+
+static
+int open_pty(void)
+{
+#ifdef HAVE_GETPT
+ int master;
+ char *slave;
+
+ if (-1 == (master = getpt()))
+ return -1;
+ if (-1 == grantpt(master) ||
+ -1 == unlockpt(master) ||
+ NULL == (slave = ptsname(master))) {
+ close(master);
+ return -1;
+ }
+ strcpy(tty_name,slave);
+ return master;
+#else
+ static char pty_name[32];
+ static char s1[] = "pqrs";
+ static char s2[] = "0123456789abcdef";
+
+ char *p1,*p2;
+ int pty;
+
+ for (p1 = s1; *p1; p1++) {
+ for (p2 = s2; *p2; p2++) {
+ sprintf(pty_name,"/dev/pty%c%c",*p1,*p2);
+ sprintf(tty_name,"/dev/tty%c%c",*p1,*p2);
+ if (-1 == access(tty_name,R_OK|W_OK))
+ continue;
+ if (-1 != (pty = open(pty_name,O_RDWR)))
+ return pty;
+ }
+ }
+ return -1;
+#endif
+}
+
+void
+ftp_init(int autologin, int passive)
+{
+ static char *doauto[] = { "ftp", NULL }; /* allow autologin via ~/.netrc */
+ static char *noauto[] = { "ftp", "-n", NULL };
+
+ if (-1 == (ftp_pty = open_pty())) {
+ fprintf(stderr,"can't grab pty\n");
+ exit(1);
+ }
+ switch (ftp_pid = fork()) {
+ case -1:
+ perror("fork");
+ exit(1);
+ case 0:
+ /* child */
+ close(ftp_pty);
+ close(0); close(1); close(2);
+ setsid();
+ open(tty_name,O_RDWR); dup(0); dup(0);
+
+ /* need english messages from ftp */
+ unsetenv("LANG");
+ unsetenv("LC_ALL");
+ unsetenv("LC_MESSAGES");
+
+ if (autologin)
+ execvp(doauto[0],doauto);
+ else
+ execvp(noauto[0],noauto);
+ perror("execvp");
+ exit(1);
+ default:
+ /* parent */
+ break;
+ }
+ ftp_recv();
+
+ /* initialisation */
+ if (passive) {
+ ftp_send(1,"pass");
+ ftp_recv();
+ }
+ return;
+}
+
+void
+ftp_send(int argc, ...)
+{
+ va_list ap;
+ char line[256],*arg;
+ int length,i;
+
+ va_start(ap,argc);
+ memset(line,0,256);
+ length = 0;
+ for (i = 0; i < argc; i++) {
+ if (i)
+ line[length++] = ' ';
+ arg = va_arg(ap,char*);
+ length += strlen(arg);
+ strcat(line,arg);
+ }
+ line[length++] = '\n';
+ va_end (ap);
+
+ if (ftp_debug)
+ fprintf(stderr,">> %s",line);
+ if (length != write(ftp_pty,line,length)) {
+ fprintf(stderr,"ftp: write error\n");
+ exit(1);
+ }
+}
+
+int
+ftp_recv()
+{
+ char line[512],*p,*n;
+ int length, done, status, ret=0;
+ fd_set set;
+
+ for (done = 0; !done;) {
+ FD_ZERO(&set);
+ FD_SET(ftp_pty,&set);
+ select(ftp_pty+1,&set,NULL,NULL,NULL);
+
+ switch (length = read(ftp_pty,line,511)) {
+ case -1:
+ perror("ftp: read error");
+ exit(1);
+ case 0:
+ fprintf(stderr,"ftp: EOF\n");
+ exit(1);
+ }
+ line[length] = 0;
+
+ for (p=line; p && *p; p = n) {
+ /* split into lines */
+ if (NULL != (n = strchr(p,'\n')) || NULL != (n = strchr(p,'\r')))
+ *(n++) = 0;
+ else
+ n = NULL;
+ if (ftp_debug)
+ fprintf(stderr,"<< %s\n",p);
+
+ /* prompt? */
+ if (NULL != strstr(p,"ftp>")) {
+ done = 1;
+ }
+
+ /* line dropped ? */
+ if (NULL != strstr(p,"closed connection")) {
+ fprintf(stderr,"ftp: lost connection\n");
+ ftp_connected = 0;
+ }
+ if (NULL != strstr(p,"Not connected")) {
+ if (ftp_connected)
+ fprintf(stderr,"ftp: lost connection\n");
+ ftp_connected = 0;
+ }
+
+ /* status? */
+ if (1 == sscanf(p,"%d",&status)) {
+ ret = status;
+ }
+ }
+ }
+ return ret;
+}
+
+void
+ftp_connect(char *host, char *user, char *pass, char *dir)
+{
+ int delay = 0, status;
+
+ for (;;) {
+ /* Wiederholungsversuche mit wachsendem Intervall, 10 min max. */
+ if (delay) {
+ fprintf(stderr,"ftp: connect failed, sleeping %d sec\n",delay);
+ sleep(delay);
+ delay *= 2;
+ if (delay > 600)
+ delay = 600;
+ } else {
+ delay = 5;
+ }
+
+ /* (re-) connect */
+ ftp_send(1,"close");
+ ftp_recv();
+ ftp_send(2,"open",host);
+ status = ftp_recv();
+ if (230 == status) {
+ fprintf(stderr,"ftp: connected to %s, login ok\n",host);
+ ftp_connected = 1;
+ goto login_ok;
+ }
+ if (220 != status && 530 != status)
+ continue;
+
+ fprintf(stderr,"ftp: connected to %s\n",host);
+ ftp_connected = 1;
+
+ /* login */
+ ftp_send(3,"user",user,pass);
+ if (230 != ftp_recv()) {
+ if (!ftp_connected)
+ continue;
+ fprintf(stderr,"ftp: login incorrect\n");
+ exit(1);
+ }
+
+ login_ok:
+ /* set directory */
+ ftp_send(2,"cd",dir);
+ if (250 != ftp_recv()) {
+ if (!ftp_connected)
+ continue;
+ fprintf(stderr,"ftp: cd %s failed\n",dir);
+ exit(1);
+ }
+
+ /* initialisation */
+ ftp_send(1,"bin");
+ ftp_recv();
+ ftp_send(1,"umask 022");
+ ftp_recv();
+
+ /* ok */
+ break;
+ }
+}
+
+void
+ftp_upload(char *local, char *remote, char *tmp)
+{
+ ftp_send(3,"put",local,tmp);
+ ftp_recv();
+ ftp_send(3,"rename",tmp,remote);
+ ftp_recv();
+}
diff --git a/console/ftp.h b/console/ftp.h
new file mode 100644
index 0000000..f11bfdb
--- /dev/null
+++ b/console/ftp.h
@@ -0,0 +1,8 @@
+extern int ftp_connected;
+extern int ftp_debug;
+
+void ftp_init(int autologin, int passive);
+void ftp_send(int argc, ...);
+int ftp_recv(void);
+void ftp_connect(char *host, char *user, char *pass, char *dir);
+void ftp_upload(char *local, char *remote, char *tmp);
diff --git a/console/matrox.c b/console/matrox.c
new file mode 100644
index 0000000..4e17f1a
--- /dev/null
+++ b/console/matrox.c
@@ -0,0 +1,232 @@
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <asm/page.h> /* PAGE_SIZE */
+#include <linux/fb.h>
+
+#include "byteswap.h"
+
+#include "fbtools.h"
+#include "matrox.h"
+
+/* ---------------------------------------------------------------------- */
+/* generic */
+
+void (*gfx_scaler_on)(int offscreen, int pitch, int width, int height,
+ int left, int right, int top, int bottom);
+void (*gfx_scaler_off)(void);
+
+static unsigned char *bmmio;
+static unsigned long *mmio;
+
+static void
+wrio4(int adr, unsigned long val)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ mmio[adr] = val;
+#else
+ mmio[adr] = SWAP4(val);
+#endif
+ /* usleep(10); */
+}
+
+/* ---------------------------------------------------------------------- */
+/* Matrox G200/G400 */
+
+#define BES_BASE 0x3d00
+#define BESA1ORG ((BES_BASE+0x00)>>2)
+#define BESA2ORG ((BES_BASE+0x04)>>2)
+#define BESB1ORG ((BES_BASE+0x08)>>2)
+#define BESB2ORG ((BES_BASE+0x0c)>>2)
+#define BESA1CORG ((BES_BASE+0x10)>>2)
+#define BESA2CORG ((BES_BASE+0x14)>>2)
+#define BESB1CORG ((BES_BASE+0x18)>>2)
+#define BESB2CORG ((BES_BASE+0x1c)>>2)
+#define BESCTL ((BES_BASE+0x20)>>2)
+#define BESPITCH ((BES_BASE+0x24)>>2)
+#define BESHCOORD ((BES_BASE+0x28)>>2)
+#define BESVCOORD ((BES_BASE+0x2c)>>2)
+#define BESHISCAL ((BES_BASE+0x30)>>2)
+#define BESVISCAL ((BES_BASE+0x34)>>2)
+#define BESHSRCST ((BES_BASE+0x38)>>2)
+#define BESHSRCEND ((BES_BASE+0x3c)>>2)
+
+#define BESV1WGHT ((BES_BASE+0x48)>>2)
+#define BESV2WGHT ((BES_BASE+0x4c)>>2)
+#define BESHSRCLST ((BES_BASE+0x50)>>2)
+#define BESV1SRCLST ((BES_BASE+0x54)>>2)
+#define BESV2SRCLST ((BES_BASE+0x58)>>2)
+#define BESGLOBCTL ((BES_BASE+0xc0)>>2)
+#define BESSTATUS ((BES_BASE+0xc4)>>2)
+
+#define PALWTADD 0x3c00
+#define X_DATAREG 0x3c0a
+#define XKEYOPMODE 0x51
+
+static void
+matrox_scaler_on(int offscreen, int pitch, int width, int height,
+ int left, int right, int top, int bottom)
+{
+ /* color keying (turn it off) */
+ bmmio[PALWTADD] = XKEYOPMODE;
+ bmmio[X_DATAREG] = 0;
+
+ /* src */
+ wrio4(BESA1ORG, offscreen);
+ wrio4(BESA2ORG, offscreen);
+ wrio4(BESB1ORG, offscreen);
+ wrio4(BESB2ORG, offscreen);
+ wrio4(BESPITCH, pitch/2);
+
+ /* dest */
+ wrio4(BESHCOORD, (left << 16) | right);
+ wrio4(BESVCOORD, (top << 16) | bottom);
+
+ /* scale horiz */
+ wrio4(BESHISCAL, width*65536/(right-left) & 0x001ffffc);
+ wrio4(BESHSRCST, 0 << 16);
+ wrio4(BESHSRCEND, width << 16);
+ wrio4(BESHSRCLST, (width-1) << 16);
+
+ /* scale vert */
+ wrio4(BESVISCAL, height*65536/(bottom-top) & 0x001ffffc);
+ wrio4(BESV1WGHT, 0);
+ wrio4(BESV2WGHT, 0);
+ wrio4(BESV1SRCLST, height-1);
+ wrio4(BESV2SRCLST, height-1);
+
+ /* turn on (enable, horizontal+vertical interpolation filters */
+ wrio4(BESCTL, (1 << 0) | (1 << 10) | (1 << 11));
+ wrio4(BESGLOBCTL, 0);
+}
+
+static void
+matrox_scaler_off(void)
+{
+ /* turn off */
+ wrio4(BESCTL, 0);
+}
+
+/* ---------------------------------------------------------------------- */
+/* ATI Mach64 VT+GT */
+
+#define OVERLAY_X_Y_START 0x0000
+#define OVERLAY_X_Y_END 0x0001
+#define OVERLAY_VIDEO_KEY_CLR 0x0002
+#define OVERLAY_VIDEO_KEY_MSK 0x0003
+#define OVERLAY_GRAPHICS_KEY_CLR 0x0004
+#define OVERLAY_GRAPHICS_KEY_MSK 0x0005
+#define OVERLAY_KEY_CNTL 0x0006
+
+#define OVERLAY_SCALE_INC 0x0008
+#define OVERLAY_SCALE_CNTL 0x0009
+#define SCALER_HEIGHT_WIDTH 0x000a
+#define SCALER_TEST 0x000b
+#define SCALER_BUF0_OFFSET 0x000d
+#define SCALER_BUF1_OFFSET 0x000e
+#define SCALER_BUF_PITCH 0x000f
+
+#define VIDEO_FORMAT 0x0012
+#define CAPTURE_CONFIG 0x0014
+
+#define SCALER_COLOR_CNTL 0x0054
+#define SCALER_H_COEFF0 0x0055
+#define SCALER_H_COEFF1 0x0056
+#define SCALER_H_COEFF2 0x0057
+#define SCALER_H_COEFF3 0x0058
+#define SCALER_H_COEFF4 0x0059
+
+/* does'nt work for all color depth yet... */
+static void
+mach64_scaler_on(int offscreen, int pitch, int width, int height,
+ int left, int right, int top, int bottom)
+{
+ int v,h;
+
+ v = (height << 12) / (bottom-top);
+ h = (width << 12) / (right-left);
+
+ wrio4(OVERLAY_SCALE_CNTL, 0);
+ wrio4(OVERLAY_SCALE_INC, (h << 16) | v);
+ wrio4(VIDEO_FORMAT, (12 << 16));
+ wrio4(SCALER_BUF0_OFFSET, offscreen);
+ wrio4(SCALER_BUF1_OFFSET, offscreen);
+ wrio4(SCALER_BUF_PITCH, pitch/2);
+ wrio4(SCALER_HEIGHT_WIDTH, (width << 16) | height);
+ wrio4(CAPTURE_CONFIG, 0);
+
+#if 1
+ /* from gatos, don't know what this does, have no specs :-( */
+ wrio4(SCALER_COLOR_CNTL, 0x00101000);
+ wrio4(SCALER_H_COEFF0, 0x00002000);
+ wrio4(SCALER_H_COEFF1, 0x0D06200D);
+ wrio4(SCALER_H_COEFF2, 0x0D0A1C0D);
+ wrio4(SCALER_H_COEFF3, 0x0C0E1A0C);
+ wrio4(SCALER_H_COEFF4, 0x0C14140C);
+#endif
+
+ wrio4(OVERLAY_X_Y_START, (left << 16) | top);
+ wrio4(OVERLAY_X_Y_END, ((right-1) << 16) | (bottom-1));
+ wrio4(OVERLAY_VIDEO_KEY_MSK, 0);
+ wrio4(OVERLAY_VIDEO_KEY_CLR, 0);
+ wrio4(OVERLAY_KEY_CNTL, 1);
+
+ wrio4(SCALER_TEST, 0); /* 2 == test mode */
+ wrio4(OVERLAY_SCALE_CNTL, (1<<31) | (1<<30));
+}
+
+static void
+mach64_scaler_off(void)
+{
+ /* off */
+ wrio4(OVERLAY_SCALE_CNTL, 0);
+}
+
+/* ---------------------------------------------------------------------- */
+/* generic */
+
+int
+gfx_init(int fd)
+{
+ int off;
+
+ switch (fb_fix.accel) {
+ case FB_ACCEL_MATROX_MGAG200:
+#ifdef FB_ACCEL_MATROX_MGAG400
+ case FB_ACCEL_MATROX_MGAG400:
+#endif
+ gfx_scaler_on = matrox_scaler_on;
+ gfx_scaler_off = matrox_scaler_off;
+ break;
+ case FB_ACCEL_ATI_MACH64VT:
+ case FB_ACCEL_ATI_MACH64GT:
+ gfx_scaler_on = mach64_scaler_on;
+ gfx_scaler_off = mach64_scaler_off;
+ break;
+ default:
+ return -1;
+ }
+ fb_var.accel_flags = 0;
+ if (0 != ioctl(fd,FBIOPUT_VSCREENINFO,&fb_var)) {
+ perror("FBIOPUT_VSCREENINFO");
+ return -1;
+ }
+ bmmio = mmap(NULL, fb_fix.mmio_len, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, fb_fix.smem_len);
+ if ((void*)-1 == bmmio) {
+ perror("mmap");
+ return -1;
+ }
+ off = (unsigned long)fb_fix.mmio_start -
+ ((unsigned long)fb_fix.mmio_start & ~(PAGE_SIZE-1));
+ bmmio += off;
+ mmio = (unsigned long*)bmmio;
+ return 0;
+}
diff --git a/console/matrox.h b/console/matrox.h
new file mode 100644
index 0000000..5323316
--- /dev/null
+++ b/console/matrox.h
@@ -0,0 +1,4 @@
+extern int gfx_init(int fd);
+extern void (*gfx_scaler_on)(int offscreen, int pitch, int width, int height,
+ int left, int right, int top, int bottom);
+extern void (*gfx_scaler_off)(void);
diff --git a/console/radio.c b/console/radio.c
new file mode 100644
index 0000000..1a66605
--- /dev/null
+++ b/console/radio.c
@@ -0,0 +1,654 @@
+/*
+ * radio.c - (c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * test tool for bttv + WinTV/Radio
+ *
+ */
+
+/* Changes:
+ * 20 Jun 99 - Juli Merino (JMMV) <jmmv@mail.com> - Added some features:
+ * visual menu, manual 'go to' function, negative symbol and a
+ * good interface. See code for more details.
+ * 30 Aug 2001 - Gunther Mayer <Gunther.Mayer@t-online.de>
+ * Scan for Stations, ad-hoc algorithm for signal strength
+ * analysis. My Temic 4009FR5 finds all 19 stations here,
+ * a Samsung TPI8PSB02P misses two stations below 90MHz,
+ * which are received fine, but the tuner doesn't indicate
+ * signal strength.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <curses.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <linux/videodev.h>
+
+/* JMMV: WINDOWS for radio */
+int ncurses = 0;
+int debug = 0;
+char *device = "/dev/radio";
+WINDOW *wfreq, *woptions, *wstations, *wcommand;
+
+/* Determine and return the appropriate frequency multiplier for
+ the first tuner on the open video device with handle FD. */
+static int get_freq_fact(int fd)
+{
+ struct video_tuner tuner;
+
+ tuner.tuner = 0;
+ if (ioctl (fd, VIDIOCGTUNER, &tuner) < 0)
+ return 16;
+ if ((tuner.flags & VIDEO_TUNER_LOW) == 0)
+ return 16;
+ return 16000;
+}
+
+static int
+radio_setfreq(int fd, float freq)
+{
+ int ifreq = (freq+1.0/32)*get_freq_fact(fd);
+ return ioctl(fd, VIDIOCSFREQ, &ifreq);
+}
+
+static void
+radio_unmute(int fd)
+{
+ struct video_audio vid_aud;
+
+ if (ioctl(fd, VIDIOCGAUDIO, &vid_aud))
+ perror("VIDIOCGAUDIO");
+ if (vid_aud.volume == 0)
+ vid_aud.volume = 65535;
+ vid_aud.flags &= ~VIDEO_AUDIO_MUTE;
+ if (ioctl(fd, VIDIOCSAUDIO, &vid_aud))
+ perror("VIDIOCSAUDIO");
+}
+
+static void
+radio_mute(int fd)
+{
+ struct video_audio vid_aud;
+
+ if (ioctl(fd, VIDIOCGAUDIO, &vid_aud))
+ perror("VIDIOCGAUDIO");
+ vid_aud.flags |= VIDEO_AUDIO_MUTE;
+ if (ioctl(fd, VIDIOCSAUDIO, &vid_aud))
+ perror("VIDIOCSAUDIO");
+}
+
+static void
+radio_getstereo(int fd)
+{
+ struct video_audio va;
+ va.mode=-1;
+
+ if (ioctl (fd, VIDIOCGAUDIO, &va) < 0)
+ mvwprintw(wfreq,2,1," ");
+ mvwprintw(wfreq,2,1,"%s", va.mode == VIDEO_SOUND_STEREO ?
+ "STEREO":" MONO ");
+}
+
+static int
+radio_getsignal(int fd)
+{
+ struct video_tuner vt;
+ int i,signal;
+
+ memset(&vt,0,sizeof(vt));
+ ioctl (fd, VIDIOCGTUNER, &vt);
+ signal=vt.signal>>13;
+
+ for(i=0;i<8;i++)
+ mvwprintw(wfreq,3,i+1,"%s", signal>i ? "*":" ");
+ return signal;
+}
+
+static int
+select_wait(int sec)
+{
+ struct timeval tv;
+ fd_set se;
+
+ FD_ZERO(&se);
+ FD_SET(0,&se);
+ tv.tv_sec = sec;
+ tv.tv_usec = 0;
+ return select(1,&se,NULL,NULL,&tv);
+}
+
+/* ---------------------------------------------------------------------- */
+
+char *digit[3][10] = {
+ { " _ ", " ", " _ ", " _ ", " ", " _ ", " _ ", " _ ", " _ ", " _ " },
+ { "| |", " | ", " _|", " _|", "|_|", "|_ ", "|_ ", " |", "|_|", "|_|" },
+ { "|_|", " | ", "|_ ", " _|", " |", " _|", "|_|", " |", "|_|", " _|" }
+};
+
+static void print_freq(float freq)
+{
+ int x,y,i;
+ char text[10];
+ sprintf(text,"%6.2f",freq);
+ for (i = 0, x = 8; i < 6; i++, x+=4) {
+ if (text[i] >= '0' && text[i] <= '9') {
+ for (y = 0; y < 3; y++)
+ mvwprintw(wfreq,y+1,x,"%s",digit[y][text[i]-'0']);
+ } else if (text[i] == '.') {
+ mvwprintw(wfreq,3,x,".");
+ x -= 2;
+ } else {
+ for (y = 0; y < 3; y++)
+ mvwprintw(wfreq,y+1,x," ");
+ }
+ }
+ wrefresh(wfreq);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int fkeys[8];
+
+int freqs[99];
+char *labels[99];
+int stations;
+
+static void
+read_kradioconfig(void)
+{
+ char name[80],file[256],n;
+ int ifreq;
+ FILE *fp;
+
+ sprintf(file,"%.225s/.kde/share/config/kradiorc",getenv("HOME"));
+ if (NULL == (fp = fopen(file,"r"))) {
+ sprintf(file,"%.225s/.radio",getenv("HOME"));
+ if (NULL == (fp = fopen(file,"r")))
+ return;
+ }
+ while (NULL != fgets(file,255,fp)) {
+ if (2 == sscanf(file,"%c=%d",&n,&ifreq) && n >= '1' && n <= '8') {
+ fkeys[n - '1'] = ifreq;
+ } else if (2 == sscanf(file,"%d=%30[^\n]",&ifreq,name) && stations < 99) {
+ freqs[stations] = ifreq;
+ labels[stations] = strdup(name);
+ stations++;
+ }
+ }
+}
+
+static char*
+find_label(int ifreq)
+{
+ int i;
+
+ for (i = 0; i < stations; i++) {
+ if (ifreq == freqs[i])
+ return labels[i];
+ }
+ return NULL;
+}
+
+static char *
+make_label(int ifreq)
+{
+ static char text[20],*l;
+
+ if (NULL != (l = find_label(ifreq)))
+ return l;
+ sprintf(text,"%6.2f MHz",(float)ifreq/1000000);
+ return text;
+}
+
+/* ---------------------------------------------------------------------- */
+/* autoscan */
+
+float g[411],baseline;
+int astation[100],max_astation=0,current_astation=-1;
+int write_config;
+
+static void
+foundone(int m)
+{
+ int i;
+
+ for (i=0; i<100 && astation[i]; i++) {
+ if(abs(astation[i]-m) <5 ) // 20 kHz width
+ break;
+ }
+ if (g[m] > g[astation[i]]) { // select bigger signal
+ astation[i]=m;
+ max_astation=i;
+ fprintf(stderr,"Station %2d: %6.2f MHz - %.2f\n",i,87.5+m*0.05,g[m]);
+ if (write_config)
+ printf("%d0000=scan-%d\n",(int)((87.5+m*0.05)*100),i);
+ }
+}
+
+static void
+maxi(int m)
+{
+ int i,l,r;
+ float halbwert;
+
+ if (debug)
+ fprintf(stderr,"maxi i %d %f %f\n",m,87.5+m*0.05,g[m]);
+ if(g[m]<baseline)
+ return;
+ halbwert=(g[m]-baseline)/2+baseline;
+
+ for(i=m;i>0;i--)
+ if(g[i]< halbwert)
+ break;
+ l=i;
+ if (debug)
+ fprintf(stderr,"Links i %d %f %f\n",i,87.5+i*0.05,g[i]);
+
+ for(i=m;i<411;i++)
+ if(g[i]< halbwert)
+ break;
+ if (debug)
+ fprintf(stderr,"Rechts i %d %f %f\n",i,87.5+i*0.05,g[i]);
+ r=i;
+ m=(l+r)/2;
+ if (debug)
+ fprintf(stderr,"Mitte %d %f %f\n",m,87.5+m*0.05,g[m]);
+ foundone(m);
+}
+
+static void
+findmax(void)
+{
+ int i;
+
+ for(i=0;i<411;i++){
+ if(g[i+1]<g[i])
+ maxi(i);
+ }
+}
+
+// find the baseline for this tuners signal strength
+static float
+get_baseline(float ming, float maxg)
+{
+ int unt,i,nullfound=0;
+ float nullinie=0,u;
+
+ if (debug)
+ fprintf(stderr,"get_baseline: min=%f max=%f\n",ming,maxg);
+ for(u=ming;u<maxg; u+=0.1) {
+ unt=0;
+ for(i=0;i<411;i++)
+ if (g[i]<u) {
+ unt++;
+ }
+ if(unt>300 && !nullfound) {
+ fprintf(stderr,"baseline at %.2f\n",u);
+ nullinie=u;
+ nullfound=1;
+ }
+ if (debug)
+ fprintf(stderr,"%f %d\n",u,unt);
+ }
+ return nullinie;
+}
+
+static void
+findstations(void)
+{
+ float maxg=0,ming=8;
+ int i;
+
+ for(i=0;i<411;i++) {
+ if(g[i]<ming) ming=g[i];
+ if(g[i]>maxg) maxg=g[i];
+ }
+
+ if (write_config)
+ printf("[Stations]\n");
+ baseline=get_baseline(ming,maxg);
+ findmax();
+}
+
+static void do_scan(int fd,int scan)
+{
+ FILE * fmap=NULL;
+ float freq,s;
+ int i,j;
+
+ if(scan > 1)
+ fmap=fopen("radio.fmmap","w");
+ for(i=0;i<411;i++) {
+ freq = 87.50+i*0.05;
+ s = 0;
+ radio_setfreq(fd,freq);
+ usleep(10000); /* give the tuner some time to settle */
+ for(j=1;j<5;j++) {
+ s+=radio_getsignal(fd);
+ radio_getstereo(fd);
+ usleep(1000);
+ }
+ s=s/5; // average
+ g[i]=s;
+ if (scan > 1)
+ fprintf(fmap,"%f %f\n", freq,s);
+ fprintf(stderr,"scanning: %6.2f MHz - %.2f\r", freq,s);
+ }
+ fprintf(stderr,"%40s\r","");
+ if (scan > 1)
+ fclose(fmap);
+ findstations();
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void
+usage(FILE *out)
+{
+ fprintf(out,
+ "radio -- interactive ncurses radio application\n"
+ "usage:\n"
+ " radio [ options ]\n"
+ "\n"
+ "options:\n"
+ " -h print this text\n"
+ " -d enable debug output\n"
+ " -m mute radio\n"
+ " -f freq tune given frequency (also unmutes)\n"
+ " -c dev use given device [default: %s]\n"
+ " -s scan\n"
+ " -S scan + write radio.fmmap\n"
+ " -i scan, write initial ~/.radio config file to\n"
+ " stdout and quit\n"
+ " -q quit. Useful with other options to control the\n"
+ " radio device without entering interactive mode,\n"
+ " i.e. \"radio -qf 91.4\"\n"
+ "\n"
+ "(c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>\n"
+ "interface by Juli Merino <jmmv@mail.com>\n"
+ "channel scan by Gunther Mayer <Gunther.Mayer@t-online.de>\n",
+ device);
+}
+
+int
+main(int argc, char *argv[])
+{
+ /* JMMV: lastfreq set to 1 to start radio at 0.0 */
+ int fd,key=0,done,i,ifreq = 0,lastfreq = 1, mute=1;
+ char *name;
+ /* Variables set by JMMV */
+ float ffreq, newfreq = 0;
+ int stset = 0, c;
+ int quit=0, scan=0, arg_mute=0;
+
+ /* parse args */
+ for (;;) {
+ c = getopt(argc, argv, "mhiqdsSf:c:");
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'm':
+ arg_mute = 1;
+ break;
+ case 'q':
+ quit = 1;
+ break;
+ case 'd':
+ debug= 1;
+ break;
+ case 'S':
+ scan = 2;
+ break;
+ case 's':
+ scan = 1;
+ break;
+ case 'i':
+ write_config = 1;
+ scan = 1;
+ quit = 1;
+ break;
+ case 'f':
+ if (1 == sscanf(optarg,"%f",&ffreq)) {
+ ifreq = (int)(ffreq * 1000000);
+ ifreq += 25000;
+ ifreq -= ifreq % 50000;
+ }
+ break;
+ case 'c':
+ device = optarg;
+ break;
+ case 'h':
+ usage(stdout);
+ exit(0);
+ default:
+ usage(stderr);
+ exit(1);
+ }
+ }
+
+ if (-1 == (fd = open(device, O_RDONLY))) {
+ fprintf(stderr,"open %s: %s\n",device,strerror(errno));
+ exit(1);
+ }
+
+ /* non-interactive stuff */
+ if (scan) {
+ do_scan(fd,scan);
+ if (!ifreq && max_astation) {
+ current_astation = 0;
+ ifreq=87500000+astation[current_astation]*50000;
+ }
+ }
+ if (ifreq) {
+ ffreq = (float)ifreq / 1000000;
+ fprintf(stderr,"tuned %.2f MHz\n",ffreq);
+ radio_setfreq(fd,ffreq);
+ radio_unmute(fd);
+ }
+ if (arg_mute) {
+ fprintf(stderr,"muted radio\n");
+ radio_mute(fd);
+ }
+ if (quit)
+ exit(0);
+
+ read_kradioconfig();
+ if (!ifreq && fkeys[0])
+ ifreq = fkeys[0];
+
+ /* enter interactive mode -- init ncurses */
+ ncurses=1;
+ initscr();
+ start_color();
+ cbreak();
+ noecho();
+ keypad(stdscr,1);
+ curs_set(0);
+
+ /* JMMV: Set colors and windows */
+ /* XXX: Color definitions are wrong! BLUE is RED, CYAN is YELLOW and
+ * viceversa */
+ init_pair(1,COLOR_WHITE,COLOR_BLACK);
+ init_pair(2,COLOR_CYAN,COLOR_BLUE);
+ init_pair(3,COLOR_WHITE,COLOR_RED);
+ bkgd(A_BOLD | COLOR_PAIR(1));
+ refresh();
+
+ wfreq = newwin(7,32,1,2);
+ wbkgd(wfreq,A_BOLD | COLOR_PAIR(2));
+ werase(wfreq);
+ box(wfreq, 0, 0);
+ mvwprintw(wfreq, 0, 1, " Tuner ");
+
+ woptions = newwin(7,COLS-38,1,36);
+ wbkgd(woptions,A_BOLD | COLOR_PAIR(3));
+ werase(woptions);
+ box(woptions, 0, 0);
+ mvwprintw(woptions, 0, 1, " Main menu ");
+
+ wstations = newwin(LINES-14,COLS-4,9,2);
+ wbkgd(wstations,A_BOLD | COLOR_PAIR(3));
+ werase(wstations);
+ box(wstations, 0, 0);
+ mvwprintw(wstations, 0, 1, " Preset stations ");
+
+ wcommand = newwin(3,COLS-4,LINES-4,2);
+ wbkgd(wcommand,A_BOLD | COLOR_PAIR(3));
+ werase(wcommand);
+ box(wcommand,0,0);
+ mvwprintw(wcommand, 0, 1, " Command window ");
+ wrefresh(wcommand);
+
+ /* JMMV: Added key information and windows division */
+ mvwprintw(woptions, 1, 1, "Up/Down - inc/dec frequency");
+ mvwprintw(woptions, 2, 1, "PgUp/PgDown - next/prev station");
+ mvwprintw(woptions, 3, 1, "g - go to frequency...");
+ mvwprintw(woptions, 4, 1, "x - exit");
+ mvwprintw(woptions, 5, 1, "ESC, q, e - mute and exit");
+ wrefresh(woptions);
+ for (i = 0, c = 1; i < 8; i++) {
+ if (fkeys[i]) {
+ mvwprintw(wstations,c,2,"F%d: %s",i+1,make_label(fkeys[i]));
+ c++;
+ stset = 1;
+ }
+ }
+ if (!stset)
+ mvwprintw(wstations,1,1,"[none]");
+ wrefresh(wstations);
+
+ radio_unmute(fd);
+ for (done = 0; done == 0;) {
+ if (ifreq != lastfreq) {
+ lastfreq = ifreq;
+ ffreq = (float)ifreq / 1000000;
+ radio_setfreq(fd,ffreq);
+ print_freq(ffreq);
+ if (NULL != (name = find_label(ifreq)))
+ mvwprintw(wfreq,5,2,"%-20.20s",name);
+ else
+ mvwprintw(wfreq,5,2,"%-20.20s","");
+ }
+ radio_getstereo(fd);
+ radio_getsignal(fd);
+ wrefresh(wfreq);
+ wrefresh(wcommand);
+
+ if (0 == select_wait(1)) {
+ mvwprintw(wcommand,1,1,"%50.50s","");
+ wrefresh(wcommand);
+ continue;
+ }
+ key = getch();
+ switch (key) {
+ case EOF:
+ case 'x':
+ case 'X':
+ mute = 0;
+ /* fall throuth */
+ case 27: /* ESC */
+ case 'q':
+ case 'Q':
+ case 'e':
+ case 'E':
+ done = 1;
+ break;
+ case 'g':
+ case 'G':
+ /* JMMV: Added 'go to frequency' function */
+ mvwprintw(wcommand,1,2,"GO: Enter frequency: ");
+ curs_set(1);
+ echo();
+ wrefresh(wcommand);
+ wscanw(wcommand,"%f",&newfreq);
+ noecho();
+ curs_set(0);
+ wrefresh(wcommand);
+ ifreq = newfreq * 1000000;
+ break;
+ case KEY_UP:
+ ifreq += 50000;
+ if (ifreq > 108000000)
+ ifreq = 87500000;
+ mvwprintw(wcommand, 1, 2, "Increment frequency");
+ break;
+ case KEY_DOWN:
+ ifreq -= 50000;
+ if (ifreq < 87500000)
+ ifreq = 108000000;
+ mvwprintw(wcommand, 1, 2, "Decrease frequency");
+ break;
+ case KEY_PPAGE:
+ case KEY_NPAGE:
+ case ' ':
+ if (max_astation) {
+ current_astation += (key == KEY_NPAGE) ? -1 : 1;
+ if(current_astation<0)
+ current_astation=max_astation;
+ if(current_astation>max_astation)
+ current_astation=0;
+ ifreq=87500000+astation[current_astation]*50000;
+ } else {
+ for (i = 0; i < stations; i++) {
+ if (ifreq == freqs[i])
+ break;
+ }
+ if (i != stations) {
+ i += (key == KEY_NPAGE) ? -1 : 1;
+ if (i < 0 || i >= stations)
+ i = 0;
+ ifreq = freqs[i];
+ }
+ }
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case KEY_F(1):
+ case KEY_F(2):
+ case KEY_F(3):
+ case KEY_F(4):
+ case KEY_F(5):
+ case KEY_F(6):
+ case KEY_F(7):
+ case KEY_F(8):
+ i = (key >= '1' && key <= '8') ? key - '1' : key - KEY_F(1);
+ if (fkeys[i]) {
+ ifreq = fkeys[i];
+ mvwprintw(wcommand, 1, 2, "Go to preset station %d", i+1);
+ }
+ break;
+ case 'L' & 0x1f: /* Ctrl-L */
+ redrawwin(stdscr);
+ redrawwin(wfreq);
+ redrawwin(woptions);
+ redrawwin(wstations);
+ redrawwin(wcommand);
+ wrefresh(stdscr);
+ wrefresh(wfreq);
+ wrefresh(woptions);
+ wrefresh(wstations);
+ wrefresh(wcommand);
+ break;
+ }
+ }
+ if (mute)
+ radio_mute(fd);
+ close(fd);
+
+ bkgd(0);
+ clear();
+ refresh();
+ endwin();
+ return 0;
+}
diff --git a/console/record.c b/console/record.c
new file mode 100644
index 0000000..c5a686b
--- /dev/null
+++ b/console/record.c
@@ -0,0 +1,806 @@
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <curses.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#ifdef HAVE_SOUNDCARD_H
+# include <soundcard.h>
+#endif
+#ifdef HAVE_SYS_SOUNDCARD_H
+# include <sys/soundcard.h>
+#endif
+
+/* -------------------------------------------------------------------- */
+
+static void
+tty_raw(void)
+{
+ initscr();
+ cbreak();
+ noecho();
+ keypad(stdscr,1);
+ refresh();
+}
+
+static void
+tty_restore(void)
+{
+ endwin();
+}
+
+/* -------------------------------------------------------------------- */
+
+static int sound_fd;
+static int sound_blksize;
+static short *sound_buffer;
+static int maxl,maxr;
+static int secl,secr;
+static int *histl,*histr,histn,histi;
+static float peak_seconds = 1.5;
+static char *audio_dev = "/dev/dsp";
+
+static int
+sound_open(int rate)
+{
+ int frag,afmt,channels,trigger,srate;
+
+ if (-1 == (sound_fd = open(audio_dev, O_RDONLY))) {
+ fprintf(stderr,"open %s: %s",audio_dev,strerror(errno));
+ exit(1);
+ }
+
+ frag = 0x7fff000d; /* 8k */
+ if (-1 == ioctl(sound_fd, SNDCTL_DSP_SETFRAGMENT, &frag))
+ perror("ioctl SNDCTL_DSP_SETFRAGMENT");
+
+ /* format */
+ afmt = AFMT_S16_LE;
+ if (-1 == ioctl(sound_fd, SNDCTL_DSP_SETFMT, &afmt)) {
+ perror("ioctl SNDCTL_DSP_SETFMT");
+ exit(1);
+ }
+ if (afmt != AFMT_S16_LE) {
+ fprintf(stderr,"can't set sound format to 16 bit (le)\n");
+ exit(1);
+ }
+
+ /* channels */
+ channels = 2;
+ if (-1 == ioctl(sound_fd, SNDCTL_DSP_CHANNELS, &channels)) {
+ perror("ioctl SNDCTL_DSP_CHANNELS");
+ exit(1);
+ }
+ if (channels != 2) {
+ fprintf(stderr,"can't record in stereo\n");
+ exit(1);
+ }
+
+ /* rate */
+ srate = rate;
+ if (-1 == ioctl(sound_fd, SNDCTL_DSP_SPEED, &srate)) {
+ perror("ioctl SNDCTL_DSP_SPEED");
+ exit(1);
+ }
+ /* accept +/- 1% */
+ if (srate < rate * 99 / 100 ||
+ srate > rate * 101 / 100) {
+ fprintf(stderr,"can't set sample rate to %d (got %d)\n",
+ rate,srate);
+ exit(1);
+ }
+
+ /* get block size */
+ if (-1 == ioctl(sound_fd, SNDCTL_DSP_GETBLKSIZE, &sound_blksize)) {
+ perror("ioctl SNDCTL_DSP_GETBLKSIZE");
+ exit(1);
+ }
+ if (0 == sound_blksize)
+ sound_blksize = 4096;
+ sound_buffer = malloc(sound_blksize);
+
+ /* peak level history */
+ histn = peak_seconds * rate * 4 / sound_blksize;
+ histl = malloc(histn * sizeof(int));
+ histr = malloc(histn * sizeof(int));
+ memset(histl,0,histn * sizeof(int));
+ memset(histr,0,histn * sizeof(int));
+
+ /* trigger record */
+ trigger = ~PCM_ENABLE_INPUT;
+ ioctl(sound_fd,SNDCTL_DSP_SETTRIGGER,&trigger);
+ trigger = PCM_ENABLE_INPUT;
+ ioctl(sound_fd,SNDCTL_DSP_SETTRIGGER,&trigger);
+
+ return sound_fd;
+}
+
+static int
+sound_read(void)
+{
+ int i,rc,have;
+ short *v;
+
+ /* read */
+ for (have = 0;have < sound_blksize;) {
+ rc = read(sound_fd,sound_buffer+have,sound_blksize-have);
+ switch (rc) {
+ case -1:
+ if (EINTR != errno) {
+ perror("read sound");
+ exit(1);
+ }
+ break;
+ case 0:
+ fprintf(stderr,"Huh? got 0 bytes from sound device?\n");
+ exit(1);
+ default:
+ have += rc;
+
+ }
+ }
+
+ /* look for peaks */
+ maxl = 0;
+ maxr = 0;
+ for (i = sound_blksize>>2, v=sound_buffer; i > 0; i--) {
+ if (abs(*v) > maxl)
+ maxl = abs(*v);
+ v++;
+ if (abs(*v) > maxr)
+ maxr = abs(*v);
+ v++;
+ }
+
+ /* max for the last second */
+ histl[histi] = maxl;
+ histr[histi] = maxr;
+ histi++;
+ if (histn == histi)
+ histi = 0;
+
+ for (secl = 0, secr = 0, i = 0; i < histn; i++) {
+ if (secl < histl[i])
+ secl = histl[i];
+ if (secr < histr[i])
+ secr = histr[i];
+ }
+ return 0;
+}
+
+/* -------------------------------------------------------------------- */
+
+char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
+char *config_names[SOUND_MIXER_NRDEVICES][4];
+
+static int mix;
+static int dev = -1;
+static int volume;
+static char *mixer_dev = "/dev/mixer";
+
+static int
+mixer_open(char *filename, char *device)
+{
+ int i, devmask;
+
+ if (-1 == (mix = open(filename,O_RDONLY))) {
+ fprintf(stderr,"open %s: %s",filename,strerror(errno));
+ exit(1);
+ }
+ if (-1 == ioctl(mix,MIXER_READ(SOUND_MIXER_DEVMASK),&devmask)) {
+ perror("mixer read devmask");
+ exit(1);
+ }
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+ if ((1<<i) & devmask && strcasecmp(names[i],device) == 0) {
+ if (-1 == ioctl(mix,MIXER_READ(i),&volume)) {
+ perror("mixer read volume");
+ exit(1);
+ } else {
+ dev = i;
+ }
+ }
+ }
+ if (-1 == dev) {
+ fprintf(stderr,"mixer: havn't found device '%s'\nmixer: available: ",device);
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if ((1<<i) & devmask)
+ fprintf(stderr," '%s'",names[i]);
+ fprintf(stderr,"\n");
+ exit(1);
+ }
+ return (-1 != dev) ? 0 : -1;
+}
+
+static void
+mixer_close(void)
+{
+ close(mix);
+ dev = -1;
+}
+
+static int
+mixer_get_volume(void)
+{
+ return (-1 == dev) ? -1 : (volume & 0x7f);
+}
+
+static int
+mixer_set_volume(int val)
+{
+ if (-1 == dev)
+ return -1;
+ val &= 0x7f;
+ volume = val | (val << 8);;
+ if (-1 == ioctl(mix,MIXER_WRITE(dev),&volume)) {
+ perror("mixer write volume");
+ return -1;
+ }
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* *.wav I/O stolen from cdda2wav */
+
+/* Copyright (C) by Heiko Eissfeldt */
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+typedef unsigned long FOURCC; /* a four character code */
+
+/* flags for 'wFormatTag' field of WAVEFORMAT */
+#define WAVE_FORMAT_PCM 1
+
+/* MMIO macros */
+#define mmioFOURCC(ch0, ch1, ch2, ch3) \
+ ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
+ ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
+
+#define FOURCC_RIFF mmioFOURCC ('R', 'I', 'F', 'F')
+#define FOURCC_LIST mmioFOURCC ('L', 'I', 'S', 'T')
+#define FOURCC_WAVE mmioFOURCC ('W', 'A', 'V', 'E')
+#define FOURCC_FMT mmioFOURCC ('f', 'm', 't', ' ')
+#define FOURCC_DATA mmioFOURCC ('d', 'a', 't', 'a')
+
+typedef struct CHUNKHDR {
+ FOURCC ckid; /* chunk ID */
+ DWORD dwSize; /* chunk size */
+} CHUNKHDR;
+
+/* simplified Header for standard WAV files */
+typedef struct WAVEHDR {
+ CHUNKHDR chkRiff;
+ FOURCC fccWave;
+ CHUNKHDR chkFmt;
+ WORD wFormatTag; /* format type */
+ WORD nChannels; /* number of channels (i.e. mono, stereo, etc.) */
+ DWORD nSamplesPerSec; /* sample rate */
+ DWORD nAvgBytesPerSec; /* for buffer estimation */
+ WORD nBlockAlign; /* block size of data */
+ WORD wBitsPerSample;
+ CHUNKHDR chkData;
+} WAVEHDR;
+
+#define IS_STD_WAV_HEADER(waveHdr) ( \
+ waveHdr.chkRiff.ckid == FOURCC_RIFF && \
+ waveHdr.fccWave == FOURCC_WAVE && \
+ waveHdr.chkFmt.ckid == FOURCC_FMT && \
+ waveHdr.chkData.ckid == FOURCC_DATA && \
+ waveHdr.wFormatTag == WAVE_FORMAT_PCM)
+
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+#define le32_to_cpu(x) (x)
+#define le16_to_cpu(x) (x)
+
+/* -------------------------------------------------------------------- */
+
+static WAVEHDR fileheader;
+static off_t wav_size;
+static off_t done_size;
+
+static void
+wav_init_header(int rate)
+{
+ /* stolen from cdda2wav */
+ int nBitsPerSample = 16;
+ int channels = 2;
+
+ unsigned long nBlockAlign = channels * ((nBitsPerSample + 7) / 8);
+ unsigned long nAvgBytesPerSec = nBlockAlign * rate;
+ unsigned long temp = /* data length */ 0 +
+ sizeof(WAVEHDR) - sizeof(CHUNKHDR);
+
+ fileheader.chkRiff.ckid = cpu_to_le32(FOURCC_RIFF);
+ fileheader.fccWave = cpu_to_le32(FOURCC_WAVE);
+ fileheader.chkFmt.ckid = cpu_to_le32(FOURCC_FMT);
+ fileheader.chkFmt.dwSize = cpu_to_le32(16);
+ fileheader.wFormatTag = cpu_to_le16(WAVE_FORMAT_PCM);
+ fileheader.nChannels = cpu_to_le16(channels);
+ fileheader.nSamplesPerSec = cpu_to_le32(rate);
+ fileheader.nAvgBytesPerSec = cpu_to_le32(nAvgBytesPerSec);
+ fileheader.nBlockAlign = cpu_to_le16(nBlockAlign);
+ fileheader.wBitsPerSample = cpu_to_le16(nBitsPerSample);
+ fileheader.chkData.ckid = cpu_to_le32(FOURCC_DATA);
+ fileheader.chkRiff.dwSize = cpu_to_le32(temp);
+ fileheader.chkData.dwSize = cpu_to_le32(0 /* data length */);
+}
+
+static void
+wav_start_write(int fd,int rate)
+{
+ wav_init_header(rate);
+ lseek(fd,0,SEEK_SET);
+ write(fd,&fileheader,sizeof(WAVEHDR));
+ wav_size = 0;
+}
+
+static int
+wav_write_audio(int fd, void *data, int len)
+{
+ int rc;
+
+ rc = write(fd,data,len);
+ if (len == rc) {
+ wav_size += len;
+ return 0;
+ } else
+ return -1;
+}
+
+static void
+wav_stop_write(int fd)
+{
+ unsigned long temp = wav_size + sizeof(WAVEHDR) - sizeof(CHUNKHDR);
+
+ fileheader.chkRiff.dwSize = cpu_to_le32(temp);
+ fileheader.chkData.dwSize = cpu_to_le32(wav_size);
+ lseek(fd,0,SEEK_SET);
+ write(fd,&fileheader,sizeof(WAVEHDR));
+ done_size += wav_size;
+}
+
+/* -------------------------------------------------------------------- */
+
+static char full[] =
+"##################################################"
+"##################################################"
+"##################################################"
+"##################################################";
+
+static char empty[] =
+"--------------------------------------------------"
+"--------------------------------------------------"
+"--------------------------------------------------"
+"--------------------------------------------------";
+
+static char blank[] =
+" "
+" "
+" "
+" ";
+
+static void
+print_bar(int line, char *name, int val1, int val2, int max)
+{
+ int total,len;
+
+ total = COLS-16;
+ len = val1*total/max;
+
+ mvprintw(line,0,"%-6s: %5d ",name,(val2 != -1) ? val2 : val1);
+ printw("%*.*s",len,len,full);
+ printw("%*.*s",total-len,total-len,empty);
+ if (val2 != -1)
+ mvprintw(line,14+val2*total/max,"|");
+}
+
+/* -------------------------------------------------------------------- */
+
+enum MODE {
+ NCURSES = 1,
+ CONSOLE = 2,
+};
+enum MODE mode = NCURSES;
+int stop,verbose;
+char *filename = "record";
+int rate = 44100;
+
+static void
+ctrlc(int signal)
+{
+ if (verbose)
+ fprintf(stderr,"\n%s - exiting\n",
+ sys_siglist[signal]);
+ stop = 1;
+}
+
+static int
+record_start(char *outfile, int *nr)
+{
+ int wav;
+
+ do {
+ sprintf(outfile,"%s%03d.wav",filename,(*nr)++);
+ wav = open(outfile, O_WRONLY | O_EXCL | O_CREAT, 0666);
+ } while ((-1 == wav) && (EEXIST == errno));
+ if (-1 == wav) {
+ perror("open");
+ exit(1);
+ }
+ wav_start_write(wav,rate);
+ return wav;
+}
+
+static void
+record_stop(int fd)
+{
+ wav_stop_write(fd);
+ close(fd);
+ switch (mode) {
+ case CONSOLE:
+ if (verbose)
+ printf("\n");
+ break;
+ case NCURSES:
+ mvprintw(3,0,"%*.*s",COLS-1,COLS-1,blank);
+ break;
+ }
+}
+
+static off_t
+parse_size(const char *arg)
+{
+ int value;
+ char mul[4];
+ off_t retval = -1;
+
+ if (2 != sscanf(arg,"%d%3s",&value,mul))
+ return -1;
+ if (0 == strcasecmp(mul,"g") ||
+ 0 == strcasecmp(mul,"gb"))
+ retval = (off_t)value * 1024 * 1024 * 1024;
+ if (0 == strcasecmp(mul,"m") ||
+ 0 == strcasecmp(mul,"mb"))
+ retval = (off_t)value * 1024 * 1024;
+ if (0 == strcasecmp(mul,"k") ||
+ 0 == strcasecmp(mul,"kb"))
+ retval = (off_t)value * 1024;
+ return retval;
+}
+
+static char*
+str_mb(off_t value)
+{
+ static char buf[32];
+
+ if (value > (1 << 30)) {
+ value = (value * 10) >> 30;
+ sprintf(buf,"%d.%d GB",(int)(value/10),(int)(value%10));
+ return buf;
+ }
+ if (value > (1 << 20)) {
+ value = (value * 10) >> 20;
+ sprintf(buf,"%d.%d MB",(int)(value/10),(int)(value%10));
+ return buf;
+ }
+ value >>= 10;
+ sprintf(buf,"%3d kB",(int)value);
+ return buf;
+}
+
+/* -------------------------------------------------------------------- */
+
+char *progname;
+char *input = "line";
+char *str_maxsize = "2GB";
+int level_trigger;
+
+static void
+usage(FILE *fp)
+{
+ fprintf(fp,
+ "\n"
+ "%s records sound in CD-Quality (44100/16bit/stereo).\n"
+ "It has a nice ascii-art input-level meter. It is a\n"
+ "interactive curses application. You'll need a fast\n"
+ "terminal, don't try this on a 9600 bps vt100...\n"
+ "\n"
+ "%s has several options:\n"
+ " -h this text\n"
+ " -o file output file basename [%s], a number and the .wav\n"
+ " extention are added by %s.\n"
+ " -i ctrl mixer control [%s]. This should be the one\n"
+ " where you can adjust the record level for\n"
+ " your audio source, \"line\", \"mic\" and \"igain\"\n"
+ " are good candidates.\n"
+ " -m dev set mixer device [%s]\n"
+ " -d dev set dsp device [%s]\n"
+ " -r rate set sample rate [%d]\n"
+ " -p sec peak seconds [%.1f]\n"
+ "\n"
+ "for non-interactive usage only:\n"
+ " -c enable console (non-interactive) mode\n"
+ " -v be verbose (show progress)\n"
+ " -t mm:ss limit the time to record. By default it records\n"
+ " until stopped by a signal (^C)\n"
+ " -s size set max file size [%s]. You have to give number\n"
+ " and unit without space inbetween, i.e. \"100mb\".\n"
+ " -l signal level triggered recording.\n"
+ " -L level same as above + specify trigger level [%d]\n"
+ "\n",
+ progname,progname,filename,progname,
+ input,mixer_dev,audio_dev,
+ rate,peak_seconds,str_maxsize,
+ level_trigger ? level_trigger : 1000);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c,key,vol,delay,auto_adjust;
+ int record,nr,wav=0;
+ char *outfile;
+ fd_set s;
+ int sec,maxhour,maxmin,maxsec;
+ off_t maxsize;
+
+ /* init some vars */
+ progname = strrchr(argv[0],'/');
+ progname = progname ? progname+1 : argv[0];
+ maxsec = 0;
+ delay = 0;
+ auto_adjust = 1;
+ record = 0;
+ nr = 0;
+
+ /* parse options */
+ for (;;) {
+ if (-1 == (c = getopt(argc, argv, "vhlci:o:d:m:r:t:s:L:p:")))
+ break;
+ switch (c) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'l':
+ level_trigger = 1000;
+ break;
+ case 'L':
+ level_trigger = atoi(optarg);
+ break;
+ case 'i':
+ input = optarg;
+ break;
+ case 'o':
+ filename = optarg;
+ break;
+ case 'd':
+ audio_dev = optarg;
+ break;
+ case 'm':
+ mixer_dev = optarg;
+ break;
+ case 'c':
+ mode = CONSOLE;
+ break;
+ case 'r':
+ rate = atoi(optarg);
+ break;
+ case 'p':
+ peak_seconds = atof(optarg);
+ break;
+ case 't':
+ if (3 != sscanf(optarg,"%d:%d:%d",&maxhour,&maxmin,&maxsec)) {
+ maxhour = 0;
+ if (2 != sscanf(optarg,"%d:%d",&maxmin,&maxsec)) {
+ fprintf(stderr,"time parse error\n");
+ exit(1);
+ }
+ }
+ maxsec += maxmin * 60;
+ maxsec += maxhour * 60 * 60;
+ break;
+ case 's':
+ str_maxsize = optarg;
+ break;
+ case 'h':
+ usage(stdout);
+ exit(0);
+ default:
+ usage(stderr);
+ exit(1);
+ }
+ }
+ maxsize = parse_size(str_maxsize);
+ if (-1 == maxsize) {
+ fprintf(stderr,"maxsize parse error [%s]\n",str_maxsize);
+ exit(1);
+ }
+
+ mixer_open(mixer_dev,input);
+ sound_open(rate);
+ outfile = malloc(strlen(filename)+16);
+
+ if (mode == NCURSES) {
+ tty_raw();
+ atexit(tty_restore);
+ }
+
+ signal(SIGINT,ctrlc);
+ signal(SIGQUIT,ctrlc);
+ signal(SIGTERM,ctrlc);
+ signal(SIGHUP,ctrlc);
+
+ if (mode == NCURSES) {
+ mvprintw( 5,0,"record to %s*.wav",filename);
+ mvprintw( 7,0,"left/right adjust mixer level for \"%s\"",input);
+ mvprintw( 8,0,"space starts/stops recording");
+ /* line 9 is printed later */
+ mvprintw(10,0," auto-adjust reduces the record level on overruns");
+ mvprintw(11,0,"'N' next file (same as space twice, but without break)");
+ mvprintw(12,0,"'Q' quit");
+ mvprintw(LINES-3,0,"--");
+ mvprintw(LINES-2,0,"(c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>");
+
+ for (;!stop;) {
+ refresh();
+ FD_ZERO(&s);
+ FD_SET(0,&s);
+ FD_SET(sound_fd,&s);
+ if (-1 == select(sound_fd+1,&s,NULL,NULL,NULL)) {
+ if (EINTR == errno)
+ continue;
+ perror("select");
+ break;
+ }
+
+ if (FD_ISSET(sound_fd,&s)) {
+ /* sound */
+ if (-1 == sound_read())
+ break;
+ if (delay)
+ delay--;
+ if (auto_adjust && (0 == delay) &&
+ (maxl >= 32767 || maxr >= 32767)) {
+ /* auto-adjust */
+ vol = mixer_get_volume();
+ vol--;
+ if (vol < 0)
+ vol = 0;
+ mixer_set_volume(vol);
+ delay = 3;
+ }
+ print_bar(0,input,mixer_get_volume(),-1,100);
+ print_bar(1,"left",maxl,secl,32768);
+ print_bar(2,"right",maxr,secr,32768);
+ mvprintw(9,0,"'A' toggle auto-adjust [%s] ",
+ auto_adjust ? "on" : "off");
+ if (record) {
+ wav_write_audio(wav,sound_buffer,sound_blksize);
+ sec = wav_size / (rate*4);
+ mvprintw(3,0,"%s: %3d:%02d (%s) ",outfile,
+ sec/60,sec%60,str_mb(wav_size));
+ } else {
+ mvprintw(3,0,"");
+ }
+ }
+
+ if (FD_ISSET(0,&s)) {
+ /* tty in */
+ switch (key = getch()) {
+ case 'Q':
+ case 'q':
+ stop = 1;
+ break;
+ case 'A':
+ case 'a':
+ auto_adjust = !auto_adjust;
+ break;
+ case 'N':
+ case 'n':
+ if (record) {
+ record_stop(wav);
+ wav = record_start(outfile,&nr);
+ }
+ break;
+ case ' ':
+ if (!filename)
+ break;
+ if (!record) {
+ /* start */
+ wav = record_start(outfile,&nr);
+ record=1;
+ auto_adjust=0;
+ } else {
+ /* stop */
+ record_stop(wav);
+ record=0;
+ }
+ break;
+ case KEY_RIGHT:
+ vol = mixer_get_volume();
+ vol++;
+ if (vol > 100)
+ vol = 100;
+ mixer_set_volume(vol);
+ break;
+ case KEY_LEFT:
+ vol = mixer_get_volume();
+ vol--;
+ if (vol < 0)
+ vol = 0;
+ mixer_set_volume(vol);
+ break;
+ }
+ }
+ }
+ }
+
+ if (mode == CONSOLE) {
+ if (!level_trigger) {
+ wav = record_start(outfile,&nr);
+ record=1;
+ }
+
+ for (;!stop;) {
+ if (-1 == sound_read())
+ break;
+ if (level_trigger) {
+ if (!record &&
+ (maxl > level_trigger ||
+ maxr > level_trigger)) {
+ wav = record_start(outfile,&nr);
+ record=1;
+ }
+ if (record &&
+ secl < level_trigger &&
+ secr < level_trigger) {
+ record_stop(wav);
+ record=0;
+ }
+ }
+ if (!record) {
+ printf("waiting for signal [%d/%d]... \r",maxl,maxr);
+ fflush(stdout);
+ continue;
+ }
+
+ sec = (done_size + wav_size) / (rate*4);
+ if (maxsec && sec >= maxsec)
+ break;
+ if (wav_size + sound_blksize + sizeof(WAVEHDR) > maxsize) {
+ record_stop(wav);
+ wav = record_start(outfile,&nr);
+ }
+ wav_write_audio(wav,sound_buffer,sound_blksize);
+ if (verbose) {
+ int total = 10;
+ int len = (maxl+maxr)*total/32768/2;
+ printf("|%*.*s%*.*s| %s %d:%02d",
+ len,len,full, total-len,total-len,empty,
+ outfile,sec/60,sec%60);
+ if (maxsec)
+ printf("/%d:%02d",maxsec/60,maxsec%60);
+ printf(" (%s",str_mb(wav_size));
+ if (done_size)
+ printf(", %s total",str_mb(done_size + wav_size));
+ printf(") \r");
+ fflush(stdout);
+ }
+ }
+ }
+
+ if (record)
+ record_stop(wav);
+ mixer_close();
+ exit(0);
+}
diff --git a/console/scantv.c b/console/scantv.c
new file mode 100644
index 0000000..118704a
--- /dev/null
+++ b/console/scantv.c
@@ -0,0 +1,395 @@
+/*
+ * (c) 2000-2002 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <time.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+/* xawtv */
+#include "channel.h"
+#include "frequencies.h"
+#include "grab-ng.h"
+#include "commands.h"
+
+/* libvbi */
+#include "vt.h"
+#include "misc.h"
+#include "fdset.h"
+#include "vbi.h"
+#include "lang.h"
+#include "dllist.h"
+
+int debug = 0;
+int have_dga = 0;
+
+int timeout = 3;
+char xpacket[64];
+char header[64];
+char scratch[1024*256];
+
+/*---------------------------------------------------------------------*/
+
+static void
+grabber_init(void)
+{
+ drv = ng_vid_open(ng_dev.video,NULL,0,&h_drv);
+ if (NULL == drv) {
+ fprintf(stderr,"no grabber device available\n");
+ exit(1);
+ }
+ f_drv = drv->capabilities(h_drv);
+ add_attrs(drv->list_attrs(h_drv));
+}
+
+static void
+event(struct dl_head *reqs, struct vt_event *ev)
+{
+ unsigned char *p;
+ struct vt_page *vtp;
+
+ switch (ev->type) {
+ case EV_HEADER:
+ p = ev->p1;
+ if (debug)
+ fprintf(stderr,"header %.32s\n", p+8);
+ memcpy(header,p+8,32);
+ header[32] = 0;
+ break;
+ case EV_PAGE:
+ vtp = ev->p1;
+ if (debug)
+ fprintf(stderr,"vtx page %x.%02x \r", vtp->pgno, vtp->subno);
+ break;
+ case EV_XPACKET:
+ p = ev->p1;
+ if (debug)
+ fprintf(stderr,"xpacket %x %x %x %x - %.20s\n",
+ p[0],p[1],p[3],p[5],p+20);
+ memcpy(xpacket,p+20,20);
+ xpacket[20] = 0;
+ break;
+ }
+}
+
+static char*
+get_vbi_name(void)
+{
+ int start;
+ char *name,*h;
+
+ xpacket[0] = 0;
+ header[0] = 0;
+ start = time(NULL);
+ for (;;) {
+ if (fdset_select(fds, 1000 * timeout) == 0) {
+ break;
+ }
+ if (time(NULL) > start+timeout) {
+ break;
+ }
+ if (xpacket[0] && header[0]) {
+ break;
+ }
+ }
+ if (xpacket[0]) {
+ for (h = xpacket+19; h >= xpacket; h--) {
+ if (32 != *h)
+ break;
+ *h = 0;
+ }
+ for (name = xpacket; *name == 32; name++)
+ ;
+ return name;
+ }
+#if 0
+ if (header[0]) {
+ for (name = header; *name && name < header+20; name++)
+ if (isalpha(*name))
+ break;
+ for (h = name; *name && name < header+20; name++)
+ if (!isalpha(*h)) {
+ *h = 0;
+ break;
+ }
+ if (*name)
+ return name;
+ }
+#endif
+ return NULL;
+}
+
+static int
+menu(char *intro, struct STRTAB *tab, char *opt)
+{
+ int i,ret;
+ char line[80];
+
+ if (NULL != opt) {
+ /* cmd line option -- non-interactive mode */
+ for (i = 0; tab[i].str != NULL; i++)
+ if (0 == strcasecmp(tab[i].str,opt))
+ return tab[i].nr;
+ fprintf(stderr,"%s: not found\n",opt);
+ exit(1);
+ }
+
+ fprintf(stderr,"\n%s\n",intro);
+ for (i = 0; tab[i].str != NULL; i++)
+ fprintf(stderr," %2ld: %s\n",tab[i].nr,tab[i].str);
+
+ for (;;) {
+ fprintf(stderr,"nr ? ");
+ fgets(line,79,stdin);
+ ret = atoi(line);
+ for (i = 0; tab[i].str != NULL; i++)
+ if (ret == tab[i].nr)
+ return ret;
+ fprintf(stderr,"invalid choice\n");
+ }
+}
+
+static void
+usage(FILE *out, char *prog, char *outfile)
+{
+ fprintf(out,
+ "This tool scan for tv stations and writes "
+ "a initial xawtv config file.\n"
+ "usage: %s [ options ]\n"
+ "options:\n"
+ " -h print this text\n"
+ " -o outfile set output file. [%s]\n"
+ " -n norm set tv norm.\n"
+ " -f table set frequency table.\n"
+ " -c device set video device file. [%s]\n"
+ " -C device set vbi device file. [%s]\n"
+ " -s skip channel scan\n",
+ prog,
+ outfile ? outfile : "stdout",
+ ng_dev.video,ng_dev.vbi);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct vbi *vbi;
+ struct ng_attribute *attr;
+ int c,f,f1,f2,fc,fi,on,tuned,i,j,scan=1,fullscan=0;
+ char *name,dummy[32];
+ char *tvnorm = NULL;
+ char *freqtab = NULL;
+ char *outfile = NULL;
+ FILE *conf = stdout;
+
+ setprgname(argv[0]);
+
+ /* parse options */
+ ng_init();
+ for (;;) {
+ if (-1 == (c = getopt(argc, argv, "hsadn:f:o:c:C:")))
+ break;
+ switch (c) {
+ case 'd':
+ debug++;
+ break;
+ case 's':
+ scan=0;
+ break;
+ case 'a':
+ fullscan=1;
+ break;
+ case 'n':
+ tvnorm = optarg;
+ break;
+ case 'f':
+ freqtab = optarg;
+ break;
+ case 'o':
+ outfile = optarg;
+ break;
+ case 'c':
+ ng_dev.video = optarg;
+ break;
+ case 'C':
+ ng_dev.vbi = optarg;
+ break;
+ case 'h':
+ usage(stdout,argv[0],outfile);
+ exit(0);
+ default:
+ usage(stderr,argv[0],outfile);
+ exit(1);
+ }
+ }
+
+ if (outfile) {
+ if (NULL == (conf = fopen(outfile,"w"))) {
+ fprintf(stderr,"open %s: %s\n",argv[1],strerror(errno));
+ exit(1);
+ }
+ }
+
+ /* video */
+ if (NULL == drv)
+ grabber_init();
+ if (NULL == drv) {
+ fprintf(stderr,"can't open video device\n");
+ exit(1);
+ }
+
+ attr_init();
+ audio_init();
+
+ /* ask the user some questions ... */
+ attr = ng_attr_byid(attrs,ATTR_ID_NORM);
+ i = menu("please select your TV norm",attr->choices,tvnorm);
+ j = menu("please select a frequency table",chanlist_names,freqtab);
+
+ fprintf(conf,"[global]\n");
+ fprintf(conf,"freqtab = %s\n",chanlist_names[j].str);
+ fprintf(conf,"\n");
+ fprintf(conf,"[defaults]\n");
+ fprintf(conf,"input = Television\n");
+ fprintf(conf,"norm = %s\n",ng_attr_getstr(attr,i));
+ fprintf(conf,"\n");
+ fflush(conf);
+ if (!scan)
+ exit(0);
+
+ if (!(f_drv & CAN_TUNE)) {
+ fprintf(stderr,"device has no tuner, exiting\n");
+ exit(0);
+ }
+ set_defaults();
+ do_va_cmd(2,"setinput","television");
+ do_va_cmd(2,"setnorm",ng_attr_getstr(attr,i));
+ do_va_cmd(2,"setfreqtab",chanlist_names[j].str);
+
+ /* vbi */
+ fdset_init(fds);
+ if (not(vbi = vbi_open(ng_dev.vbi, 0, 0, -1)))
+ fatal("cannot open %s", ng_dev.vbi);
+ vbi_add_handler(vbi, event, NULL);
+
+ if (!fullscan) {
+ /* scan channels */
+ fprintf(stderr,"\nscanning channel list %s...\n",
+ chanlist_names[j].str);
+ for (i = 0; i < chancount; i++) {
+ fprintf(stderr,"%-4s (%6.2f MHz): ",chanlist[i].name,
+ (float)chanlist[i].freq/1000);
+ do_va_cmd(2,"setchannel",chanlist[i].name);
+ usleep(200000); /* 0.2 sec */
+ if (0 == drv->is_tuned(h_drv)) {
+ fprintf(stderr,"no station\n");
+ continue;
+ }
+ fdset_select(fds, 1000 * timeout);
+ name = get_vbi_name();
+ fprintf(stderr,"%s\n",name ? name : "???");
+ if (NULL == name) {
+ sprintf(dummy,"unknown (%s)",chanlist[i].name);
+ name = dummy;
+ }
+ fprintf(conf,"[%s]\nchannel = %s\n\n",name,chanlist[i].name);
+ fflush(conf);
+ }
+ } else {
+ /* scan freqnencies */
+ fprintf(stderr,"\nscanning freqencies...\n");
+ on = 0;
+ fc = 0;
+ f1 = 0;
+ f2 = 0;
+ fi = -1;
+ for (f = 44*16; f <= 958*16; f += 4) {
+ for (i = 0; i < chancount; i++)
+ if (chanlist[i].freq * 16 == f * 1000)
+ break;
+ fprintf(stderr,"?? %6.2f MHz (%-4s): ",f/16.0,
+ (i == chancount) ? "-" : chanlist[i].name);
+ drv->setfreq(h_drv,f);
+ usleep(200000); /* 0.2 sec */
+ tuned = drv->is_tuned(h_drv);
+
+ /* state machine */
+ if (0 == on && 0 == tuned) {
+ fprintf(stderr,"| no\n");
+ continue;
+ }
+ if (0 == on && 0 != tuned) {
+ fprintf(stderr," \\ raise\n");
+ f1 = f;
+ if (i != chancount) {
+ fi = i;
+ fc = f;
+ }
+ on = 1;
+ continue;
+ }
+ if (0 != on && 0 != tuned) {
+ fprintf(stderr," | yes\n");
+ if (i != chancount) {
+ fi = i;
+ fc = f;
+ }
+ continue;
+ }
+ /* if (on != 0 && 0 == tuned) -- found one, read name from vbi */
+ fprintf(stderr," / fall\n");
+ f2 = f;
+ if (0 == fc)
+ fc = (f1+f2)/2;
+
+ fprintf(stderr,"=> %6.2f MHz (%-4s): ", fc/16.0,
+ (-1 != fi) ? chanlist[fi].name : "-");
+ drv->setfreq(h_drv,fc);
+
+ fdset_select(fds, 1000 * timeout);
+ name = get_vbi_name();
+ fprintf(stderr,"%s\n",name ? name : "???");
+ if (NULL == name) {
+ sprintf(dummy,"unknown (%s)",chanlist[fi].name);
+ name = dummy;
+ }
+ if (-1 != fi) {
+ if (NULL == name) {
+ sprintf(dummy,"unknown (%s)",chanlist[fi].name);
+ name = dummy;
+ }
+ fprintf(conf,"[%s]\nchannel = %s\n\n",name,chanlist[fi].name);
+ } else {
+ if (NULL == name) {
+ sprintf(dummy,"unknown (%.3f)", fc/16.0);
+ name = dummy;
+ }
+ fprintf(conf,"[%s]\nfreq = %.3f\n\n", name, fc/16.0);
+ }
+ fflush(conf);
+
+ on = 0;
+ fc = 0;
+ f1 = 0;
+ f2 = 0;
+ fi = -1;
+ }
+ }
+
+ /* cleanup */
+ audio_off();
+ drv->close(h_drv);
+
+ vbi_del_handler(vbi, event, NULL);
+ vbi_close(vbi);
+
+ exit(0);
+}
diff --git a/console/showriff.c b/console/showriff.c
new file mode 100644
index 0000000..e069fd8
--- /dev/null
+++ b/console/showriff.c
@@ -0,0 +1,575 @@
+/* SHOWRIFF.c
+ * Extracts some infos from RIFF files
+ * (c)94 UP-Vision Computergrafik for c't
+ * Written in ANSI-C. No special header files needed to compile.
+ *
+ * modified by Gerd Knorr:
+ * - dos2unix :-)
+ * - fixed warnings
+ * - added some tags (checked xanim sources for info)
+ * - LFS + OpenDML + mjpeg
+ * - bytesex fixes
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define SWAP2(x) (((x>>8) & 0x00ff) |\
+ ((x<<8) & 0xff00))
+
+# define SWAP4(x) (((x>>24) & 0x000000ff) |\
+ ((x>>8) & 0x0000ff00) |\
+ ((x<<8) & 0x00ff0000) |\
+ ((x<<24) & 0xff000000))
+#else
+# define SWAP2(a) (a)
+# define SWAP4(a) (a)
+#endif
+
+#ifndef HAVE_FTELLO
+# define ftello ftell
+#endif
+#ifndef HAVE_FSEEKO
+# define fseeko fseek
+#endif
+
+typedef unsigned long DWORD;
+typedef unsigned short WORD;
+typedef DWORD FOURCC; /* Type of FOUR Character Codes */
+typedef unsigned char boolean;
+#define TRUE 1
+#define FALSE 0
+#define BUFSIZE 4096
+
+/* Macro to convert expressions of form 'F','O','U','R' to
+ numbers of type FOURCC: */
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define MAKEFOURCC(a,b,c,d) ((((DWORD)a)<<24) | (((DWORD)b)<<16) | \
+ (((DWORD)c)<< 8) | ( (DWORD)d) )
+#else
+# define MAKEFOURCC(a,b,c,d) ( ((DWORD)a) | (((DWORD)b)<< 8) | \
+ (((DWORD)c)<<16) | (((DWORD)d)<<24) )
+#endif
+
+/* The only FOURCCs interpreted by this program: */
+
+#define RIFFtag MAKEFOURCC('R','I','F','F')
+#define LISTtag MAKEFOURCC('L','I','S','T')
+#define avihtag MAKEFOURCC('a','v','i','h')
+#define strhtag MAKEFOURCC('s','t','r','h')
+#define strftag MAKEFOURCC('s','t','r','f')
+#define vidstag MAKEFOURCC('v','i','d','s')
+#define audstag MAKEFOURCC('a','u','d','s')
+#define dmlhtag MAKEFOURCC('d','m','l','h')
+
+#define MJPGtag MAKEFOURCC('M','J','P','G')
+#define _00dbtag MAKEFOURCC('0','0','d','b')
+#define _00dctag MAKEFOURCC('0','0','d','c')
+
+/* Build a string from a FOURCC number
+ (s must have room for at least 5 chars) */
+
+static void FOURCC2Str(FOURCC fcc, char* s)
+{
+#if BYTE_ORDER == BIG_ENDIAN
+ s[0]=(fcc >> 24) & 0xFF;
+ s[1]=(fcc >> 16) & 0xFF;
+ s[2]=(fcc >> 8) & 0xFF;
+ s[3]=(fcc ) & 0xFF;
+#else
+ s[0]=(fcc ) & 0xFF;
+ s[1]=(fcc >> 8) & 0xFF;
+ s[2]=(fcc >> 16) & 0xFF;
+ s[3]=(fcc >> 24) & 0xFF;
+#endif
+ s[4]=0;
+}
+
+static DWORD fcc_type;
+static int stop_on_errors = 1;
+static int print_mjpeg = 0;
+
+#define EoLST 0
+#define INT32 1
+#define INT16 2
+#define FLAGS 3
+#define CCODE 4
+
+struct FLAGLIST {
+ int bit;
+ char *name;
+};
+
+struct VAL {
+ int type;
+ char *name;
+ struct FLAGLIST *flags;
+};
+
+struct FLAGLIST flags_avih[] = {
+ { 0x00000010, "hasindex" },
+ { 0x00000020, "useindex" },
+ { 0x00000100, "interleaved" },
+ { 0x00010000, "for_capture" },
+ { 0x00020000, "copyrighted" },
+ { 0, NULL }
+};
+
+struct VAL names_avih[] = {
+ { INT32, "us_frame" },
+ { INT32, "max_bps" },
+ { INT32, "pad_gran" },
+ { FLAGS, "flags", flags_avih },
+ { INT32, "tot_frames" },
+ { INT32, "init_frames" },
+ { INT32, "streams" },
+ { INT32, "sug_bsize" },
+ { INT32, "width" },
+ { INT32, "height" },
+ { INT32, "scale" },
+ { INT32, "rate" },
+ { INT32, "start" },
+ { INT32, "length" },
+ { EoLST, NULL }
+};
+
+struct VAL names_strh[] = {
+ { CCODE, "fcc_handler" },
+ { FLAGS, "flags" },
+ { INT32, "priority" },
+ { INT32, "init_frames" },
+ { INT32, "scale" },
+ { INT32, "rate" },
+ { INT32, "start" },
+ { INT32, "length" },
+ { INT32, "sug_bsize" },
+ { INT32, "quality" },
+ { INT32, "samp_size" },
+ { EoLST, NULL }
+};
+
+struct VAL names_strf_vids[] = {
+ { INT32, "size" },
+ { INT32, "width" },
+ { INT32, "height" },
+ { INT16, "planes" },
+ { INT16, "bit_cnt" },
+ { CCODE, "compression" },
+ { INT32, "image_size" },
+ { INT32, "xpels_meter" },
+ { INT32, "ypels_meter" },
+ { INT32, "num_colors" },
+ { INT32, "imp_colors" },
+ { EoLST, NULL }
+};
+
+struct VAL names_strf_auds[] = {
+ { INT16, "format" },
+ { INT16, "channels" },
+ { INT32, "rate" },
+ { INT32, "av_bps" },
+ { INT16, "blockalign" },
+ { INT16, "size" },
+ { EoLST, NULL }
+};
+
+struct VAL names_dmlh[] = {
+ { INT32, "frames" },
+ { EoLST, NULL }
+};
+
+static void dump_vals(FILE *f, int count, struct VAL *names)
+{
+ DWORD i,j,val32;
+ WORD val16;
+
+ for (i = 0; names[i].type != EoLST; i++) {
+ switch (names[i].type) {
+ case INT32:
+ fread(&val32,4,1,f);
+ val32 = SWAP4(val32);
+ printf("\t%-12s = %ld\n",names[i].name,val32);
+ break;
+ case CCODE:
+ fread(&val32,4,1,f);
+ val32 = SWAP4(val32);
+ if (val32) {
+ printf("\t%-12s = %c%c%c%c (0x%lx)\n",names[i].name,
+ (int)( val32 & 0xff),
+ (int)((val32 >> 8) & 0xff),
+ (int)((val32 >> 16) & 0xff),
+ (int)((val32 >> 24) & 0xff),
+ val32);
+ } else {
+ printf("\t%-12s = unset (0)\n",names[i].name);
+ }
+ break;
+ case FLAGS:
+ fread(&val32,4,1,f);
+ val32 = SWAP4(val32);
+ printf("\t%-12s = 0x%lx\n",names[i].name,val32);
+ if (names[i].flags) {
+ for (j = 0; names[i].flags[j].bit != 0; j++)
+ if (names[i].flags[j].bit & val32)
+ printf("\t\t0x%x: %s\n",
+ names[i].flags[j].bit,names[i].flags[j].name);
+ }
+ break;
+ case INT16:
+ fread(&val16,2,1,f);
+ val16 = SWAP2(val16);
+ printf("\t%-12s = %ld\n",names[i].name,(long)val16);
+ break;
+ }
+ }
+}
+
+struct JPEG_MARKER {
+ unsigned char val;
+ char *name;
+ char *desc;
+} mark[] = {
+ { 0xc0, "SOF0 ", "start of frame 0" },
+ { 0xc4, "DHT ", "huffmann table(?)" },
+ { 0xd8, "SOI ", "start of image" },
+ { 0xda, "SOS ", "start of scan" },
+ { 0xdb, "DQT ", "quantization table" },
+ { 0xe0, "APP0 ", NULL },
+ { 0xfe, "COM ", "comment" },
+ { 0, NULL, NULL }
+};
+
+static void hexlog(unsigned char *buf, int count)
+{
+ int l,i;
+
+ for (l = 0; l < count; l+= 16) {
+ printf("\t ");
+ for (i = l; i < l+16; i++) {
+ if (i < count)
+ printf("%02x ",buf[i]);
+ else
+ printf(" ");
+ if ((i%4) == 3)
+ printf(" ");
+ }
+ for (i = l; i < l+16; i++) {
+ if (i < count)
+ printf("%c",isprint(buf[i]) ? buf[i] : '.');
+ }
+ printf("\n");
+ }
+}
+
+static void dump_jpeg(unsigned char *buf, int len)
+{
+ int i,j,type,skip;
+
+ if (!print_mjpeg)
+ return;
+
+ for (i = 0; i < len;) {
+ if (buf[i] != 0xff) {
+ printf("\tjpeg @ 0x%04x: oops 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ i,buf[i],buf[i+1],buf[i+2],buf[i+3]);
+ return;
+ }
+ type = buf[i+1];
+ for (j = 0; 0 != mark[j].val; j++)
+ if (mark[j].val == type)
+ break;
+ printf("\tjpeg @ 0x%04x: %s (0x%x) %s\n",i,
+ mark[j].name ? mark[j].name : "???", type,
+ mark[j].desc ? mark[j].desc : "???");
+ i+=2;
+ skip = buf[i] << 8 | buf[i+1];
+ switch (type) {
+ case 0xd8:
+ skip=0;
+ break;
+ case 0xc0: /* SOF0 */
+ printf("\t\tsize: %dx%d prec=%d comp=%d\n",
+ buf[i+6] | (buf[i+5] << 8),
+ buf[i+4] | (buf[i+3] << 8),
+ buf[i+2], buf[i+7]);
+ for (j = 0; j < buf[i+7]; j++) {
+ printf("\t\tcomp%d: id=%d h=%d v=%d qt=%d\n",j,
+ buf[i+3*j+8],
+ (buf[i+3*j+9] >> 4) & 0x0f,
+ buf[i+3*j+9] & 0x0f,
+ buf[i+3*j+10]);
+ }
+ break;
+ case 0xc4: /* DHT */
+ printf("\t\tindex=%d\n",buf[i+2]);
+ break;
+ case 0xdb: /* DQT */
+ printf("\t\tprec=%d, nr=%d\n",
+ (buf[i+2] >> 4) & 0x0f,
+ buf[i+2] & 0x0f);
+ break;
+ case 0xda:
+ return;
+ }
+ hexlog(buf+i+2,skip-2);
+ i += skip;
+ }
+}
+
+static unsigned char*
+off_t_to_char(off_t val, int base, int len)
+{
+ static const char digit[] = "0123456789abcdef";
+ static char outbuf[32];
+ char *p = outbuf + sizeof(outbuf);
+ int i;
+
+ *(--p) = 0;
+ for (i = 0; i < len || val > 0; i++) {
+ *(--p) = digit[ val % base ];
+ val = val / base;
+ }
+ return p;
+}
+
+/* Reads a chunk ID and the chunk's size from file f at actual
+ file position : */
+
+static boolean ReadChunkHead(FILE* f, FOURCC* ID, DWORD* size)
+{
+ if (!fread(ID,sizeof(FOURCC),1,f)) return(FALSE);
+ if (!fread(size,sizeof(DWORD),1,f)) return(FALSE);
+ *size = SWAP4(*size);
+ return(TRUE);
+}
+
+/* Processing of a chunk. (Will be called recursively!).
+ Processes file f starting at position filepos.
+ f contains filesize bytes.
+ If DesiredTag!=0, ProcessChunk tests, whether the chunk begins
+ with the DesiredTag. If the read chunk is not identical to
+ DesiredTag, an error message is printed.
+ RekDepth determines the recursion depth of the chunk.
+ chunksize is set to the length of the chunk's data (excluding
+ header and padding byte).
+ ProcessChunk prints out information of the chunk to stdout
+ and returns FALSE, if an error occured. */
+
+static boolean ProcessChunk(FILE* f, off_t filepos, off_t filesize,
+ FOURCC DesiredTag, int RekDepth,
+ DWORD* chunksize)
+{
+ char buf[BUFSIZE];
+ int buflen;
+ char tagstr[5]; /* FOURCC of chunk converted to string */
+ FOURCC chunkid; /* read FOURCC of chunk */
+ off_t datapos; /* position of data in file to process */
+
+ if (filepos>filesize-1) { /* Oops. Must be something wrong! */
+ printf(" ***** Error: Data would be behind end of file!\n");
+ if (stop_on_errors)
+ return(FALSE);
+ }
+ fseeko(f,filepos,SEEK_SET); /* Go to desired file position! */
+
+ if (!ReadChunkHead(f,&chunkid,chunksize)) { /* read chunk header */
+ printf(" ***** Error reading chunk at filepos 0x%s\n",
+ off_t_to_char(filepos,16,1));
+ return(FALSE);
+ }
+ FOURCC2Str(chunkid,tagstr); /* now we can PRINT the chunkid */
+ if (DesiredTag) { /* do we have to test identity? */
+ if (DesiredTag!=chunkid) {
+ char ds[5];
+ FOURCC2Str(DesiredTag,ds);
+ printf("\n\n *** Error: Expected chunk '%s', found '%s'\n",
+ ds,tagstr);
+ return(FALSE);
+ }
+ }
+
+ datapos=filepos+sizeof(FOURCC)+sizeof(DWORD); /* here is the data */
+
+ /* print out header: */
+ printf("(0x%s) %*c ID:<%s> Size: 0x%08lx\n",
+ off_t_to_char(filepos,16,8),(RekDepth+1)*4,' ',tagstr,*chunksize);
+
+ if (datapos + ((*chunksize+1)&~1) > filesize) { /* too long? */
+ printf(" ***** Error: Chunk exceeds file\n");
+ if (stop_on_errors)
+ return(FALSE);
+ }
+
+ switch (chunkid) {
+
+ /* Depending on the ID of the chunk and the internal state, the
+ different IDs can be interpreted. At the moment the only
+ interpreted chunks are RIFF- and LIST-chunks. For all other
+ chunks only their header is printed out. */
+
+ case RIFFtag:
+ case LISTtag: {
+
+ DWORD datashowed;
+ FOURCC formtype; /* format of chunk */
+ char formstr[5]; /* format of chunk converted to string */
+ DWORD subchunksize; /* size of a read subchunk */
+
+ fread(&formtype,sizeof(FOURCC),1,f); /* read the form type */
+ FOURCC2Str(formtype,formstr); /* make it printable */
+
+ /* print out the indented form of the chunk: */
+ if (chunkid==RIFFtag)
+ printf("%12c %*c Form Type = <%s>\n",
+ ' ',(RekDepth+1)*4,' ',formstr);
+ else
+ printf("%12c %*c List Type = <%s>\n",
+ ' ',(RekDepth+1)*4,' ',formstr);
+
+ datashowed=sizeof(FOURCC); /* we showed the form type */
+ datapos+=datashowed; /* for the rest of the routine */
+
+ while (datashowed<*chunksize) { /* while not showed all: */
+
+ long subchunklen; /* complete size of a subchunk */
+
+ /* recurse for subchunks of RIFF and LIST chunks: */
+ if (!ProcessChunk(f,datapos,filesize,0,
+ RekDepth+1,&subchunksize)) return(FALSE);
+
+ subchunklen = sizeof(FOURCC) + /* this is the complete.. */
+ sizeof(DWORD) + /* .. size of the subchunk */
+ ((subchunksize+1) & ~1);
+
+ datashowed += subchunklen; /* we showed the subchunk */
+ datapos += subchunklen; /* for the rest of the loop */
+ }
+ } break;
+
+ /* Feel free to put your extensions here! */
+
+ case avihtag:
+ dump_vals(f,sizeof(names_avih)/sizeof(struct VAL),names_avih);
+ break;
+ case strhtag:
+ {
+ char typestr[5];
+ fread(&fcc_type,sizeof(FOURCC),1,f);
+ FOURCC2Str(fcc_type,typestr);
+ printf("\tfcc_type = %s\n",typestr);
+ dump_vals(f,sizeof(names_strh)/sizeof(struct VAL),names_strh);
+ break;
+ }
+ case strftag:
+ switch (fcc_type) {
+ case vidstag:
+ dump_vals(f,sizeof(names_strf_vids)/sizeof(struct VAL),names_strf_vids);
+ break;
+ case audstag:
+ dump_vals(f,sizeof(names_strf_auds)/sizeof(char*),names_strf_auds);
+ break;
+ default:
+ printf("unknown\n");
+ break;
+ }
+ break;
+ case dmlhtag:
+ dump_vals(f,sizeof(names_dmlh)/sizeof(struct VAL),names_dmlh);
+ break;
+ case _00dbtag:
+ case _00dctag:
+ buflen = (*chunksize > BUFSIZE) ? BUFSIZE : *chunksize;
+ fread(buf, buflen, 1, f);
+ dump_jpeg(buf,buflen);
+ break;
+ }
+
+ return(TRUE);
+}
+
+static void
+usage(char *prog)
+{
+ char *h;
+
+ if (NULL != (h = strrchr(prog,'/')))
+ prog = h+1;
+ fprintf(stderr,
+ "\n"
+ "%s shows contents of RIFF files (AVI,WAVE...).\n"
+ "(c) 1994 UP-Vision Computergrafik for c't\n"
+ "unix port and some extentions (for avi) by Gerd Knorr\n"
+ "\n"
+ "usage: %s [ -j ] [ -e ] filename\n"
+ "options:\n"
+ " -j try to decode some mjpeg headers\n"
+ " -e don't stop on errors\n"
+ "\n",
+ prog,prog);
+}
+
+int main (int argc, char **argv)
+{
+ FILE* f; /* the input file */
+ off_t filesize; /* its size */
+ off_t filepos;
+ DWORD chunksize; /* size of the RIFF chunk data */
+ int c;
+
+ /* parse options */
+ for (;;) {
+ if (-1 == (c = getopt(argc, argv, "jeh")))
+ break;
+ switch (c) {
+ case 'j':
+ print_mjpeg = 1;
+ break;
+ case 'e':
+ stop_on_errors = 0;
+ break;
+ case 'h':
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
+ if (optind == argc) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ if (!(f=fopen(argv[optind],"rb"))) {
+ printf("\n\n *** Error opening file %s. Program aborted!\n",
+ argv[optind]);
+ return(1);
+ }
+
+ fseeko(f, 0, SEEK_END);
+ filesize = ftello(f);
+ fseeko(f, 0, SEEK_SET);
+
+ printf("Contents of file %s (%s/0x%s bytes):\n\n",argv[optind],
+ off_t_to_char(filesize,10,1),
+ off_t_to_char(filesize,16,1));
+
+ for (filepos = 0; filepos < filesize;) {
+ chunksize = 0;
+ if (!ProcessChunk(f,filepos,filesize,RIFFtag,0,&chunksize))
+ break;
+ filepos += chunksize + 8;
+ printf("\n");
+ }
+
+ return(0);
+}
diff --git a/console/streamer.c b/console/streamer.c
new file mode 100644
index 0000000..601833f
--- /dev/null
+++ b/console/streamer.c
@@ -0,0 +1,486 @@
+/*
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/ipc.h>
+#include <sys/wait.h>
+
+#include "grab-ng.h"
+#include "writefile.h"
+#include "channel.h"
+#include "sound.h"
+#include "capture.h"
+#include "commands.h"
+
+/* ---------------------------------------------------------------------- */
+
+static int bufcount = 16;
+static int parallel = 1;
+static char* tvnorm = NULL;
+static char* input = NULL;
+static char* moviename = NULL;
+static char* audioname = NULL;
+static char* vfmt_name;
+static char* afmt_name;
+
+static const struct ng_writer *writer;
+static const void *video_priv;
+static const void *audio_priv;
+static struct ng_video_fmt video = {
+ width: 320,
+ height: 240,
+};
+static struct ng_audio_fmt audio = {
+ rate: 44100,
+};
+static void *movie_state;
+
+static int absframes = 1;
+static int quiet = 0, fps = 10000;
+
+static int signaled = 0, wait_seconds = 0;
+
+int debug = 0, have_dga = 0;
+
+/* ---------------------------------------------------------------------- */
+
+static void
+list_formats(FILE *out)
+{
+ const struct ng_writer *wr;
+ int i,j;
+
+ fprintf(out,"\nmovie writers:\n");
+ for (i = 0; NULL != ng_writers[i]; i++) {
+ wr = ng_writers[i];
+ fprintf(out," %s - %s\n",wr->name,
+ wr->desc ? wr->desc : "-");
+ if (NULL != wr->video) {
+ fprintf(out," video formats:\n");
+ for (j = 0; NULL != wr->video[j].name; j++) {
+ fprintf(out," %-7s %-28s [%s]\n",wr->video[j].name,
+ wr->video[j].desc ? wr->video[j].desc :
+ ng_vfmt_to_desc[wr->video[j].fmtid],
+ wr->video[j].ext);
+ }
+ }
+ if (NULL != wr->audio) {
+ fprintf(out," audio formats:\n");
+ for (j = 0; NULL != wr->audio[j].name; j++) {
+ fprintf(out," %-7s %-28s [%s]\n",wr->audio[j].name,
+ wr->audio[j].desc ? wr->audio[j].desc :
+ ng_afmt_to_desc[wr->audio[j].fmtid],
+ wr->audio[j].ext ? wr->audio[j].ext : "-");
+ }
+ }
+ fprintf(out,"\n");
+ }
+}
+
+static void
+usage(FILE *out)
+{
+ fprintf(out,
+ "streamer grabs image(s), records movies and sound\n"
+ "\n"
+ "usage: streamer [ options ]\n"
+ "\n"
+ "general options:\n"
+ " -h print this help text\n"
+ " -q quiet operation\n"
+ " -p n use n compression threads [%d]\n"
+ " -w seconds wait before grabbing [%d]\n"
+ "\n"
+ "video options:\n"
+ " -o file video/movie file name\n"
+ " -f format specify video format\n"
+ " -c device specify video4linux device [%s]\n"
+ " -r fps frame rate [%d.%03d]\n"
+ " -s size specify size [%dx%d]\n"
+ "\n"
+ " -t times number of frames or hh:mm:ss [%d]\n"
+ " -b buffers specify # of buffers [%d]\n"
+ " -j quality quality for mjpeg or jpeg [%d]\n"
+ " -n tvnorm set pal/ntsc/secam\n"
+ " -i input set video source\n"
+ "\n"
+ "audio options:\n"
+ " -O file wav file name\n"
+ " -F format specify audio format\n"
+ " -C device specify dsp device [%s]\n"
+ " -R rate sample rate [%d]\n"
+ "\n",
+
+ parallel,wait_seconds,
+ ng_dev.video, fps/1000, fps%1000,
+ video.width, video.height,
+ absframes, bufcount, ng_jpeg_quality,
+ ng_dev.dsp, audio.rate
+ );
+
+ list_formats(out);
+ fprintf(out,
+ "If you want to capture to multiple image files you should include some\n"
+ "digits into the movie filename (foo0000.jpeg for example), streamer will\n"
+ "use the digit block to enumerate the image files.\n"
+ "\n"
+ "For file formats which can hold *both* audio and video (like AVI and\n"
+ "QuickTime) the -O option has no effect.\n"
+ "\n"
+ "streamer will use the file extention of the output file name to figure\n"
+ "which format to use. You need the -f/-F options only if the extention\n"
+ "allows more than one format.\n"
+ "\n"
+ "Examples:\n"
+ " capture a single frame:\n"
+ " streamer -o foobar.ppm\n"
+ "\n"
+ " capture ten frames, two per second:\n"
+ " streamer -t 10 -r 2 -o foobar00.jpeg\n"
+ "\n"
+ " record 30 seconds stereo sound:\n"
+ " streamer -t 0:30 -O soundtrack.wav -F stereo\n"
+ "\n"
+ " record a quicktime movie with sound:\n"
+ " streamer -t 0:30 -o movie.mov -f jpeg -F mono16\n"
+ "\n"
+ " build mpeg movies using mjpegtools + compressed avi file:\n"
+ " streamer -t 0:30 -s 352x240 -r 24 -o movie.avi -f mjpeg -F stereo\n"
+ " lav2wav +p movie.avi | mp2enc -o audio.mp2\n"
+ " lav2yuv +p movie.avi | mpeg2enc -o video.m1v\n"
+ " mplex audio.mp2 video.m1v -o movie.mpg\n"
+ "\n"
+ " build mpeg movies using mjpegtools + raw, uncompressed video:\n"
+ " streamer -t 0:30 -s 352x240 -r 24 -o video.yuv -O audio.wav -F stereo\n"
+ " mp2enc -o audio.mp2 < audio.wav\n"
+ " mpeg2enc -o video.m1v < video.yuv\n"
+ " mplex audio.mp2 video.m1v -o movie.mpg\n"
+ "\n"
+ "-- \n"
+ "(c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>\n");
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void
+find_formats(void)
+{
+ const struct ng_writer *wr = NULL;
+ char *mext = NULL;
+ char *aext = NULL;
+ int w,v=-1,a=-1;
+
+ if (moviename) {
+ mext = strrchr(moviename,'.');
+ if (mext)
+ mext++;
+ }
+ if (audioname) {
+ aext = strrchr(audioname,'.');
+ if (aext)
+ aext++;
+ }
+ for (w = 0; NULL != ng_writers[w]; w++) {
+ wr = ng_writers[w];
+ if (debug)
+ fprintf(stderr,"checking writer %s... ",wr->name);
+ if ((/*!wr->combined && */mext) || NULL != vfmt_name) {
+ if (NULL == wr->video) {
+ if (debug)
+ fprintf(stderr,"no video\n");
+ continue;
+ }
+ for (v = 0; NULL != wr->video[v].name; v++) {
+ if (mext && 0 != strcasecmp(wr->video[v].ext,mext))
+ continue;
+ if (vfmt_name && 0 != strcasecmp(wr->video[v].name,vfmt_name))
+ continue;
+ break;
+ }
+ if (NULL == wr->video[v].name) {
+ if (debug)
+ fprintf(stderr,"video fmt not found [ext=%s,name=%s]\n",
+ mext,vfmt_name);
+ continue;
+ }
+ }
+ if ((!wr->combined && aext) || NULL != afmt_name) {
+ if (NULL == wr->audio) {
+ if (debug)
+ fprintf(stderr,"no audio\n");
+ continue;
+ }
+ for (a = 0; NULL != wr->audio[a].name; a++) {
+ if (!wr->combined &&
+ aext && 0 != strcasecmp(wr->audio[a].ext,aext))
+ continue;
+ if (wr->combined &&
+ mext && 0 != strcasecmp(wr->audio[a].ext,mext))
+ continue;
+ if (afmt_name && 0 != strcasecmp(wr->audio[a].name,afmt_name))
+ continue;
+ break;
+ }
+ if (NULL == wr->audio[a].name) {
+ if (debug)
+ fprintf(stderr,"audio fmt not found [ext=%s,name=%s]\n",
+ wr->combined ? mext : aext, afmt_name);
+ continue;
+ }
+ }
+ if (debug)
+ fprintf(stderr,"ok:");
+ break;
+ }
+ if (NULL != ng_writers[w]) {
+ writer = wr;
+ if (-1 != v) {
+ if (debug)
+ fprintf(stderr," video=%s",wr->video[v].name);
+ video.fmtid = wr->video[v].fmtid;
+ video_priv = wr->video[v].priv;
+ }
+ if (-1 != a) {
+ if (debug)
+ fprintf(stderr," audio=%s",wr->audio[a].name);
+ audio.fmtid = wr->audio[a].fmtid;
+ audio_priv = wr->audio[a].priv;
+ }
+ if (debug)
+ fprintf(stderr,"\n");
+ }
+}
+
+static int
+parse_time(char *time)
+{
+ int hours, minutes, seconds, total=0;
+
+ if (3 == sscanf(time,"%d:%d:%d",&hours,&minutes,&seconds))
+ total = hours * 60*60 + minutes * 60 + seconds;
+ else if (2 == sscanf(time,"%d:%d",&minutes,&seconds))
+ total = minutes * 60 + seconds;
+
+ if (0 != total) {
+ /* hh:mm:ss => framecount */
+ return total * fps / 1000;
+ }
+
+ return atoi(time);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+static void
+do_rec_status(char *message)
+{
+ if (!quiet)
+ fprintf(stderr,"%s \r",message);
+}
+
+static void
+ctrlc(int signal)
+{
+ static char text[] = "^C - one moment please\n";
+ if (!quiet)
+ write(2,text,strlen(text));
+ signaled=1;
+}
+
+int
+main(int argc, char **argv)
+{
+ int c,queued=0;
+ char *raw_length=NULL;
+
+ /* parse options */
+ ng_init();
+ for (;;) {
+ if (-1 == (c = getopt(argc, argv,
+ "hqdp:w:" "o:c:f:r:s:t:n:i:b:j:" "O:C:F:R:")))
+ break;
+ switch (c) {
+ /* general options */
+ case 'q':
+ quiet = 1;
+ break;
+ case 'd':
+ debug++;
+ ng_debug++;
+ break;
+ case 'w':
+ wait_seconds = atoi(optarg);
+ break;
+ case 'p':
+ parallel = atoi(optarg);
+ break;
+
+ /* video options */
+ case 'o':
+ moviename = optarg;
+ break;
+ case 'f':
+ vfmt_name = optarg;
+ break;
+ case 'c':
+ ng_dev.video = optarg;
+ break;
+ case 'r':
+ fps = (int)(atof(optarg) * 1000 + 0.5);
+ break;
+ case 's':
+ if (2 != sscanf(optarg,"%dx%d",&video.width,&video.height))
+ video.width = video.height = 0;
+ break;
+
+ case 't':
+ raw_length = optarg;
+ break;
+ case 'b':
+ bufcount = atoi(optarg);
+ break;
+ case 'j':
+ ng_jpeg_quality = atoi(optarg);
+ break;
+ case 'n':
+ tvnorm = optarg;
+ break;
+ case 'i':
+ input = optarg;
+ break;
+
+ /* audio options */
+ case 'O':
+ audioname = optarg;
+ break;
+ case 'F':
+ afmt_name = optarg;
+ break;
+ case 'C':
+ ng_dev.dsp = optarg;
+ break;
+ case 'R':
+ audio.rate = atoi(optarg);
+ break;
+
+ /* errors / help */
+ case 'h':
+ usage(stdout);
+ exit(0);
+ default:
+ usage(stderr);
+ exit(1);
+ }
+ }
+ if (raw_length)
+ absframes = parse_time(raw_length);
+ find_formats();
+
+ /* sanity checks */
+ if (video.fmtid == VIDEO_NONE && audio.fmtid == AUDIO_NONE) {
+ fprintf(stderr,"neither audio nor video format specified/found\n");
+ exit(1);
+ }
+ if (NULL == writer) {
+ fprintf(stderr,"no output driver found\n");
+ exit(1);
+ }
+ if (audio.fmtid != AUDIO_NONE && !writer->combined && NULL == audioname) {
+ fprintf(stderr,"no audio file name specified\n");
+ exit(1);
+ }
+
+ /* set hooks */
+ rec_status = do_rec_status;
+
+ /* open */
+ if (writer && !quiet)
+ fprintf(stderr,"%s / video: %s / audio: %s\n",writer->name,
+ ng_vfmt_to_desc[video.fmtid],ng_afmt_to_desc[audio.fmtid]);
+
+ if (video.fmtid != VIDEO_NONE) {
+ drv = ng_vid_open(ng_dev.video,NULL,0,&h_drv);
+ if (NULL == drv) {
+ fprintf(stderr,"no grabber device available\n");
+ exit(1);
+ }
+ f_drv = drv->capabilities(h_drv);
+ add_attrs(drv->list_attrs(h_drv));
+ if (!(f_drv & CAN_CAPTURE)) {
+ fprintf(stderr,"%s: capture not supported\n",drv->name);
+ exit(1);
+ }
+ audio_on();
+ audio_init();
+
+ /* modify settings */
+ if (input != NULL)
+ do_va_cmd(2,"setinput",input);
+ if (tvnorm != NULL)
+ do_va_cmd(2,"setnorm",tvnorm);
+ }
+
+ /* init movie writer */
+ ng_ratio_x = video.width;
+ ng_ratio_y = video.height;
+ movie_state = movie_writer_init
+ (moviename, audioname, writer,
+ &video, video_priv, fps,
+ &audio, audio_priv, ng_dev.dsp,
+ bufcount, parallel);
+ if (NULL == movie_state) {
+ fprintf(stderr,"movie writer initialisation failed\n");
+ if (video.fmtid != VIDEO_NONE) {
+ audio_off();
+ drv->close(h_drv);
+ }
+ exit(1);
+ }
+
+ /* catch ^C */
+ signal(SIGINT,ctrlc);
+
+ /* wait for some cameras to wake up and adjust light and all that */
+ if (wait_seconds)
+ sleep(wait_seconds);
+
+ /* main loop */
+ movie_writer_start(movie_state);
+ for (;queued < absframes && !signaled;) {
+ if (video.fmtid != VIDEO_NONE) {
+ /* video */
+ queued = movie_grab_put_video(movie_state,NULL);
+ } else {
+ sleep(1);
+ queued += fps / 1000;
+ }
+ }
+ movie_writer_stop(movie_state);
+
+ /* done */
+ if (video.fmtid != VIDEO_NONE) {
+ audio_off();
+ drv->close(h_drv);
+ }
+ return 0;
+}
diff --git a/console/v4l-conf.c b/console/v4l-conf.c
new file mode 100644
index 0000000..1012d29
--- /dev/null
+++ b/console/v4l-conf.c
@@ -0,0 +1,601 @@
+/*
+ * Set the framebuffer parameters for bttv.
+ * tries to ask the X-Server if $DISPLAY is set,
+ * otherwise it checks /dev/fb0
+ *
+ * (c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * Security checks by okir@caldera.de
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <linux/vt.h>
+#include <linux/fb.h>
+#include <linux/videodev.h>
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#ifndef X_DISPLAY_MISSING
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# ifdef HAVE_LIBXXF86DGA
+# include <X11/extensions/xf86dga.h>
+# endif
+#endif
+
+#ifndef VIDIOC_QUERYCAP
+/* v4l2 not in kernel's videodev.h */
+# include "videodev2.h"
+#endif
+
+struct DISPLAYINFO {
+ int width; /* visible display width (pixels) */
+ int height; /* visible display height (pixels) */
+ int depth; /* color depth */
+ int bpp; /* bit per pixel */
+ int bpl; /* bytes per scanline */
+ unsigned char *base;
+};
+
+int verbose = 1;
+int yuv = 0;
+int user_bpp = 0;
+int user_shift = 0;
+void *user_base = NULL;
+char *display = NULL;
+char *fbdev = NULL;
+char *videodev = "/dev/video0";
+
+/* ---------------------------------------------------------------- */
+/* this is required for MkLinux */
+
+#ifdef __powerpc__
+struct vc_mode {
+ int height;
+ int width;
+ int depth;
+ int pitch;
+ int mode;
+ char name[32];
+ unsigned long fb_address;
+ unsigned long cmap_adr_address;
+ unsigned long cmap_data_address;
+ unsigned long disp_reg_address;
+};
+
+#define VC_GETMODE 0x7667
+#define VC_SETMODE 0x7668
+#define VC_INQMODE 0x7669
+
+#define VC_SETCMAP 0x766a
+#define VC_GETCMAP 0x766b
+
+static int
+is_mklinux(void)
+{
+ int fd;
+ if(-1 == (fd = open("/proc/osfmach3", O_RDONLY)))
+ return 0;
+ close(fd);
+ return 1;
+}
+
+static void
+displayinfo_mklinux(struct DISPLAYINFO *d)
+{
+ struct vc_mode mode;
+ int fd;
+
+ if (verbose)
+ fprintf(stderr,"v4l-conf: using mklinux console driver\n");
+
+ if (-1 == (fd = open("/dev/console",O_RDWR|O_NDELAY))) {
+ fprintf(stderr,"open console: %s\n",strerror(errno));
+ exit(1);
+ }
+ if (-1 == ioctl(fd, VC_GETMODE, (unsigned long)&mode)) {
+ perror("ioctl VC_GETMODE");
+ exit(1);
+ }
+ close(fd);
+ d->width = mode.width;
+ d->height = mode.height;
+ d->bpp = mode.depth;
+ d->bpl = mode.pitch;
+ d->base = (void*)mode.fb_address;
+}
+#endif
+
+/* ---------------------------------------------------------------- */
+
+#ifndef major
+# define major(dev) (((dev) >> 8) & 0xff)
+#endif
+
+static int
+dev_open(const char *device, int major)
+{
+ struct stat stb;
+ int fd;
+
+ if (strncmp(device, "/dev/", 5)) {
+ fprintf(stderr, "error: %s is not a /dev file\n", device);
+ exit(1);
+ }
+
+ /* open & check v4l device */
+ if (-1 == (fd = open(device,O_RDWR))) {
+ fprintf(stderr, "can't open %s: %s\n", device, strerror(errno));
+ exit(1);
+ }
+
+ if (-1 == fstat(fd,&stb)) {
+ fprintf(stderr, "fstat(%s): %s\n", device, strerror(errno));
+ exit(1);
+ }
+ if (!S_ISCHR(stb.st_mode) || (major(stb.st_rdev) != major)) {
+ fprintf(stderr, "%s: wrong device\n", device);
+ exit(1);
+ }
+ return fd;
+}
+
+static void real_user(void)
+{
+ if (-1 == seteuid(getuid())) {
+ perror("seteuid(user)");
+ exit(1);
+ }
+}
+
+static void root_user(void)
+{
+ if (-1 == seteuid(0)) {
+ perror("seteuid(root)");
+ exit(1);
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* get mode info */
+
+#ifndef X_DISPLAY_MISSING
+static void
+displayinfo_x11(Display *dpy, struct DISPLAYINFO *d)
+{
+ Window root;
+ XVisualInfo *info, template;
+ XPixmapFormatValues *pf;
+ XWindowAttributes wts;
+ int found,v,i,n;
+
+ if (verbose)
+ fprintf(stderr,"v4l-conf: using X11 display %s\n",display);
+
+ /* take size from root window */
+ root = DefaultRootWindow(dpy);
+ XGetWindowAttributes(dpy, root, &wts);
+ d->width = wts.width;
+ d->height = wts.height;
+
+ /* look for a usable visual */
+ template.screen = XDefaultScreen(dpy);
+ info = XGetVisualInfo(dpy, VisualScreenMask,&template,&found);
+ v = -1;
+ for (i = 0; v == -1 && i < found; i++)
+ if (info[i].class == TrueColor && info[i].depth >= 15)
+ v = i;
+ for (i = 0; v == -1 && i < found; i++)
+ if (info[i].class == StaticGray && info[i].depth == 8)
+ v = i;
+ if (-1 == v) {
+ fprintf(stderr,"x11: no approximate visual available\n");
+ exit(1);
+ }
+
+ /* get depth + bpp (heuristic) */
+ pf = XListPixmapFormats(dpy,&n);
+ for (i = 0; i < n; i++) {
+ if (pf[i].depth == info[v].depth) {
+ d->depth = pf[i].depth;
+ d->bpp = pf[i].bits_per_pixel;
+ d->bpl = d->bpp * d->width / 8;
+ break;
+ }
+ }
+ if (0 == d->bpp) {
+ fprintf(stderr,"x11: can't detect framebuffer depth\n");
+ exit(1);
+ }
+}
+
+static void
+displayinfo_dga(Display *dpy, struct DISPLAYINFO *d)
+{
+#ifdef HAVE_LIBXXF86DGA
+ int width,bar,foo,major,minor,flags=0;
+ void *base = 0;
+
+ if (!XF86DGAQueryExtension(dpy,&foo,&bar)) {
+ fprintf(stderr,"WARNING: Your X-Server has no DGA support.\n");
+ return;
+ }
+ XF86DGAQueryVersion(dpy,&major,&minor);
+ if (verbose)
+ fprintf(stderr,"dga: version %d.%d\n",major,minor);
+ XF86DGAQueryDirectVideo(dpy,XDefaultScreen(dpy),&flags);
+ if (!(flags & XF86DGADirectPresent)) {
+ fprintf(stderr,"WARNING: No DGA support available for this display.\n");
+ return;
+ }
+ XF86DGAGetVideoLL(dpy,XDefaultScreen(dpy),(int*)&base,&width,&foo,&bar);
+ d->bpl = width * d->bpp/8;
+ d->base = base;
+#else
+ fprintf(stderr,"WARNING: v4l-conf is compiled without DGA support.\n");
+#endif
+}
+#endif
+
+static void
+displayinfo_fbdev(struct DISPLAYINFO *d)
+{
+ struct fb_fix_screeninfo fix;
+ struct fb_var_screeninfo var;
+ struct fb_con2fbmap c2m;
+ struct vt_stat vstat;
+ int fd;
+
+ if (NULL == fbdev) {
+ if (-1 == (fd = open("/dev/tty0",O_RDWR,0))) {
+ fprintf(stderr,"open /dev/tty0: %s\n",strerror(errno));
+ exit(1);
+ }
+ if (-1 == ioctl(fd, VT_GETSTATE, &vstat)) {
+ perror("ioctl VT_GETSTATE");
+ exit(1);
+ }
+ close(fd);
+ c2m.console = vstat.v_active;
+ if (-1 == (fd = open("/dev/fb0",O_RDWR,0))) {
+ fprintf(stderr,"open /dev/fb0: %s\n",strerror(errno));
+ exit(1);
+ }
+ if (-1 == ioctl(fd, FBIOGET_CON2FBMAP, &c2m)) {
+ perror("ioctl FBIOGET_CON2FBMAP");
+ c2m.framebuffer = 0;
+ }
+ close(fd);
+ fprintf(stderr,"map: vt%02d => fb%d\n",c2m.console,c2m.framebuffer);
+ sprintf(fbdev=malloc(16),"/dev/fb%d",c2m.framebuffer);
+ }
+ if (verbose)
+ fprintf(stderr,"v4l-conf: using framebuffer device %s\n",fbdev);
+
+ /* Open frame buffer device, with security checks */
+ fd = dev_open(fbdev, 29 /* VIDEO_MAJOR */);
+ if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,&fix)) {
+ perror("ioctl FBIOGET_FSCREENINFO");
+ exit(1);
+ }
+ if (-1 == ioctl(fd,FBIOGET_VSCREENINFO,&var)) {
+ perror("ioctl FBIOGET_VSCREENINFO");
+ exit(1);
+ }
+ if (fix.type != FB_TYPE_PACKED_PIXELS) {
+ fprintf(stderr,"can handle only packed pixel frame buffers\n");
+ exit(1);
+ }
+ close(fd);
+
+ d->width = var.xres_virtual;
+ d->height = var.yres_virtual;
+ d->bpp = var.bits_per_pixel;
+ d->bpl = fix.line_length;
+ d->base = (unsigned char*)fix.smem_start;
+
+ d->depth = d->bpp;
+ if (var.green.length == 5)
+ d->depth = 15;
+}
+
+/* ---------------------------------------------------------------- */
+/* set mode info */
+
+static int
+displayinfo_v4l2(int fd, struct DISPLAYINFO *d)
+{
+ struct v4l2_capability cap;
+ struct v4l2_framebuffer fb;
+
+ if (-1 == ioctl(fd,VIDIOC_QUERYCAP,&cap)) {
+ if (verbose)
+ fprintf(stderr,"%s [v4l2]: ioctl VIDIOC_QUERYCAP: %s\n",
+ videodev,strerror(errno));
+ return -1;
+ }
+ if (!(cap.flags & V4L2_FLAG_PREVIEW)) {
+ fprintf(stderr,"%s [v4l2]: no overlay support\n",videodev);
+ exit(1);
+ }
+
+ /* read-modify-write v4l screen parameters */
+ if (-1 == ioctl(fd,VIDIOC_G_FBUF,&fb)) {
+ fprintf(stderr,"%s [v4l2]: ioctl VIDIOC_G_FBUF: %s\n",
+ videodev,strerror(errno));
+ exit(1);
+ }
+
+ /* set values */
+ fb.fmt.width = d->width;
+ fb.fmt.height = d->height;
+ fb.fmt.depth = d->bpp;
+ switch (fb.fmt.depth) {
+ case 8: fb.fmt.pixelformat = V4L2_PIX_FMT_HI240; break;
+#if BYTE_ORDER == BIG_ENDIAN
+ case 15: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB555X; break;
+ case 16: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565X; break;
+ case 24: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB24; break;
+ case 32: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB32; break;
+#else
+ case 15: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB555; break;
+ case 16: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565; break;
+ case 24: fb.fmt.pixelformat = V4L2_PIX_FMT_BGR24; break;
+ case 32: fb.fmt.pixelformat = V4L2_PIX_FMT_BGR32; break;
+#endif
+ }
+ if (yuv)
+ fb.fmt.pixelformat = V4L2_PIX_FMT_YUYV;
+ fb.fmt.bytesperline = d->bpl;
+ fb.fmt.sizeimage = fb.fmt.height * fb.fmt.bytesperline;
+ if (NULL != d->base)
+ fb.base[0] = d->base;
+ if (NULL == fb.base[0])
+ fprintf(stderr,
+ "WARNING: couldn't find framebuffer base address, try manual\n"
+ " configuration (\"v4l-conf -a <addr>\")\n");
+
+ if (-1 == ioctl(fd,VIDIOC_S_FBUF,&fb)) {
+ fprintf(stderr,"%s [v4l2]: ioctl VIDIOC_S_FBUF: %s\n",
+ videodev,strerror(errno));
+ if (EPERM == errno && 0 != geteuid())
+ fprintf(stderr,
+ "v4l-conf: You should install me suid root, I need\n"
+ " root priviliges for the VIDIOC_S_FBUF ioctl.\n");
+ exit(1);
+ }
+ if (verbose)
+ fprintf(stderr,"%s [v4l2]: configuration done\n",videodev);
+ return 0;
+}
+
+static int
+displayinfo_v4l(int fd, struct DISPLAYINFO *d)
+{
+ struct video_capability capability;
+ struct video_buffer fbuf;
+
+ if (-1 == ioctl(fd,VIDIOCGCAP,&capability)) {
+ fprintf(stderr,"%s [v4l]: ioctl VIDIOCGCAP: %s\n",
+ videodev,strerror(errno));
+ return -1;
+ }
+ if (!(capability.type & VID_TYPE_OVERLAY)) {
+ fprintf(stderr,"%s [v4l]: no overlay support\n",videodev);
+ exit(1);
+ }
+
+ /* read-modify-write v4l screen parameters */
+ if (-1 == ioctl(fd,VIDIOCGFBUF,&fbuf)) {
+ fprintf(stderr,"%s [v4l]: ioctl VIDIOCGFBUF: %s\n",
+ videodev,strerror(errno));
+ exit(1);
+ }
+
+ /* set values */
+ fbuf.width = d->width;
+ fbuf.height = d->height;
+ fbuf.depth = d->bpp;
+ fbuf.bytesperline = d->bpl;
+ if (NULL != d->base)
+ fbuf.base = d->base;
+ if (NULL == fbuf.base)
+ fprintf(stderr,
+ "WARNING: couldn't find framebuffer base address, try manual\n"
+ " configuration (\"v4l-conf -a <addr>\")\n");
+
+ /* XXX bttv confuses color depth and bits/pixel */
+ if (d->depth == 15)
+ fbuf.depth = 15;
+
+ if (-1 == ioctl(fd,VIDIOCSFBUF,&fbuf)) {
+ fprintf(stderr,"%s [v4l]: ioctl VIDIOCSFBUF: %s\n",
+ videodev,strerror(errno));
+ if (EPERM == errno && 0 != geteuid())
+ fprintf(stderr,
+ "v4l-conf: You should install me suid root, I need\n"
+ " root priviliges for the VIDIOCSFBUF ioctl.\n");
+ exit(1);
+ }
+ if (verbose)
+ fprintf(stderr,"%s [v4l]: configuration done\n",videodev);
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+
+int
+main(int argc, char *argv[])
+{
+ struct DISPLAYINFO d;
+ int fd,c,i,n;
+ char *h;
+#ifndef X_DISPLAY_MISSING
+ Display *dpy;
+#endif
+
+ /* we don't need root proviliges for now ... */
+ real_user();
+
+ /* Make sure fd's 0 1 2 are open, otherwise
+ * we might end up sending perror() messages to
+ * the `device' file */
+ for (i = 0; i < 3; i++) {
+ if (-1 == fcntl(i, F_GETFL, &n))
+ exit(1);
+ }
+
+ /* take defaults from environment */
+ if (NULL != (h = getenv("DISPLAY")))
+ display = h;
+ if (NULL != (h = getenv("FRAMEBUFFER")))
+ fbdev = h;
+
+ /* parse options */
+ for (;;) {
+ if (-1 == (c = getopt(argc, argv, "hyqd:c:b:s:fa:")))
+ break;
+ switch (c) {
+ case 'q':
+ verbose = 0;
+ break;
+ case 'y':
+ yuv = 1;
+ break;
+ case 'd':
+ display = optarg;
+ break;
+ case 'c':
+ videodev = optarg;
+ break;
+ case 'b':
+ user_bpp = atoi(optarg);
+ break;
+ case 's':
+ user_shift = atoi(optarg);
+ if (user_shift < 0 || user_shift > 8192)
+ user_shift = 0;
+ break;
+ case 'f':
+ display = NULL;
+ break;
+ case 'a':
+ if (0 == getuid()) {
+ /* only root is allowed to set this, and it will work only
+ * if v4l-conf can't figure out the correct address itself.
+ * Useful for "post-install bttv ..." */
+ sscanf(optarg,"%p",&user_base);
+ } else {
+ fprintf(stderr,"only root is allowed to use the -a option\n");
+ exit(1);
+ }
+ break;
+ case 'h':
+ default:
+ fprintf(stderr,
+ "usage: %s [ options ] \n"
+ "\n"
+ "options:\n"
+ " -q quiet\n"
+#ifndef X_DISPLAY_MISSING
+ " -d <dpy> X11 Display [%s]\n"
+#endif
+ " -c <dev> video device [%s]\n"
+ " -b <n> displays color depth is <n> bpp\n"
+ " -s <n> shift display by <n> bytes\n"
+ " -f query frame buffer device for info\n"
+ " -a <addr> set framebuffer address to <addr>\n"
+ " (in hex, root only, successful autodetect\n"
+ " will overwrite this address)\n",
+ argv[0],
+#ifndef X_DISPLAY_MISSING
+ display ? display : "none",
+#endif
+ videodev);
+ exit(1);
+ }
+ }
+
+ /* figure out display parameters */
+ memset(&d,0,sizeof(struct DISPLAYINFO));
+#ifdef __powerpc__
+ if (is_mklinux()) {
+ displayinfo_mklinux(&d);
+ } else
+#endif
+#ifndef X_DISPLAY_MISSING
+ if (NULL != display) {
+ /* using X11 */
+ if (display[0] != ':') {
+ fprintf(stderr,"WARNING: remote display `%s' not allowed, ",
+ display);
+ display = strchr(display,':');
+ if (NULL == display) {
+ fprintf(stderr,"exiting");
+ exit(1);
+ } else {
+ fprintf(stderr,"using `%s' instead\n",display);
+ }
+ }
+ if (NULL == (dpy = XOpenDisplay(display))) {
+ fprintf(stderr,"can't open x11 display %s\n",display);
+ exit(1);
+ }
+ displayinfo_x11(dpy,&d);
+ displayinfo_dga(dpy,&d);
+ } else
+#endif
+ {
+ /* try framebuffer device */
+ displayinfo_fbdev(&d);
+ }
+
+ /* fixup struct displayinfo according to the given command line options */
+ if (user_base) {
+ if (NULL == d.base) {
+ fprintf(stderr,"using user provided base address %p\n",user_base);
+ d.base = user_base;
+ } else {
+ fprintf(stderr,"user provided base address %p ignored.\n",
+ user_base);
+ }
+ }
+ if (d.base)
+ d.base += user_shift;
+ if ((user_bpp == 24 || user_bpp == 32) &&
+ (d.bpp == 24 || d.bpp == 32)) {
+ d.bpp = user_bpp;
+ d.bpl = d.width * d.bpp/8;
+ }
+ if ((user_bpp == 15 || user_bpp == 16) &&
+ (d.depth == 15 || d.depth == 16))
+ d.depth = user_bpp;
+
+ if (verbose) {
+ fprintf(stderr,"mode: %dx%d, depth=%d, bpp=%d, bpl=%d, ",
+ d.width,d.height,d.depth,d.bpp,d.bpl);
+ if (NULL != d.base)
+ fprintf(stderr,"base=%p\n",d.base);
+ else
+ fprintf(stderr,"base=unknown\n");
+ }
+
+ /* Set the parameters (needs root) */
+ root_user();
+ fd = dev_open(videodev, 81 /* VIDEO_MAJOR */);
+ if (-1 == displayinfo_v4l2(fd,&d))
+ displayinfo_v4l(fd,&d);
+ close(fd);
+ return 0;
+}
diff --git a/console/webcam.c b/console/webcam.c
new file mode 100644
index 0000000..9a2d600
--- /dev/null
+++ b/console/webcam.c
@@ -0,0 +1,599 @@
+/*
+ * (c) 1998-2002 Gerd Knorr
+ *
+ * capture a image, compress as jpeg and upload to the webserver
+ * using the ftp utility or ssh
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "grab-ng.h"
+#include "jpeglib.h"
+#include "ftp.h"
+#include "parseconfig.h"
+
+
+/* ---------------------------------------------------------------------- */
+/* configuration */
+
+enum mode {
+ FTP = 1,
+ SSH = 2,
+ LOCAL = 3,
+};
+
+char *ftp_host = "www";
+char *ftp_user = "webcam";
+char *ftp_pass = "xxxxxx";
+char *ftp_dir = "public_html/images";
+char *ftp_file = "webcam.jpeg";
+char *ftp_tmp = "uploading.jpeg";
+char *ssh_cmd;
+int ftp_passive = 1;
+int ftp_auto = 0;
+enum mode ftp_mode = FTP;
+int daemonize = 0;
+
+char *grab_text = "webcam %Y-%m-%d %H:%M:%S"; /* strftime */
+char *grab_infofile = NULL;
+int grab_width = 320;
+int grab_height = 240;
+int grab_delay = 3;
+int grab_rotate = 0;
+int grab_top = 0;
+int grab_left = 0;
+int grab_bottom = -1;
+int grab_right = -1;
+int grab_quality= 75;
+int grab_trigger= 0;
+int grab_once = 0;
+char *archive = NULL;
+
+char *grab_input;
+char *grab_norm;
+
+/* ---------------------------------------------------------------------- */
+/* jpeg stuff */
+
+static int
+write_file(int fd, char *data, int width, int height)
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ FILE *fp;
+ int i;
+ unsigned char *line;
+
+ fp = fdopen(fd,"w");
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+ jpeg_stdio_dest(&cinfo, fp);
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, grab_quality, TRUE);
+ jpeg_start_compress(&cinfo, TRUE);
+
+ for (i = 0, line = data; i < height; i++, line += width*3)
+ jpeg_write_scanlines(&cinfo, &line, 1);
+
+ jpeg_finish_compress(&(cinfo));
+ jpeg_destroy_compress(&(cinfo));
+ fclose(fp);
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* capture stuff */
+
+const struct ng_vid_driver *drv;
+void *h_drv;
+struct ng_video_fmt fmt,gfmt;
+struct ng_video_conv *conv;
+void *hconv;
+
+static void
+grab_init(void)
+{
+ struct ng_attribute *attr;
+ int val,i;
+
+ drv = ng_vid_open(ng_dev.video,NULL,0,&h_drv);
+ if (NULL == drv) {
+ fprintf(stderr,"no grabber device available\n");
+ exit(1);
+ }
+ if (!(drv->capabilities(h_drv) & CAN_CAPTURE)) {
+ fprintf(stderr,"device does'nt support capture\n");
+ exit(1);
+ }
+
+ if (grab_input) {
+ attr = ng_attr_byid(drv->list_attrs(h_drv),ATTR_ID_INPUT);
+ val = ng_attr_getint(attr,grab_input);
+ if (-1 == val) {
+ fprintf(stderr,"invalid input: %s\n",grab_input);
+ exit(1);
+ }
+ attr->write(attr,val);
+ }
+ if (grab_norm) {
+ attr = ng_attr_byid(drv->list_attrs(h_drv),ATTR_ID_NORM);
+ val = ng_attr_getint(attr,grab_norm);
+ if (-1 == val) {
+ fprintf(stderr,"invalid norm: %s\n",grab_norm);
+ exit(1);
+ }
+ attr->write(attr,val);
+ }
+
+ /* try native */
+ fmt.fmtid = VIDEO_RGB24;
+ fmt.width = grab_width;
+ fmt.height = grab_height;
+ if (0 == drv->setformat(h_drv,&fmt))
+ return;
+
+ /* check all available conversion functions */
+ fmt.bytesperline = fmt.width*ng_vfmt_to_depth[fmt.fmtid]/8;
+ for (i = 0;;) {
+ conv = ng_conv_find(fmt.fmtid, &i);
+ if (NULL == conv)
+ break;
+ gfmt = fmt;
+ gfmt.fmtid = conv->fmtid_in;
+ gfmt.bytesperline = 0;
+ if (0 == drv->setformat(h_drv,&gfmt)) {
+ fmt.width = gfmt.width;
+ fmt.height = gfmt.height;
+ hconv = conv->init(&fmt,conv->priv);
+ return;
+ }
+ }
+ fprintf(stderr,"can't get rgb24 data\n");
+ exit(1);
+}
+
+static unsigned char*
+grab_one(int *width, int *height)
+{
+ static struct ng_video_buf *cap,*buf;
+
+ if (NULL != buf)
+ ng_release_video_buf(buf);
+ if (NULL == (cap = drv->getimage(h_drv))) {
+ fprintf(stderr,"capturing image failed\n");
+ exit(1);
+ }
+
+ if (NULL != conv) {
+ buf = ng_malloc_video_buf(&fmt,3*fmt.width*fmt.height);
+ conv->frame(hconv,buf,cap);
+ buf->info = cap->info;
+ ng_release_video_buf(cap);
+ } else {
+ buf = cap;
+ }
+
+ *width = buf->fmt.width;
+ *height = buf->fmt.height;
+ return buf->data;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#define MSG_MAXLEN 256
+
+#define CHAR_HEIGHT 11
+#define CHAR_WIDTH 6
+#define CHAR_START 4
+#include "font-6x11.h"
+
+static char*
+get_message(void)
+{
+ static char buffer[MSG_MAXLEN+1];
+ FILE *fp;
+ char *p;
+
+ if (NULL == grab_infofile)
+ return grab_text;
+
+ if (NULL == (fp = fopen(grab_infofile, "r"))) {
+ fprintf(stderr,"open %s: %s\n",grab_infofile,strerror(errno));
+ return grab_text;
+ }
+
+ fgets(buffer, MSG_MAXLEN, fp);
+ fclose(fp);
+ if (NULL != (p = strchr(buffer,'\n')))
+ *p = '\0';
+ return buffer;
+}
+
+static void
+add_text(char *image, int width, int height)
+{
+ time_t t;
+ struct tm *tm;
+ char line[MSG_MAXLEN+1],*ptr;
+ int i,x,y,f,len;
+
+ time(&t);
+ tm = localtime(&t);
+ len = strftime(line,MSG_MAXLEN,get_message(),tm);
+ fprintf(stderr,"%s\n",line);
+
+ for (y = 0; y < CHAR_HEIGHT; y++) {
+ ptr = image + 3 * width * (height-CHAR_HEIGHT-2+y) + 12;
+ for (x = 0; x < len; x++) {
+ f = fontdata[line[x] * CHAR_HEIGHT + y];
+ for (i = CHAR_WIDTH-1; i >= 0; i--) {
+ if (f & (CHAR_START << i)) {
+ ptr[0] = 255;
+ ptr[1] = 255;
+ ptr[2] = 255;
+ }
+ ptr += 3;
+ }
+ }
+ }
+}
+
+static unsigned char *
+rotate_image(unsigned char * in, int *wp, int *hp, int rot,
+ int top, int left, int bottom, int right)
+{
+ static unsigned char * rotimg = NULL;
+
+ int i, j;
+
+ int w = *wp;
+ int ow = (right-left);
+ int oh = (bottom-top);
+
+ if (rotimg == NULL && (rotimg = malloc(ow*oh*3)) == NULL ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ switch ( rot ) {
+ default:
+ case 0:
+ for (j = 0; j < oh; j++) {
+ int ir = (j+top)*w+left;
+ int or = j*ow;
+ for (i = 0; i < ow; i++) {
+ rotimg[3*(or + i)] = in[3*(ir+i)];
+ rotimg[3*(or + i)+1] = in[3*(ir+i)+1];
+ rotimg[3*(or + i)+2] = in[3*(ir+i)+2];
+ }
+ }
+ *wp = ow;
+ *hp = oh;
+ break;
+ case 1:
+ for (i = 0; i < ow; i++) {
+ int rr = (ow-1-i)*oh;
+ int ic = i+left;
+ for (j = 0; j < oh; j++) {
+ rotimg[3*(rr+j)] = in[3*((j+top)*w+ic)];
+ rotimg[3*(rr+j)+1] = in[3*((j+top)*w+ic)+1];
+ rotimg[3*(rr+j)+2] = in[3*((j+top)*w+ic)+2];
+ }
+ }
+ *wp = oh;
+ *hp = ow;
+ break;
+ case 2:
+ for (j = 0; j < oh; j++) {
+ int ir = (j+top)*w;
+ for (i = 0; i < ow; i++) {
+ rotimg[3*((oh-1-j)*ow + (ow-1-i))] = in[3*(ir+i+left)];
+ rotimg[3*((oh-1-j)*ow + (ow-1-i))+1] = in[3*(ir+i+left)+1];
+ rotimg[3*((oh-1-j)*ow + (ow-1-i))+2] = in[3*(ir+i+left)+2];
+ }
+ }
+ *wp = ow;
+ *hp = oh;
+ break;
+ case 3:
+ for (i = 0; i < ow; i++) {
+ int rr = i*oh;
+ int ic = i+left;
+ rr += oh-1;
+ for (j = 0; j < oh; j++) {
+ rotimg[3*(rr-j)] = in[3*((j+top)*w+ic)];
+ rotimg[3*(rr-j)+1] = in[3*((j+top)*w+ic)+1];
+ rotimg[3*(rr-j)+2] = in[3*((j+top)*w+ic)+2];
+ }
+ }
+ *wp = oh;
+ *hp = ow;
+ break;
+ }
+ return rotimg;
+}
+
+static unsigned int
+compare_images(unsigned char *last, unsigned char *current,
+ int width, int height)
+{
+ unsigned char *p1 = last;
+ unsigned char *p2 = current;
+ int avg, diff, max, i = width*height*3;
+
+ for (max = 0, avg = 0; --i; p1++,p2++) {
+ diff = (*p1 < *p2) ? (*p2 - *p1) : (*p1 - *p2);
+ avg += diff;
+ if (diff > max)
+ max = diff;
+ }
+ avg = avg / width / height;
+ fprintf(stderr,"compare: max=%d,avg=%d\n",max,avg);
+ /* return avg */
+ return max;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void ssh_upload(char *filename)
+{
+ unsigned char ssh_buf[4096];
+ FILE *sshp, *imgdata;
+ int len;
+
+ if ((sshp=popen(ssh_cmd, "w")) == NULL) {
+ perror("open");
+ exit(1);
+ }
+ if ((imgdata = fopen(filename,"rb"))==NULL) {
+ perror("fopen");
+ exit(1);
+ }
+ for (;;) {
+ len = fread(ssh_buf,1,sizeof(ssh_buf),imgdata);
+ if (len <= 0)
+ break;
+ fwrite(ssh_buf,1,len,sshp);
+ }
+ fclose(imgdata);
+ pclose(sshp);
+}
+
+int
+main(int argc, char *argv[])
+{
+ unsigned char *image,*val,*gimg,*lastimg = NULL;
+ char filename[1024], *tmpdir;
+ int width, height, i, fh;
+
+ /* read config */
+ if (argc > 1) {
+ strcpy(filename,argv[1]);
+ } else {
+ sprintf(filename,"%s/%s",getenv("HOME"),".webcamrc");
+ }
+ fprintf(stderr,"reading config file: %s\n",filename);
+ cfg_parse_file(filename);
+ ng_init();
+
+ if (NULL != (val = cfg_get_str("ftp","host")))
+ ftp_host = val;
+ if (NULL != (val = cfg_get_str("ftp","user")))
+ ftp_user = val;
+ if (NULL != (val = cfg_get_str("ftp","pass")))
+ ftp_pass = val;
+ if (NULL != (val = cfg_get_str("ftp","dir")))
+ ftp_dir = val;
+ if (NULL != (val = cfg_get_str("ftp","file")))
+ ftp_file = val;
+ if (NULL != (val = cfg_get_str("ftp","tmp")))
+ ftp_tmp = val;
+ if (-1 != (i = cfg_get_int("ftp","passive")))
+ ftp_passive = i;
+ if (-1 != (i = cfg_get_int("ftp","auto")))
+ ftp_auto = i;
+ if (-1 != (i = cfg_get_int("ftp","debug")))
+ ftp_debug = i;
+ if (-1 != (i = cfg_get_int("ftp","local")))
+ if (i)
+ ftp_mode = LOCAL;
+ if (-1 != (i = cfg_get_int("ftp","ssh")))
+ if (i)
+ ftp_mode = SSH;
+
+ if (NULL != (val = cfg_get_str("grab","device")))
+ ng_dev.video = val;
+ if (NULL != (val = cfg_get_str("grab","text")))
+ grab_text = val;
+ if (NULL != (val = cfg_get_str("grab","infofile")))
+ grab_infofile = val;
+ if (NULL != (val = cfg_get_str("grab","input")))
+ grab_input = val;
+ if (NULL != (val = cfg_get_str("grab","norm")))
+ grab_norm = val;
+ if (-1 != (i = cfg_get_int("grab","width")))
+ grab_width = i;
+ if (-1 != (i = cfg_get_int("grab","height")))
+ grab_height = i;
+ if (-1 != (i = cfg_get_int("grab","delay")))
+ grab_delay = i;
+ if (-1 != (i = cfg_get_int("grab","rotate")))
+ grab_rotate = i;
+ if (-1 != (i = cfg_get_int("grab","top")))
+ grab_top = i;
+ if (-1 != (i = cfg_get_int("grab","left")))
+ grab_left = i;
+ grab_bottom = cfg_get_int("grab","bottom");
+ grab_right = cfg_get_int("grab","right");
+ if (-1 != (i = cfg_get_int("grab","quality")))
+ grab_quality = i;
+ if (-1 != (i = cfg_get_int("grab","trigger")))
+ grab_trigger = i;
+ if (-1 != (i = cfg_get_int("grab","once")))
+ grab_once = i;
+ if (NULL != (val = cfg_get_str("grab","archive")))
+ archive = val;
+
+ if ( grab_top < 0 ) grab_top = 0;
+ if ( grab_left < 0 ) grab_left = 0;
+ if ( grab_bottom > grab_height ) grab_bottom = grab_height;
+ if ( grab_right > grab_width ) grab_right = grab_width;
+ if ( grab_bottom < 0 ) grab_bottom = grab_height;
+ if ( grab_right < 0 ) grab_right = grab_width;
+ if ( grab_top >= grab_bottom ) grab_top = 0;
+ if ( grab_left >= grab_right ) grab_left = 0;
+
+ /* init everything */
+ grab_init();
+ tmpdir = (NULL != getenv("TMPDIR")) ? getenv("TMPDIR") : "/tmp";
+ switch (ftp_mode) {
+ case LOCAL:
+ if (ftp_dir != NULL && ftp_dir[0] != '\0' ) {
+ char * t = malloc(strlen(ftp_tmp)+strlen(ftp_dir)+2);
+ sprintf(t, "%s/%s", ftp_dir, ftp_tmp);
+ ftp_tmp = t;
+
+ t = malloc(strlen(ftp_file)+strlen(ftp_dir)+2);
+ sprintf(t, "%s/%s", ftp_dir, ftp_file);
+ ftp_file = t;
+ }
+ break;
+ case FTP:
+ ftp_init(ftp_auto,ftp_passive);
+ ftp_connect(ftp_host,ftp_user,ftp_pass,ftp_dir);
+ break;
+ case SSH:
+ ssh_cmd = malloc(strlen(ftp_user)+strlen(ftp_host)+strlen(ftp_tmp)*2+
+ strlen(ftp_dir)+strlen(ftp_file)+32);
+ sprintf(ssh_cmd, "ssh %s@%s \"cat >%s && mv %s %s/%s\"",
+ ftp_user,ftp_host,ftp_tmp,ftp_tmp,ftp_dir,ftp_file);
+ break;
+ }
+
+ /* print config */
+ fprintf(stderr,"video4linux webcam v1.4 - (c) 1998-2002 Gerd Knorr\n");
+ fprintf(stderr,"grabber config:\n size %dx%d [%s]\n",
+ fmt.width,fmt.height,ng_vfmt_to_desc[gfmt.fmtid]);
+ fprintf(stderr," input %s, norm %s, jpeg quality %d\n",
+ grab_input,grab_norm, grab_quality);
+ fprintf(stderr," rotate=%d, top=%d, left=%d, bottom=%d, right=%d\n",
+ grab_rotate, grab_top, grab_left, grab_bottom, grab_right);
+ switch (ftp_mode) {
+ case LOCAL:
+ fprintf(stderr,"write config:\n local transfer %s => %s\n",
+ ftp_tmp,ftp_file);
+ break;
+ case FTP:
+ fprintf(stderr,"ftp config:\n %s@%s:%s\n %s => %s\n",
+ ftp_user,ftp_host,ftp_dir,ftp_tmp,ftp_file);
+ break;
+ case SSH:
+ fprintf(stderr,"ssh config:\n %s@%s:%s\n %s => %s\n",
+ ftp_user,ftp_host,ftp_dir,ftp_tmp,ftp_file);
+ break;
+ }
+
+ /* run as daemon - detach from terminal */
+ if (!ftp_debug && daemonize) {
+ switch (fork()) {
+ case -1:
+ perror("fork");
+ exit(1);
+ case 0:
+ close(0); close(1); close(2); setsid();
+ break;
+ default:
+ exit(0);
+ }
+ }
+
+ /* main loop */
+ for (;;) {
+ /* grab a new one */
+ gimg = grab_one(&width,&height);
+ image = rotate_image(gimg, &width, &height, grab_rotate,
+ grab_top, grab_left, grab_bottom, grab_right);
+
+ if (grab_trigger) {
+ /* look if it has changed */
+ if (NULL != lastimg) {
+ i = compare_images(lastimg,image,width,height);
+ if (i < grab_trigger)
+ continue;
+ } else {
+ lastimg = malloc(width*height*3);
+ }
+ memcpy(lastimg,image,width*height*3);
+ }
+
+ /* ok, label it and upload */
+ add_text(image,width,height);
+ switch (ftp_mode) {
+ case LOCAL:
+ if (-1 == (fh = open(ftp_tmp,O_CREAT|O_WRONLY|O_TRUNC,0666))) {
+ fprintf(stderr,"open %s: %s\n",ftp_tmp,strerror(errno));
+ exit(1);
+ }
+ write_file(fh, image, width, height);
+ if (rename(ftp_tmp, ftp_file) ) {
+ fprintf(stderr, "can't move %s -> %s\n", ftp_tmp, ftp_file);
+ }
+ break;
+ case FTP:
+ case SSH:
+ sprintf(filename,"%s/webcamXXXXXX",tmpdir);
+ if (-1 == (fh = mkstemp(filename))) {
+ perror("mkstemp");
+ exit(1);
+ }
+ write_file(fh, image, width, height);
+ if (FTP == ftp_mode) {
+ if (!ftp_connected)
+ ftp_connect(ftp_host,ftp_user,ftp_pass,ftp_dir);
+ ftp_upload(filename,ftp_file,ftp_tmp);
+ }
+ if (SSH == ftp_mode)
+ ssh_upload(filename);
+ unlink(filename);
+ break;
+ }
+ if (archive) {
+ time_t t;
+ struct tm *tm;
+
+ time(&t);
+ tm = localtime(&t);
+ strftime(filename,sizeof(filename)-1,archive,tm);
+ if (-1 == (fh = open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666))) {
+ fprintf(stderr,"open %s: %s\n",ftp_tmp,strerror(errno));
+ exit(1);
+ }
+ write_file(fh, image, width, height);
+ }
+
+ if (grab_once)
+ break;
+ if (grab_delay > 0)
+ sleep(grab_delay);
+ }
+ if (FTP == ftp_mode) {
+ ftp_send(1,"bye");
+ ftp_recv();
+ }
+ return 0;
+}

Privacy Policy