summaryrefslogtreecommitdiffstats
path: root/uirdesktop/fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'uirdesktop/fb.c')
-rw-r--r--uirdesktop/fb.c719
1 files changed, 713 insertions, 6 deletions
diff --git a/uirdesktop/fb.c b/uirdesktop/fb.c
index 955432d9..752b69da 100644
--- a/uirdesktop/fb.c
+++ b/uirdesktop/fb.c
@@ -22,11 +22,17 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
-#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+#include <linux/kd.h>
#include "uimain.h"
+#include "bsops.h"
extern char g_username[];
extern char g_hostname[];
@@ -43,8 +49,24 @@ extern int g_tcp_port_rdp; /* in tcp.c */
extern int g_bytes_in;
extern int pal_entries[];
+extern int g_bs_bpp;
+extern int g_bs_Bpp;
extern char * g_bs;
+
+static int g_bpp = 8;
+static int g_Bpp = 1;
+
+/* keys */
+struct key
+{
+ int scancode;
+ int rdpcode;
+ int ext;
+};
+static struct key g_keys[256];
+static char g_keyfile[64] = "./default.key";
+
struct cursor
{
unsigned char andmask[32 * 32];
@@ -57,18 +79,53 @@ struct cursor
static struct cursor g_mcursor; /* current mouse */
static int g_mouse_x = 0;
static int g_mouse_y = 0;
+static int g_mouse_buttons = 0; /* mouse button states */
+static int g_mousefd = 0; /* mouse fd */
+static int g_mouse_state = 0; /* used when reading mouse device */
+static int g_uts = 0; /* updates to skip */
+static int g_alt_down = 0; /* used to disable control alt delete */
+static int g_control_down = 0;
+static int g_shift_down = 0;
+static int g_disable_cad = 0; /* disable control alt delete */
+ /* and ctrl shift esc */
static int g_wfpx = 0; /* wait for pixel stuff */
static int g_wfpy = 0;
static int g_wfpv = 0;
static int g_show_wfp = 0;
static int g_no_draw = 0; /* this means don't draw the screen but draw on
backingstore */
-
/* for transparent colour */
static int g_use_trans = 0;
static int g_trans_colour = 0;
+
+/* clip */
+static int g_clip_left = 0;
+static int g_clip_top = 0;
+static int g_clip_right = 0;
+static int g_clip_bottom = 0;
+
+static int g_kbfd = 0; /* keyboard fd */
+
+static int g_fbfd = 0; /* framebuffer fd */
+static char * g_sdata = 0;
+static struct fb_var_screeninfo g_vinfo;
+static struct fb_fix_screeninfo g_finfo;
+
+static short g_saved_red[256]; /* original hw palette */
+static short g_saved_green[256];
+static short g_saved_blue[256];
+
+struct my_rect
+{
+ int x;
+ int y;
+ int w;
+ int h;
+};
+static struct my_rect g_rect = {0, 0, 0, 0};
+
/*****************************************************************************/
void
mi_error(char * msg)
@@ -102,12 +159,270 @@ mi_create_window(void)
void
mi_update_screen(void)
{
+ int i;
+ int j;
+ int endi;
+ int endj;
+ int x;
+ int y;
+ int pixel;
+ int r;
+ int g;
+ int b;
+
+ endi = UI_MIN(g_rect.y + g_rect.h, g_clip_bottom);
+ endj = UI_MIN(g_rect.x + g_rect.w, g_clip_right);
+ x = UI_MAX(g_rect.x, g_clip_left);
+ y = UI_MAX(g_rect.y, g_clip_top);
+ //printf("hi %d %d %d %d\n", x, y, endi, endj);
+ if (g_bpp == 16 && g_bs_bpp == 32)
+ {
+ for (i = y; i < endi; i++)
+ {
+ for (j = x; j < endj; j++)
+ {
+ pixel = ((unsigned int *) g_bs)[i * g_width + j];
+ SPLIT_COLOUR32(pixel, b, g, r);
+ MAKE_COLOUR16(pixel, r, g, b);
+ ((unsigned short *) g_sdata)[i * g_width + j] = pixel;
+ }
+ }
+ }
+ g_rect.x = 0;
+ g_rect.y = 0;
+ g_rect.w = 0;
+ g_rect.h = 0;
+ //printf("bye\n");
+}
+
+/*****************************************************************************/
+static void
+process_keyboard(void)
+{
+ char buf[128];
+ unsigned char ch;
+ int count;
+ int index;
+ int keyup;
+ int rdpkey;
+ int ext;
+
+ ext = 0;
+ index = 0;
+ count = read(g_kbfd, buf, 128);
+ while (index < count)
+ {
+ ch = (unsigned char)buf[index];
+ //printf("%2.2x\n", ch);
+ keyup = ch & 0x80;
+ rdpkey = ch & 0x7f;
+ ext = g_keys[rdpkey].ext ? 0x100 : 0;
+ rdpkey = g_keys[rdpkey].rdpcode;
+ if (rdpkey == 0x1d) /* control */
+ {
+ g_control_down = !keyup;
+ }
+ if (rdpkey == 0x38) /* alt */
+ {
+ g_alt_down = !keyup;
+ }
+ if (rdpkey == 0x2a || rdpkey == 0x36) /* shift */
+ {
+ g_shift_down = !keyup;
+ }
+ if (g_disable_cad) /* diable control alt delete and control shift escape */
+ {
+ if (rdpkey == 0x53 && g_alt_down && g_control_down) /* delete */
+ {
+ rdpkey = 0;
+ }
+ if (rdpkey == 0x01 && g_shift_down && g_control_down) /* escape */
+ {
+ rdpkey = 0;
+ }
+ }
+ if (rdpkey > 0 && g_mouse_buttons == 0)
+ {
+ if (!keyup)
+ {
+ ui_key_down(rdpkey, ext);
+ }
+ else
+ {
+ ui_key_up(rdpkey, ext);
+ }
+ }
+ index++;
+ }
+}
+
+/*****************************************************************************/
+static int
+process_mouse(void)
+{
+ char d[128];
+ int c;
+ int i;
+ int b;
+ int old_x;
+ int old_y;
+ int old_but1;
+ int old_but2;
+ int mouse_x; /* hot spot */
+ int mouse_y; /* hot spot */
+
+ mouse_x = g_mouse_x + g_mcursor.x;
+ mouse_y = g_mouse_y + g_mcursor.y;
+ old_x = mouse_x;
+ old_y = mouse_y;
+ old_but1 = g_mouse_buttons & 1;
+ old_but2 = g_mouse_buttons & 2;
+ c = read(g_mousefd, &d, 128);
+ for (i = 0; i < c; i++)
+ {
+ b = (unsigned char)d[i];
+ switch (g_mouse_state)
+ {
+ case 0:
+ if (b & 0x08) /* PS2_CTRL_BYTE */
+ {
+ g_mouse_buttons = b & (1 | 2);
+ g_mouse_state = 1;
+ }
+ break;
+ case 1: /* x */
+ if (b > 127)
+ {
+ b -= 256;
+ }
+ mouse_x += b;
+ if (mouse_x < 0)
+ {
+ mouse_x = 0;
+ }
+ else if (mouse_x >= g_width)
+ {
+ mouse_x = g_width - 1;
+ }
+ g_mouse_state = 2;
+ break;
+ case 2: /* y */
+ if (b > 127)
+ {
+ b -= 256;
+ }
+ mouse_y += -b;
+ if (mouse_y < 0)
+ {
+ mouse_y = 0;
+ }
+ else if (mouse_y >= g_height)
+ {
+ mouse_y = g_height - 1;
+ }
+ g_mouse_state = 0;
+ break;
+ }
+ }
+ if (old_x != mouse_x || old_y != mouse_y) /* mouse pos changed */
+ {
+ ui_mouse_move(mouse_x, mouse_y);
+ }
+ if (old_but1 != (g_mouse_buttons & 1)) /* left button changed */
+ {
+ if (g_mouse_buttons & 1)
+ {
+ ui_mouse_button(1, mouse_x, mouse_y, 1);
+ }
+ else
+ {
+ ui_mouse_button(1, mouse_x, mouse_y, 0);
+ }
+ }
+ if (old_but2 != (g_mouse_buttons & 2)) /* right button changed */
+ {
+ if (g_mouse_buttons & 2)
+ {
+ ui_mouse_button(2, mouse_x, mouse_y, 1);
+ }
+ else
+ {
+ ui_mouse_button(2, mouse_x, mouse_y, 0);
+ }
+ }
+ //undraw_mouse();
+ g_mouse_x = mouse_x - g_mcursor.x;
+ g_mouse_y = mouse_y - g_mcursor.y;
+ //draw_mouse();
+ return 0;
}
/*****************************************************************************/
int
mi_main_loop(void)
{
+ fd_set rfds;
+// fd_set wfds;
+ int rv;
+ int fd;
+ struct timeval tv;
+
+ fd = UI_MAX(g_tcp_sck, UI_MAX(g_mousefd, g_kbfd));
+ FD_ZERO(&rfds);
+ FD_SET(g_tcp_sck, &rfds);
+ FD_SET(g_mousefd, &rfds);
+ FD_SET(g_kbfd, &rfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ rv = select(fd + 1, &rfds, 0, 0, &tv);
+ while (rv > -1)
+ {
+ if (rv == 0)
+ {
+ usleep(0);
+ }
+ if (FD_ISSET(g_kbfd, &rfds))
+ {
+ process_keyboard();
+ }
+ if (FD_ISSET(g_mousefd, &rfds))
+ {
+ process_mouse();
+ }
+ if (FD_ISSET(g_tcp_sck, &rfds))
+ {
+ if (!ui_read_wire())
+ {
+ return 0;
+ }
+ }
+ fd = UI_MAX(g_tcp_sck, UI_MAX(g_mousefd, g_kbfd));
+ FD_ZERO(&rfds);
+ FD_SET(g_tcp_sck, &rfds);
+ FD_SET(g_mousefd, &rfds);
+ FD_SET(g_kbfd, &rfds);
+#ifdef WITH_RDPSND
+// if (g_rdpsnd && g_dsp_busy)
+// {
+// fd = MAX(fd, g_dsp_fd);
+// FD_ZERO(&wfds);
+// FD_SET(g_dsp_fd, &wfds);
+// rv = select(fd + 1, &rfds, &wfds, 0, 0);
+// if (rv > 0 && FD_ISSET(g_dsp_fd, &wfds))
+// {
+// wave_out_play();
+// }
+// }
+// else
+// {
+// rv = select(fd + 1, &rfds, 0, 0, 0);
+// }
+#else
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ rv = select(fd + 1, &rfds, 0, 0, &tv);
+#endif
+ }
return 0;
}
@@ -115,7 +430,6 @@ mi_main_loop(void)
void
mi_add_to(int x, int y, int cx, int cy)
{
-/*
int right;
int bottom;
@@ -149,7 +463,6 @@ mi_add_to(int x, int y, int cx, int cy)
g_rect.w = right - g_rect.x;
g_rect.h = bottom - g_rect.y;
}
-*/
}
/*****************************************************************************/
@@ -188,6 +501,8 @@ mi_fill_rect(int x, int y, int cx, int cy, int colour)
{
return;
}
+ mi_add_to(x, y, cx, cy);
+ mi_update_screen();
}
/*****************************************************************************/
@@ -198,6 +513,17 @@ mi_line(int x1, int y1, int x2, int y2, int colour)
{
return;
}
+ int x;
+ int y;
+ int cx;
+ int cy;
+
+ x = UI_MIN(x1, x2);
+ y = UI_MIN(y1, y2);
+ cx = (UI_MAX(x1, x2) + 1) - x;
+ cy = (UI_MAX(y1, y2) + 1) - y;
+ mi_add_to(x, y, cx, cy);
+ mi_update_screen();
}
/*****************************************************************************/
@@ -208,18 +534,32 @@ mi_screen_copy(int x, int y, int cx, int cy, int srcx, int srcy)
{
return;
}
+ mi_add_to(x, y, cx, cy);
+ mi_update_screen();
}
/*****************************************************************************/
void
mi_set_clip(int x, int y, int cx, int cy)
{
+ g_clip_left = x;
+ g_clip_top = y;
+ g_clip_right = x + cx;
+ g_clip_bottom = y + cy;
+ g_clip_left = UI_MAX(g_clip_left, 0);
+ g_clip_top = UI_MAX(g_clip_top, 0);
+ g_clip_right = UI_MIN(g_clip_right, g_width);
+ g_clip_bottom = UI_MIN(g_clip_bottom, g_height);
}
/*****************************************************************************/
void
mi_reset_clip(void)
{
+ g_clip_left = 0;
+ g_clip_top = 0;
+ g_clip_right = g_width;
+ g_clip_bottom = g_height;
}
/*****************************************************************************/
@@ -228,13 +568,41 @@ mi_create_cursor(unsigned int x, unsigned int y,
int width, int height,
unsigned char * andmask, unsigned char * xormask)
{
- return (void *) 1;
+ struct cursor * c;
+ int i;
+ int j;
+
+ c = (struct cursor *) malloc(sizeof(struct cursor));
+ memset(c, 0, sizeof(struct cursor));
+ c->w = width;
+ c->h = height;
+ c->x = x;
+ c->y = y;
+ for (i = 0; i < 32; i++)
+ {
+ for (j = 0; j < 32; j++)
+ {
+ if (bs_is_pixel_on(andmask, j, i, 32, 1))
+ {
+ bs_set_pixel_on(c->andmask, j, 31 - i, 32, 8, 255);
+ }
+ if (bs_is_pixel_on(xormask, j, i, 32, 1))
+ {
+ bs_set_pixel_on(c->xormask, j, 31 - i, 32, 8, 255);
+ }
+ }
+ }
+ return c;
}
/*****************************************************************************/
void
mi_destroy_cursor(void * cursor)
{
+ struct cursor * c;
+
+ c = (struct cursor *) cursor;
+ free(c);
}
/*****************************************************************************/
@@ -342,12 +710,351 @@ parse_parameters(int in_argc, char ** in_argv)
}
/*****************************************************************************/
+static void
+get_username_and_hostname(void)
+{
+ char fullhostname[64];
+ char * p;
+ struct passwd * pw;
+
+ strncpy(g_username, "unknown", 255);
+ strncpy(g_hostname, "unknown", 255);
+ pw = getpwuid(getuid());
+ if (pw != 0)
+ {
+ if (pw->pw_name != 0)
+ {
+ strncpy(g_username, pw->pw_name, 255);
+ }
+ }
+ if (gethostname(fullhostname, sizeof(fullhostname)) != -1)
+ {
+ p = strchr(fullhostname, '.');
+ if (p != 0)
+ {
+ *p = 0;
+ }
+ strncpy(g_hostname, fullhostname, 255);
+ }
+}
+
+/*****************************************************************************/
+static void
+save_palette(void)
+{
+ struct fb_cmap cmap;
+
+ cmap.start = 0;
+ if (g_bpp == 15)
+ {
+ cmap.len = 16;
+ }
+ else
+ {
+ cmap.len = 256;
+ }
+ cmap.red = (unsigned short *) g_saved_red;
+ cmap.green = (unsigned short *) g_saved_green;
+ cmap.blue = (unsigned short *) g_saved_blue;
+ cmap.transp = 0;
+ ioctl(g_fbfd, FBIOGETCMAP, &cmap);
+}
+
+/*****************************************************************************/
+static void
+restore_palette(void)
+{
+ struct fb_cmap cmap;
+
+ cmap.start = 0;
+ if (g_bpp == 15)
+ {
+ cmap.len = 16;
+ }
+ else
+ {
+ cmap.len = 256;
+ }
+ cmap.red = (unsigned short *) g_saved_red;
+ cmap.green = (unsigned short *) g_saved_green;
+ cmap.blue = (unsigned short *) g_saved_blue;
+ cmap.transp = 0;
+ ioctl(g_fbfd, FBIOPUTCMAP, &cmap);
+}
+
+/*****************************************************************************/
+static void
+set_directcolor_palette(void)
+{
+ short r[256];
+ int i;
+ struct fb_cmap cmap;
+
+ if (g_bpp == 15)
+ {
+ for (i = 0; i < 32; i++)
+ {
+ r[i] = i << 11;
+ }
+ cmap.len = 32;
+ }
+ else
+ {
+ for (i = 0; i < 256; i++)
+ {
+ r[i] = i << 8;
+ }
+ cmap.len = 256;
+ }
+ cmap.start = 0;
+ cmap.red = (unsigned short *) r;
+ cmap.green = (unsigned short *) r;
+ cmap.blue = (unsigned short *) r;
+ cmap.transp = 0;
+ ioctl(g_fbfd, FBIOPUTCMAP, &cmap);
+}
+
+/*****************************************************************************/
+static int
+htoi(char * val)
+{
+ int rv;
+
+ rv = 0;
+ switch (val[0])
+ {
+ case '1': rv = 16; break;
+ case '2': rv = 16 * 2; break;
+ case '3': rv = 16 * 3; break;
+ case '4': rv = 16 * 4; break;
+ case '5': rv = 16 * 5; break;
+ case '6': rv = 16 * 6; break;
+ case '7': rv = 16 * 7; break;
+ case '8': rv = 16 * 8; break;
+ case '9': rv = 16 * 9; break;
+ case 'a': rv = 16 * 10; break;
+ case 'b': rv = 16 * 11; break;
+ case 'c': rv = 16 * 12; break;
+ case 'd': rv = 16 * 13; break;
+ case 'e': rv = 16 * 14; break;
+ case 'f': rv = 16 * 15; break;
+ }
+ switch (val[1])
+ {
+ case '1': rv += 1; break;
+ case '2': rv += 2; break;
+ case '3': rv += 3; break;
+ case '4': rv += 4; break;
+ case '5': rv += 5; break;
+ case '6': rv += 6; break;
+ case '7': rv += 7; break;
+ case '8': rv += 8; break;
+ case '9': rv += 9; break;
+ case 'a': rv += 10; break;
+ case 'b': rv += 11; break;
+ case 'c': rv += 12; break;
+ case 'd': rv += 13; break;
+ case 'e': rv += 14; break;
+ case 'f': rv += 15; break;
+ }
+ return rv;
+}
+
+
+/*****************************************************************************/
+static int
+load_keys(void)
+{
+ int fd;
+ int len;
+ int index;
+ int i1;
+ int comment;
+ int val1;
+ int val2;
+ int val3;
+ char all_lines[8192];
+ char line[256];
+ char val[4];
+
+ memset(g_keys, 0, sizeof(g_keys));
+ fd = open(g_keyfile, O_RDWR);
+ if (fd > 0)
+ {
+ i1 = 0;
+ line[0] = 0;
+ comment = 0;
+ len = read(fd, all_lines, 8192);
+ for (index = 0; index < len ; index++)
+ {
+ if (all_lines[index] == '#')
+ {
+ comment = 1;
+ }
+ else if (all_lines[index] == 13 || all_lines[index] == 10)
+ {
+ if (strlen(line) > 7)
+ {
+ val[0] = line[0];
+ val[1] = line[1];
+ val[2] = 0;
+ val1 = htoi(val);
+ val[0] = line[3];
+ val[1] = line[4];
+ val[2] = 0;
+ val2 = htoi(val);
+ val[0] = line[6];
+ val[1] = line[7];
+ val[2] = 0;
+ val3 = htoi(val);
+ g_keys[val1].scancode = val1;
+ g_keys[val1].rdpcode = val2;
+ g_keys[val1].ext = val3;
+ }
+ line[0] = 0;
+ i1 = 0;
+ comment = 0;
+ }
+ else if (!comment)
+ {
+ line[i1] = all_lines[index];
+ i1++;
+ line[i1] = 0;
+ }
+ }
+ close(fd);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
int
-main(int argc, char ** argv)
+main(int in_argc, char ** in_argv)
{
int rv;
+ int screensize;
+ struct termios new_termios;
rv = 0;
+ g_server_depth = 24;
+ memset(&g_mcursor, 0, sizeof(struct cursor));
+ get_username_and_hostname();
+ /* read command line options */
+ if (!parse_parameters(in_argc, in_argv))
+ {
+ exit(0);
+ }
+ /* Open the file for reading and writing */
+ g_fbfd = open("/dev/fb0", O_RDWR);
+ if (g_fbfd == -1)
+ {
+ printf("Error: cannot open framebuffer device.\n");
+ exit(101);
+ }
+ printf("The framebuffer device was opened successfully.\n");
+ /* Get fixed screen information */
+ if (ioctl(g_fbfd, FBIOGET_FSCREENINFO, &g_finfo))
+ {
+ printf("Error reading fixed information.\n");
+ exit(102);
+ }
+ /* Get variable screen information */
+ if (ioctl(g_fbfd, FBIOGET_VSCREENINFO, &g_vinfo))
+ {
+ printf("Error reading variable information.\n");
+ exit(103);
+ }
+ g_bpp = g_vinfo.bits_per_pixel;
+ g_Bpp = (g_bpp + 7) / 8;
+ g_width = g_vinfo.xres;
+ g_height = g_vinfo.yres;
+ g_clip_right = g_width;
+ g_clip_bottom = g_height;
+ printf("%dx%d, %dbpp\n", g_vinfo.xres, g_vinfo.yres, g_vinfo.bits_per_pixel);
+ /* Figure out the size of the screen in bytes */
+ screensize = g_vinfo.xres * g_vinfo.yres * g_Bpp;
+ /* Map the device to memory */
+ g_sdata = (char *) mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
+ g_fbfd, 0);
+ g_bs = malloc(screensize);
+ if ((int) g_sdata == -1)
+ {
+ printf("Error: failed to map framebuffer device to memory.\n");
+ exit(104);
+ }
+ printf("The framebuffer device was mapped to memory successfully.\n");
+ /* open mouse */
+ g_mousefd = open("/dev/mouse", O_RDWR);
+ if (g_mousefd == -1)
+ {
+ g_mousefd = open("/dev/psaux", O_RDWR);
+ }
+ if (g_mousefd == -1)
+ {
+ printf("Error: failed to open /dev/mouse or /dev/psaux\n");
+ exit(105);
+ }
+ g_kbfd = open("/dev/tty0", O_RDWR);
+ if (g_kbfd == -1)
+ {
+ printf("Error: failed to open /dev/tty0\n");
+ exit(106);
+ }
+ /* check fb type */
+ if (g_finfo.visual != FB_VISUAL_DIRECTCOLOR &&
+ g_finfo.visual != FB_VISUAL_TRUECOLOR)
+ {
+ printf("unsupports fb\n");
+ exit(107);
+ }
+ if (g_finfo.visual == FB_VISUAL_DIRECTCOLOR)
+ {
+ /* save hardware palette */
+ save_palette();
+ /* set palette to match truecolor */
+ set_directcolor_palette();
+ }
+ /* clear the screen */
+ mi_fill_rect(0, 0, g_width, g_height, 0);
+ /* connect */
+#ifdef WITH_RDPSND
+ /* init sound */
+// if (g_rdpsnd)
+// {
+// rdpsnd_init();
+// }
+#endif
+#if 0
+ /* setup keyboard */
+ ioctl(g_kbfd, KDGKBMODE, &g_org_kbmode); /* save this */
+ tcgetattr(g_kbfd, &org_termios); /* save this */
+ new_termios = org_termios;
+ new_termios.c_lflag &= ~(ICANON | ECHO | ISIG);
+ new_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
+ new_termios.c_cc[VMIN] = 0;
+ new_termios.c_cc[VTIME] = 0;
+ tcsetattr(g_kbfd, TCSAFLUSH, &new_termios);
+ ioctl(g_kbfd, KDSKBMODE, K_MEDIUMRAW);
+#endif
+ load_keys();
+ /* do it all here */
+ rv = ui_main();
+ /* clear the screen when done */
+ mi_fill_rect(0, 0, g_width, g_height, 0);
+ /* restore some stuff */
+ if (g_finfo.visual == FB_VISUAL_DIRECTCOLOR)
+ {
+ restore_palette();
+ }
+ munmap(g_sdata, screensize);
+ close(g_fbfd);
+ close(g_mousefd);
+#if 0
+ ioctl(g_kbfd, KDSKBMODE, g_org_kbmode);
+ tcsetattr(g_kbfd, TCSANOW, &org_termios);
+#endif
+ close(g_kbfd);
+ free(g_bs);
return rv;
}