From 470457e22a1b5537013603d5e367c51e47bb61bf Mon Sep 17 00:00:00 2001 From: James Date: Mon, 5 May 2014 17:50:20 +0100 Subject: fish --- Makefile | 40 +++ dispatch.c | 233 +++++++++++++++ input.c | 130 ++++++++ kmd.c | 89 ++++++ layout.c | 156 ++++++++++ lcd.c | 328 ++++++++++++++++++++ libdpf/Makefile | 12 + libdpf/bootload.c | 379 ++++++++++++++++++++++++ libdpf/dpf.h | 189 ++++++++++++ libdpf/dpflib.c | 436 +++++++++++++++++++++++++++ libdpf/flash.h | 19 ++ libdpf/fwload.c | 121 ++++++++ libdpf/rawusb.c | 195 ++++++++++++ libdpf/scsi.c | 412 ++++++++++++++++++++++++++ libdpf/sglib.h | 19 ++ libdpf/spiflash.h | 30 ++ libdpf/usbuser.h | 29 ++ lirc.h | 168 +++++++++++ map.c | 167 +++++++++++ output.c | 441 +++++++++++++++++++++++++++ output_map.h | 871 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ project.h | 57 ++++ prototypes.h | 52 ++++ status.c | 141 +++++++++ video_switch.c | 365 +++++++++++++++++++++++ 25 files changed, 5079 insertions(+) create mode 100644 Makefile create mode 100644 dispatch.c create mode 100644 input.c create mode 100644 kmd.c create mode 100644 layout.c create mode 100644 lcd.c create mode 100644 libdpf/Makefile create mode 100644 libdpf/bootload.c create mode 100644 libdpf/dpf.h create mode 100644 libdpf/dpflib.c create mode 100644 libdpf/flash.h create mode 100644 libdpf/fwload.c create mode 100644 libdpf/rawusb.c create mode 100644 libdpf/scsi.c create mode 100644 libdpf/sglib.h create mode 100644 libdpf/spiflash.h create mode 100644 libdpf/usbuser.h create mode 100644 lirc.h create mode 100644 map.c create mode 100644 output.c create mode 100644 output_map.h create mode 100644 project.h create mode 100644 prototypes.h create mode 100644 status.c create mode 100644 video_switch.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..76953c5 --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +CSRCS=kmd.c status.c lcd.c input.c dispatch.c output.c map.c layout.c video_switch.c + + +WHERE=$(shell hostname | sed -e 's/^.*medaka.james.local/BROMIUM/g' -e 's/^.*panaceas.*/HOME/g' ) + +CFLAGS=-g -Wall -D${WHERE} -Wno-unused + +all: kmd + +%.o: %.c + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $^ + +OBJS=${CSRCS:%.c=%.o} + + +kmd: ${OBJS} libdpf/libdpf.a + $(CC) -o $@ ${OBJS} libdpf/libdpf.a -lusb + + +libdpf/libdpf.a: + make -C libdpf + +clean: + make -C libdpf clean + rm -f *.o kmd *~ + +protos: + echo > prototypes.h + cproto -e -v ${CSRCS} >> prototypes.tmp + mv -f prototypes.tmp prototypes.h + +install: kmd + sleep 1 + rsync -varP kmd /usr/local/bin/kmd + killall -9 kmd + telinit q + + + + diff --git a/dispatch.c b/dispatch.c new file mode 100644 index 0000000..ec8da7b --- /dev/null +++ b/dispatch.c @@ -0,0 +1,233 @@ +#include "project.h" + +#define N_SCREENS 4 +#define GRACE 10 + +#define W 2048 +#define H 2048 + +static int current_computer = 0; +static int keys_down; +static int current_x, current_y; +static int mouse_button[0x10]; + + +void +dispatch_key (int key, int ud) +{ + static int keys[KEY_MAX]; + +// ignore autorepeat + if (ud == 2) + return; + + if (keys[key] != ud) + { + keys[key] = ud; + if (ud) + keys_down++; + else + keys_down--; + } + + if (ud && keys[KEY_RIGHTALT] && (key == KEY_RIGHTMETA)) + { + lcd_off(); + output_reset (); + status_reset (); + } + + if (ud && keys[KEY_LEFTALT] && (key == KEY_LEFTMETA)) + layout_toggle_lock (current_computer); + + send_keyboard_event (current_computer, key, ud); +} + +void +dispatch_mouse_button (int button, int ud) +{ + + if (mouse_button[button] != ud) + { + mouse_button[button] = ud; + if (ud) + keys_down++; + else + keys_down--; + } + + send_mouse_event (current_computer, current_x, current_y, 0, + mouse_button[0], mouse_button[2], mouse_button[1]); +} + + +void +dispatch_mouse_wheel (int d) +{ + send_mouse_event (current_computer, current_x, current_y, d, + mouse_button[0], mouse_button[2], mouse_button[1]); +} + +static int +accell (int a) +{ + + int m = a / 10; + + if (m < 0) + m = -m; + if (m == 0) + m = 1; + if (m > 4) + m = 4; + + return m * a; +} + + +void +dispatch_mouse_motion (int rx, int ry) +{ + + ry += ry; + + rx = accell (rx); + ry = accell (ry); + + current_x += rx; + current_y += ry; + + if (current_y < 0) + current_y = 0; + if (current_y >= H) + current_y = H - 1; + + if (current_x < 0) + { + if (map_grace_left (current_computer)) + { + if (keys_down) + { + current_x = 0; + } + else if (current_x < -GRACE) + { + if (map_switch_left (¤t_computer)) + { + current_x = W - 1; + } + else + { + current_x = -GRACE; + } + } + } + else + { + if (map_switch_left (¤t_computer)) + { + current_x = W - 1; + } + else + { + current_x = 0; + } + } + } + + if (current_x >= W) + { + if (map_grace_right (current_computer)) + { + if (keys_down) + { + current_x = W - 1; + } + else if (current_x > (W + GRACE)) + { + if (map_switch_right (¤t_computer)) + { + current_x = 0; + } + else + { + current_x = W + GRACE; + } + } + } + else + { + if (map_switch_right (¤t_computer)) + { + current_x = 0; + } + else + { + current_x = W - 1; + } + } + } + + send_mouse_event (current_computer, current_x, current_y, 0, + mouse_button[0], mouse_button[2], mouse_button[1]); +} + + +void +dispatch_event (struct input_event *ev) +{ + static int rel_x, rel_y, rel_wheel; + + if (ev->type == EV_REL) + { + + if (ev->code == REL_X) + rel_x = ev->value; + if (ev->code == REL_Y) + rel_y = ev->value; + if (ev->code == REL_WHEEL) + rel_wheel = ev->value; + } + else if (ev->type == EV_KEY) + { + switch (ev->code) + { + case BTN_LEFT: + case BTN_RIGHT: + case BTN_MIDDLE: + case BTN_SIDE: + case BTN_EXTRA: + case BTN_FORWARD: + case BTN_BACK: + case BTN_TASK: + dispatch_mouse_button (ev->code - BTN_LEFT, ev->value); + break; + default: + dispatch_key (ev->code, ev->value); + } + } + else if (ev->type == EV_SYN) + { + if (rel_x || rel_y) + { + dispatch_mouse_motion (rel_x, rel_y); + rel_x = 0; + rel_y = 0; + } + if (rel_wheel) + { + dispatch_mouse_wheel (rel_wheel); + rel_wheel = 0; + } + + } + +//print_event(ev); + +} + +void +dispatch_init (void) +{ + current_computer = map_init (); +} diff --git a/input.c b/input.c new file mode 100644 index 0000000..bb1d82d --- /dev/null +++ b/input.c @@ -0,0 +1,130 @@ +#include "project.h" + +input_dev_t *input_devs = NULL; + + +static void +set_nonblocking (int fd) +{ + long arg = 0; + arg = fcntl (fd, F_GETFL, arg); + arg |= O_NONBLOCK; + fcntl (fd, F_SETFL, arg); +} + +static char * +input_dev_name (int i) +{ + static char fn[1024]; + sprintf (fn, "/dev/input/event%d", i); + return fn; +} + +static input_dev_t * +get_input_dev (int id) +{ + input_dev_t *ret; + int fd; + unsigned short ids[4]; + char *fn; + + for (ret = input_devs; ret; ret = ret->next) + if (ret->id == id) + return ret; + + + fn = input_dev_name (id); + + fd = open (fn, O_RDWR); + if (fd < 0) + return NULL; + + set_nonblocking (fd); + + ret = malloc (sizeof (*ret)); + bzero (ret, sizeof (*ret)); + + ret->id = id; + ret->fd = fd; + + ioctl (fd, EVIOCGID, ids); + + if ((ids[ID_VENDOR] == 0xea0) && (ids[ID_PRODUCT] == 0x2211)) + ret->blacklistid = 1; + + printf + ("New input device %s (%d) bus 0x%x vendor 0x%x product 0x%x version 0x%x\n", + fn, id, ids[ID_BUS], ids[ID_VENDOR], ids[ID_PRODUCT], ids[ID_VERSION]); + + ret->next = input_devs; + input_devs = ret; + + return ret; +} + +static void +free_input_dev (input_dev_t * d) +{ + printf ("Removid input device %s (%d)\n", input_dev_name (d->id), d->id); + + if (d->fd > -1) + close (d->fd); + free (d); +} + + +void +scan_input_devs (void) +{ + DIR *dir = opendir ("/dev/input"); + struct dirent *de; + int i; + input_dev_t *id, **idp; + int version; + + + for (idp = &input_devs; (id = *idp);) + { + id->present = 0; + if (access (input_dev_name (id->id), F_OK) + || ioctl (id->fd, EVIOCGVERSION, &version)) + { + *idp = id->next; + free_input_dev (id); + } + else + { + idp = &id->next; + } + } + + if (dir) + { + while ((de = readdir (dir))) + { + if (!strcmp (de->d_name, "event")) + continue; + i = atoi (de->d_name + 5); + id = get_input_dev (i); + if (id) + id->present = 1; + } + closedir (dir); + } + + + for (idp = &input_devs; (id = *idp);) + { + if (!id->present) + { + *idp = id->next; + free_input_dev (id); + } + else + { + idp = &id->next; + } + } + + +} diff --git a/kmd.c b/kmd.c new file mode 100644 index 0000000..ca2a66a --- /dev/null +++ b/kmd.c @@ -0,0 +1,89 @@ +#include "project.h" + + + + +static void +check_bored (int b) +{ + static int lcd = 1; + + if ((b > 8) && (lcd)) + { + lcd_off (); + lcd = 0; + } + + if ((b == 0) && (!lcd)) + { + lcd_on (); + lcd = 1; + } +} + + +#define SCAN_TIME 4 + + +int +main (int argc, char *argv[]) +{ + struct input_event ev; + struct timeval tv = { 0 }; + fd_set rfds; + int n; + int bored = 0; + + usb_init (); + + status_init (); + + dispatch_init (); + + scan_output_devs (1); + for (;;) + { + input_dev_t *id; + + if (!tv.tv_usec && !tv.tv_sec) + { + scan_input_devs (); + scan_output_devs (0); + tv.tv_sec = SCAN_TIME; + bored++; + check_bored (bored); + } + + + FD_ZERO (&rfds); + n = 0; + for (id = input_devs; id; id = id->next) + { + if (id->fd == -1 || id->blacklistid) + continue; + FD_SET (id->fd, &rfds); + if (id->fd >= n) + n = id->fd + 1; + } + + if (!select (n, &rfds, NULL, NULL, &tv)) + continue; + + for (id = input_devs; id; id = id->next) + { + if (id->fd == -1 || id->blacklistid) + continue; + if (!FD_ISSET (id->fd, &rfds)) + continue; + if (read (id->fd, &ev, sizeof (struct input_event)) == + sizeof (struct input_event)) + { + dispatch_event (&ev); + bored = 0; + check_bored (bored); + } + } + } + + return 0; +} diff --git a/layout.c b/layout.c new file mode 100644 index 0000000..32f1cdf --- /dev/null +++ b/layout.c @@ -0,0 +1,156 @@ +#include "project.h" + +static int computer_to_console[N_COMPUTER + 1]; +static int console_to_computer[N_CONSOLE + 1]; +static int console_locked[N_CONSOLE + 1]; + +static MM *mm; + +int +layout_computer_to_console (int computer) +{ + if ((computer < 1) || (computer > N_COMPUTER)) + return 0; + return computer_to_console[computer]; + +} + +int +layout_console_to_computer (int console) +{ + if ((console < 1) || (console > N_CONSOLE)) + return 0; + return console_to_computer[console]; +} + +#ifdef LAYOUT_NULL +int +layout_possible (int console, int computer) +{ + if ((console < 1) || (console > N_CONSOLE)) + return 0; + if ((computer < 1) || (computer > N_COMPUTER)) + return 0; + + if (console_locked[console]) + return 0; + +return 1; +} +#elif defined(LAYOUT_HOME) +int +layout_possible (int console, int computer) +{ + if ((console < 1) || (console > N_CONSOLE)) + return 0; + if ((computer < 1) || (computer > N_COMPUTER)) + return 0; + + if (console_locked[console]) + return 0; + + switch (computer) + { + case 1: + case 2: + case 3: + if (console != 1) + return 0; + return 1; + } + + switch (console) + { + case 1: + if (computer > 3) + return 0; + return 1; + } + + + return 1; +} +#endif + +void +layout_map (int console, int computer) +{ + int oc; + + if ((console < 1) || (console > N_CONSOLE)) + return; + if ((computer < 1) || (computer > N_COMPUTER)) + return; + + oc = console_to_computer[console]; + + if ((oc > 0) && (oc <= N_COMPUTER)) + { + computer_to_console[oc] = 0; + } + computer_to_console[computer] = console; + console_to_computer[console] = computer; + +#ifdef LAYOUT_HOME + switch (console) + { + case 1: + VS_set (mm, 4 - computer); + break; + case 2: + MM_set (mm, computer - 3, -1); + break; + case 3: + MM_set (mm, -1, computer - 3); + break; + } +#endif + +} + +void +layout_status (int active_computer) +{ + int i; + for (i = 1; i <= N_COMPUTER; ++i) + { + int console = layout_computer_to_console (i); + status_draw_computer (i, console_locked[console], console, + active_computer == i, 0); + } + + for (i = 1; i <= N_CONSOLE; ++i) + { + int computer = layout_console_to_computer (i); + status_draw_console (i, console_locked[i], computer, + active_computer == computer, 0); + } +} + + +void +layout_toggle_lock (int computer) +{ + int console = layout_computer_to_console (computer); + if ((console < 1) || (console > N_CONSOLE)) + return; + + console_locked[console] = !console_locked[console]; + layout_status (computer); +} + + +int +layout_init (void) +{ + mm = MM_open (); + + layout_map (1, 3); + layout_map (2, 4); + layout_map (3, 5); + + + layout_status (3); + + return 3; +} diff --git a/lcd.c b/lcd.c new file mode 100644 index 0000000..cd652b3 --- /dev/null +++ b/lcd.c @@ -0,0 +1,328 @@ +#include +#include +#include +#include +#include +#include + +#include "libdpf/dpf.h" + +typedef struct +{ + unsigned char R; + unsigned char G; + unsigned char B; + unsigned char A; +} RGBA; + +static DPFContext *dpf; +static RGBA *fb; +static RGBA *fbo; +static uint8_t *fb_16; + + + + +void +lcd_on (void) +{ + DPFValue val; + if (!dpf) + return; + val.type = TYPE_INTEGER; + val.value.integer = 7; + dpf_setproperty (dpf, PROPERTY_BRIGHTNESS, &val); +} + + + +void +lcd_off (void) +{ + DPFValue val; + if (!dpf) + return; + val.type = TYPE_INTEGER; + val.value.integer = 0; + dpf_setproperty (dpf, PROPERTY_BRIGHTNESS, &val); +} + + + + +void +lcd_close (void) +{ + if (!dpf) + return; + dpf_close (dpf); + dpf = NULL; + free (fb); + free (fb_16); +} + +#define _RGB565_0(p) \ + (( (((p)->R) & 0xf8) ) | ((((p)->G) & 0xe0) >> 5)) +#define _RGB565_1(p) \ + (( (((p)->G) & 0x1c) << 3 ) | ((((p)->B) & 0xf8) >> 3)) + + +static int +find_dr (short *rect) +{ + RGBA *p = fb, *po = fbo; + int e; + int x, y; + rect[0] = dpf->width; + rect[1] = dpf->height; + rect[2] = 0; + rect[3] = 0; + + for (y = 0; y < dpf->height; y++) + { + e = 0; + for (x = 0; x < dpf->width; x++) + { + if (memcmp (p, po, 4)) + { + if (x < rect[0]) + rect[0] = x; + if (x >= rect[2]) + rect[2] = x + 1; + e = 1; + } + p++; + po++; + } + if (e) + { + if (y < rect[1]) + rect[1] = y; + if (y >= rect[3]) + rect[3] = y + 1; + } + } + return rect[2]; + +} + +static void +blit (int x1, int y1, int x2, int y2) +{ + int r; + int c; + short rect[4] = { x1, y1, x2, y2 }; + + RGBA *p, *rp, *po, *rpo; + uint8_t *p_16; + + if (!dpf) + return; + + if (x1 == -1) + { + if (!find_dr (rect)) + return; + } + + rp = fb + (dpf->width * rect[1]) + rect[0]; + rpo = fbo + (dpf->width * rect[1]) + rect[0]; + + p_16 = fb_16; + + for (r = rect[1]; r < rect[3]; r++) + { + p = rp; + po = rpo; + for (c = rect[0]; c < rect[2]; c++) + { + *p_16++ = _RGB565_0 (p); + *p_16++ = _RGB565_1 (p); + memcpy (po, p, 4); + p++; + po++; + } + rp += dpf->width; + } + + //printf ("%d %d %d %d\n", rect[0], rect[1], rect[2], rect[3]); + + + dpf_screen_blit (dpf, fb_16, rect); +} + + +void +lcd_vline (int x, int y1, int y2, int r, int g, int b) +{ + RGBA c = {.R = r,.G = g,.B = b }; + RGBA *p = fb; + int y; + + if (!dpf) + return; + + if (y1 > y2) + { + y = y1; + y1 = y2; + y2 = y; + } + + p += x + y1 * dpf->width; + + + for (y = y1; y <= y2; ++y) + { + memcpy (p, &c, sizeof (c)); + p += dpf->width; + } + +} + +void +lcd_hline (int y, int x1, int x2, int r, int g, int b) +{ + RGBA c = {.R = r,.G = g,.B = b }; + RGBA *p = fb; + int x; + + if (!dpf) + return; + + + if (x1 > x2) + { + x = x1; + x1 = x2; + x2 = x; + } + + p += x1 + y * dpf->width; + + for (x = x1; x <= x2; ++x) + { + memcpy (p, &c, sizeof (c)); + p++; + } + +} + +void +lcd_box (int x1, int y1, int x2, int y2, int r, int g, int b) +{ + lcd_vline (x1, y1, y2, r, g, b); + blit (x1, y1, x1 + 1, y2 + 1); + lcd_vline (x2, y1, y2, r, g, b); + blit (x2, y1, x2 + 1, y2 + 1); + lcd_hline (y1, x1 + 1, x2 - 1, r, g, b); + blit (x1 + 1, y1, x2, y1 + 1); + lcd_hline (y2, x1 + 1, x2 - 1, r, g, b); + blit (x1 + 1, y2, x2, y2 + 1); +} + +#define LCD_SS_A (1 << 0) +#define LCD_SS_B (1 << 1) +#define LCD_SS_C (1 << 2) +#define LCD_SS_D (1 << 3) +#define LCD_SS_E (1 << 4) +#define LCD_SS_F (1 << 5) +#define LCD_SS_G (1 << 6) + +void +lcd_ss (int v, int x1, int y1, int w, int h) +{ + int x2 = x1 + w; + int y2 = y1 + (h / 2); + int y3 = y1 + h; + + int lut[] = + { LCD_SS_A | LCD_SS_B | LCD_SS_C | LCD_SS_D | LCD_SS_E | LCD_SS_F, + LCD_SS_B | LCD_SS_C, + LCD_SS_A | LCD_SS_B | LCD_SS_D | LCD_SS_E | LCD_SS_G, + LCD_SS_A | LCD_SS_B | LCD_SS_C | LCD_SS_D | LCD_SS_G, + LCD_SS_B | LCD_SS_C | LCD_SS_F | LCD_SS_G, + LCD_SS_A | LCD_SS_C | LCD_SS_D | LCD_SS_F | LCD_SS_G, + LCD_SS_A | LCD_SS_C | LCD_SS_D | LCD_SS_E | LCD_SS_F | LCD_SS_G, + LCD_SS_A | LCD_SS_B | LCD_SS_C, + LCD_SS_A | LCD_SS_B | LCD_SS_C | LCD_SS_D | LCD_SS_E | LCD_SS_F | + LCD_SS_G, + LCD_SS_A | LCD_SS_B | LCD_SS_C | LCD_SS_D | LCD_SS_F | LCD_SS_G, + 0 + }; + + int l; + int c; + + + if (v == 0) + v = 10; + + l = lut[v]; + + printf ("SS %d %x %d %d %d %d %d\n", v, l, x1, x2, y1, y2, y3); + + c = (l & LCD_SS_A) ? 255 : 0; + lcd_hline (y1, x1, x2, c, c, c); + + c = (l & LCD_SS_B) ? 255 : 0; + lcd_vline (x2, y1, y2, c, c, c); + + c = (l & LCD_SS_C) ? 255 : 0; + lcd_vline (x2, y2, y3, c, c, c); + + c = (l & LCD_SS_D) ? 255 : 0; + lcd_hline (y3, x1, x2, c, c, c); + + c = (l & LCD_SS_E) ? 255 : 0; + lcd_vline (x1, y2, y3, c, c, c); + + c = (l & LCD_SS_F) ? 255 : 0; + lcd_vline (x1, y1, y2, c, c, c); + + c = (l & LCD_SS_G) ? 255 : 0; + lcd_hline (y2, x1, x2, c, c, c); + + blit (x1, y1, x1 + 1, y3 + 1); + blit (x2, y1, x2 + 1, y3 + 1); + + blit (x1, y1, x2 + 1, y1 + 1); + blit (x1, y2, x2 + 1, y2 + 1); + blit (x1, y3, x2 + 1, y3 + 1); + +} + + + +int +lcd_open (void) +{ + int err; + DPFValue val; + + + err = dpf_open ("usb0", &dpf); + + if (err < 0) + { + dpf = NULL; + return -1; + } + + + val.type = TYPE_INTEGER; + val.value.integer = 1; + dpf_setproperty (dpf, PROPERTY_ORIENTATION, &val); + + + fb_16 = malloc (dpf->height * dpf->width * dpf->bpp); + fb = malloc (dpf->height * dpf->width * sizeof (RGBA)); + fbo = malloc (dpf->height * dpf->width * sizeof (RGBA)); + + bzero (fb, dpf->height * dpf->width * sizeof (RGBA)); + blit (0, 0, 320, 240); + + + + return 0; +} diff --git a/libdpf/Makefile b/libdpf/Makefile new file mode 100644 index 0000000..3c39ac5 --- /dev/null +++ b/libdpf/Makefile @@ -0,0 +1,12 @@ +OBJS = dpflib.o rawusb.o scsi.o bootload.o + +CFLAGS = -Wall -fPIC -I. -g +# CFLAGS += -DDEBUG + +all: libdpf.a + +libdpf.a: $(OBJS) + ar ruv $@ $(OBJS) + +clean: + -rm -f libdpf.a *.o diff --git a/libdpf/bootload.c b/libdpf/bootload.c new file mode 100644 index 0000000..2d882cf --- /dev/null +++ b/libdpf/bootload.c @@ -0,0 +1,379 @@ +// Bootstream generator for Buildwin firmware loader +// +// (c) 2011, +// +// + +#include "dpf.h" +#include "usbuser.h" // our user defined flash commands +#include +#include +#include +#include + +// Jump offsets for USB command: +#define JMP_LOAD 0x0dae +#define JMP_SPILIB 0x11bf +#define JMP_USER 0x1000 + +#define PAGESIZE 256 +#define BUFSIZE (64 - 6) +#define PKTSIZE (64 - 7) + +typedef struct { + unsigned char len; + unsigned char chk; + unsigned char jmp[2]; + union { + // Structures for various backends + // The default memory loader: + struct { + unsigned char offset[2]; // XDATA memory dest address + unsigned char buf[BUFSIZE]; // Binary data to write + } loader; + struct { + unsigned char opcode; // SPI operation opcode + unsigned char wnum; // Number of bytes to send (Host -> DPF) + unsigned char rnum; // Number of bytes to recv (DPF -> Host) + unsigned char seq[PKTSIZE]; // SPI cmd sequence + } spi; + } u; +} UsbMsg; + +#define OPCODE_SPISEL 0x01 // assert SELECT +#define OPCODE_CRYPT0 0x02 +#define OPCODE_CRYPT1 0x04 +#define OPCODE_SPIDES 0x10 // assert DESELECT + +int validate(UsbMsg *msg) +{ + unsigned short c = 0; + unsigned char *b = (unsigned char *) msg; + unsigned short l = msg->len; + + if (l < 6 || l > 64) return -1; + + while (l--) { + c += *b++; + } + + msg->chk -= c; + + return 0; +} + +void hexdump(unsigned char *buf, unsigned long n) +{ + int i = 0; + int c = 0; + + while (i < n) { + printf("%02x ", buf[i]); + c++; + if (c == 16) { c = 0; printf("\n"); } + i++; + } + if (c) + printf("\n"); +} + +int transmit(DPFContext *dpf, UsbMsg *m) +{ + int error; + unsigned char *s = (unsigned char *) m; + // hexdump(s, m->len); + error = usb_rawwrite(dpf->dev.udev, s, m->len); + if (error < 0) { + perror("Writing to USB"); + } + return error; +} + +int spilib_process(DPFContext *h, UsbMsg *umsg, unsigned char *out) +{ + int error; + umsg->jmp[0] = JMP_SPILIB & 0xff; umsg->jmp[1] = JMP_SPILIB >> 8; + umsg->len = 7 + umsg->u.spi.wnum; + + validate(umsg); + error = transmit(h, umsg); + if (umsg->u.spi.rnum > 0 && error >= 0) { + error = usb_rawread(h->dev.udev, out, 64); + } + if (error < 0) perror("Reading USB"); + else error = 0; + return error; +} + +int go_hid(DPFContext *dpf, ADDR jmpoffset) +{ + UsbMsg umsg; + umsg.jmp[0] = jmpoffset; umsg.jmp[1] = jmpoffset >> 8; + umsg.len = 8; + validate(&umsg); + return transmit(dpf, &umsg); +} + +int load(DPFContext *dpf, FILE *f, uint16_t jmpoffset) +{ + int size; + UsbMsg umsg; + + unsigned short offset = jmpoffset - 0x800; + + umsg.jmp[0] = JMP_LOAD & 0xff; umsg.jmp[1] = JMP_LOAD >> 8; + umsg.chk = 0xce; + size = fread(umsg.u.loader.buf, 1, BUFSIZE, f); + if (size < 0) return size; + + while (size > 0) { + umsg.u.loader.offset[0] = offset; + umsg.u.loader.offset[1] = offset >> 8; + umsg.len = sizeof(UsbMsg) - BUFSIZE + size; + offset += size; + validate(&umsg); + transmit(dpf, &umsg); + size = fread(umsg.u.loader.buf, 1, BUFSIZE, f); + } + + // And jump into the code: + if (jmpoffset != 0x0000) { + go_hid(dpf, jmpoffset); + } + return size; +} +/* Flash stuff, HID wrapped */ + +static unsigned char s_rbuf[64]; + +static +int flash_probe_hid(DPFContext *h, unsigned char *id) +{ + int error; + UsbMsg umsg; + FILE *f; + + // First, load spilib.bin + f = fopen("spilib.bin", "rb"); + + if (!f) { + printf("failed to open flash driver\n"); + return -1; + } + umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES; + + error = load(h, f, 0x0000); // Load, but do not execute + fclose(f); + usleep(500000); + if (error == 0) { + umsg.u.spi.wnum = 1; + umsg.u.spi.rnum = 4; + umsg.u.spi.seq[0] = SPM_RDID; + error = spilib_process(h, &umsg, s_rbuf); + id[0] = s_rbuf[0]; id[1] = s_rbuf[1]; id[2] = s_rbuf[2]; + } + return error; +} + +static +int flash_cmd_hid(DPFContext *h, int command, int cmdlen, ADDR addr) +{ + UsbMsg umsg; + umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES; + umsg.u.spi.wnum = cmdlen; + umsg.u.spi.rnum = 0; + umsg.u.spi.seq[0] = command; + umsg.u.spi.seq[1] = addr >> 16; + umsg.u.spi.seq[2] = addr >> 8; + umsg.u.spi.seq[3] = addr; + + return spilib_process(h, &umsg, 0); +} + +int flash_status_hid(DPFHANDLE h, uint8_t *status) +{ + int error; + UsbMsg umsg; + umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES; + umsg.u.spi.wnum = 1; + umsg.u.spi.rnum = 1; + umsg.u.spi.seq[0] = SPM_RDSR; + + error = spilib_process(h, &umsg, s_rbuf); + *status = s_rbuf[0]; + return error; +} + +static +int chunk_read(DPFContext *h, unsigned char *buf, ADDR offset, int len) +{ + int error; + UsbMsg umsg; + + if (len > PKTSIZE) len = PKTSIZE; + + umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES; + umsg.u.spi.wnum = 4; + umsg.u.spi.rnum = PKTSIZE; + umsg.u.spi.seq[0] = SPM_READ; + umsg.u.spi.seq[1] = offset >> 16; + umsg.u.spi.seq[2] = offset >> 8; + umsg.u.spi.seq[3] = offset; + + error = spilib_process(h, &umsg, buf); + if (error < 0) return error; + + return len; +} + + +static +int flash_read_hid(DPFContext *h, unsigned char *buf, ADDR offset, int len) +{ + int n; + + while (len > 0) { + n = chunk_read(h, buf, offset, len); + if (n < 0) return n; + len -= n; offset += n; buf += n; + } + return 0; +} + +int fill_spimsg(UsbMsg *umsg, const unsigned char *buf, + unsigned short offset, int len) +{ + int n = PKTSIZE - offset; + if (len > n) len = n; + memcpy(&umsg->u.spi.seq[offset], buf, len); + umsg->u.spi.wnum = offset + len; + return len; +} + +static +int flash_writechunk_hid(DPFContext *h, + const unsigned char *buf, ADDR offset, int len) +{ + UsbMsg umsg; + int error; + int n; + + if (len > PAGESIZE) len = PAGESIZE; + + umsg.u.spi.rnum = 0; + umsg.u.spi.seq[0] = SPM_PP; + umsg.u.spi.seq[1] = offset >> 16; + umsg.u.spi.seq[2] = offset >> 8; + umsg.u.spi.seq[3] = offset; + + n = fill_spimsg(&umsg, buf, 4, len); + len -= n; buf += n; offset += n; + + umsg.u.spi.opcode = OPCODE_SPISEL; + error = spilib_process(h, &umsg, 0); + if (error < 0) return error; + + umsg.u.spi.opcode = 0; + while (len > PKTSIZE) { + n = fill_spimsg(&umsg, buf, 0, PKTSIZE); + error = spilib_process(h, &umsg, 0); + if (error < 0) return error; + len -= n; buf += n; offset += n; + } + + umsg.u.spi.opcode = OPCODE_SPIDES; + fill_spimsg(&umsg, buf, 0, len); + error = spilib_process(h, &umsg, 0); + if (error < 0) return error; + + return PAGESIZE; +} + +int blk_write(DPFContext *h, ADDR dst, const unsigned char *src, + unsigned short len) +{ + static UsbMsg umsg; + + if (len > BUFSIZE) len = BUFSIZE; + + umsg.jmp[0] = JMP_LOAD & 0xff; umsg.jmp[1] = JMP_LOAD >> 8; + memcpy(umsg.u.loader.buf, src, len); + umsg.u.loader.offset[0] = dst; + umsg.u.loader.offset[1] = dst >> 8; + umsg.len = sizeof(UsbMsg) - BUFSIZE + len; + + validate(&umsg); + transmit(h, &umsg); + return len; +} + +int mem_write_hid(DPFContext *h, + ADDR dst, const unsigned char *src, unsigned short n) +{ + int len; + + while (n > 0) { + len = blk_write(h, dst, src, n); + n -= len; src += len; dst += len; + } + return n; +} + + +AccessMethods +hid_methods = { + .mem_read = NULL, + .mem_write = mem_write_hid, + .go = go_hid, + .bootstrap = NULL, + .flash_probe = flash_probe_hid, + .flash_cmd = flash_cmd_hid, + .flash_status = flash_status_hid, + .flash_read = flash_read_hid, + .flash_writechunk = flash_writechunk_hid, + .flash_lock = NULL, +}; + + +#ifdef TEST +int main(int argc, char **argv) +{ + FILE *f; + int error; + DPFHANDLE dpf; + uint16_t startaddr = 0x1000; + + if (argc >= 2) { + + f = fopen(argv[1], "rb"); + + if (!f) { + printf("failed to open file\n"); + return -1; + } + if (argc == 3) { + startaddr = strtol(argv[2], NULL, 16); + printf("Starting at %04x\n", startaddr); + } + + error = dpf_open("usb0", &dpf); + if (error < 0) { + printf("Failed to open DPF\n"); + return error; + } + if (dpf->mode == MODE_USBHID) { + error = load(dpf, f, startaddr); + } else { + printf("Not in BOOTLOAD mode! Press Reset and hold MENU\n"); + } + dpf_close(dpf); + } else { + printf("Needs boot image argument\n"); + } + + if (error < 0) { + printf("Error\n"); + } + return error; +} +#endif diff --git a/libdpf/dpf.h b/libdpf/dpf.h new file mode 100644 index 0000000..d8d698d --- /dev/null +++ b/libdpf/dpf.h @@ -0,0 +1,189 @@ +/** libdpf header file + * + * (c) 2010, 2011 + * + */ + +#include +#include +#include "usbuser.h" +#include "spiflash.h" + +#define ADDR unsigned int + +#define MODE_SG 0x00 ///< generic device mode (original) +#define MODE_USB 0x01 ///< libusb operation mode (hacked) +#define MODE_USBHID 0x02 ///< libusb HID boot mode + +#define FLAG_CAN_LOCK 0x80 ///< Has the locking feature (new firmware) + +enum { + DEVERR_FILE = -16, + DEVERR_OPEN, + DEVERR_HEX, + DEVERR_CHK, + DEVERR_IO, + DEVERR_MALLOC, + DEVERR_TIMEOUT, + DEVERR_UNSUPP, +}; + +/** The DPF context structure */ +struct dpf_context; +#define DPFHANDLE struct dpf_context * + +typedef struct { + int (*mem_read)(DPFHANDLE h, unsigned char *buf, ADDR offset, int len); + int (*mem_write)(DPFHANDLE h, + ADDR dst, const unsigned char *buf, unsigned short n); + int (*go)(DPFHANDLE h, ADDR start); + int (*bootstrap)(DPFHANDLE h, + ADDR dest, unsigned char *src, unsigned short n, ADDR start); + int (*flash_probe)(DPFHANDLE h, unsigned char *id); + int (*flash_cmd)(DPFHANDLE h, int command, int cmdlen, ADDR addr); + int (*flash_status)(DPFHANDLE h, uint8_t *status); + int (*flash_read)(DPFHANDLE h, uint8_t *buf, ADDR offset, int len); + int (*flash_writechunk)(DPFHANDLE h, + const uint8_t *buf, ADDR offset, int len); + int (*flash_lock)(DPFHANDLE h, char enable); +} AccessMethods; + +typedef +struct dpf_context { + unsigned char mode; + unsigned char flags; + union { + usb_dev_handle *udev; + int fd; + } dev; + AccessMethods methods; + unsigned int width; + unsigned int height; + int bpp; + int proto; + char* buff; + unsigned char* oldpix; + int offx; + int offy; +} DPFContext; + + +/** A value proxy for the property API */ +typedef struct dpf_proxy { + union { + short integer; + char *sequence; + } value; + char type; +} DPFValue; + +enum { + TYPE_INTEGER, + TYPE_STRING, +}; + +/** + Opens the DPF device. if dev is not NULL, open device, otherwise, look for + USB device. + */ +int dpf_open(const char *dev, DPFHANDLE *h); + +/** Close DPF device */ +void dpf_close(DPFHANDLE h); + +/** Set color register + * \param rgb RGB tuple */ +int dpf_setcol(DPFHANDLE h, const unsigned char *rgb); + +/** Blit data to screen + * + * \param buf buffer to 16 bpp RGB 565 image data + * \param rect rectangle tuple: [x0, y0, x1, y1] + */ + +int dpf_screen_blit(DPFHANDLE h, const unsigned char *buf, short rect[4]); + +/** Set property on DPF + * \param token Property token + * \param value Pointer to value + */ +int dpf_setproperty(DPFHANDLE h, int token, const DPFValue *value); + +/* USB raw */ + +int emulate_scsi(usb_dev_handle *d, unsigned char *cmd, int cmdlen, char out, + unsigned char *data, unsigned long block_len); + +const char *dev_errstr(int err); + +// Private stuff: +int dpf_usb_open(int index, usb_dev_handle **u); +int sgdev_open(const char *portname, int *fd); +int usb_rawread(usb_dev_handle *dev, unsigned char *buf, int len); +int usb_rawwrite(usb_dev_handle *dev, const unsigned char *buf, int len); +int probe(DPFHANDLE h); + +//////////////////////////////////////////////////////////////////////////// +// Bootloader functionality + +int bl_go(DPFContext *dpf, uint16_t jmpoffset); + +//////////////////////////////////////////////////////////////////////////// +// FLASH stuff + +// Maximum size for flash_read +#define MAX_CHUNKSIZE 0x10000 + +int read_mem(DPFHANDLE h, unsigned char *buf, ADDR src, unsigned short len); +int write_mem(DPFHANDLE h, + ADDR dst, const unsigned char *buf, unsigned short len); + +int load_hexfile(DPFHANDLE h, const char *hexfile); +int code_go(DPFHANDLE h, ADDR start); + +int dpf_bootstrap(DPFHANDLE h, + ADDR dst, unsigned char *src, unsigned short n, ADDR start); + +int flash_cmd(DPFHANDLE h, int command, int cmdlen, ADDR addr); +int flash_probe(DPFContext *h, unsigned char *id); +int flash_erase(DPFHANDLE h, ADDR offset); +int flash_erase_full(DPFHANDLE h); +int flash_write(DPFHANDLE h, const unsigned char *buf, ADDR offset, int len); +int flash_read(DPFHANDLE h, unsigned char *buf, ADDR offset, int len); + +int load_ihx(DPFHANDLE h, const char *fname, unsigned char *data, + unsigned int *buflen, unsigned int reloc); + +int patch_sector(DPFHANDLE h, + ADDR reloc, unsigned long addr, const char *hexfile); + +//////////////////////////////////////////////////////////////////////////// +/* DPF specific stuff: */ + +#define RGB565_0(r, g, b) \ + (( ((r) & 0xf8) ) | (((g) & 0xe0) >> 5)) +#define RGB565_1(r, g, b) \ + (( ((g) & 0x1c) << 3 ) | (((b) & 0xf8) >> 3)) + +#define RGB565(r, g, b) { RGB565_0(r, g, b), RGB565_1(r, g, b) } + +#define RGB565_S(r, g, b) ((RGB565_0(r, g, b) << 8) | RGB565_1(r, g, b)) + +int dpfcpy(ADDR dst, unsigned char *src, unsigned short n); + +// int clr_screen(DPFHANDLE h, const unsigned char *col); +int write_screen(DPFHANDLE h, const unsigned char *buf, unsigned int len); + + +// Some internal address offsets. They may change, but so far all types +// seem to have the same +// +// w: word, : length, [LE, BE] +// +// FIXME: Use packed struct later. + +// FIXME: Should be 0x0020, once we have the firmware replaced +#define OFFSET_PROPS 0x3f0020 ///< w[2]:LE : Resolution X, Y + + + diff --git a/libdpf/dpflib.c b/libdpf/dpflib.c new file mode 100644 index 0000000..cfda55b --- /dev/null +++ b/libdpf/dpflib.c @@ -0,0 +1,436 @@ +/** DPF access library for AX206 based HW + * + * 12/2010 + * + * This is an ugly hack, because we use existing SCSI vendor specific + * extensions to pass on our requests to the DPF. + * + * One day we might use a proper protocol like netpp. + * + */ + +// FIXME: Put all those SCSI commands in one (wrapped) place. + +#include "dpf.h" + +#include +#include +#include +#include + +#ifdef DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +extern AccessMethods scsi_methods; +extern AccessMethods hid_methods; + + +/* +static +int dpf_query(DPFHANDLE h) +{ + int ret; + unsigned char buf[64]; // Do not change size + + static + unsigned char cmd[16] = { + 0xcd, 0, 0, 0, + 0, 3, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + }; + + return wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, buf, sizeof(buf)); +} +*/ + + + +int dpf_open(const char *dev, DPFHANDLE *h) +{ + int error = 0; + DPFContext *dpf; + int i; + usb_dev_handle *u; + + int fd; + + if (!dev) { + fprintf(stderr, "Please specify a string like 'usb0' or a sg device\n"); + return DEVERR_OPEN; + } + + if (strncmp(dev, "usb", 3) == 0) { + i = dev[3] - '0'; + error = dpf_usb_open(i, &u); + if (error < 0) return error; + if (!u) return DEVERR_OPEN; + i = error; // USB mode + error = 0; + } else { + fprintf(stderr, "Opening generic SCSI device '%s'\n", dev); + if (sgdev_open(dev, &fd) < 0) return DEVERR_OPEN; + i = MODE_SG; + } + + dpf = (DPFHANDLE) malloc(sizeof(DPFContext)); + if (!dpf) return DEVERR_MALLOC; + + dpf->flags = 0; + dpf->mode = i; + + switch (dpf->mode) { + case MODE_USB: + dpf->dev.udev = u; + error = probe(dpf); + fprintf(stderr, "Got LCD dimensions: %dx%d\n", + dpf->width, dpf->height); + dpf->methods = scsi_methods; + break; + case MODE_USBHID: + dpf->dev.udev = u; + dpf->methods = hid_methods; + break; + case MODE_SG: + dpf->dev.fd = fd; + dpf->methods = scsi_methods; + break; + default: + fprintf(stderr, "Unknown interface mode\n"); + error = -1; + } + + *h = dpf; + return error; +} + +void dpf_close(DPFContext *h) +{ + switch (h->mode) { + case MODE_USBHID: + case MODE_SG: + close(h->dev.fd); + break; + case MODE_USB: + usb_release_interface(h->dev.udev, 0); + usb_close(h->dev.udev); + break; + } + free(h); +} + +const char *dev_errstr(int err) +{ + switch (err) { + case DEVERR_FILE: return "File I/O error"; + case DEVERR_OPEN: return "File open error"; + case DEVERR_HEX: return "Hex file error"; + case DEVERR_CHK: return "Checksum error"; + case DEVERR_IO: return "Common I/O error"; + case DEVERR_UNSUPP: return "Unsupported feature"; + default: return "Unknown error"; + } +} + + +int flash_probe(DPFContext *h, unsigned char *id) +{ + return h->methods.flash_probe(h, id); +} + +int flash_cmd(DPFContext *h, int command, int cmdlen, ADDR addr) +{ + return h->methods.flash_cmd(h, command, cmdlen, addr); +} + + +/* Flash functions, API */ + +int flash_read(DPFContext *h, unsigned char *buf, ADDR offset, int len) +{ + return h->methods.flash_read(h, buf, offset, len); +} + +int flash_status_wait(DPFContext *h, uint8_t mask) +{ + int error; + uint8_t status; + + do { + error = h->methods.flash_status(h, &status); + } while ((status & mask) && !error); + + return error; +} + + +int flash_write(DPFContext *h, const unsigned char *buf, ADDR offset, int len) +{ + int n; + int error = 0; + + while (len > 0) { + error = h->methods.flash_cmd(h, SPM_WREN, 1, 0); + DEB(printf("Write pages at %06x\n", offset)); + n = h->methods.flash_writechunk(h, buf, offset, len); + error = flash_status_wait(h, SPS_WIP); + + if (n < 0) break; + len -= n; buf += n; offset += n; + } + return error; +} + +/* Mid level flash */ + +int load_ihx(DPFContext *h, const char *fname, unsigned char *data, + unsigned int *buflen, unsigned int reloc) +{ + unsigned char csum_is, csum_need; + int ret; + FILE *f; + + static char line[512]; + static unsigned char buf[0x100]; + int count; + unsigned int addr, len, type; + unsigned short b; + unsigned int total = 0; + + DEB(printf("Opening %s...\n", fname)); + f = fopen(fname, "r"); + if (f == NULL) { + return DEVERR_OPEN; + } + + while(1) { + fgets(line, sizeof(line), f); + + if (feof(f) || ferror(f)) break; + + if ((line[0] != ':') || (strlen(line) < 9)) { + fprintf(stderr, "invalid line in ihx\n"); + break; + } + + ret = sscanf(&line[1], "%02x", &len); + if (ret != 1) { ret = DEVERR_HEX; break; } + + ret = sscanf(&line[3], "%04x", &addr); + if (ret != 1) { ret = DEVERR_HEX; break; } + + ret = sscanf(&line[7], "%02x", &type); + if (ret != 1) { ret = DEVERR_HEX; break; } + +#ifdef DEBUG + printf("len %u addr %04x type %u\n", len, addr, type); +#endif + + if (type == 1) break; + + if (type != 0) { + fprintf(stderr, "ihx: unknown type %u\n", type); + continue; + } + + csum_need = len + (addr & 0xff) + (addr >> 8) + type; + + total += len; + if (total > *buflen) { + fprintf(stderr, "Buffer length exceeded. IHX file too big.\n"); + ret = DEVERR_HEX; + break; + } + + if (len > sizeof(buf)) { + fprintf(stderr, "Buffer length exceeded. Too long lines.\n"); + ret = DEVERR_HEX; + break; + } + + for(count = 0; count < len; count++) { + ret = sscanf(&line[9 + count * 2], "%02hx", &b); + if (ret != 1) { + fprintf(stderr, "hex file: could not parse data!\n"); + break; + } + + buf[count] = b; + csum_need += buf[count]; + } + + if (ret != 1) { ret = DEVERR_HEX; break; } + + ret = sscanf(&line[9 + len * 2], "%02hx", &b); + if (ret != 1) { ret = DEVERR_HEX; break; } + + csum_is = b; + if (((csum_need+csum_is) & 0xff) != 0x00) { + fprintf(stderr, "ihx: checksum failure! is: %02x should be:%02x\n", + csum_is, csum_need); + ret = DEVERR_CHK; + break; + } + + if (addr < reloc) { + fprintf(stderr, "Bad relocation value\n"); + ret = DEVERR_HEX; + break; + } + // Copy to data buffer at relocated address + if (data) { + DEB(printf("Patching at offset %08x, chunk size %d\n", + addr - reloc, len)); + memcpy(&data[addr - reloc], buf, len); + } else { + DEB(printf("Writing to %04x (CODE: %04x), chunk size %d\n", + addr - reloc, addr, len)); + h->methods.mem_write(h, addr - reloc, buf, len); + } + } + *buflen = total; + fclose(f); + return ret; +} + +int flash_erase_full(DPFContext *h) +{ + flash_cmd(h, SPM_RES, 1, 0); + flash_cmd(h, SPM_WRSR, 2, 0); // clr status + flash_cmd(h, SPM_WREN, 1, 0); + flash_cmd(h, SPM_FLASH_BE, 1, 0); + printf("Erase full flash...\n"); + + return flash_status_wait(h, SPS_WIP); +} + +int flash_erase(DPFContext *h, ADDR addr) +{ + int error; + flash_cmd(h, SPM_RES, 1, 0); + flash_cmd(h, SPM_WREN, 1, 0); + flash_cmd(h, SPM_WRSR, 2, 0); // clr status + + // now erase flash sector: + flash_cmd(h, SPM_WREN, 1, 0); + flash_cmd(h, SPM_FLASH_SE, 4, addr); + + error = flash_status_wait(h, SPS_WIP); + flash_cmd(h, SPM_WRDI, 1, 0); + + return error; +} + +int dpf_flash_lock(DPFContext *h, char enable) +{ + if (h->methods.flash_lock) + return h->methods.flash_lock(h, enable); + else + return DEVERR_UNSUPP; +} + + +int patch_sector(DPFContext *h, + ADDR reloc, unsigned long addr, const char *hexfile) +{ + int error; + unsigned short offset; + static + unsigned char readbuf[0x10000]; + unsigned int len = sizeof(readbuf); + + offset = addr & 0xffff; + addr -= offset; + + error = flash_read(h, readbuf, addr, 0x10000); + if (error < 0) { + perror("Reading flash"); + return error; + } + + error = load_ihx(h, hexfile, &readbuf[offset], &len, reloc); + if (error < 0) { + fprintf(stderr, "Failed to load HEX file\n"); + return error; + } + // Lock DPF handler so nothing can interfere with the flashing (in case + // we flash ourselves) + dpf_flash_lock(h, 1); + error = flash_cmd(h, SPM_WREN, 1, 0); + error = flash_cmd(h, SPM_WRSR, 2, 0); // clr status + + error = flash_erase(h, addr); + if (error < 0) return error; + + error = flash_write(h, readbuf, addr, 0x10000); // clr status + dpf_flash_lock(h, 0); + + return error; +} + +//////////////////////////////////////////////////////////////////////////// +// High level functions, generic +// These require a hacked command handler with extended command set. + + +int load_hexfile(DPFContext *h, const char *hexfile) +{ + unsigned int len = 0xc000; + int error; + + error = load_ihx(h, hexfile, 0, &len, 0x800); + return error; +} + +#define CHUNK_SIZE 1024 + +int read_mem(DPFContext *h, unsigned char *buf, ADDR src, unsigned short len) +{ + int error = 0; + if (!h->methods.mem_read) return DEVERR_UNSUPP; + + while (len > CHUNK_SIZE && error >= 0) { + error = h->methods.mem_read(h, buf, src, CHUNK_SIZE); + src += CHUNK_SIZE; len -= CHUNK_SIZE; buf += CHUNK_SIZE; + } + error = h->methods.mem_read(h, buf, src, len); + + return error; +} + +int write_mem(DPFContext *h, ADDR dst, const unsigned char *buf, unsigned short len) +{ + return h->methods.mem_write(h, dst, buf, len); +} + +int code_go(DPFContext *h, ADDR start) +{ + printf("Executing applet..\n"); + if (h->methods.go) + return h->methods.go(h, start); + return DEVERR_UNSUPP; +} + + + +//////////////////////////////////////////////////////////////////////////// +// High level functions, DPF specific + +/* Bootstrap mode: Expects contiguous memory block to download, then jumps + * into start address + */ + +int dpf_bootstrap(DPFContext *h, + ADDR dest, unsigned char *src, unsigned short n, ADDR start) +{ + if (h->methods.bootstrap) + return h->methods.bootstrap(h, dest, src, n, start); + else + return DEVERR_UNSUPP; +} + + + diff --git a/libdpf/flash.h b/libdpf/flash.h new file mode 100644 index 0000000..f753bd5 --- /dev/null +++ b/libdpf/flash.h @@ -0,0 +1,19 @@ +// SPI STM flash commands: +// stolen from BFloader + +#define SPM_RDID 0x9f // Read ID +#define SPM_WREN 0x06 // Write enable +#define SPM_WRDI 0x04 // Write disable +#define SPM_RDSR 0x05 // Read status register +#define SPM_WRSR 0x01 // Write status register +#define SPM_READ 0x03 // Read data bytes +#define SPM_PP 0x02 // Page program +#define SPM_DP 0xb9 // Deep power down +#define SPM_RES 0xab // Release from deep power down + // and read signature +#define SPM_FLASH_SE 0xd8 // Sector erase +#define SPM_FLASH_BE 0xc7 // Bulk erase +#define SPM_FLASH_FAST_READ 0x0B // Read data bytes fast + +#define SPM_SR_SRWD 0x80 // SR write protection (HW) + diff --git a/libdpf/fwload.c b/libdpf/fwload.c new file mode 100644 index 0000000..2b98762 --- /dev/null +++ b/libdpf/fwload.c @@ -0,0 +1,121 @@ +/** DPF firmware loader + * + * 12/2010 + * + * Based on the FX2 ihx loader + * + */ + +#include "dpf.h" +#include + +//////////////////////////////////////////////////////////////////////////// + +// Demo stuff: + +void memory_dump(unsigned char *buf, unsigned int n) +{ + int i = 0; + int c = 0; + + while (i < n) { + printf("%02x ", buf[i]); + c++; + if (c == 16) { c = 0; printf("\n"); } + i++; + } + if (c) + printf("\n"); +} + +//////////////////////////////////////////////////////////////////////////// + + +#if EXPERIMENTAL + +int xmain(int argc, char **argv) +{ + int ret; + int i; + struct banktable *bt; + + // flash offset, offset after jump table + unsigned int offset = 0x80000 + 0x200; + + + static unsigned char buf[0x10000]; + unsigned int len = sizeof(buf); + ret = load_ihx(argv[1], buf, &len, 0x127c, g_banktab); + if (ret < 0) { + fprintf(stderr, "Failed to load HEX file\n"); + return ret; + } else { + printf("Read %d banks\n", ret); + for (i = 0; i < ret; i++) { + bt = &g_banktab[i]; + printf(" { XADDR(0x%04x), XADDR(0x%04x), FOFFS(0x%06x) },\n", + bt->reloc, bt->reloc + bt->len, offset + bt->offset); + + } + } + return 0; +} + +#endif + +int main(int argc, char **argv) +{ + int ret; + DPFHANDLE h; + + int i = 2; + + if (argc < 2 || argc > 3) { + fprintf(stderr, "Usage:\n" + "%s <.ihx file>\n" + "or in USB mode:\n" + "%s <.ihx file>\n", + argv[0], argv[0]); + return -1; + } + + if (argc == 2) { + ret = dpf_open(NULL, &h); + i--; + } else + if (argc == 3) { + ret = dpf_open(argv[1], &h); + } + + if (ret < 0) { + perror("opening DPF device:"); + return ret; + } + +// This patches a module to init the relocated jump table on a certain +// menu action: +// ret = patch_sector(h, 0x1330, 0x4af7a, "hack2.ihx"); + + +// patch_sector(h, 0x0, 0x100000, "jumptbl.ihx"); + + if (0) { + patch_sector(h, 0x0, 0x100000, "jumptbl.ihx"); + ret = patch_sector(h, 0x1330, 0x110000, "hack.ihx"); + ret = patch_sector(h, 0x132a, 0x120000, "main.ihx"); + if (ret < 0) printf("Failed.\n"); + } else { + // demo0(h); + + } + ret = load_hexfile(h, argv[i]); + code_go(h, 0x18a0); + if (ret < 0) printf("Failed.\n"); + + // unsigned char buf[256]; + // ret = read_mem(h, buf, 0x18a0, 64); + // memory_dump(buf, 64); + + dpf_close(h); + return ret; +} diff --git a/libdpf/rawusb.c b/libdpf/rawusb.c new file mode 100644 index 0000000..cbd344c --- /dev/null +++ b/libdpf/rawusb.c @@ -0,0 +1,195 @@ +/* Low level USB code to access DPF. + * + * (c) 2010, 2011 + * + * This currently uses the SCSI command set + * + * The reason for this is that we want to access the hacked frame + * non-root and without having to wait for the SCSI interface to + * intialize. + * + * Later, we'll replace the SCSI command stuff. + */ + +#include "dpf.h" +#include "sglib.h" + +#include +#include + +#define ENDPT_OUT 1 +#define ENDPT_IN 0x81 + +struct known_device { + char *desc; + unsigned short vid; + unsigned short pid; +} g_known_devices[] = { + { "AX206 DPF", 0x1908, 0x0102 }, + { "AX206 DPF (bootloader)", 0x1908, 0x3318 }, + { 0 , 0, 0 } /* NEVER REMOVE THIS */ +}; + +int handle_error(char *txt) +{ + fprintf(stderr, "Error: %s\n", txt); + return -1; +} + +void usb_flush(usb_dev_handle *dev) +{ + char buf[20]; + usb_bulk_read(dev, ENDPT_IN, buf, 3, 1000); +} + +int check_known_device(struct usb_device *d) +{ + struct known_device *dev = g_known_devices; + + while (dev->desc) { + if ((d->descriptor.idVendor == dev->vid) && + (d->descriptor.idProduct == dev->pid)) { + fprintf(stderr, "Found %s\n", dev->desc); + return 1; + } + dev++; + } + return 0; +} + +static struct usb_device *find_dev(int index) +{ + struct usb_bus *b; + struct usb_device *d; + int enumeration = 0; + + b = usb_get_busses(); + + while (b) { + d = b->devices; + while (d) { + if (check_known_device(d)) { + if (enumeration == index) return d; + else enumeration++; + } + +#ifdef DEBUG + printf("enum: %d index: %d\n", enumeration, index); + printf("%04x %04x\n", + d->descriptor.idVendor, + d->descriptor.idProduct); +#endif + d = d->next; + } + b = b->next; + } + return NULL; +} + +char g_buf[] = { + 0x55, 0x53, 0x42, 0x43, // dCBWSignature + 0xde, 0xad, 0xbe, 0xef, // dCBWTag + 0x00, 0x80, 0x00, 0x00, // dCBWLength + 0x00, // bmCBWFlags: 0x80: data in (dev to host), 0x00: Data out + 0x00, // bCBWLUN + 0x10, // bCBWCBLength + + // SCSI cmd: + 0xcd, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x11, 0xf8, + 0x70, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +int emulate_scsi(usb_dev_handle *dev, unsigned char *cmd, int cmdlen, char out, + unsigned char *data, unsigned long block_len) +{ + int len; + int ret; + static unsigned char ansbuf[13]; // Do not change size. + + g_buf[14] = cmdlen; + memcpy(&g_buf[15], cmd, cmdlen); + + g_buf[8] = block_len; + g_buf[9] = block_len >> 8; + g_buf[10] = block_len >> 16; + g_buf[11] = block_len >> 24; + + ret = usb_bulk_write(dev, ENDPT_OUT, g_buf, sizeof(g_buf), 1000); + if (ret < 0) return ret; + + if (out == DIR_OUT) { + if (data) { + ret = usb_bulk_write(dev, ENDPT_OUT, (char* )data, + block_len, 3000); + if (ret != block_len) { + perror("bulk write"); + return ret; + } + } + } else if (data) { + ret = usb_bulk_read(dev, ENDPT_IN, (char *) data, block_len, 4000); + if (ret != block_len) { + perror("bulk data read"); + } + } + // get ACK: + len = sizeof(ansbuf); + int retry = 0; + do { + ret = usb_bulk_read(dev, ENDPT_IN, (char *) ansbuf, len, 5000); + if (ret != len) { + perror("bulk ACK read"); + ret = DEVERR_TIMEOUT; + } + retry++; + } while (ret == DEVERR_TIMEOUT && retry < 5); + if (strncmp((char *) ansbuf, "USBS", 4)) { + return handle_error("Got invalid reply\n"); + } + // pass back return code set by peer: + return ansbuf[12]; +} + +int dpf_usb_open(int index, usb_dev_handle **u) +{ + struct usb_device *d; + usb_dev_handle *usb_dev; + + usb_find_busses(); + usb_find_devices(); + + d = find_dev(index); + if (!d) { + handle_error("No matching USB device found!"); + return -1; + } + + usb_dev = usb_open(d); + if (usb_dev == NULL) { + handle_error("Failed to open usb device!"); + return -1; + } + if (usb_claim_interface(usb_dev, 0) < 0) { + handle_error("Failed to claim usb device!"); + printf("Possibly you have to 'sudo libhid-detach-device 1908:3318'\n"); + return -1; + } + *u = usb_dev; + + if (d->descriptor.idProduct == 0x3318) + return MODE_USBHID; + else + return MODE_USB; +} + +int usb_rawwrite(usb_dev_handle *dev, const unsigned char *buf, int len) +{ + return usb_interrupt_write(dev, ENDPT_OUT, (char *) buf, len, 1000); +} + +int usb_rawread(usb_dev_handle *dev, unsigned char *buf, int len) +{ + return usb_interrupt_read(dev, ENDPT_IN, (char *) buf, len, 4000); +} diff --git a/libdpf/scsi.c b/libdpf/scsi.c new file mode 100644 index 0000000..3f82fc7 --- /dev/null +++ b/libdpf/scsi.c @@ -0,0 +1,412 @@ +/** + * (c) 2011, + * + */ + +#include "sglib.h" +#include "usbuser.h" // our user defined flash commands +#include "dpf.h" + +#include +#include +#include +#include +#include +#include +#include + + +int do_scsi(int fd, unsigned char *cmd, int cmdlen, char out, + unsigned char *data, unsigned long block_len) +{ + int error; + unsigned char sensebuf[32]; + sg_io_hdr_t io_hdr; + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + + io_hdr.interface_id = 'S'; + io_hdr.sbp = sensebuf; + io_hdr.mx_sb_len = sizeof(sensebuf); + if (data == 0) { + io_hdr.dxfer_direction = SG_DXFER_NONE; + } else { + if (out) { + io_hdr.dxfer_direction = SG_DXFER_TO_DEV; + } else { + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + } + } + io_hdr.dxferp = data; + io_hdr.dxfer_len = block_len; + io_hdr.cmdp = cmd; + io_hdr.cmd_len = cmdlen; + io_hdr.timeout = 5000; // in ms + error = ioctl(fd, SG_IO, &io_hdr); + if (error < 0) perror("calling SCSI ioctl()"); + return error; +} + + +int wrap_scsi(DPFContext *h, unsigned char *cmd, int cmdlen, char out, + unsigned char *data, unsigned long block_len) +{ + int error; + switch (h->mode) { + case MODE_USB: + error = emulate_scsi(h->dev.udev, + cmd, cmdlen, out, data, block_len); + break; + case MODE_SG: + error = do_scsi(h->dev.fd, cmd, cmdlen, out, data, block_len); + break; + case MODE_USBHID: + fprintf(stderr, "USBHID mode not (yet) supported\n"); + error = -1; + } + return error; +} + + +/** Vendor command for our hacks */ +static +unsigned char g_excmd[16] = { + 0xcd, 0, 0, 0, + 0, 6, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 +}; + + +/* device wrapper */ + +const char idstring[] = "buildwin Photo Frame 1.01"; + +#define INQ_REPLY_LEN 96 + +int sgdev_open(const char *portname, int *fd) +{ + int error; + + static + unsigned char inquiry[] = { + INQUIRY, 0, 0, 0, + INQ_REPLY_LEN, 0 + }; + + static unsigned char inqbuf[INQ_REPLY_LEN + 2]; + + *fd = open(portname, O_RDONLY | O_NONBLOCK ); + error = do_scsi(*fd, inquiry, sizeof(inquiry), DIR_IN, inqbuf, + INQ_REPLY_LEN); + + if (error < 0) { + fprintf(stderr, "SCSI inquiry failed\n"); + close(*fd); error = DEVERR_OPEN; + } else + if (memcmp(idstring, &inqbuf[8], sizeof(idstring) - 1) != 0) { + close(*fd); error = DEVERR_OPEN; + fprintf(stderr, "Not a photo frame. Refuse to open device.\n"); + } + return error; +} + +int probe(DPFHANDLE h) +{ + int ret; + + // We abuse a command that just responds with a '0' status in the + // original firmware. + static unsigned char buf[5]; + + + static + unsigned char cmd[16] = { + 0xcd, 0, 0, 0, + 0, 3, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + }; + + cmd[5] = 3; + ret = wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, 0, 0); + + switch (ret) { + case 0: + // The original protocol. + fprintf(stderr, + "Warning: This firmware can not lock the flash\n"); + break; + case 1: + // The improved hack + h->flags |= FLAG_CAN_LOCK; + break; + } + + cmd[5] = 2; // get LCD parameters + ret = wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, buf, 5); + h->width = (buf[0]) | (buf[1] << 8); + h->height = (buf[2]) | (buf[3] << 8); + h->bpp = 2; + + return ret; +} + +/* Memory stuff */ + +static +int mem_read_scsi(DPFContext *h, unsigned char *buf, ADDR offset, int len) +{ + unsigned char *cmd = g_excmd; + + if (h->mode == MODE_USBHID) return DEVERR_UNSUPP; + + cmd[6] = USBCMD_MEMREAD; // memory_read + cmd[7] = offset; + cmd[8] = offset >> 8; + cmd[9] = len; + cmd[10] = len >> 8; + + return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_IN, buf, len); +} + +int mem_write_scsi(DPFContext *h, + ADDR dst, const unsigned char *src, unsigned short n) +{ + unsigned char *cmd = g_excmd; + + cmd[6] = 0x01; // memory_write + cmd[7] = dst; + cmd[8] = dst >> 8; + cmd[9] = n; + cmd[10] = n >> 8; + + return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, (unsigned char *) src, n); +} + + + +/* Flash stuff, SCSI wrapped */ + +static +int flash_cmd_scsi(DPFContext *h, int command, int cmdlen, ADDR addr) +{ + static + unsigned char cmd[16] = { + 0xcb, 0, 0, 0, 0, 0, + 1, 0, 0, 0, + 0, 0, 0, 0, + 0, 0 + }; + + cmd[10] = command; + cmd[6] = cmdlen; + + // Sector number or addr: + cmd[13] = addr; + cmd[12] = addr >> 8; + cmd[11] = addr >> 16; + + return wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, 0, 0); +} + +int flash_status_scsi(DPFHANDLE h, uint8_t *status) +{ + *status = 0; + // FIXME : Really get status + return 0; +} + +static +int flash_read_scsi(DPFContext *h, unsigned char *buf, ADDR offset, int len) +{ + static + unsigned char cmd[16] = { + 0xcd, 0, 0, 0, 0, 0, + 0x04, /* num of bytes: */ 0, 0, 0, + SPM_READ, /* SPI offset: */ 0, 0, 0, + 0, 0 + }; + + cmd[9] = len >> 0; + cmd[8] = len >> 8; + cmd[7] = len >> 16; + + cmd[13] = offset >> 0; + cmd[12] = offset >> 8; + cmd[11] = offset >> 16; + + return wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, buf, len); +} + +static +int flash_writechunk_scsi(DPFContext *h, + const unsigned char *buf, ADDR offset, int len) +{ + int error; + static + unsigned char cmd[16] = { + 0xcb, 0, 0, 0, 0, 0, + 4, /* num of bytes: */ 0, 0, 0, + SPM_PP, /* SPI offset: */ 0, 0, 0, + 0, 0 + }; + + if (len > MAX_CHUNKSIZE) len = MAX_CHUNKSIZE; + + cmd[9] = len >> 0; + cmd[8] = len >> 8; + cmd[7] = len >> 16; + + cmd[13] = offset >> 0; + cmd[12] = offset >> 8; + cmd[11] = offset >> 16; + + error = wrap_scsi(h, cmd, sizeof(cmd), DIR_OUT, + (unsigned char*) buf, len); + if (error < 0) return error; + return len; +} + +int flash_lock_usb(DPFContext *h, char enable) +{ + unsigned char *cmd = g_excmd; + + if (!(h->flags & FLAG_CAN_LOCK)) return DEVERR_UNSUPP; + + printf("Lock flash %d\n", enable); + cmd[6] = USBCMD_FLASHLOCK; // flash lock + cmd[7] = enable; + + wrap_scsi(h, cmd, sizeof(g_excmd), DIR_IN, 0, 0); + return 0; +} + +static +int flash_probe_scsi(DPFContext *h, unsigned char *id) +{ + int error; + static + unsigned char buf[64]; + static + unsigned char cmd[16] = { + 0xcd, 0, 0, 0, 0, 0, + 1, sizeof(buf) >> 16, sizeof(buf) >> 8, sizeof(buf) >> 0, + // flash command sequence: + SPM_RDID, 0, 0, 0, + 0, 0 + }; + + error = wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, buf, sizeof(buf)); + id[0] = buf[0]; id[1] = buf[1]; id[2] = buf[2]; + return error; +} + + +static +int go_scsi(DPFContext *h, ADDR start) +{ + unsigned char *cmd = g_excmd; + cmd[6] = 0x02; // execute + cmd[7] = start; + cmd[8] = start >> 8; + + return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_IN, 0, 0); +} + +static +int bootstrap_scsi(DPFContext *h, + ADDR dest, unsigned char *src, unsigned short n, ADDR start) +{ + unsigned char *cmd = g_excmd; + + cmd[6] = USBCMD_APPLOAD; // Enter bootstrap mode + cmd[7] = dest; + cmd[8] = dest >> 8; + cmd[9] = n; + cmd[10] = n >> 8; + cmd[11] = start; + cmd[12] = start >> 8; + + return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, src, n); +} + +AccessMethods +scsi_methods = { + .mem_read = mem_read_scsi, + .mem_write = mem_write_scsi, + .go = go_scsi, + .bootstrap = bootstrap_scsi, + .flash_probe = flash_probe_scsi, + .flash_cmd = flash_cmd_scsi, + .flash_status = flash_status_scsi, + .flash_read = flash_read_scsi, + .flash_writechunk = flash_writechunk_scsi, + .flash_lock = flash_lock_usb, +}; + +//////////////////////////////////////////////////////////////////////////// +// SCSI only high level commands: + +int dpf_setcol(DPFContext *h, const unsigned char *rgb) +{ + unsigned char *cmd = g_excmd; + + if (h->mode == MODE_USBHID) return DEVERR_UNSUPP; + + cmd[6] = USBCMD_SETPROPERTY; + cmd[7] = PROPERTY_FGCOLOR; + cmd[8] = PROPERTY_FGCOLOR >> 8; + + cmd[9] = RGB565_0(rgb[0], rgb[1], rgb[2]); + cmd[10] = RGB565_1(rgb[0], rgb[1], rgb[2]); + + return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, NULL, 0); +} + +int dpf_screen_blit(DPFContext *h, + const unsigned char *buf, short rect[4]) +{ + unsigned long len = (rect[2] - rect[0]) * (rect[3] - rect[1]); + len <<= 1; + unsigned char *cmd = g_excmd; + + if (h->mode == MODE_USBHID) return DEVERR_UNSUPP; + + cmd[6] = USBCMD_BLIT; + cmd[7] = rect[0]; + cmd[8] = rect[0] >> 8; + cmd[9] = rect[1]; + cmd[10] = rect[1] >> 8; + cmd[11] = rect[2] - 1; + cmd[12] = (rect[2] - 1) >> 8; + cmd[13] = rect[3] - 1; + cmd[14] = (rect[3] - 1) >> 8; + cmd[15] = 0; + + return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, + (unsigned char*) buf, len); +} + +int dpf_setproperty(DPFContext *h, int token, const DPFValue *value) +{ + unsigned char *cmd = g_excmd; + + if (h->mode == MODE_USBHID) return DEVERR_UNSUPP; + + cmd[6] = USBCMD_SETPROPERTY; + cmd[7] = token; + cmd[8] = token >> 8; + + switch (value->type) { + case TYPE_INTEGER: + cmd[9] = value->value.integer; + cmd[10] = value->value.integer >> 8; + break; + default: + break; + } + + return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, NULL, 0); +} + + diff --git a/libdpf/sglib.h b/libdpf/sglib.h new file mode 100644 index 0000000..a2bc232 --- /dev/null +++ b/libdpf/sglib.h @@ -0,0 +1,19 @@ +#include + + +/* generic device wrapper: */ + +const char* dev_errstr(int error); + + +/* generic SCSI device stuff: */ + +#define DIR_IN 0 +#define DIR_OUT 1 + + +/* Special functions */ + + + + diff --git a/libdpf/spiflash.h b/libdpf/spiflash.h new file mode 100644 index 0000000..fe7a8fd --- /dev/null +++ b/libdpf/spiflash.h @@ -0,0 +1,30 @@ +/** \file flashcmd_st.h + * + * ST compatible flash cmds + * + */ + + +#define SPM_RDID 0x9f // Read Id +#define SPM_NO_CMD 0x00 // No command + +#define SPM_WREN 0x06 // Write enable +#define SPM_WRDI 0x04 // Write disable +#define SPM_RDSR 0x05 // Read status register +#define SPM_WRSR 0x01 // Write status register +#define SPM_READ 0x03 // Read data bytes +#define SPM_PP 0x02 // Page program +#define SPM_DP 0xb9 // Deep power down +#define SPM_RES 0xab // Release from deep power down + // and read signature +#define SPM_FLASH_SE 0xd8 // Sector erase +#define SPM_FLASH_BE 0xc7 // Bulk erase +#define SPM_FLASH_FAST_READ 0x0B // Read data bytes fast + +#define SPM_SR_SRWD 0x80 // SR write protection (HW) + +// Status register bit definitions +#define SPS_WIP 0x01 // write in progress +#define SPS_WEL 0x02 // write enable latch + + diff --git a/libdpf/usbuser.h b/libdpf/usbuser.h new file mode 100644 index 0000000..37fb705 --- /dev/null +++ b/libdpf/usbuser.h @@ -0,0 +1,29 @@ +/* USB user commands + * + * Only temporary. Should move to dpflib or into a dclib configuration. + * + */ + +#define PROTOCOL_VERSION 1 + +/** Our vendor specific USB commands to do stuff on the DPF */ + +#define USBCMD_GETPROPERTY 0x00 ///< Get property +#define USBCMD_SETPROPERTY 0x01 ///< Set property +#define USBCMD_MEMREAD 0x04 ///< Memory read +#define USBCMD_APPLOAD 0x05 ///< Load and run applet +#define USBCMD_FILLRECT 0x11 ///< Fill screen rectangle +#define USBCMD_BLIT 0x12 ///< Blit to screen +#define USBCMD_COPYRECT 0x13 ///< Copy screen rectangle +#define USBCMD_FLASHLOCK 0x20 ///< Lock USB for flash access +#define USBCMD_PROBE 0xff ///< Get version code (probe) + +/* Some special return codes */ +#define USB_IN_SEQUENCE 0x7f ///< We're inside a command sequence + +// Property handling: + +#define PROPERTY_BRIGHTNESS 0x01 +#define PROPERTY_FGCOLOR 0x02 +#define PROPERTY_BGCOLOR 0x03 +#define PROPERTY_ORIENTATION 0x10 diff --git a/lirc.h b/lirc.h new file mode 100644 index 0000000..4b3ab29 --- /dev/null +++ b/lirc.h @@ -0,0 +1,168 @@ +/* + * lirc.h - linux infrared remote control header file + * last modified 2010/07/13 by Jarod Wilson + */ + +#ifndef _LINUX_LIRC_H +#define _LINUX_LIRC_H + +#include +#include + +#define PULSE_BIT 0x01000000 +#define PULSE_MASK 0x00FFFFFF + +#define LIRC_MODE2_SPACE 0x00000000 +#define LIRC_MODE2_PULSE 0x01000000 +#define LIRC_MODE2_FREQUENCY 0x02000000 +#define LIRC_MODE2_TIMEOUT 0x03000000 + +#define LIRC_VALUE_MASK 0x00FFFFFF +#define LIRC_MODE2_MASK 0xFF000000 + +#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE) +#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE) +#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY) +#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT) + +#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK) +#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK) + +#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE) +#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE) +#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY) +#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT) + +/* used heavily by lirc userspace */ +#define lirc_t int + +/*** lirc compatible hardware features ***/ + +#define LIRC_MODE2SEND(x) (x) +#define LIRC_SEND2MODE(x) (x) +#define LIRC_MODE2REC(x) ((x) << 16) +#define LIRC_REC2MODE(x) ((x) >> 16) + +#define LIRC_MODE_RAW 0x00000001 +#define LIRC_MODE_PULSE 0x00000002 +#define LIRC_MODE_MODE2 0x00000004 +#define LIRC_MODE_LIRCCODE 0x00000010 + + +#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW) +#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE) +#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2) +#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE) + +#define LIRC_CAN_SEND_MASK 0x0000003f + +#define LIRC_CAN_SET_SEND_CARRIER 0x00000100 +#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200 +#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400 + +#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW) +#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE) +#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2) +#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE) + +#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK) + +#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16) +#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16) + +#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000 +#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000 +#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000 +#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000 +#define LIRC_CAN_SET_REC_FILTER 0x08000000 + +#define LIRC_CAN_MEASURE_CARRIER 0x02000000 +#define LIRC_CAN_USE_WIDEBAND_RECEIVER 0x04000000 + +#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK) +#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK) + +#define LIRC_CAN_NOTIFY_DECODE 0x01000000 + +/*** IOCTL commands for lirc driver ***/ + +#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) + +#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, __u32) +#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) +#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, __u32) +#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, __u32) +#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, __u32) +#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, __u32) +#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, __u32) + +#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, __u32) +#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, __u32) + +#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, __u32) +#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, __u32) +#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, __u32) +#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, __u32) + +/* code length in bits, currently only for LIRC_MODE_LIRCCODE */ +#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, __u32) + +#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, __u32) +#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) +/* Note: these can reset the according pulse_width */ +#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, __u32) +#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, __u32) +#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, __u32) +#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, __u32) +#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, __u32) + +/* + * when a timeout != 0 is set the driver will send a + * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is + * never sent, timeout is disabled by default + */ +#define LIRC_SET_REC_TIMEOUT _IOW('i', 0x00000018, __u32) + +/* 1 enables, 0 disables timeout reports in MODE2 */ +#define LIRC_SET_REC_TIMEOUT_REPORTS _IOW('i', 0x00000019, __u32) + +/* + * pulses shorter than this are filtered out by hardware (software + * emulation in lirc_dev?) + */ +#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x0000001a, __u32) +/* + * spaces shorter than this are filtered out by hardware (software + * emulation in lirc_dev?) + */ +#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001b, __u32) +/* + * if filter cannot be set independently for pulse/space, this should + * be used + */ +#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001c, __u32) + +/* + * if enabled from the next key press on the driver will send + * LIRC_MODE2_FREQUENCY packets + */ +#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32) + +/* + * to set a range use + * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the + * lower bound first and later + * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound + */ + +#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, __u32) +#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, __u32) + +#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020) + +#define LIRC_SETUP_START _IO('i', 0x00000021) +#define LIRC_SETUP_END _IO('i', 0x00000022) + +#define LIRC_SET_WIDEBAND_RECEIVER _IOW('i', 0x00000023, __u32) + +#endif diff --git a/map.c b/map.c new file mode 100644 index 0000000..d3bd341 --- /dev/null +++ b/map.c @@ -0,0 +1,167 @@ +#include "project.h" + +#ifdef MAP_NULL + +void +map_output (int *computer, int *x, int *y) +{ +} + +#elif defined(MAP_HOME) + +void +map_output (int *computer, int *x, int *y) +{ + + switch (*computer) + { + case 1: + *computer = 5; + break; + case 2: + *computer = 4; + break; + case 3: + *computer = 0; + if (x) + *x = *x / 2; + break; + case 4: + *computer = 0; + if (x) + *x = (*x / 2) + 1024; + break; + case 5: + case 6: + case 7: + (*computer) -= 4; + break; + } +} + +#endif + +int +map_grace_left (int computer) +{ + int console = layout_computer_to_console (computer); + int cl = layout_console_to_computer (console - 1); + + if ((cl < 1) || (cl > N_COMPUTER)) + return 1; + + map_output (&computer, NULL, NULL); + map_output (&cl, NULL, NULL); + + return cl != computer; +} + +int +map_grace_right (int computer) +{ + int console = layout_computer_to_console (computer); + int cl = layout_console_to_computer (console + 1); + if ((cl < 1) || (cl > N_COMPUTER)) + return 1; + + map_output (&computer, NULL, NULL); + map_output (&cl, NULL, NULL); + + return cl != computer; +} + +int +map_switch_left (int *cc) +{ + int computer; + int console; + int ok; + + for (computer = *cc - 1; computer > 0; computer--) + { + +/* First see if this computer is being displayed - if so easy*/ + + if (layout_computer_to_console (computer) > 0) + { + *cc = computer; + layout_status (*cc); + return 1; + } + +/* We're switching left so try console from the left to the right */ + ok = 0; + + for (console = 1; console <= N_CONSOLE; ++console) + { + if (layout_possible (console, computer)) + { + layout_map (console, computer); + if (!ok) + *cc = computer; + computer++; + ok++; + } + } + if (ok) + { + layout_status (*cc); + return 1; + } + } + + + return 0; +} + +int +map_switch_right (int *cc) +{ + int computer; + int console; + int ok; + + + for (computer = *cc + 1; computer <= N_COMPUTER; computer++) + { + +/* First see if this computer is being displayed - if so easy*/ + + if (layout_computer_to_console (computer) > 0) + { + *cc = computer; + layout_status (*cc); + return 1; + } + +/* We're switching right so try console from the left to the right */ + ok = 0; + + for (console = N_CONSOLE; console > 0; --console) + { + if (layout_possible (console, computer)) + { + layout_map (console, computer); + if (!ok) + *cc = computer; + + computer--; + ok++; + } + } + if (ok) + { + layout_status (*cc); + return 1; + } + } + + + return 0; +} + +int +map_init (void) +{ + return layout_init (); +} diff --git a/output.c b/output.c new file mode 100644 index 0000000..c12262c --- /dev/null +++ b/output.c @@ -0,0 +1,441 @@ +#include "project.h" + +#include "output_map.h" + +output_dev_t *output_devs; + +static output_dev_t * +iface_to_dev (int iface) +{ + output_dev_t *ret; + for (ret = output_devs; ret; ret = ret->next) + { + if (!(iface--)) + return ret; + } + return NULL; +} + + + +static int +send_flush (output_dev_t * o) +{ + int ret; + uint8_t rbuf[36]; + uint8_t xbuf[31] = { + 0x55, 0x53, 0x42, 0x43, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, + 0x00, 0x00 + }; + memcpy (&xbuf[4], &o->seq, 4); + o->seq++; + +/*Sends SCSI test unit ready*/ + + if (usb_bulk_write (o->devh, 0x2, (char *) xbuf, 31, 10) != 31) + return -1; + ret = usb_bulk_read (o->devh, 0x81, (char *) rbuf, 36, 10); + if (ret <= 0) + return -1; + + + return 0; +} + +static int +send_msg (output_dev_t * o, uint8_t * msg) +{ + int ret; + uint8_t xbuf[31] = { + 0x55, 0x53, 0x42, 0x43, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0xd9, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, + 0x4f, 0x54 + }; + uint8_t rbuf[36]; + + memcpy (&xbuf[16], msg, 13); + memcpy (&xbuf[4], &o->seq, 4); + o->seq++; + +/* READ CD-DA MSF !*/ + + if (usb_bulk_write (o->devh, 0x2, (char *) xbuf, 31, 10) != 31) + return -1; + ret = usb_bulk_read (o->devh, 0x81, (char *) rbuf, 36, 10); + if (ret <= 0) + return -1; + + + return 0; +} + +static int +mouse (output_dev_t * o, uint16_t x, uint16_t y, uint8_t s, int l, + int m, int r) +{ + uint8_t bmask = (l ? 1 : 0) | (m ? 4 : 0) | (r ? 2 : 0); + uint8_t msg[13] = { 0x33, bmask, s, x & 0xff, + x >> 8, y & 0xff, y >> 8, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00 + }; + +// printf ("Mouse x=%4d y=%4d scroll=%2x bmask=%x\n", x, y, s, bmask); + + return send_msg (o, msg); +} + +static int +send_key_list (output_dev_t * o, uint8_t modifiers) +{ + uint8_t msg[13] = { 0x34, modifiers, 0x00 }; + memcpy (&msg[3], o->keys, OUTPUT_KEY_LIST_LEN); + +#if 0 + int i; + printf ("Keybd modifiers mask=%x key list=", modifiers); + + for (i = 0; i < OUTPUT_KEY_LIST_LEN; ++i) + { + if (o->keys[i]) + printf ("%02x ", o->keys[i]); + } + printf ("\n"); +#endif + + return send_msg (o, msg); +} + + + +static int +key_down (output_dev_t * o, uint8_t key, uint8_t modifiers) +{ + int i; + +//printf("Key %d down modifiers %x\n",key,modifiers); + + if (key) + { + do + { + for (i = 0; i < sizeof (o->keys); ++i) + { + if (o->keys[i] == key) + break; + } + + for (i = 0; i < sizeof (o->keys); ++i) + { + if (!o->keys[i]) + { + o->keys[i] = key; + break; + } + } + } + while (0); + } + + return send_key_list (o, modifiers); +} + + +static int +key_up (output_dev_t * o, uint8_t key, uint8_t modifiers) +{ + int i; + +//printf("Key %d up modifiers %x\n",key,modifiers); + + if (key) + { + for (i = 0; i < sizeof (o->keys); ++i) + { + if (o->keys[i] == key) + o->keys[i] = 0; + } + } + + return send_key_list (o, modifiers); +} + + + + + +struct map_ent * +lookup_map_ent (int keycode, uint8_t modifiers) +{ + int i; + + for (i = 0; i < MAP_LEN; ++i) + { + if (map[i].keycode == keycode) + { + if (map[i].hacks & (HACK_RCS | HACK_HS)) + { /*Do we require a shift key to match ? */ + if (modifiers & HACK_SHIFT_MASK) + return &map[i]; + } + else + { + return &map[i]; + } + } + } + return NULL; +} + + + + + +void +send_keyboard_event (int computer, int k, int ud) +{ + static uint8_t modifiers; + uint8_t mods; + struct map_ent *e = lookup_map_ent (k, modifiers); + output_dev_t *o; + + map_output (&computer, NULL, NULL); + + o = iface_to_dev (computer); + + if (!o) + return; + + if (!e) + return; + + if (e->hacks & HACK_MODIFIER_MASK) + { + if (ud) + { + modifiers |= e->hacks & HACK_MODIFIER_MASK; + } + else + { + modifiers &= ~(e->hacks & HACK_MODIFIER_MASK); + } + } + + if (e->hacks & HACK_HS) + { + mods = modifiers & ~HACK_SHIFT_MASK; + + if (ud) + { + if (modifiers & HACK_SHIFT_L) + key_up (o, 0xe1, mods); + if (modifiers & HACK_SHIFT_R) + key_up (o, 0xe5, mods); + } + + + } + else + { + mods = modifiers; + } + +#if 0 + printf + ("Hacks %8x, modifiers=%4x, mods=%4x, e->keysym=%4x, e->keycode=%4x, e->code=%2x\n", + e->hacks, modifiers, mods, e->keysym, e->keycode, e->code); +#endif + + if (ud) + key_down (o, e->code, mods); + else + key_up (o, e->code, mods); + + if (e->hacks & HACK_HS) + { + if (!ud) + { + if (modifiers & HACK_SHIFT_L) + key_down (o, 0xe1, modifiers); + if (modifiers & HACK_SHIFT_R) + key_down (o, 0xe5, modifiers); + } + } + + + send_flush (o); +} + + + +void +send_mouse_event (int computer, int x, int y, int s, int l, int m, int r) +{ + output_dev_t *o; + + + map_output (&computer, &x, &y); + + o = iface_to_dev (computer); + + + if (!o) + return; + + if (s < 0) + s += 256; + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + if (x > 2047) + x = 2047; + if (y > 2047) + y = 2047; + + mouse (o, x, y, s, l, m, r); + + if (s) + send_flush (o); +} + + + +static output_dev_t * +get_output_dev (struct usb_device *dev) +{ + struct usb_dev_handle *devh; + + output_dev_t *o; + + + for (o = output_devs; o; o = o->next) + if (!strcmp (o->filename, dev->filename)) + return o; + + + printf ("New output: %s\n", dev->filename); + + devh = usb_open (dev); + if (!devh) + return NULL; + + usb_reset (devh); + usb_close (devh); + usleep (100000); + + devh = usb_open (dev); + + if (!devh) + return NULL; + + + + usb_detach_kernel_driver_np (devh, 0); + usb_detach_kernel_driver_np (devh, 1); + usb_detach_kernel_driver_np (devh, 2); + usb_claim_interface (devh, 0); + + + usb_clear_halt (devh, 0x81); + usb_clear_halt (devh, 0x2); + + o = malloc (sizeof (*o)); + bzero (o, sizeof (*o)); + + strcpy (o->filename, dev->filename); + o->devh = devh; + + o->next = output_devs; + + output_devs = o; + + return o; +} + +static void +free_output_dev (output_dev_t * o) +{ + printf ("Lost output: %s\n", o->filename); + if (o->devh) + usb_close (o->devh); + free (o); +} + + +void +scan_output_devs (int init) +{ + struct usb_bus *bus; + struct usb_device *dev; + output_dev_t *od, **odp; + + usb_find_busses (); + if (!init && !usb_find_devices ()) + return; + + for (od = output_devs; od; od = od->next) + od->present = 0; + + for (bus = usb_get_busses (); bus; bus = bus->next) + { + for (dev = bus->devices; dev; dev = dev->next) + { + if ((dev->descriptor.idVendor == 0x0ea0) && + (dev->descriptor.idProduct == 0x2211)) + { + + od = get_output_dev (dev); + if (od) + od->present = 1; + } + } + } + + + + for (odp = &output_devs; (od = *odp);) + { + if (!od->present) + { + *odp = od->next; + free_output_dev (od); + } + else + { + odp = &od->next; + } + } + + +} + +void +output_reset (void) +{ + output_dev_t *od, **odp; + + for (odp = &output_devs; (od = *odp);) + { + *odp = od->next; + free_output_dev (od); + } + + scan_output_devs (1); + + +} diff --git a/output_map.h b/output_map.h new file mode 100644 index 0000000..978a17c --- /dev/null +++ b/output_map.h @@ -0,0 +1,871 @@ + +#define HACK_NONE 0UL /*Do nothing special */ + +#define HACK_CTRL_L 1UL<<0 +#define HACK_SHIFT_L 1UL<<1 +#define HACK_ALT_L 1UL<<2 +#define HACK_SUPER_L 1UL<<3 + +#define HACK_CTRL_R 1UL<<4 +#define HACK_SHIFT_R 1UL<<5 +#define HACK_ALT_R 1UL<<6 +#define HACK_SUPER_R 1UL<<7 + +#define HACK_SHIFT_MASK 0x22 +#define HACK_MODIFIER_MASK 0xff + +#define HACK_RCS 1UL<<16 /*Require a shift key to be pressed and pass it through */ +#define HACK_HS 1UL<<17 /*Require and then hide a shift key */ +#define HACK_ILS 1UL<<18 /*Insert left shift */ + + +struct map_ent +{ + uint32_t hacks; + uint8_t code; + uint32_t keycode; +}; + + +static struct map_ent map[] = { +/* Crazy parenthesis*/ + { + HACK_RCS, 0x26, KEY_9}, /* parenleft */ + { + HACK_RCS, 0x27, KEY_0}, /* parenright */ + +#ifdef APPLE_KEYBOARD + { + HACK_NONE, 0x29, KEY_102ND }, + { + HACK_NONE, 0x65, KEY_ESC}, + { + HACK_NONE, 0x48, KEY_F19}, + { + HACK_NONE, 0x64, KEY_GRAVE}, +#endif + +#if 0 +#if 0 +/* UK - US misery for windows UK map*/ + { + HACK_RCS, 0x34, 0x32}, /* shift 2 ->shift ' */ + { + HACK_RCS, 0x1f, 0x27}, /* shift ' -> shift 2 */ + { + HACK_RCS, 0x31, 0x60}, /* shift ` -> shift # */ + { + HACK_HS, 0x31, 0x33}, /* shift 3 -> # */ + { + HACK_NONE, 0x64, 0x5c}, /* backslash -> backslash */ +#endif +#if 1 +/*misery for james' gbus keymap */ + { + HACK_CTRL_L, 0xE0, 0xffe5}, /* Caps_Lock */ + { + HACK_NONE, 0x39, 0xffe3}, /* Control_L */ + { + HACK_NONE, 0x31, 0x60}, /* ` -> ` */ + { + HACK_NONE, 0x64, 0x5c}, /* backslash -> backslash */ +#endif +#endif + +/*Modifier keys*/ + { + HACK_CTRL_L, 0xE0, KEY_LEFTCTRL}, /* Control_L */ + { + HACK_SHIFT_L, 0xE1, KEY_LEFTSHIFT}, /* Shift_L */ + { + HACK_ALT_L, 0xE2, KEY_LEFTALT}, /* Alt_L */ + { + HACK_SUPER_L, 0xE3, KEY_LEFTMETA}, /* Super_L */ + { + HACK_CTRL_R, 0xE4, KEY_RIGHTCTRL}, /* Control_R */ + { + HACK_SHIFT_R, 0xE5, KEY_RIGHTSHIFT}, /* Shift_R */ + { + HACK_ALT_R, 0xE6, KEY_RIGHTALT}, /* Alt_R */ + { + HACK_SUPER_R, 0xE7, KEY_RIGHTMETA}, /* Super_R */ +/* normal service below here */ + { + HACK_NONE, 0x04, KEY_A}, /* a */ + { + HACK_NONE, 0x05, KEY_B}, /* b */ + { + HACK_NONE, 0x06, KEY_C}, /* c */ + { + HACK_NONE, 0x07, KEY_D}, /* d */ + { + HACK_NONE, 0x08, KEY_E}, /* e */ + { + HACK_NONE, 0x09, KEY_F}, /* f */ + { + HACK_NONE, 0x0a, KEY_G}, /* g */ + { + HACK_NONE, 0x0b, KEY_H}, /* h */ + { + HACK_NONE, 0x0c, KEY_I}, /* i */ + { + HACK_NONE, 0x0d, KEY_J}, /* j */ + { + HACK_NONE, 0x0e, KEY_K}, /* k */ + { + HACK_NONE, 0x0f, KEY_L}, /* l */ + { + HACK_NONE, 0x10, KEY_M}, /* m */ + { + HACK_NONE, 0x11, KEY_N}, /* n */ + { + HACK_NONE, 0x12, KEY_O}, /* o */ + { + HACK_NONE, 0x13, KEY_P}, /* p */ + { + HACK_NONE, 0x14, KEY_Q}, /* q */ + { + HACK_NONE, 0x15, KEY_R}, /* r */ + { + HACK_NONE, 0x16, KEY_S}, /* s */ + { + HACK_NONE, 0x17, KEY_T}, /* t */ + { + HACK_NONE, 0x18, KEY_U}, /* u */ + { + HACK_NONE, 0x19, KEY_V}, /* v */ + { + HACK_NONE, 0x1a, KEY_W}, /* w */ + { + HACK_NONE, 0x1b, KEY_X}, /* x */ + { + HACK_NONE, 0x1c, KEY_Y}, /* y */ + { + HACK_NONE, 0x1d, KEY_Z}, /* z */ + { + HACK_NONE, 0x1e, KEY_1}, /* 1 */ + { + HACK_NONE, 0x1f, KEY_2}, /* 2 */ + { + HACK_NONE, 0x20, KEY_3}, /* 3 */ + { + HACK_NONE, 0x21, KEY_4}, /* 4 */ + { + HACK_NONE, 0x22, KEY_5}, /* 5 */ + { + HACK_NONE, 0x23, KEY_6}, /* 6 */ + { + HACK_NONE, 0x24, KEY_7}, /* 7 */ + { + HACK_NONE, 0x25, KEY_8}, /* 8 */ + { + HACK_NONE, 0x26, KEY_9}, /* 9 */ + { + HACK_NONE, 0x27, KEY_0}, /* 0 */ + { + HACK_NONE, 0x28, KEY_ENTER}, /* Return */ + { + HACK_NONE, 0x29, KEY_ESC}, /* Escape */ + { + HACK_NONE, 0x2a, KEY_BACKSPACE}, /* BackSpace */ + { + HACK_NONE, 0x2b, KEY_TAB}, /* Tab */ + { + HACK_NONE, 0x2c, KEY_SPACE}, /* space */ + { + HACK_NONE, 0x2d, KEY_MINUS}, /* minus */ + { + HACK_NONE, 0x2e, KEY_EQUAL}, /* equal */ + { + HACK_NONE, 0x2f, KEY_LEFTBRACE}, /* bracketleft */ + { + HACK_NONE, 0x30, KEY_RIGHTBRACE}, /* bracketright */ + { + HACK_NONE, 0x31, KEY_BACKSLASH}, /* backslash */ + { + HACK_NONE, 0x32, KEY_BACKSLASH}, /* backslash */ + { + HACK_NONE, 0x33, KEY_SEMICOLON}, /* semicolon */ + { + HACK_NONE, 0x34, KEY_APOSTROPHE}, /* apostrophe */ + { + HACK_NONE, 0x35, KEY_GRAVE}, /* grave */ + { + HACK_NONE, 0x36, KEY_COMMA}, /* comma */ + { + HACK_NONE, 0x37, KEY_DOT}, /* period */ + { + HACK_NONE, 0x38, KEY_SLASH}, /* slash */ + { + HACK_NONE, 0x39, KEY_CAPSLOCK}, /* Caps_Lock */ + { + HACK_NONE, 0x3A, KEY_F1}, /* F1 */ + { + HACK_NONE, 0x3B, KEY_F2}, /* F2 */ + { + HACK_NONE, 0x3C, KEY_F3}, /* F3 */ + { + HACK_NONE, 0x3D, KEY_F4}, /* F4 */ + { + HACK_NONE, 0x3E, KEY_F5}, /* F5 */ + { + HACK_NONE, 0x3F, KEY_F6}, /* F6 */ + { + HACK_NONE, 0x40, KEY_F7}, /* F7 */ + { + HACK_NONE, 0x41, KEY_F8}, /* F8 */ + { + HACK_NONE, 0x42, KEY_F9}, /* F9 */ + { + HACK_NONE, 0x43, KEY_F10}, /* F10 */ + { + HACK_NONE, 0x44, KEY_F11}, /* F11 */ + { + HACK_NONE, 0x45, KEY_F12}, /* F12 */ + { + HACK_NONE, 0x46, KEY_SYSRQ}, /* Print */ + { + HACK_NONE, 0x47, KEY_SCROLLLOCK}, /* Scroll_Lock */ + { + HACK_NONE, 0x48, KEY_PAUSE}, /* Pause */ + { + HACK_NONE, 0x49, KEY_INSERT}, /* Insert */ + { + HACK_NONE, 0x4A, KEY_HOME}, /* Home */ + { + HACK_NONE, 0x4B, KEY_PAGEUP}, /* Prior */ + { + HACK_NONE, 0x4C, KEY_DELETE}, /* Delete */ + { + HACK_NONE, 0x4D, KEY_END}, /* End */ + { + HACK_NONE, 0x4E, KEY_PAGEDOWN}, /* Next */ + { + HACK_NONE, 0x4F, KEY_RIGHT}, /* Right */ + { + HACK_NONE, 0x50, KEY_LEFT}, /* Left */ + { + HACK_NONE, 0x51, KEY_DOWN}, /* Down */ + { + HACK_NONE, 0x52, KEY_UP}, /* Up */ + { + HACK_NONE, 0x53, KEY_NUMLOCK}, /* Num_Lock */ + { + HACK_NONE, 0x54, KEY_KPSLASH}, /* KP_Divide */ + { + HACK_NONE, 0x55, KEY_KPASTERISK}, /* KP_Multiply */ + { + HACK_NONE, 0x56, KEY_KPMINUS}, /* KP_Subtract */ + { + HACK_NONE, 0x57, KEY_KPPLUS}, /* KP_Add */ + { + HACK_NONE, 0x58, KEY_KPENTER}, /* KP_Enter */ + { + HACK_NONE, 0x59, KEY_KP1}, /* KP_1 */ + { + HACK_NONE, 0x5A, KEY_KP2}, /* KP_2 */ + { + HACK_NONE, 0x5B, KEY_KP3}, /* KP_3 */ + { + HACK_NONE, 0x5C, KEY_KP4}, /* KP_4 */ + { + HACK_NONE, 0x5D, KEY_KP5}, /* KP_5 */ + { + HACK_NONE, 0x5E, KEY_KP6}, /* KP_6 */ + { + HACK_NONE, 0x5F, KEY_KP7}, /* KP_7 */ + { + HACK_NONE, 0x60, KEY_KP8}, /* KP_8 */ + { + HACK_NONE, 0x61, KEY_KP9}, /* KP_9 */ + { + HACK_NONE, 0x62, KEY_KP0}, /* KP_0 */ + { + HACK_NONE, 0x63, KEY_KPDOT}, /* KP_Decimal */ + { + HACK_NONE, 0x64, KEY_102ND}, /* less */ + { + HACK_NONE, 0x65, KEY_COMPOSE}, /* Menu */ + { + HACK_NONE, 0x65, KEY_MENU}, /* Menu */ + { + HACK_NONE, 0x66, KEY_POWER}, /* XF86PowerOff */ + { + HACK_NONE, 0x67, KEY_KPEQUAL}, /* KP_Equal */ + { + HACK_NONE, 0x68, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x69, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x6A, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x6B, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x6C, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x6D, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x6E, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x6F, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x70, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x71, 0x0}, /* TouchpadToggle */ + { + HACK_NONE, 0x72, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x73, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x74, KEY_OPEN}, /* SunOpen */ + { + HACK_NONE, 0x75, KEY_HELP}, /* Help */ + { + HACK_NONE, 0x76, KEY_PROPS}, /* SunProps */ + { + HACK_NONE, 0x77, KEY_FRONT}, /* SunFront */ + { + HACK_NONE, 0x78, KEY_STOP}, /* Cancel */ + { + HACK_NONE, 0x79, KEY_AGAIN}, /* Again */ + { + HACK_NONE, 0x7A, KEY_UNDO}, /* Undo */ + { + HACK_NONE, 0x7B, KEY_CUT}, /* Cut */ + { + HACK_NONE, 0x7C, KEY_COPY}, /* Copy */ + { + HACK_NONE, 0x7D, KEY_PASTE}, /* Paste */ + { + HACK_NONE, 0x7E, KEY_FIND}, /* Find */ + { + HACK_NONE, 0x7F, KEY_MUTE}, /* Mute */ + { + HACK_NONE, 0x80, KEY_VOLUMEDOWN}, /* RaiseVolume */ + { + HACK_NONE, 0x81, KEY_VOLUMEUP}, /* LowerVolume */ + { + HACK_NONE, 0x82, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x83, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x84, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x85, KEY_KPDOT}, /* KP_Decimal */ + { + HACK_NONE, 0x86, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x87, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x88, KEY_KATAKANAHIRAGANA}, /* Hiragana_Katakana */ + { + HACK_NONE, 0x89, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x8A, KEY_HENKAN}, /* Henkan_Mode */ + { + HACK_NONE, 0x8B, KEY_MUHENKAN}, /* Muhenkan */ + { + HACK_NONE, 0x8C, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x8D, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x8E, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x8F, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x90, KEY_HANGEUL}, /* Hangul */ + { + HACK_NONE, 0x91, KEY_HANJA}, /* Hangul_Hanja */ + { + HACK_NONE, 0x92, KEY_KATAKANA}, /* Katakana */ + { + HACK_NONE, 0x93, KEY_HIRAGANA}, /* Hiragana */ + { + HACK_NONE, 0x94, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x95, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x96, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x97, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x98, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x99, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x9A, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x9B, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x9C, KEY_DELETE}, /* Delete */ + { + HACK_NONE, 0x9D, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x9E, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0x9F, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xA0, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xA1, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xA2, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xA3, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xA4, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xA5, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xA6, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xA7, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xA8, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xA9, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xAA, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xAB, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xAC, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xAD, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xAE, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xAF, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xB0, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xB1, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xB2, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xB3, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xB4, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xB5, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xB6, KEY_9}, /* parenleft */ + { + HACK_NONE, 0xB7, KEY_0}, /* parenright */ + { + HACK_NONE, 0xB8, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xB9, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xBA, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xBB, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xBC, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xBD, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xBE, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xBF, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xC0, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xC1, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xC2, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xC3, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xC4, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xC5, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xC6, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xC7, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xC8, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xC9, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xCA, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xCB, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xCC, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xCD, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xCE, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xCF, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xD0, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xD1, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xD2, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xD3, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xD4, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xD5, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xD6, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xD7, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xD8, KEY_DELETE}, /* Delete */ + { + HACK_NONE, 0xD9, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xDA, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xDB, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xDC, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xDD, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xDE, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xDF, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xE0, KEY_LEFTCTRL}, /* Control_L */ + { + HACK_NONE, 0xE1, KEY_LEFTSHIFT}, /* Shift_L */ + { + HACK_NONE, 0xE2, KEY_LEFTALT}, /* Alt_L */ + { + HACK_NONE, 0xE3, KEY_LEFTMETA}, /* Super_L */ + { + HACK_NONE, 0xE4, KEY_RIGHTCTRL}, /* Control_R */ + { + HACK_NONE, 0xE5, KEY_RIGHTSHIFT}, /* Shift_R */ + { + HACK_NONE, 0xE6, KEY_RIGHTALT}, /* Alt_R */ + { + HACK_NONE, 0xE7, KEY_RIGHTMETA}, /* Super_R */ + { + HACK_NONE, 0xE8, KEY_PLAYPAUSE}, /* Play */ + { + HACK_NONE, 0xE9, KEY_STOPCD}, /* Stop */ + { + HACK_NONE, 0xEA, KEY_PREVIOUSSONG}, /* |< */ + { + HACK_NONE, 0xEB, KEY_NEXTSONG}, /* >| */ + { + HACK_NONE, 0xEC, KEY_EJECTCD}, /* XF86Eject */ + { + HACK_NONE, 0xED, KEY_VOLUMEUP}, /* RaiseVolume */ + { + HACK_NONE, 0xEE, KEY_VOLUMEDOWN}, /* LowerVolume */ + { + HACK_NONE, 0xEF, KEY_MUTE}, /* Mute */ + { + HACK_NONE, 0xF0, KEY_WWW}, /* WWW */ + { + HACK_NONE, 0xF1, KEY_BACK}, /* Back */ + { + HACK_NONE, 0xF2, KEY_FORWARD}, /* Forward */ + { + HACK_NONE, 0xF3, KEY_CANCEL}, /* Cancel */ + { + HACK_NONE, 0xF4, KEY_FIND}, /* Find */ + { + HACK_NONE, 0xF5, KEY_SCROLLUP}, /* ScrollUp */ + { + HACK_NONE, 0xF6, KEY_SCROLLDOWN}, /* ScrollDown */ + { + HACK_NONE, 0xF7, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xF8, KEY_SLEEP}, /* Sleep */ + { + HACK_NONE, 0xF9, KEY_COFFEE}, /* ScreenSaver */ + { + HACK_NONE, 0xFA, KEY_REFRESH}, /* Reload */ + { + HACK_NONE, 0xFB, KEY_CALC}, /* Calculator */ + { + HACK_NONE, 0xFC, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xFD, 0x0}, /* NoSymbol */ + { + HACK_NONE, 0xFE, 0x0}, /* NoSymbol */ +}; + +#define MAP_LEN (sizeof(map)/sizeof(struct map_ent)) + + +#if 0 +#define MAP_LEN 256 +static int kc_map[MAP_LEN]; +static KeySym kc_map[MAP_LEN] = { + [0x04] = 0x61, /* a */ + [0x05] = 0x62, /* b */ + [0x06] = 0x63, /* c */ + [0x07] = 0x64, /* d */ + [0x08] = 0x65, /* e */ + [0x09] = 0x66, /* f */ + [0x0a] = 0x67, /* g */ + [0x0b] = 0x68, /* h */ + [0x0c] = 0x69, /* i */ + [0x0d] = 0x6a, /* j */ + [0x0e] = 0x6b, /* k */ + [0x0f] = 0x6c, /* l */ + [0x10] = 0x6d, /* m */ + [0x11] = 0x6e, /* n */ + [0x12] = 0x6f, /* o */ + [0x13] = 0x70, /* p */ + [0x14] = 0x71, /* q */ + [0x15] = 0x72, /* r */ + [0x16] = 0x73, /* s */ + [0x17] = 0x74, /* t */ + [0x18] = 0x75, /* u */ + [0x19] = 0x76, /* v */ + [0x1a] = 0x77, /* w */ + [0x1b] = 0x78, /* x */ + [0x1c] = 0x79, /* y */ + [0x1d] = 0x7a, /* z */ + [0x1e] = 0x31, /* 1 */ + [0x1f] = 0x32, /* 2 */ + [0x20] = 0x33, /* 3 */ + [0x21] = 0x34, /* 4 */ + [0x22] = 0x35, /* 5 */ + [0x23] = 0x36, /* 6 */ + [0x24] = 0x37, /* 7 */ + [0x25] = 0x38, /* 8 */ + [0x26] = 0x39, /* 9 */ + [0x27] = 0x30, /* 0 */ + [0x28] = 0xff0d, /* Return */ + [0x29] = 0xff1b, /* Escape */ + [0x2a] = 0xff08, /* BackSpace */ + [0x2b] = 0xff09, /* Tab */ + [0x2c] = 0x20, /* space */ + [0x2d] = 0x2d, /* minus */ + [0x2e] = 0x3d, /* equal */ + [0x2f] = 0x5b, /* bracketleft */ + [0x30] = 0x5d, /* bracketright */ + [0x31] = 0x5c, /* backslash */ + [0x32] = 0x5c, /* backslash */ + [0x33] = 0x3b, /* semicolon */ + [0x34] = 0x27, /* apostrophe */ + [0x35] = 0x60, /* grave */ + [0x36] = 0x2c, /* comma */ + [0x37] = 0x2e, /* period */ + [0x38] = 0x2f, /* slash */ + [0x39] = 0xffe5, /* Caps_Lock */ + [0x3A] = 0xffbe, /* F1 */ + [0x3B] = 0xffbf, /* F2 */ + [0x3C] = 0xffc0, /* F3 */ + [0x3D] = 0xffc1, /* F4 */ + [0x3E] = 0xffc2, /* F5 */ + [0x3F] = 0xffc3, /* F6 */ + [0x40] = 0xffc4, /* F7 */ + [0x41] = 0xffc5, /* F8 */ + [0x42] = 0xffc6, /* F9 */ + [0x43] = 0xffc7, /* F10 */ + [0x44] = 0xffc8, /* F11 */ + [0x45] = 0xffc9, /* F12 */ + [0x46] = 0xff61, /* Print */ + [0x47] = 0xff14, /* Scroll_Lock */ + [0x48] = 0xff13, /* Pause */ + [0x49] = 0xff63, /* Insert */ + [0x4A] = 0xff50, /* Home */ + [0x4B] = 0xff55, /* Prior */ + [0x4C] = 0xffff, /* Delete */ + [0x4D] = 0xff57, /* End */ + [0x4E] = 0xff56, /* Next */ + [0x4F] = 0xff53, /* Right */ + [0x50] = 0xff51, /* Left */ + [0x51] = 0xff54, /* Down */ + [0x52] = 0xff52, /* Up */ + [0x53] = 0xff7f, /* Num_Lock */ + [0x54] = 0xffaf, /* KP_Divide */ + [0x55] = 0xffaa, /* KP_Multiply */ + [0x56] = 0xffad, /* KP_Subtract */ + [0x57] = 0xffab, /* KP_Add */ + [0x58] = 0xff8d, /* KP_Enter */ + [0x59] = 0xffb1, /* KP_1 */ + [0x5A] = 0xffb2, /* KP_2 */ + [0x5B] = 0xffb3, /* KP_3 */ + [0x5C] = 0xffb4, /* KP_4 */ + [0x5D] = 0xffb5, /* KP_5 */ + [0x5E] = 0xffb6, /* KP_6 */ + [0x5F] = 0xffb7, /* KP_7 */ + [0x60] = 0xffb8, /* KP_8 */ + [0x61] = 0xffb9, /* KP_9 */ + [0x62] = 0xffb0, /* KP_0 */ + [0x63] = 0xffae, /* KP_Decimal */ + [0x64] = 0x3c, /* less */ + [0x65] = 0xff67, /* Menu */ + [0x66] = 0x1008ff2a, /* XF86PowerOff */ + [0x67] = 0xffbd, /* KP_Equal */ + [0x68] = 0x0, /* NoSymbol */ + [0x69] = 0x0, /* NoSymbol */ + [0x6A] = 0x0, /* NoSymbol */ + [0x6B] = 0x0, /* NoSymbol */ + [0x6C] = 0x0, /* NoSymbol */ + [0x6D] = 0x0, /* NoSymbol */ + [0x6E] = 0x0, /* NoSymbol */ + [0x6F] = 0x0, /* NoSymbol */ + [0x70] = 0x0, /* NoSymbol */ + [0x71] = 0x1008ffa9, /* XF86TouchpadToggle */ + [0x72] = 0x0, /* NoSymbol */ + [0x73] = 0x0, /* NoSymbol */ + [0x74] = 0x1005ff73, /* SunOpen */ + [0x75] = 0xff6a, /* Help */ + [0x76] = 0x1005ff70, /* SunProps */ + [0x77] = 0x1005ff71, /* SunFront */ + [0x78] = 0xff69, /* Cancel */ + [0x79] = 0xff66, /* Redo */ + [0x7A] = 0xff65, /* Undo */ + [0x7B] = 0x1008ff58, /* XF86Cut */ + [0x7C] = 0x1008ff57, /* XF86Copy */ + [0x7D] = 0x1008ff6d, /* XF86Paste */ + [0x7E] = 0xff68, /* Find */ + [0x7F] = 0x1008ff12, /* XF86AudioMute */ + [0x80] = 0x1008ff13, /* XF86AudioRaiseVolume */ + [0x81] = 0x1008ff11, /* XF86AudioLowerVolume */ + [0x82] = 0x0, /* NoSymbol */ + [0x83] = 0x0, /* NoSymbol */ + [0x84] = 0x0, /* NoSymbol */ + [0x85] = 0xffae, /* KP_Decimal */ + [0x86] = 0x0, /* NoSymbol */ + [0x87] = 0x0, /* NoSymbol */ + [0x88] = 0xff27, /* Hiragana_Katakana */ + [0x89] = 0x0, /* NoSymbol */ + [0x8A] = 0xff23, /* Henkan_Mode */ + [0x8B] = 0xff22, /* Muhenkan */ + [0x8C] = 0x0, /* NoSymbol */ + [0x8D] = 0x0, /* NoSymbol */ + [0x8E] = 0x0, /* NoSymbol */ + [0x8F] = 0x0, /* NoSymbol */ + [0x90] = 0xff31, /* Hangul */ + [0x91] = 0xff34, /* Hangul_Hanja */ + [0x92] = 0xff26, /* Katakana */ + [0x93] = 0xff25, /* Hiragana */ + [0x94] = 0x0, /* NoSymbol */ + [0x95] = 0x0, /* NoSymbol */ + [0x96] = 0x0, /* NoSymbol */ + [0x97] = 0x0, /* NoSymbol */ + [0x98] = 0x0, /* NoSymbol */ + [0x99] = 0x0, /* NoSymbol */ + [0x9A] = 0x0, /* NoSymbol */ + [0x9B] = 0x0, /* NoSymbol */ + [0x9C] = 0xffff, /* Delete */ + [0x9D] = 0x0, /* NoSymbol */ + [0x9E] = 0x0, /* NoSymbol */ + [0x9F] = 0x0, /* NoSymbol */ + [0xA0] = 0x0, /* NoSymbol */ + [0xA1] = 0x0, /* NoSymbol */ + [0xA2] = 0x0, /* NoSymbol */ + [0xA3] = 0x0, /* NoSymbol */ + [0xA4] = 0x0, /* NoSymbol */ + [0xA5] = 0x0, /* NoSymbol */ + [0xA6] = 0x0, /* NoSymbol */ + [0xA7] = 0x0, /* NoSymbol */ + [0xA8] = 0x0, /* NoSymbol */ + [0xA9] = 0x0, /* NoSymbol */ + [0xAA] = 0x0, /* NoSymbol */ + [0xAB] = 0x0, /* NoSymbol */ + [0xAC] = 0x0, /* NoSymbol */ + [0xAD] = 0x0, /* NoSymbol */ + [0xAE] = 0x0, /* NoSymbol */ + [0xAF] = 0x0, /* NoSymbol */ + [0xB0] = 0x0, /* NoSymbol */ + [0xB1] = 0x0, /* NoSymbol */ + [0xB2] = 0x0, /* NoSymbol */ + [0xB3] = 0x0, /* NoSymbol */ + [0xB4] = 0x0, /* NoSymbol */ + [0xB5] = 0x0, /* NoSymbol */ + [0xB6] = 0x28, /* parenleft */ + [0xB7] = 0x29, /* parenright */ + [0xB8] = 0x0, /* NoSymbol */ + [0xB9] = 0x0, /* NoSymbol */ + [0xBA] = 0x0, /* NoSymbol */ + [0xBB] = 0x0, /* NoSymbol */ + [0xBC] = 0x0, /* NoSymbol */ + [0xBD] = 0x0, /* NoSymbol */ + [0xBE] = 0x0, /* NoSymbol */ + [0xBF] = 0x0, /* NoSymbol */ + [0xC0] = 0x0, /* NoSymbol */ + [0xC1] = 0x0, /* NoSymbol */ + [0xC2] = 0x0, /* NoSymbol */ + [0xC3] = 0x0, /* NoSymbol */ + [0xC4] = 0x0, /* NoSymbol */ + [0xC5] = 0x0, /* NoSymbol */ + [0xC6] = 0x0, /* NoSymbol */ + [0xC7] = 0x0, /* NoSymbol */ + [0xC8] = 0x0, /* NoSymbol */ + [0xC9] = 0x0, /* NoSymbol */ + [0xCA] = 0x0, /* NoSymbol */ + [0xCB] = 0x0, /* NoSymbol */ + [0xCC] = 0x0, /* NoSymbol */ + [0xCD] = 0x0, /* NoSymbol */ + [0xCE] = 0x0, /* NoSymbol */ + [0xCF] = 0x0, /* NoSymbol */ + [0xD0] = 0x0, /* NoSymbol */ + [0xD1] = 0x0, /* NoSymbol */ + [0xD2] = 0x0, /* NoSymbol */ + [0xD3] = 0x0, /* NoSymbol */ + [0xD4] = 0x0, /* NoSymbol */ + [0xD5] = 0x0, /* NoSymbol */ + [0xD6] = 0x0, /* NoSymbol */ + [0xD7] = 0x0, /* NoSymbol */ + [0xD8] = 0xffff, /* Delete */ + [0xD9] = 0x0, /* NoSymbol */ + [0xDA] = 0x0, /* NoSymbol */ + [0xDB] = 0x0, /* NoSymbol */ + [0xDC] = 0x0, /* NoSymbol */ + [0xDD] = 0x0, /* NoSymbol */ + [0xDE] = 0x0, /* NoSymbol */ + [0xDF] = 0x0, /* NoSymbol */ + [0xE0] = 0xffe3, /* Control_L */ + [0xE1] = 0xffe1, /* Shift_L */ + [0xE2] = 0xffe9, /* Alt_L */ + [0xE3] = 0xffeb, /* Super_L */ + [0xE4] = 0xffe4, /* Control_R */ + [0xE5] = 0xffe2, /* Shift_R */ + [0xE6] = 0xffea, /* Alt_R */ + [0xE7] = 0xffec, /* Super_R */ + [0xE8] = 0x1008ff14, /* XF86AudioPlay */ + [0xE9] = 0x1008ff15, /* XF86AudioStop */ + [0xEA] = 0x1008ff16, /* XF86AudioPrev */ + [0xEB] = 0x1008ff17, /* XF86AudioNext */ + [0xEC] = 0x1008ff2c, /* XF86Eject */ + [0xED] = 0x1008ff13, /* XF86AudioRaiseVolume */ + [0xEE] = 0x1008ff11, /* XF86AudioLowerVolume */ + [0xEF] = 0x1008ff12, /* XF86AudioMute */ + [0xF0] = 0x1008ff2e, /* XF86WWW */ + [0xF1] = 0x1008ff26, /* XF86Back */ + [0xF2] = 0x1008ff27, /* XF86Forward */ + [0xF3] = 0xff69, /* Cancel */ + [0xF4] = 0xff68, /* Find */ + [0xF5] = 0x1008ff78, /* XF86ScrollUp */ + [0xF6] = 0x1008ff79, /* XF86ScrollDown */ + [0xF7] = 0x0, /* NoSymbol */ + [0xF8] = 0x1008ff2f, /* XF86Sleep */ + [0xF9] = 0x1008ff2d, /* XF86ScreenSaver */ + [0xFA] = 0x1008ff73, /* XF86Reload */ + [0xFB] = 0x1008ff1d, /* XF86Calculator */ + [0xFC] = 0x0, /* NoSymbol */ + [0xFD] = 0x0, /* NoSymbol */ + [0xFE] = 0x0, /* NoSymbol */ +}; + + +static uint8_t +keycode_to_usb (int k) +{ + int i; + for (i = 0; i < MAP_LEN; ++i) + { + if (kc_map[i] == k) + return i; + } + return 0; +} +#endif diff --git a/project.h b/project.h new file mode 100644 index 0000000..eba3de8 --- /dev/null +++ b/project.h @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BROMIUM +#define APPLE_KEYBOARD +#define N_COMPUTER 4 +#define N_CONSOLE 1 +#define MAP_NULL +#define LAYOUT_NULL +#endif + +#ifdef HOME +#define N_COMPUTER 7 +#define N_CONSOLE 3 +#define MAP_HOME +#define LAYOUT_HOME +#endif + +typedef struct MM_struct MM; + +typedef struct input_dev +{ + struct input_dev *next; + int id; /* /dev/input/event%d */ + int present; /* !0 if the device file exists */ + int fd; /* fd if the device is open, -1 otherwise */ + int blacklistid; /* !0 if the device is a km link */ +} input_dev_t; + +#define OUTPUT_KEY_LIST_LEN 10 + +typedef struct output_dev +{ + struct output_dev *next; + + char filename[PATH_MAX + 1]; + int present; + + struct usb_dev_handle *devh; + uint32_t seq; + + uint8_t keys[OUTPUT_KEY_LIST_LEN]; + +} output_dev_t; + + + +#include "prototypes.h" diff --git a/prototypes.h b/prototypes.h new file mode 100644 index 0000000..695315d --- /dev/null +++ b/prototypes.h @@ -0,0 +1,52 @@ +/* kmd.c */ +extern int main(int argc, char *argv[]); +/* status.c */ +extern void status_draw_computer(int computer, int locked, int console, int active, int force); +extern void status_draw_console(int console, int locked, int computer, int active, int force); +extern void status_init(void); +extern void status_reset(void); +/* lcd.c */ +extern void lcd_on(void); +extern void lcd_off(void); +extern void lcd_close(void); +extern void lcd_vline(int x, int y1, int y2, int r, int g, int b); +extern void lcd_hline(int y, int x1, int x2, int r, int g, int b); +extern void lcd_box(int x1, int y1, int x2, int y2, int r, int g, int b); +extern void lcd_ss(int v, int x1, int y1, int w, int h); +extern int lcd_open(void); +/* input.c */ +extern input_dev_t *input_devs; +extern void scan_input_devs(void); +/* dispatch.c */ +extern void dispatch_key(int key, int ud); +extern void dispatch_mouse_button(int button, int ud); +extern void dispatch_mouse_wheel(int d); +extern void dispatch_mouse_motion(int rx, int ry); +extern void dispatch_event(struct input_event *ev); +extern void dispatch_init(void); +/* output.c */ +extern output_dev_t *output_devs; +extern struct map_ent *lookup_map_ent(int keycode, uint8_t modifiers); +extern void send_keyboard_event(int computer, int k, int ud); +extern void send_mouse_event(int computer, int x, int y, int s, int l, int m, int r); +extern void scan_output_devs(int init); +extern void output_reset(void); +/* map.c */ +extern void map_output(int *computer, int *x, int *y); +extern int map_grace_left(int computer); +extern int map_grace_right(int computer); +extern int map_switch_left(int *cc); +extern int map_switch_right(int *cc); +extern int map_init(void); +/* layout.c */ +extern int layout_computer_to_console(int computer); +extern int layout_console_to_computer(int console); +extern int layout_possible(int console, int computer); +extern void layout_map(int console, int computer); +extern void layout_status(int active_computer); +extern void layout_toggle_lock(int computer); +extern int layout_init(void); +/* video_switch.c */ +extern MM *MM_open(void); +extern int MM_set(MM *m, int a, int b); +extern int VS_set(MM *m, int v); diff --git a/status.c b/status.c new file mode 100644 index 0000000..e627338 --- /dev/null +++ b/status.c @@ -0,0 +1,141 @@ +#include "project.h" + + +static int computer_old_locked[N_COMPUTER + 1]; +static int computer_old_active[N_COMPUTER + 1]; +static int computer_old_console[N_COMPUTER + 1]; + + +static int console_old_locked[N_CONSOLE + 1]; +static int console_old_active[N_CONSOLE + 1]; +static int console_old_computer[N_CONSOLE + 1]; + + +void +status_draw_computer (int computer, int locked, int console, int active, + int force) +{ + + int x = (computer - 1) * 45; + int y = 5; + x += 2; + + if (force || (computer_old_locked[computer] != locked)) + { + if (locked != -1) + computer_old_locked[computer] = locked; + else + locked = computer_old_locked[computer]; + lcd_box (x, y, x + 44, y + 44, locked ? 255 : 0, locked ? 0 : 255, + locked ? 127 : 0); + } + + if (force || (computer_old_console[computer] != console)) + { + if (console != -1) + computer_old_console[computer] = console; + else + console = computer_old_console[computer]; + lcd_ss (console ? console : 10, x + 17, y + 11, 11, 22); + } + + if (force || (computer_old_active[computer] != active)) + { + if (active != -1) + computer_old_active[computer] = active; + else + active = computer_old_active[computer]; + lcd_box (x + 5, y + 5, x + 9, y + 9, active ? 255 : 0, active ? 255 : 0, + active ? 255 : 0); + } + +} + +void +status_draw_console (int console, int locked, int computer, int active, + int force) +{ + int x = (console - 1) * 106; + int y = 100; + + + if (force || (console_old_locked[console] != locked)) + { + if (locked != -1) + console_old_locked[console] = locked; + else + locked = console_old_locked[console]; + lcd_box (x, y, x + 105, y + 105, locked ? 255 : 0, locked ? 0 : 255, + locked ? 127 : 0); + } + + if (force || (console_old_computer[console] != computer)) + { + if (computer != -1) + console_old_computer[console] = computer; + else + computer = console_old_computer[console]; + lcd_ss (computer ? computer : 10, x + 35, y + 20, 30, 60); + } + + if (force || (console_old_active[console] != active)) + { + if (active != -1) + console_old_active[console] = active; + else + active = console_old_active[console]; + lcd_box (x + 5, y + 5, x + 9, y + 9, active ? 255 : 0, active ? 255 : 0, + active ? 255 : 0); + } + +} + + +void +status_init (void) +{ + int i; + + lcd_open (); + lcd_on (); + + memset (computer_old_locked, 0xff, sizeof (computer_old_locked)); + memset (computer_old_active, 0xff, sizeof (computer_old_active)); + memset (computer_old_console, 0xff, sizeof (computer_old_console)); + + for (i = 1; i <= N_COMPUTER; ++i) + { + status_draw_computer (i, 0, 0, 0, 0); + } + + memset (console_old_locked, 0xff, sizeof (console_old_locked)); + memset (console_old_active, 0xff, sizeof (console_old_active)); + memset (console_old_computer, 0xff, sizeof (console_old_computer)); + + for (i = 1; i <= N_CONSOLE; ++i) + { + status_draw_console (i, 0, 0, 0, 0); + } + +} + +void +status_reset (void) +{ + int i; + + lcd_close (); + lcd_open (); + lcd_on (); + + for (i = 1; i <= N_COMPUTER; ++i) + { + status_draw_computer (i, -1, -1, -1, 0); + } + + for (i = 1; i <= N_CONSOLE; ++i) + { + status_draw_console (i, -1, -1, -1, 0); + } + +} diff --git a/video_switch.c b/video_switch.c new file mode 100644 index 0000000..74d70b5 --- /dev/null +++ b/video_switch.c @@ -0,0 +1,365 @@ +#include "project.h" +#include "lirc.h" + +#define NOTPULSE 0 +#define PULSE 0 + + +#define ONE(a) ((a) | PULSE) +#define ZERO(a) ((a) | NOTPULSE) + + +typedef struct +{ + int fd; + int a; + int b; + unsigned mask; +} MS; + +struct MM_struct +{ + MS *left, *right, *top; +}; + + +static uint8_t +read_byte (int **bits, int *n) +{ + uint8_t c = 0; + int i = 8; + + while (i-- && (*n)--) + { + c <<= 1; + c |= ! !(*((*bits)++)); + } + + return c; +} + +static void +dump_bits (int *bits, int n) +{ + uint8_t b; + int i; + + for (i = 0; i < n; ++i) + { + printf ("%d", bits[i]); + if ((i % 8) == 7) + printf (" "); + } + printf ("\n"); + + while (n > 0) + { + b = read_byte (&bits, &n); + printf ("%02x ", b); + } + printf ("\n"); + + +} + + + + + +static void +bit (int b) +{ + static int bits[1024]; + static int bc; + + + if (b == 2) + { + bc = 0; + return; + } + + + + if (b == 3) + { + if (bc) + dump_bits (bits, bc); + bc = 0; + return; + } + +// printf(" > bit[%3d]=%d\n",bc,b); + + bits[bc++] = b; +} + + +static void +ana (lirc_t * buf, int n, int mode) +{ + int s = 0; + + while (n--) + { + lirc_t v = *(buf++); + + if (mode == 2) + s = (v & 0xff000000U) ? 1 : 0; + else + s = !s; + + v &= 0xffffff; + +// printf ("%5d %d\n", v, s); + + if (s) + continue; + + if ((v < 5000) && (v > 4000)) + { + bit (2); + } + else if ((v < 750) && (v > 450)) + { + bit (0); + } + else if ((v < 1850) && (v > 1500)) + { + bit (1); + } + else + { + bit (3); + } + } + + + +} + +static void +listen (int fd) +{ + + for (;;) + { + lirc_t v; + + read (fd, &v, sizeof (v)); + ana (&v, 1, 2); + + + + } +} + +static int +send_command (int fd, unsigned mask, uint8_t * buf, int n) +{ + lirc_t cbuf[128], *ptr = cbuf; + uint8_t c; + int b = 0; + + printf ("Sending %x %x %x %x to fd %d mask %x\n", + buf[0], buf[1], buf[2], buf[3], fd, mask); + + *(ptr++) = ONE (9300); + *(ptr++) = ZERO (4500); + b += 2; + + while (n--) + { + for (c = 128; c; c >>= 1) + { + if ((*buf) & c) + { + *(ptr++) = ONE (550); + *(ptr++) = ZERO (1650); + } + else + { + *(ptr++) = ONE (550); + *(ptr++) = ZERO (600); + } + b += 2; + + + } + buf++; + } + *(ptr++) = ONE (550); + b++; + + + + +#if 0 + ana (cbuf, b, 0); + bit (3); +#endif + + + ioctl (fd, LIRC_SET_TRANSMITTER_MASK, &mask); + +#if 0 + if (write (fd, cbuf, sizeof (lirc_t) * b) != (b * sizeof (lirc_t))) + return -1; + usleep (20000); +#endif + if (write (fd, cbuf, sizeof (lirc_t) * b) != (b * sizeof (lirc_t))) + return -1; + usleep (100000); + return 0; +} + + +static int +send_command4 (int fd, unsigned m, uint8_t c1, uint8_t c2, uint8_t c3, + uint8_t c4) +{ + uint8_t c[] = { c1, c2, c3, c4 }; + return send_command (fd, m, c, sizeof (c)); +} + +static int +s42 (int fd, int ab, unsigned mask, int d) +{ + uint8_t c3[2][5] = + { {0xb0, 0x98, 0xa8, 0x0a, 0x52}, {0x40, 0x18, 0x8a, 0xca, 0xa2} }; + uint8_t c4[2][5] = + { {0x4f, 0x67, 0x57, 0xf5, 0xad}, {0xbf, 0xe7, 0x75, 0x35, 0x5d} }; + + if (ab < 0) + return -1; + if (ab > 1) + return -1; + if (d < 0) + return -1; + if (d > 4) + return -1; + + + return send_command4 (fd, mask, 0x00, 0xff, c3[ab][d], c4[ab][d]); + +} + +static int +s51 (int fd, unsigned mask, int d) +{ + uint8_t c3[6] = { 0x00, 0xa0, 0x10, 0x90, 0x50, 0xb0 }; + uint8_t c4[6] = { 0x00, 0x5f, 0xef, 0x6f, 0xaf, 0x4f }; + + if (d < 1) + return -1; + if (d > 5) + return -1; + + + return send_command4 (fd, mask, 0x00, 0xfd, c3[d], c4[d]); +} + + +static int +MS_set (MS * m, int a, int b) +{ + if (!m) + return -1; + + + + if ((a != -1) && (m->a != a)) + { + + if (s42 (m->fd, 0, m->mask, a)) + return -1; + m->a = a; + } + + + if ((b != -1) && (m->b != b)) + { + if (s42 (m->fd, 1, m->mask, b)) + return -1; + m->b = b; + } + + + return 0; +} + + +static MS * +MS_open (int fd, unsigned mask) +{ + MS *ret = malloc (sizeof (MS)); + + ret->fd = fd; + ret->a = -1; + ret->b = -1; + ret->mask = mask; + + return ret; +} + +MM * +MM_open (void) +{ + int fd; + MM *ret = malloc (sizeof (MM)); + unsigned u; + + fd = open ("/dev/lirc0", O_RDWR); + u = 40000; + ioctl (fd, LIRC_SET_SEND_CARRIER, &u); + + //s51(fd,1,2); + + //listen(fd); + + ret->left = MS_open (fd, 1); + ret->right = NULL; //MS_open (fd, 2); + + fd = open ("/dev/lirc1", O_RDWR); + u = 40000; + ioctl (fd, LIRC_SET_SEND_CARRIER, &u); + ret->top = NULL; // MS_open (fd, 1); + + + + return ret; +} + + +int +MM_set (MM * m, int a, int b) +{ + + return MS_set (m->left, a, b); + + +} + +int +VS_set (MM * m, int v) +{ + return s51 (m->left->fd, 2, v); +} + + + + +#if 0 +main (int argc, char *argv[]) +{ + + MM *mm; + + mm = MM_open (); + +// MM_set (mm,1, 2); + //MM_set (mm,-1, 1); +// MM_set (mm,1, -1); + +} +#endif -- cgit v1.2.3