From 0883767476de975465b4afcdf7d39354f391d6bb Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 17 Jan 2023 10:35:38 +0200 Subject: [PATCH 1/1] initial commit --- Makefile | 37 ++++++++++ README.md | 4 ++ src/client.c | 171 ++++++++++++++++++++++++++++++++++++++++++++ src/client.h | 37 ++++++++++ src/dos/dpmi.c | 55 ++++++++++++++ src/dos/dpmi.h | 26 +++++++ src/dos/gfx.c | 158 +++++++++++++++++++++++++++++++++++++++++ src/dos/keyb.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/dos/mouse.c | 93 ++++++++++++++++++++++++ src/dos/pit8254.h | 34 +++++++++ src/dos/scancode.h | 17 +++++ src/dos/timer.c | 135 +++++++++++++++++++++++++++++++++++ src/dos/vbe.c | 153 +++++++++++++++++++++++++++++++++++++++ src/dos/vbe.h | 70 ++++++++++++++++++ src/gfx.h | 24 +++++++ src/inttypes.h | 18 +++++ src/keyb.h | 69 ++++++++++++++++++ src/logger.c | 30 ++++++++ src/logger.h | 17 +++++ src/main.c | 141 ++++++++++++++++++++++++++++++++++++ src/mouse.h | 31 ++++++++ src/proto.c | 33 +++++++++ src/proto.h | 87 +++++++++++++++++++++++ src/server.c | 71 +++++++++++++++++++ src/server.h | 10 +++ src/timer.h | 38 ++++++++++ src/util.c | 11 +++ src/util.h | 12 ++++ src/xtypes.h | 143 +++++++++++++++++++++++++++++++++++++ 29 files changed, 1926 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 src/client.c create mode 100644 src/client.h create mode 100644 src/dos/dpmi.c create mode 100644 src/dos/dpmi.h create mode 100644 src/dos/gfx.c create mode 100644 src/dos/keyb.c create mode 100644 src/dos/mouse.c create mode 100644 src/dos/pit8254.h create mode 100644 src/dos/scancode.h create mode 100644 src/dos/timer.c create mode 100644 src/dos/vbe.c create mode 100644 src/dos/vbe.h create mode 100644 src/gfx.h create mode 100644 src/inttypes.h create mode 100644 src/keyb.h create mode 100644 src/logger.c create mode 100644 src/logger.h create mode 100644 src/main.c create mode 100644 src/mouse.h create mode 100644 src/proto.c create mode 100644 src/proto.h create mode 100644 src/server.c create mode 100644 src/server.h create mode 100644 src/timer.h create mode 100644 src/util.c create mode 100644 src/util.h create mode 100644 src/xtypes.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3a1841b --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +mainobj = main.obj logger.obj client.obj server.obj proto.obj util.obj +sysobj = gfx.obj vbe.obj dpmi.obj timer.obj mouse.obj keyb.obj +obj = $(mainobj) $(sysobj) +bin = xdos.exe + +opt = -5 -fp5 -otexan +dbg = -d2 + +AS = nasm +CC = wcc386 +CXX = wpp386 +ASFLAGS = -fobj +CFLAGS = $(dbg) $(opt) -zq -bt=dos -mf -Isrc -Isrc\dos -I$(%WATT_ROOT)\inc +CXXFLAGS = $(CFLAGS) -Isrc\stl +LD = wlink +LDFLAGS = library $(%WATT_ROOT)\lib\wattcpwf.lib + +$(bin): $(obj) + %write objects.lnk file { $(obj) } + $(LD) debug all name $@ @objects $(LDFLAGS) + +.c: src;src\dos +.cc: src +.asm: src + +.c.obj: .autodepend + $(CC) $(CFLAGS) $[* + +.cc.obj: .autodepend + $(CXX) $(CXXFLAGS) $[* + +.asm.obj: + $(AS) $(ASFLAGS) -o $@ $[*.asm + +clean: .symbolic + del *.obj + del $(bin) diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ff1c6a --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +build instructions +------------------ +- make sure you have WATT_TCP32 installed and you've set the WATT_ROOT env var + to point to its location (default: c:\net\watt). diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..4f23def --- /dev/null +++ b/src/client.c @@ -0,0 +1,171 @@ +#include +#include +#include +#include "proto.h" +#include "client.h" +#include "logger.h" + +static int handle_client_setup(struct client *c); +static int send_server_info(struct client *c); + +static struct client *clist; + +int add_client(int s) +{ + struct client *c = malloc(sizeof *c); + if(!c) { + printlog("failed to allocate memory for new client\n"); + return -1; + } + memset(c, 0, sizeof *c); + c->sock = s; + c->state = CLIENT_SETUP; + + c->next = clist; + clist = c; + return 0; +} + +int remove_client(int s) +{ + struct client dummy; + struct client *iter = &dummy; + + dummy.next = clist; + while(iter->next) { + if(iter->next->sock == s) { + struct client *tmp = iter->next; + iter->next = tmp->next; + free(tmp); + return 0; + } + iter = iter->next; + } + return -1; +} + +/* remove all clients with closed invalid sockets */ +int remove_closed(void) +{ + int removed = 0; + struct client dummy; + struct client *iter = &dummy; + dummy.next = clist; + + while(iter->next) { + if(iter->next->sock == -1) { + struct client *tmp = iter->next; + iter->next = tmp->next; + free(tmp); + ++removed; + } else { + iter = iter->next; + } + } + return removed; +} + +struct client *find_client_sock(int s) +{ + struct client *c = clist; + while(c && c->sock != s) { + c = c->next; + } + return c; +} + +struct client *get_clients(void) +{ + return clist; +} + +void free_clients(void) +{ + while(clist) { + struct client *c = clist; + clist = clist->next; + free(c); + } + clist = 0; +} + +/* --- client comms --- */ + +/* handles all communications with clients */ +int handle_client(struct client *c) +{ + if(c->state == CLIENT_SETUP) { + if(handle_client_setup(c) == -1) { + return -1; + } + if(c->bufsz <= 0) { /* consumed all data, done */ + return 0; + } + } + + /* TODO handle client requests ... */ + c->bufsz = 0; + return 0; +} + +/* handles data coming from a client in the CLIENT_SETUP state */ +static int handle_client_setup(struct client *c) +{ + int rd, auth_name_len, auth_data_len, fullsz, must_swap = 0; + struct xconn_setup_header *setup; + char *start = c->inbuf + c->bufsz; + int avail = CLIENT_BUF_SIZE - c->bufsz; + + if((rd = recv(c->sock, start, avail, 0)) <= 0) { + return -1; + } + + c->bufsz += rd; + if(c->bufsz < sizeof(struct xconn_setup_header)) { + return 0; /* need more data */ + } + + setup = (struct xconn_setup_header*)c->inbuf; + if(setup->byteorder == 'B') { + must_swap = 1; + auth_name_len = ntohs(setup->auth_name_length); + auth_data_len = ntohs(setup->auth_data_length); + } else { + must_swap = 0; + auth_name_len = setup->auth_name_length; + auth_data_len = setup->auth_data_length; + } + + /* take padding to the next 32bit-aligned address into account */ + auth_name_len = (auth_name_len + 3) & 0xfffc; + auth_data_len = (auth_data_len + 3) & 0xfffc; + fullsz = sizeof(struct xconn_setup_header) + auth_name_len + auth_data_len; + + if(c->bufsz < fullsz) { + return 0; /* more to read... */ + } + + /* ok we've read it all, act on it... */ + c->swap = must_swap; + if(must_swap) { + printlog("big endian client, protocol: %d.%d\n", ntohs(setup->proto_major), ntohs(setup->proto_minor)); + } else { + printlog("little endian client, protocol: %d.%d\n", setup->proto_major, setup->proto_minor); + } + /* TODO send response */ + c->state = CLIENT_ACTIVE; + + if(c->bufsz > fullsz) { + int rem = c->bufsz - fullsz; + memmove(c->inbuf, c->inbuf + fullsz, rem); + c->bufsz = rem; + } + return 0; +} + +static int send_server_info(struct client *c) +{ + struct xconn_accept_header *hdr; + + return -1; /* TODO */ +} diff --git a/src/client.h b/src/client.h new file mode 100644 index 0000000..03bce5b --- /dev/null +++ b/src/client.h @@ -0,0 +1,37 @@ +#ifndef CLIENT_H_ +#define CLIENT_H_ + +enum client_state { + CLIENT_SETUP, /* setup stage: waiting for the initial byteorder/version data */ + CLIENT_ACTIVE, /* main stage: accepting requests and sending events */ + CLIENT_TEARDOWN /* TBD */ +}; + +#define CLIENT_BUF_SIZE 256 + +struct client { + int sock; + int swap; /* true if we must byteswap all data to/from this client */ + + enum client_state state; + + char inbuf[CLIENT_BUF_SIZE]; + int bufsz; + + struct client *next; +}; + +/* functions to manage the client list */ +int add_client(int s); +int remove_client(int s); +int remove_closed(void); + +struct client *find_client_sock(int s); /* find by socket */ +struct client *get_clients(void); + +void free_clients(void); + +/* functions to handle client communictation */ +int handle_client(struct client *c); + +#endif /* CLIENT_H_ */ diff --git a/src/dos/dpmi.c b/src/dos/dpmi.c new file mode 100644 index 0000000..7d2c2b5 --- /dev/null +++ b/src/dos/dpmi.c @@ -0,0 +1,55 @@ +#include "dpmi.h" + +void dpmi_real_int(int inum, struct dpmi_real_regs *regs) +{ + unsigned char int_num = (unsigned char)inum; + __asm { + mov eax, 0x300 + mov edi, regs + mov bl, int_num + mov bh, 0 + xor ecx, ecx + int 0x31 + } +} + +void *dpmi_mmap(uint32_t phys_addr, unsigned int size) +{ + uint16_t mem_high, mem_low; + uint16_t phys_high = phys_addr >> 16; + uint16_t phys_low = phys_addr & 0xffff; + uint16_t size_high = size >> 16; + uint16_t size_low = size & 0xffff; + unsigned int err, res = 0; + + __asm { + mov eax, 0x800 + mov bx, phys_high + mov cx, phys_low + mov si, size_high + mov di, size_low + int 0x31 + add res, 1 + mov err, eax + mov mem_high, bx + mov mem_low, cx + } + + if(res == 2) { + return 0; + } + return (void*)(((uint32_t)mem_high << 16) | ((uint32_t)mem_low)); +} + +void dpmi_munmap(void *addr) +{ + uint16_t mem_high = (uint32_t)addr >> 16; + uint16_t mem_low = (uint16_t)addr; + + __asm { + mov eax, 0x801 + mov bx, mem_high + mov cx, mem_low + int 0x31 + } +} diff --git a/src/dos/dpmi.h b/src/dos/dpmi.h new file mode 100644 index 0000000..352b9c1 --- /dev/null +++ b/src/dos/dpmi.h @@ -0,0 +1,26 @@ +#ifndef DPMI_H_ +#define DPMI_H_ + +#include "inttypes.h" + +struct dpmi_real_regs { + uint32_t edi, esi, ebp; + uint32_t reserved; + uint32_t ebx, edx, ecx, eax; + uint16_t flags; + uint16_t es, ds, fs, gs; + uint16_t ip, cs, sp, ss; +}; + +unsigned short dpmi_alloc(unsigned int par); +#pragma aux dpmi_alloc = \ + "mov eax, 0x100" \ + "int 0x31" \ + value[ax] parm[ebx]; + +void dpmi_real_int(int inum, struct dpmi_real_regs *regs); + +void *dpmi_mmap(uint32_t phys_addr, unsigned int size); +void dpmi_munmap(void *addr); + +#endif /* DPMI_H_ */ diff --git a/src/dos/gfx.c b/src/dos/gfx.c new file mode 100644 index 0000000..b8c0517 --- /dev/null +++ b/src/dos/gfx.c @@ -0,0 +1,158 @@ +#ifndef GFX_H_ +#define GFX_H_ + +#include +#include +#include +#include "vbe.h" +#include "logger.h" + +#define REALPTR(s, o) (void*)(((uint32_t)(s) << 4) + (uint32_t)(o)) +#define VBEPTR(x) REALPTR(((x) & 0xffff0000) >> 16, (x) & 0xffff) +#define VBEPTR_SEG(x) (((x) & 0xffff0000) >> 16) +#define VBEPTR_OFF(x) ((x) & 0xffff) + +#define SAME_BPP(a, b) \ + ((a) == (b) || (a) == 16 && (b) == 15 || (a) == 15 && (b) == 16 || (a) == 32 && (b) == 24 || (a) == 24 && (b) == 32) + +static unsigned int make_mask(int sz, int pos); + +static struct vbe_info *vbe_info; +static struct vbe_mode_info *mode_info; +static int pal_bits = 6; + +void *set_video_mode(int xsz, int ysz, int bpp) +{ + int i; + uint16_t *modes, best = 0; + unsigned int fbsize; + + /* check for VBE2 support and output some info */ + if(!vbe_info) { + if(!(vbe_info = vbe_get_info())) { + fprintf(stderr, "VESA BIOS Extensions not available\n"); + return 0; + } + + printlog("VBE Version: %x.%x\n", vbe_info->version >> 8, vbe_info->version & 0xff); + if(vbe_info->version < 0x200) { + fprintf(stderr, "This program requires VBE 2.0 or greater. Try running UniVBE\n"); + return 0; + } + + printlog("Graphics adapter: %s, %s (%s)\n", VBEPTR(vbe_info->oem_vendor_name_ptr), + VBEPTR(vbe_info->oem_product_name_ptr), VBEPTR(vbe_info->oem_product_rev_ptr)); + printlog("Video memory: %dmb\n", vbe_info->total_mem << 6); + + modes = VBEPTR(vbe_info->vid_mode_ptr); + } + + for(i=0; i<1024; i++) { /* impose an upper limit to avoid inf-loops */ + if(modes[i] == 0xffff) { + break; /* reached the end */ + } + + mode_info = vbe_get_mode_info(modes[i] | VBE_MODE_LFB); + if(!mode_info || mode_info->xres != xsz || mode_info->yres != ysz) { + continue; + } + if(SAME_BPP(mode_info->bpp, bpp)) { + best = modes[i]; + } + } + + if(best) { + mode_info = vbe_get_mode_info(best); + } else { + fprintf(stderr, "Requested video mode (%dx%d %dbpp) is unavailable\n", xsz, ysz, bpp); + return 0; + } + + if(vbe_set_mode(best | VBE_MODE_LFB) == -1) { + fprintf(stderr, "Failed to set video mode %dx%d %dbpp\n", mode_info->xres, mode_info->yres, mode_info->bpp); + return 0; + } + + /* attempt to set 8 bits of color per component in palettized modes */ + if(bpp <= 8) { + pal_bits = vbe_set_palette_bits(8); + printlog("palette bits per color primary: %d\n", pal_bits); + } + + fbsize = xsz * ysz * mode_info->num_img_pages * (bpp / CHAR_BIT); + return (void*)dpmi_mmap(mode_info->fb_addr, fbsize); +} + +int set_text_mode(void) +{ + vbe_set_mode(0x3); + return 0; +} + +int get_color_depth(void) +{ + if(!mode_info) { + return -1; + } + return mode_info->bpp; +} + +int get_color_bits(int *rbits, int *gbits, int *bbits) +{ + if(!mode_info) { + return -1; + } + *rbits = mode_info->rmask_size; + *gbits = mode_info->gmask_size; + *bbits = mode_info->bmask_size; + return 0; +} + +int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask) +{ + if(!mode_info) { + return -1; + } + *rmask = make_mask(mode_info->rmask_size, mode_info->rpos); + *gmask = make_mask(mode_info->gmask_size, mode_info->gpos); + *bmask = make_mask(mode_info->bmask_size, mode_info->bpos); + return 0; +} + +int get_color_shift(int *rshift, int *gshift, int *bshift) +{ + if(!mode_info) { + return -1; + } + *rshift = mode_info->rpos; + *gshift = mode_info->gpos; + *bshift = mode_info->bpos; + return 0; +} + +void set_palette(int idx, int r, int g, int b) +{ + int col[3]; + col[0] = r; + col[1] = g; + col[2] = b; + vbe_set_palette(idx, col, 1, pal_bits); +} + +void wait_vsync(void) +{ + /* TODO */ +} + +static unsigned int make_mask(int sz, int pos) +{ + unsigned int i, mask = 0; + + for(i=0; i + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the program. If not, see +*/ +#define KEYB_C_ + +#include +#include +#include +#include +#include +#include +#include "keyb.h" +#include "scancode.h" + +#define KB_INTR 0x9 +#define KB_PORT 0x60 + +#define PIC1_CMD_PORT 0x20 +#define OCW2_EOI (1 << 5) + +#define DONE_INIT (prev_handler) + +static void __interrupt __far kbintr(); + +static void (__interrupt __far *prev_handler)(); + +static int *buffer; +static int buffer_size, buf_ridx, buf_widx; +static int last_key; + +static unsigned int num_pressed; +static unsigned char keystate[256]; + +#define ADVANCE(x) ((x) = ((x) + 1) % buffer_size) + +int kb_init(int bufsz) +{ + if(DONE_INIT) { + fprintf(stderr, "keyboard driver already initialized!\n"); + return 0; + } + + buffer_size = bufsz; + if(buffer_size && !(buffer = malloc(buffer_size * sizeof *buffer))) { + fprintf(stderr, "failed to allocate input buffer, continuing without\n"); + buffer_size = 0; + } + buf_ridx = buf_widx = 0; + last_key = -1; + + memset(keystate, 0, sizeof keystate); + num_pressed = 0; + + /* set our interrupt handler */ + _disable(); + prev_handler = _dos_getvect(KB_INTR); + _dos_setvect(KB_INTR, kbintr); + _enable(); + + return 0; +} + +void kb_shutdown(void) +{ + if(!DONE_INIT) { + return; + } + + /* restore the original interrupt handler */ + _disable(); + _dos_setvect(KB_INTR, prev_handler); + _enable(); + + free(buffer); +} + +int kb_isdown(int key) +{ + switch(key) { + case KB_ANY: + return num_pressed; + + case KB_ALT: + return keystate[KB_LALT] + keystate[KB_RALT]; + + case KB_CTRL: + return keystate[KB_LCTRL] + keystate[KB_RCTRL]; + } + return keystate[key]; +} + +void kb_wait(void) +{ + int key; + while((key = kb_getkey()) == -1) { + /* put the processor to sleep while waiting for keypresses, but first + * make sure interrupts are enabled, or we'll sleep forever + */ + __asm { + sti + hlt + } + } + kb_putback(key); +} + +int kb_getkey(void) +{ + int res; + + if(buffer) { + if(buf_ridx == buf_widx) { + return -1; + } + res = buffer[buf_ridx]; + ADVANCE(buf_ridx); + } else { + res = last_key; + last_key = -1; + } + return res; +} + +void kb_putback(int key) +{ + if(buffer) { + /* go back a place */ + if(--buf_ridx < 0) { + buf_ridx += buffer_size; + } + + /* if the write end hasn't caught up with us, go back one place + * and put it there, otherwise just overwrite the oldest key which + * is right where we were. + */ + if(buf_ridx == buf_widx) { + ADVANCE(buf_ridx); + } + + buffer[buf_ridx] = key; + } else { + last_key = key; + } +} + +static void __interrupt __far kbintr() +{ + unsigned char code; + int key, press; + + code = inp(KB_PORT); + + if(code >= 128) { + press = 0; + code -= 128; + + if(num_pressed > 0) { + num_pressed--; + } + } else { + press = 1; + + num_pressed++; + } + + key = scantbl[code]; + + if(press) { + /* append to buffer */ + last_key = key; + if(buffer_size > 0) { + buffer[buf_widx] = key; + ADVANCE(buf_widx); + /* if the write end overtook the read end, advance the read end + * too, to discard the oldest keypress from the buffer + */ + if(buf_widx == buf_ridx) { + ADVANCE(buf_ridx); + } + } + } + + /* and update keystate table */ + keystate[key] = press; + + outp(PIC1_CMD_PORT, OCW2_EOI); /* send end-of-interrupt */ +} diff --git a/src/dos/mouse.c b/src/dos/mouse.c new file mode 100644 index 0000000..18fa24a --- /dev/null +++ b/src/dos/mouse.c @@ -0,0 +1,93 @@ +#include "mouse.h" +#include "inttypes.h" + +#define INTR 0x33 + +#define QUERY 0 +#define SHOW 1 +#define HIDE 2 +#define READ 3 +#define WRITE 4 +#define PIXRATE 0xf + +#define XLIM 7 +#define YLIM 8 + +int have_mouse(void) +{ + uint16_t res = 0; + _asm { + mov eax, QUERY + int INTR + mov res, ax + } + return res; +} + +void show_mouse(int show) +{ + uint16_t cmd = show ? SHOW : HIDE; + _asm { + mov ax, cmd + int INTR + } +} + +int read_mouse(int *xp, int *yp) +{ + uint16_t x, y, state; + _asm { + mov eax, READ + int INTR + mov state, bx + mov x, cx + mov y, dx + } + + if(xp) *xp = x; + if(yp) *yp = y; + return state; +} + +void set_mouse(int x, int y) +{ + _asm { + mov eax, WRITE + mov ecx, x + mov edx, y + int INTR + } +} + +void set_mouse_limits(int xmin, int ymin, int xmax, int ymax) +{ + _asm { + mov eax, XLIM + mov ecx, xmin + mov edx, xmax + int INTR + mov eax, YLIM + mov ecx, ymin + mov edx, ymax + int INTR + } +} + +void set_mouse_rate(int xrate, int yrate) +{ + _asm { + mov ax, PIXRATE + mov ecx, xrate + mov edx, yrate + int INTR + } +} + +void set_mouse_mode(enum mouse_mode mode) +{ + if(mode == MOUSE_GFX) { + set_mouse_rate(1, 1); + } else { + set_mouse_rate(8, 16); + } +} diff --git a/src/dos/pit8254.h b/src/dos/pit8254.h new file mode 100644 index 0000000..5d45f55 --- /dev/null +++ b/src/dos/pit8254.h @@ -0,0 +1,34 @@ +#ifndef PIT8254_H_ +#define PIT8254_H_ + +/* frequency of the oscillator driving the 8254 timer */ +#define OSC_FREQ_HZ 1193182 + +/* I/O ports connected to the 8254 */ +#define PORT_DATA0 0x40 +#define PORT_DATA1 0x41 +#define PORT_DATA2 0x42 +#define PORT_CMD 0x43 + +/* command bits */ +#define CMD_CHAN0 0 +#define CMD_CHAN1 (1 << 6) +#define CMD_CHAN2 (2 << 6) +#define CMD_RDBACK (3 << 6) + +#define CMD_LATCH 0 +#define CMD_ACCESS_LOW (1 << 4) +#define CMD_ACCESS_HIGH (2 << 4) +#define CMD_ACCESS_BOTH (3 << 4) + +#define CMD_OP_INT_TERM 0 +#define CMD_OP_ONESHOT (1 << 1) +#define CMD_OP_RATE (2 << 1) +#define CMD_OP_SQWAVE (3 << 1) +#define CMD_OP_SW_STROBE (4 << 1) +#define CMD_OP_HW_STROBE (5 << 1) + +#define CMD_MODE_BIN 0 +#define CMD_MODE_BCD 1 + +#endif /* PIT8254_H_ */ diff --git a/src/dos/scancode.h b/src/dos/scancode.h new file mode 100644 index 0000000..d012f14 --- /dev/null +++ b/src/dos/scancode.h @@ -0,0 +1,17 @@ +#ifndef KEYB_C_ +#error "do not include scancode.h anywhere..." +#endif + +/* table with rough translations from set 1 scancodes to ASCII-ish */ +static int scantbl[] = { + 0, KB_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', /* 0 - e */ + '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* f - 1c */ + KB_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', /* 1d - 29 */ + KB_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KB_RSHIFT, /* 2a - 36 */ + KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, /* 37 - 44 */ + KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS, /* 45 - 4e */ + KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12, /* 4d - 58 */ + 0, 0, 0, 0, 0, 0, 0, /* 59 - 5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 70 - 7f */ +}; diff --git a/src/dos/timer.c b/src/dos/timer.c new file mode 100644 index 0000000..ab0027a --- /dev/null +++ b/src/dos/timer.c @@ -0,0 +1,135 @@ +/* +pit8254 timer code for DOS programs. +Copyright (C) 2011-2014 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include +#include +#include +#include +#include "pit8254.h" + +#ifdef BORLANDC +#error borland unsupported +#endif + +#define PIT_TIMER_INTR 8 +#define DOS_TIMER_INTR 0x1c + +/* macro to divide and round to the nearest integer */ +#define DIV_ROUND(a, b) \ + ((a) / (b) + ((a) % (b)) / ((b) / 2)) + +static void set_timer_reload(int reload_val); +static void cleanup(void); +static void __interrupt __far timer_irq(); +static void __interrupt __far dos_timer_intr(); + +static void (__interrupt __far *prev_timer_intr)(); + +static unsigned long ticks; +static unsigned long tick_interval, ticks_per_dos_intr; +static int inum; + +void init_timer(int res_hz) +{ + _disable(); + + if(res_hz > 0) { + int reload_val = DIV_ROUND(OSC_FREQ_HZ, res_hz); + set_timer_reload(reload_val); + + tick_interval = DIV_ROUND(1000, res_hz); + ticks_per_dos_intr = DIV_ROUND(65535L, reload_val); + + inum = PIT_TIMER_INTR; + prev_timer_intr = _dos_getvect(inum); + _dos_setvect(inum, timer_irq); + } else { + tick_interval = 55; + + inum = DOS_TIMER_INTR; + prev_timer_intr = _dos_getvect(inum); + _dos_setvect(inum, dos_timer_intr); + } + _enable(); + + atexit(cleanup); +} + +static void cleanup(void) +{ + if(!prev_timer_intr) { + return; /* init hasn't ran, there's nothing to cleanup */ + } + + _disable(); + if(inum == PIT_TIMER_INTR) { + /* restore the original timer frequency */ + set_timer_reload(65535); + } + + /* restore the original interrupt handler */ + _dos_setvect(inum, prev_timer_intr); + _enable(); +} + +void reset_timer(void) +{ + ticks = 0; +} + +unsigned long get_msec(void) +{ + return ticks * tick_interval; +} + +static void set_timer_reload(int reload_val) +{ + outp(PORT_CMD, CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE); + outp(PORT_DATA0, reload_val & 0xff); + outp(PORT_DATA0, (reload_val >> 8) & 0xff); +} + +static void __interrupt __far dos_timer_intr() +{ + ticks++; + _chain_intr(prev_timer_intr); /* DOES NOT RETURN */ +} + +/* first PIC command port */ +#define PIC1_CMD 0x20 +/* end of interrupt control word */ +#define OCW2_EOI (1 << 5) + +static void __interrupt __far timer_irq() +{ + static unsigned long dos_ticks; + + ticks++; + + if(++dos_ticks >= ticks_per_dos_intr) { + /* I suppose the dos irq handler does the EOI so I shouldn't + * do it if I am to call the previous function + */ + dos_ticks = 0; + _chain_intr(prev_timer_intr); /* XXX DOES NOT RETURN */ + return; /* just for clarity */ + } + + /* send EOI to the PIC */ + outp(PIC1_CMD, OCW2_EOI); +} diff --git a/src/dos/vbe.c b/src/dos/vbe.c new file mode 100644 index 0000000..5182e0a --- /dev/null +++ b/src/dos/vbe.c @@ -0,0 +1,153 @@ +#include +#include +#include "vbe.h" +#include "dpmi.h" + +/* VGA DAC registers used for palette setting in 8bpp modes */ +#define VGA_DAC_STATE 0x3c7 +#define VGA_DAC_ADDR_RD 0x3c7 +#define VGA_DAC_ADDR_WR 0x3c8 +#define VGA_DAC_DATA 0x3c9 + +#define MODE_LFB (1 << 14) + + +struct vbe_info *vbe_get_info(void) +{ + static unsigned short info_block_seg; + static struct vbe_info *info; + struct dpmi_real_regs regs; + + if(!info) { + /* allocate 32 paragraphs (512 bytes) */ + info_block_seg = dpmi_alloc(32); + info = (struct vbe_info*)(info_block_seg << 4); + } + + memcpy(info->sig, "VBE2", 4); + + memset(®s, 0, sizeof regs); + regs.es = info_block_seg; + regs.eax = 0x4f00; + + dpmi_real_int(0x10, ®s); + + return info; +} + +struct vbe_mode_info *vbe_get_mode_info(int mode) +{ + static unsigned short mode_info_seg; + static struct vbe_mode_info *mi; + struct dpmi_real_regs regs; + + if(!mi) { + /* allocate 16 paragraphs (256 bytes) */ + mode_info_seg = dpmi_alloc(16); + mi = (struct vbe_mode_info*)(mode_info_seg << 4); + } + + memset(®s, 0, sizeof regs); + regs.es = mode_info_seg; + regs.eax = 0x4f01; + regs.ecx = mode; + regs.es = mode_info_seg; + + dpmi_real_int(0x10, ®s); + if(regs.eax & 0xff00) { + return 0; + } + + return mi; +} + +int vbe_set_mode(int mode) +{ + struct dpmi_real_regs regs; + + memset(®s, 0, sizeof regs); + regs.eax = 0x4f02; + regs.ebx = mode; + dpmi_real_int(0x10, ®s); + + if(regs.eax == 0x100) { + return -1; + } + return 0; +} + +int vbe_set_palette_bits(int bits) +{ + struct dpmi_real_regs regs; + + memset(®s, 0, sizeof regs); + regs.eax = 0x4f08; + regs.ebx = bits << 8; /* bits in bh */ + dpmi_real_int(0x10, ®s); + + if((regs.eax >> 8) & 0xff == 3) { + return -1; + } + return regs.ebx >> 8 & 0xff; /* new color bits in bh */ +} + +/* TODO: implement palette setting through the VBE2 interface for + * non-VGA displays (actually don't). + */ +void vbe_set_palette(int idx, int *col, int count, int bits) +{ + int i, shift = 8 - bits; + + __asm { + mov dx, VGA_DAC_ADDR_WR + mov eax, idx + out dx, al + } + + for(i=0; i>= shift; + g >>= shift; + b >>= shift; + } + + __asm { + mov dx, VGA_DAC_DATA + mov al, r + out dx, al + mov al, g + out dx, al + mov al, b + out dx, al + } + } +} + +static unsigned int get_mask(int sz, int pos) +{ + unsigned int i, mask = 0; + + for(i=0; ixres, mi->yres); + fprintf(fp, "color depth: %d\n", mi->bpp); + fprintf(fp, "mode attributes: %x\n", mi->mode_attr); + fprintf(fp, "bytes per scanline: %d\n", mi->scanline_bytes); + fprintf(fp, "number of planes: %d\n", (int)mi->num_planes); + fprintf(fp, "number of banks: %d\n", (int)mi->num_banks); + fprintf(fp, "mem model: %d\n", (int)mi->mem_model); + fprintf(fp, "red bits: %d (mask: %x)\n", (int)mi->rmask_size, get_mask(mi->rmask_size, mi->rpos)); + fprintf(fp, "green bits: %d (mask: %x)\n", (int)mi->gmask_size, get_mask(mi->gmask_size, mi->gpos)); + fprintf(fp, "blue bits: %d (mask: %x)\n", (int)mi->bmask_size, get_mask(mi->bmask_size, mi->bpos)); + fprintf(fp, "framebuffer address: %x\n", mi->fb_addr); +} diff --git a/src/dos/vbe.h b/src/dos/vbe.h new file mode 100644 index 0000000..d29052e --- /dev/null +++ b/src/dos/vbe.h @@ -0,0 +1,70 @@ +#ifndef VBE_H_ +#define VBE_H_ + +#include "inttypes.h" + +#define VBE_ATTR_LFB (1 << 7) +#define VBE_MODE_LFB (1 << 14) + +#pragma pack (push, 0) +struct vbe_info { + uint8_t sig[4]; + uint16_t version; + uint32_t oem_str_ptr; + uint8_t caps[4]; /* capabilities */ + uint32_t vid_mode_ptr; /* vbefarptr to video mode list */ + uint16_t total_mem; /* num of 64k mem blocks */ + uint16_t oem_sw_rev; /* VBE implementation software revision */ + uint32_t oem_vendor_name_ptr; + uint32_t oem_product_name_ptr; + uint32_t oem_product_rev_ptr; + uint8_t reserved[222]; + uint8_t oem_data[256]; +}; + +struct vbe_mode_info { + uint16_t mode_attr; + uint8_t wina_attr, winb_attr; + uint16_t win_gran, win_size; + uint16_t wina_seg, winb_seg; + uint32_t win_func; + uint16_t scanline_bytes; + + /* VBE 1.2 and above */ + uint16_t xres, yres; + uint8_t xcharsz, ycharsz; + uint8_t num_planes; + uint8_t bpp; + uint8_t num_banks; + uint8_t mem_model; + uint8_t bank_size; /* bank size in KB */ + uint8_t num_img_pages; + uint8_t reserved1; + + /* direct color fields */ + uint8_t rmask_size, rpos; + uint8_t gmask_size, gpos; + uint8_t bmask_size, bpos; + uint8_t xmask_size, xpos; + uint8_t cmode_info; /* direct color mode attributes */ + + /* VBE 2.0 and above */ + uint32_t fb_addr; /* physical address of the linear framebuffer */ + uint32_t reserved2; + uint16_t reserved3; + + uint8_t reserved4[206]; +}; +#pragma pack (pop) + +struct vbe_info *vbe_get_info(void); +struct vbe_mode_info *vbe_get_mode_info(unsigned int mode); + +int vbe_set_mode(unsigned int mode); + +int vbe_set_palette_bits(int bits); +void vbe_set_palette(int idx, int *col, int count, int bits); + +void print_mode_info(FILE *fp, struct vbe_mode_info *modei); + +#endif /* VBE_H_ */ diff --git a/src/gfx.h b/src/gfx.h new file mode 100644 index 0000000..b19c992 --- /dev/null +++ b/src/gfx.h @@ -0,0 +1,24 @@ +#ifndef GFX_H_ +#define GFX_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void *set_video_mode(int xsz, int ysz, int bpp); +int set_text_mode(void); + +int get_color_depth(void); +int get_color_bits(int *rbits, int *gbits, int *bbits); +int get_color_shift(int *rshift, int *gshift, int *bshift); +int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask); + +void set_palette(int idx, int r, int g, int b); + +void wait_vsync(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_H_ */ diff --git a/src/inttypes.h b/src/inttypes.h new file mode 100644 index 0000000..1742166 --- /dev/null +++ b/src/inttypes.h @@ -0,0 +1,18 @@ +#ifndef INT_TYPES_H_ +#define INT_TYPES_H_ + +#if defined(__DOS__) || defined(WIN32) +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; + +typedef unsigned long intptr_t; +#else +#include +#endif + +#endif /* INT_TYPES_H_ */ diff --git a/src/keyb.h b/src/keyb.h new file mode 100644 index 0000000..3007ac5 --- /dev/null +++ b/src/keyb.h @@ -0,0 +1,69 @@ +/* +DOS interrupt-based keyboard driver. +Copyright (C) 2013 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the program. If not, see +*/ +#ifndef KEYB_H_ +#define KEYB_H_ + +#define KB_ANY (-1) +#define KB_ALT (-2) +#define KB_CTRL (-3) +#define KB_SHIFT (-4) + +/* special keys */ +enum { + KB_LALT, KB_RALT, + KB_LCTRL, KB_RCTRL, + KB_LSHIFT, KB_RSHIFT, + KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, + KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, + KB_CAPSLK, KB_NUMLK, KB_SCRLK, KB_SYSRQ, + KB_ESC = 27, + KB_INSERT, KB_DEL, KB_HOME, KB_END, KB_PGUP, KB_PGDN, + KB_LEFT, KB_RIGHT, KB_UP, KB_DOWN, + KB_NUM_DOT, KB_NUM_ENTER, KB_NUM_PLUS, KB_NUM_MINUS, KB_NUM_MUL, KB_NUM_DIV, + KB_NUM_0, KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_4, + KB_NUM_5, KB_NUM_6, KB_NUM_7, KB_NUM_8, KB_NUM_9, + KB_BACKSP = 127 +}; + + +#ifdef __cplusplus +extern "C" { +#endif + +int kb_init(int bufsz); /* bufsz can be 0 for no buffered keys */ +void kb_shutdown(void); /* don't forget to call this at the end! */ + +/* Boolean predicate for testing the current state of a particular key. + * You may also pass KB_ANY to test if any key is held down. + */ +int kb_isdown(int key); + +/* waits for any keypress */ +void kb_wait(void); + +/* removes and returns a single key from the input buffer. + * If buffering is disabled (initialized with kb_init(0)), then it always + * returns the last key pressed. + */ +int kb_getkey(void); + +#ifdef __cplusplus +} +#endif + +#endif /* KEYB_H_ */ diff --git a/src/logger.c b/src/logger.c new file mode 100644 index 0000000..f1873cb --- /dev/null +++ b/src/logger.c @@ -0,0 +1,30 @@ +#include +#include +#include "logger.h" + +#define LOGFNAME "xdos.log" + +static FILE *logfile; + +void logger_output(FILE *fp) +{ + if(logfile) fclose(logfile); + logfile = fp; +} + +void printlog(const char *fmt, ...) +{ + va_list ap; + + if(!logfile) { + if(!(logfile = fopen(LOGFNAME, "w"))) { + return; + } + setvbuf(logfile, 0, _IOLBF, 0); + } + + va_start(ap, fmt); + vfprintf(logfile, fmt, ap); + va_end(ap); + fflush(logfile); +} diff --git a/src/logger.h b/src/logger.h new file mode 100644 index 0000000..aec7d3b --- /dev/null +++ b/src/logger.h @@ -0,0 +1,17 @@ +#ifndef LOGGER_H_ +#define LOGGER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void logger_output(FILE *fp); +void printlog(const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* LOGGER_H_ */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..1c3f3ec --- /dev/null +++ b/src/main.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include "proto.h" +#include "client.h" +#include "logger.h" +#include "keyb.h" + +static int init(void); +static void cleanup(void); +static void handle_key(int key); + +static int lis; /* the listening socket */ + +int main(int argc, char **argv) +{ + if(init() == -1) { + return 1; + } + + main_loop(); + + cleanup(); + return 0; +} + +static int init(void) +{ + struct sockaddr_in sa; + + /* initialize input */ + if(kb_init(32) == -1) { + printlog("failed to initialize keyboard driver\n"); + return -1; + } + + /* start network server */ + if((lis = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + printlog("failed to create listening socket\n"); + return -1; + } + + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = INADDR_ANY; + sa.sin_port = htons(6000); + + if(bind(lis, (struct sockaddr*)&sa, sizeof sa) == -1) { + printlog("failed to bind socket to port 6000\n"); + return -1; + } + listen(lis, 8); + + return 0; +} + +static void cleanup(void) +{ + struct client *iter = get_clients(); + + while(iter) { + close(iter->sock); + iter = iter->next; + } + free_clients(); + + kb_shutdown(); +} + +static int main_loop(void) +{ + for(;;) { + int key; + int s, maxfd; + struct client *c; + struct timeval tv = {0, 0}; + fd_set rdset; + + /* ctrl-alt-backspace quits */ + if(kb_isdown(KB_ALT) && kb_isdown(KB_CTRL) && kb_isdown('\b')) { + return 0; + } + + /* get any key events and process them */ + while((key = kb_getkey()) != -1) { + handle_key(key); + } + + /* construct the socket set of all open sockets */ + FD_ZERO(&rdset); + FD_SET(lis, &rdset); + maxfd = lis; + + c = get_clients(); + while(c) { + FD_SET(c->sock, &rdset); + if(c->sock > maxfd) + maxfd = c->sock; + c = c->next; + } + + if(select_s(maxfd + 1, &rdset, 0, 0, &tv) == -1) { + continue; + } + + /* check for any unread messages from clients and call handle_client */ + c = get_clients(); + while(c) { + if(FD_ISSET(c->sock, &rdset)) { + if(handle_client(c) == -1) { + close(c->sock); + c->sock = -1; /* this effectively marks it for removal */ + } + } + c = c->next; + } + + /* accept any new incoming connections on the listening socket */ + if(FD_ISSET(lis, &rdset)) { + struct sockaddr_in addr; + int addrlen; + + if((s = accept(lis, (struct sockaddr*)&addr, &addrlen)) == -1) { + printlog("failed to accept new connection\n"); + } else { + printlog("new client from host: %s\n", inet_ntoa(addr.sin_addr)); + + add_client(s); + } + } + + /* remove any clients with closed sockets */ + remove_closed(); + } +} + +static void handle_key(int key) +{ +} diff --git a/src/mouse.h b/src/mouse.h new file mode 100644 index 0000000..7dd17b8 --- /dev/null +++ b/src/mouse.h @@ -0,0 +1,31 @@ +#ifndef MOUSE_H_ +#define MOUSE_H_ + +enum { + MOUSE_LEFT = 1, + MOUSE_RIGHT = 2, + MOUSE_MIDDLE = 4 +}; + +enum mouse_mode { + MOUSE_GFX, + MOUSE_TEXT +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int have_mouse(void); +void show_mouse(int show); +int read_mouse(int *xp, int *yp); +void set_mouse(int x, int y); +void set_mouse_limits(int xmin, int ymin, int xmax, int ymax); +void set_mouse_rate(int xrate, int yrate); +void set_mouse_mode(enum mouse_mode mode); + +#ifdef __cplusplus +} +#endif + +#endif /* MOUSE_H_ */ diff --git a/src/proto.c b/src/proto.c new file mode 100644 index 0000000..949cb94 --- /dev/null +++ b/src/proto.c @@ -0,0 +1,33 @@ +#include "proto.h" + +static uint16_t swap16(uint16_t x) +{ + return ((x & 0xff) << 8) | ((x & 0xff00) >> 8); +} + +static uint32_t swap32(uint32_t x) +{ + return ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | + ((x & 0xff000000) >> 24); +} + +#define SWAP16(x) ((x) = swap16(x)) +#define SWAP32(x) ((x) = swap32(x)) + +void swap_xconn_accept(struct xconn_accept_header *hdr) +{ + SWAP16(hdr->proto_major); + SWAP16(hdr->proto_minor); + SWAP16(hdr->add_length); + SWAP32(hdr->release); + SWAP32(hdr->resid_base); + SWAP32(hdr->resid_mask); + SWAP32(hdr->motionbuf_size); + SWAP16(hdr->vendor_length); + SWAP16(hdr->max_req_length); + /* TODO swap pixel formats and screens */ +} + +void swap_xreq_header(struct xrequest_header *hdr) +{ +} diff --git a/src/proto.h b/src/proto.h new file mode 100644 index 0000000..10a7aee --- /dev/null +++ b/src/proto.h @@ -0,0 +1,87 @@ +#ifndef PROTO_H_ +#define PROTO_H_ + +#include "xtypes.h" + +#define PROTO_MAJOR 11 +#define PROTO_MINOR 0 + +struct xconn_setup_header { + char byteorder, unused1; + CARD16 proto_major, proto_minor; + CARD16 auth_name_length; + CARD16 auth_data_length; + CARD16 unused2; + /* then followed by: + * - n auth_name bytes + * - pad to next 32bit-aligned address + * - m auth_data bytes + * - pad to next 32bit-aligned address + */ +}; + +struct xconn_accept_header { + CARD8 success, unused1; + CARD16 proto_major, proto_minor; + CARD16 add_length; /* 8+2*numfmt+(vendor_len+pad+m?)/4 */ + CARD32 release; + CARD32 resid_base, resid_mask; + CARD32 motionbuf_size; + CARD16 vendor_length; + CARD16 max_req_length; + CARD8 num_screens; + CARD8 num_pixfmt; + CARD8 img_byteorder; + CARD8 bm_fmt_bitorder; + CARD8 bm_fmt_scanline_unit; + CARD8 bm_fmt_scanline_pad; + KEYCODE min_keycode, max_keycode; + CARD32 unused2; + /* followed by: + * - vendor string of size vendor_length + * - pad to next 32bit-aligned address + * - 8*num_pixfmt pixel formats + * - list of screens (multiple of 4?) + */ +}; + +struct xformat { + CARD8 depth; + CARD8 bpp; + CARD8 scanline_pad; + char unused[5]; +}; + +struct xrequest_header { + CARD8 major; + CARD8 data; + CARD16 length; +}; + +struct xreply { + CARD32 length; + CARD16 req; + char data[28]; +}; + +struct xerror { + CARD8 error; + CARD8 code; + CARD16 seqnum; + char data[28]; +}; + +struct xevent { + CARD8 code; + CARD8 detail; + CARD16 seqnum; + char data[28]; +}; + +/* in-place byteorder swapping functions for all protocol structures */ +void swap_xconn_accept(struct xconn_accept_header *hdr); + +void swap_xreq_header(struct xrequest_header *hdr); +/* TODO: all possible requests */ + +#endif /* PROTO_H_ */ diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..c9e421c --- /dev/null +++ b/src/server.c @@ -0,0 +1,71 @@ +#include +#include "server.h" +#include "proto.h" +#include "util.h" +#include "client.h" + +#define NUM_SCR 1 +#define NUM_PIXFMT 1 +static const char *vendor = "John Tsiombikas"; + +static int calc_add_size(void); +static int calc_info_size(void); + +int server_info(void *buf, int sz) +{ + struct xconn_accept_header *info; + char *vendptr; + struct xformat *pixfmt; + int addsz = calc_add_size(); + int infosz = addsz + sizeof *info; + int vendsz = strlen(vendor); + + if(!buf) return infosz; + if(sz < infosz) return -1; + + info = buf; + vendptr = (char*)buf + sizeof *info; + pixfmt = (struct xformat*)(vendptr + padded_size(vendsz)); + + info->success = 1; + info->proto_major = PROTO_MAJOR; + info->proto_minor = PROTO_MINOR; + info->add_length = addsz / 4; /* in words */ + info->release = 1; + info->resid_base = 0; + info->resid_mask = 0xffff; + info->motionbuf_size = 0; + info->vendor_length = vendsz; + info->max_req_length = CLIENT_BUF_SIZE; + info->num_screens = NUM_SCR; + info->num_pixfmt = NUM_PIXFMT; + info->img_byteorder = 0; /* LSB first */ + info->bm_fmt_bitorder = 0; /* least significant */ + info->bm_fmt_scanline_unit = 1; /* TODO */ + info->bm_fmt_scanline_pad = 0; + info->min_keycode = 0; + info->max_keycode = 0xff; + + memcpy(vendptr, vendor, vendsz); + + pixfmt->depth = 24; + pixfmt->bpp = 24; + pixfmt->scanline_pad = 0; + + return infosz; +} + +static int calc_add_size(void) +{ + int ven_len = strlen(vendor); + int ven_pad = padding(ven_len); + int max_scr = padded_size(NUM_SCR); /* must be multiple of 4 */ + + /* additional data size */ + return 32 + 8 * NUM_PIXFMT + ven_len + ven_pad + max_scr; +} + +static int calc_info_size(void) +{ + return sizeof(struct xconn_accept_header) + calc_add_size(); +} diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..0d793ee --- /dev/null +++ b/src/server.h @@ -0,0 +1,10 @@ +#ifndef SERVER_H_ +#define SERVER_H_ + +/* if buf is null, returns the size required for the server info data. + * if buf is not null and sz is less than the required size, returns -1. + * otherwise fills the buffer with the server info data and returns the size + */ +int server_info(void *buf, int sz); + +#endif /* SERVER_H_ */ diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 0000000..1164792 --- /dev/null +++ b/src/timer.h @@ -0,0 +1,38 @@ +/* +pit8254 timer code for DOS programs. +Copyright (C) 2011-2014 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef TIMER_H_ +#define TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* expects the required timer resolution in hertz + * if res_hz is 0, the current resolution is retained + */ +void init_timer(int res_hz); + +void reset_timer(void); +unsigned long get_msec(void); +unsigned long get_ticks(void); + +#ifdef __cplusplus +} +#endif + +#endif /* TIMER_H_ */ diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..7b55924 --- /dev/null +++ b/src/util.c @@ -0,0 +1,11 @@ +#include "util.h" + +int padded_size(int sz) +{ + return (sz + 3) & 0xfffffffc; +} + +int padding(int sz) +{ + return padded_size(sz) - sz; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..2ee1fb0 --- /dev/null +++ b/src/util.h @@ -0,0 +1,12 @@ +#ifndef UTIL_H_ +#define UTIL_H_ + +/* calculates the padded size of an object of size "sz" */ +int padded_size(int sz); + +/* calculates the padding required for 32bit alignment after an object + * of size "sz" assuming itself is also aligned. + */ +int padding(int sz); + +#endif /* UTIL_H_ */ diff --git a/src/xtypes.h b/src/xtypes.h new file mode 100644 index 0000000..9c63eae --- /dev/null +++ b/src/xtypes.h @@ -0,0 +1,143 @@ +#ifndef XTYPES_H_ +#define XTYPES_H_ + +#include "inttypes.h" + +typedef int8_t INT8; +typedef int16_t INT16; +typedef int32_t INT32; + +#ifndef BYTE +typedef uint8_t BYTE; +#endif + +typedef uint8_t CARD8; +typedef uint16_t CARD16; +typedef uint32_t CARD32; + +typedef CARD32 BITMASK; +typedef CARD32 WINDOW; +typedef CARD32 PIXMAP; +typedef CARD32 CURSOR; +typedef CARD32 FONT; +typedef CARD32 GCONTEXT; +typedef CARD32 COLORMAP; +typedef CARD32 DRAWABLE; +typedef CARD32 FONTABLE; +typedef CARD32 ATOM; +typedef CARD32 VISUALID; +typedef CARD32 TIMESTAMP; +typedef CARD32 KEYSYM; +typedef CARD8 KEYCODE; +typedef CARD8 BUTTON; + +typedef CARD8* STRING8; + +/* BITGRAVITY, WINGRAVITY */ +#define Forget 0 +#define Unmap 0 +#define NorthWest 1 +#define North 2 +#define NorthEast 3 +#define West 4 +#define Center 5 +#define East 6 +#define SouthWest 7 +#define South 8 +#define SouthEast 9 +#define Static 10 + +#define False 0 +#define True 1 + +/* SETofEVENT, SETofPOINTEREVENT, SETofDEVICEEVENT bitmasks */ +#define KeyPress 0x00000001 +#define KeyRelease 0x00000002 +#define ButtonPress 0x00000004 +#define ButtonRelease 0x00000008 +#define EnterWindow 0x00000010 +#define LeaveWindow 0x00000020 +#define PointerMotion 0x00000040 +#define PointerMotionHint 0x00000080 +#define Button1Motion 0x00000100 +#define Button2Motion 0x00000200 +#define Button3Motion 0x00000400 +#define Button4Motion 0x00000800 +#define Button5Motion 0x00001000 +#define ButtonMotion 0x00002000 +#define KeymapState 0x00004000 +#define Exposure 0x00008000 +#define VisibilityChange 0x00010000 +#define StructureNotify 0x00020000 +#define ResizeRedirect 0x00040000 +#define SubstructureNotify 0x00080000 +#define SubstructureRedirect 0x00100000 +#define FocusChange 0x00200000 +#define PropertyChange 0x00400000 +#define ColormapChange 0x00800000 +#define OwnerGrabButton 0x01000000 + +#define SetOfEventUnused 0xfe000000 +#define SetOfPointerEventUnused 0xffff8003 +#define SetOfDeviceEventUnused 0xffffc0b0 + +/* SETofKEYBUTMASK, SETofKEYMASK bitmasks */ +#define Shift 0x0001 +#define Lock 0x0002 +#define Control 0x0004 +#define Mod1 0x0008 +#define Mod2 0x0010 +#define Mod3 0x0020 +#define Mod4 0x0040 +#define Mod5 0x0080 +#define Button1 0x0100 +#define Button2 0x0200 +#define Button3 0x0400 +#define Button4 0x0800 +#define Button5 0x1000 + +#define SetOfKeyButMaskUnused 0xe000 +#define SetOfKeyMaskUnused 0xff00 + +typedef struct { + CARD8 byte1, byte2; +} CHAR2B; + +typedef CHAR2B* STRING16; + +typedef struct { + INT16 x, y; +} POINT; + +typedef struct { + INT16 x, y; + CARD16 width, height; +} RECTANGLE; + +typedef struct { + INT16 x, y; + CARD16 width, height; + INT16 angle1, angle2; +} ARC; + +/* family field of the HOST structure */ +enum { + Internet = 0, + DECnet = 1, + Chaos = 2, + ServerInterpreted = 5, + InternetV6 = 6 +}; + +typedef struct { + CARD8 family, unused1; + CARD16 addr_length; + BYTE addr[1]; +} HOST; + +typedef struct { + CARD8 length; + STRING8 name; +} STR; + +#endif /* XTYPES_H_ */ -- 1.7.10.4