--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <ibmpc.h>
+
+/*
+ * 8259A interrupt controllers
+ *
+ * Implement the interrupt logic for classic PC, PC/XT and PC/AT
+ * platforms.
+ */
+
+static irqvector_t irqvec[16];
+static uint8_t irq_mask[2];
+static uint8_t irq_port[2] = { 0x21, 0xA1 };
+
+void mask_irq(uint8_t irq)
+{
+ irqflags_t mask = di();
+ uint8_t chip = irq >> 3;
+ irq &= 7;
+ irq_mask[chip] |= (1 << irq);
+ outb(irq_mask[chip], irq_port[chip]);
+ irqrestore(mask);
+}
+
+void unmask_irq(uint8_t irq)
+{
+ irqflags_t mask = di();
+ uint8_t chip = irq >> 3;
+ irq &= 7;
+ irq_mask[chip] &= ~(1 << irq);
+ outb(irq_mask[chip], irq_port[chip]);
+ irqrestore(mask);
+}
+
+int8_t int_to_irq(uint8_t irq)
+{
+ if (irq > 15)
+ return -EINVAL;
+ if (irq > 7 && pc_at == 0)
+ return -EINVAL;
+ if (irq == 2 && pc_at == 1)
+ irq = 9;
+ return irq;
+}
+
+void init_irq(void)
+{
+ if (inb(0xA1) == 0xFF)
+ pc_at = 0;
+}
+
+int set_irq(int8_t i, irqvector_t handler)
+{
+ irqflags_t mask = di();
+ i = int_to_irq(i);
+ if (i < 0)
+ return i;
+ if (irqvec[i])
+ return -EBUSY;
+ /*
+ * Replace the existing vector with the right irq{n} handler from our
+ * table. We don't replace them at start up as we are mostly a BIOS user
+ */
+//FIXME hook_irqvec(i);
+ irqvec[i] = handler;
+ unmask_irq(i);
+ irqrestore(mask);
+ return 0;
+}
+
+void do_platform_interrupt(int16_t irq)
+{
+ (irqvec[irq])(irq);
+}
CSRCS = devtty.c
-CSRCS += devices.c main.c libc.c biosdisk.c
+CSRCS += devices.c main.c libc.c biosdisk.c bioscon.c 8259a.c
-ASRCS = ibmpc.S crt0.S
+ASRCS = ibmpc.S crt0.S biosvid.S
ASRCS += tricks.S
COBJS = $(CSRCS:.c=$(BINEXT))
../tty.o ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
ibmpc.o ../syscall_proc.o ../syscall_other.o ../mm.o \
../devsys.o ../usermem.o ../syscall_exec16.o ../syscall_fs2.o \
- tricks.o ../syscall_fs3.o biosdisk.o \
+ tricks.o ../syscall_fs3.o biosdisk.o ../vt.o bioscon.o biosvid.o \
+ ../bank8086.o 8259a.o \
../usermem_std-8086.o devtty.o libc.o > ../fuzix.map
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <device.h>
+#include <vt.h>
+#include <tty.h>
+#include <graphics.h>
+
+/*
+ * Minimal BIOS mode console. We could do a lot more by using the
+ * attributes, mode information and pages properly but this will get
+ * us going.
+ */
+
+/*
+ * Private helpers in the asm library
+ */
+extern uint16_t bios_videomode(void);
+extern uint16_t bios_setpage(uint16_t page);
+extern void bios_videopage(uint16_t page);
+extern void bios_setcursor(uint16_t xy, uint16_t page);
+extern void bios_setchar(uint16_t ch, uint16_t pgattr, uint16_t rep);
+extern void bios_scrollup(void);
+extern void bios_scrolldown(void);
+extern void bios_clearscreen(void);
+
+/*
+ * These get mapped to VT_HEIGHT and friends by config.h
+ */
+int8_t vt_height = 25; /* Fixed for now */
+int8_t vt_width;
+uint8_t vtattr_cap = VTA_INVERSE|VTA_UNDERLINE|VTA_BOLD|VTA_NOCURSOR;
+/* Ok we don't do them yet but .. */
+
+/* Methods we must supply to the VT core */
+void cursor_off(void)
+{
+}
+
+void cursor_on(int8_t y, int8_t x)
+{
+ bios_setcursor((y << 8) | x, 0);
+}
+
+void plot_char(int8_t y, int8_t x, uint16_t ch)
+{
+ bios_setcursor((y << 8) | x, 0);
+ bios_setchar(ch, 7, 1);
+}
+
+void clear_lines(int8_t y, int8_t ct)
+{
+ uint8_t i;
+ if (ct == 25)
+ bios_clearscreen();
+ else {
+ for(i = 0; i < ct; y++) {
+ bios_setcursor((y + i) << 8, 0);
+ bios_setchar(' ', 7, vt_width);
+ }
+ }
+}
+
+void clear_across(int8_t y, int8_t x, int16_t l)
+{
+ bios_setchar(' ', y + (x << 8), l);
+}
+
+void vtattr_notify(void)
+{
+}
+
+void scroll_up(void)
+{
+ bios_scrollup();
+}
+
+void scroll_down(void)
+{
+ bios_scrolldown();
+}
+
+/* We only have one console */
+void console_switch(uint8_t n)
+{
+}
+
+/* Sit in the current mode in black and white and hope it carries on working */
+void bioscon_init(void)
+{
+ uint16_t mode = bios_videomode();
+ vt_width = mode >> 8;
+ if (vt_width == 0) /* In case of busted stuff we try */
+ vt_width = 80;
+ bios_setpage(0);
+ bios_videopage(0);
+}
/*
* PC BIOS disk driver
+ *
+ * FIXME: make this use the block stuff and partitions
+ * FIXME2: some crapware blows up if the buffer crosses a 64K boundary
+ * so we need to check this for user (and do smaller I/O) and it probably
+ * means we need to 512 byte align the buffer cache (ick). Whle user is
+ * 4K aligned they could pass a pointer on a DMA boundary so we may need
+ * a global disk bounce buffer too 8(
+ * (OTOH it's a real hardware limit so we can't escape it in native
+ * drivers either)
+ * FIXME3: some crapware also blows up if a track or head boundary
+ * is crossed, maybe we should just do 512 bytes at a time and cry
+ * in our beer.
+ * FIXME4: for floppies we need to try and read sector 0/0/1 on open
+ * and use fn 17 to try different settings until it works (and work out
+ * how to deal with 1.44 ??)
+ * FIXME5: we need an ioctl to setup and use the format services for
+ * floppy
*/
#include <kernel.h>
return bios_transfer(false, rawflag, &harddisk[minor]);
}
+/* FIXME: udata.u_page points into the mm so we need a helper to get our
+ mapping *but* we don't know if it's cs: or ds: because we might be
+ loading it ???? */
static int bios_transfer(bool is_read, uint8_t rawflag, struct disk_geom *g)
{
uint16_t dptr;
uint16_t ct = 0;
uint32_t st;
- int map = 0;
uint16_t page = kernel_ds;
uint16_t left;
uint16_t cylsec;
uint8_t tries;
/* Sort the actual request out */
- if(rawflag == 1) {
+ if(rawflag == 1 || rawflag == 3) {
if (d_blkoff(9))
return -1;
- map = 1;
- page = udata.u_page;
+ /* We need a standard way to wrap the segment gets and page so
+ we can share code with PDP11 etc */
+ if (rawflag == 1)
+ page = get_data_segment(udata.u_page2);
+ else
+ page = get_code_segment(udata.u_page2);
#ifdef SWAPDEV
} else if (rawflag == 2) { /* Swap device special */
page = swappage; /* Acting on this page */
- map = 1;
+ /* FIXME: EMM means bank flipping here */
#endif
}
--- /dev/null
+/*
+ * BIOS keyboard driver for annoying systems
+ *
+ * We are hooked into the int handler for the keyboard and then abuse
+ * that as a way to tell that we are safe from re-entry because we only
+ * do keyboard in the keyboard handler
+ *
+ * In addition we include an int 4f handler so that on most machines we
+ * can screen out annoyances like pause and printscreen.
+ */
+
+/* Called every keypress. We run the BIOS handler and see if a char is
+ present. If not get out. This is the fast path */
+bioskbd_handler:
+ lcall %cs:*bioskbd_old
+ cli
+ pushw %ax
+ movb $01,%ah
+ int $0x16
+ jnz nochar
+ xorw %ax,%ax
+ int $0x16
+ cmpb $0,%al
+ jnz has_char
+nochar:
+ popw %ax
+ reti
+
+/* The heavyweight path - dropping into C space */
+has_char:
+ pushw %ds
+ pushw %es
+ pushw %bp
+ pushw %bx
+ pushw %cx
+ pushw %dx
+ movw kernel_ds,%ds
+ movw %ss, kbd_ss
+ movw %sp, kbd_sp
+ cld
+ movw %ds,%bx
+ movw %bx,%es
+ movw %bx,%ss
+ movw $kbstack,%sp
+ pushw %ax
+ movw $1,%ax
+ pushw %ax
+ call tty_inproc
+ popw %ax
+ popw %ax
+ movw kbd_ss,%ss
+ movw kbd_sp,%sp
+ popw %dx
+ popw %cx
+ pop %bx
+ popw %bp
+ popw %es
+ popw %ds
+ popw %ax
+ reti
+
+/*
+ * We screen out printscreen and pause funnies. Some ancient systems
+ * don't have this hook so pause will cause the system to hang until
+ * it is done, print screen will call int 5 (we fix it up there) and
+ * ctrl-alt-del will do the usual
+ */
+
+int4f_hook:
+ pushw %ds
+ pushw %bx
+ movw %cs,%bx
+ movw %bx,%ds
+ movb %al,%ah
+ andb $0x7F,%ah
+ cmpb $0x1D,%ah
+ je cntrl
+ cmpb $0x2A,%ah
+ je lshift
+ cmpb $0x36,%ah
+ je rshift
+ cmpb $0x38,%ah
+ je alt
+ cmpb $37,%al /* prtscrn */
+ je magicop1
+ cmpb $45,%al
+ je magicop2
+ cmp $46,%al
+ je magicop2
+ cmp $0x53,%al
+ je magicop3
+passthrough:
+ popf
+ sec
+ ret
+/*
+ * Prevent the print screen callback and also the pause behaviour
+ * on the pause key.
+ */
+magicop1: /* ignore with shift | ctrl */
+ movw shift_1,%bx
+ cmpw $0,%bx
+ je passthrough
+magicop2: /* igmore with ctrl */
+ movb cntrl_1,%bl
+ cmpb $0,%bl
+ je passthrough
+ clc
+ ret
+magicop3: /* ignore with ctrl alt */
+ movw alt_1,%bx
+ cmpw $0,%bx
+ je passthrough
+ clc
+ ret
+lshift:
+ pushw %ax
+ andb $0x80,%al
+ movb %al,shift_1
+ popw %ax
+ sec
+ ret
+rshift:
+ push %ax
+ andb $0x80,%al
+ movb %al,shift_2
+ popw %ax
+ sec
+ ret
+cntrl:
+ push %ax
+ andb $0x80,%al
+ movb %al,cntrl_1
+ popw %ax
+ sec
+ ret
+alt:
+ push %ax
+ andb $0x80,%al
+ movb %al,alt_1
+ popw %ax
+ sec
+ ret
+
+/* In CS: for simplicity */
+alt_1:
+ .byte 0
+cntrl_1:
+ .byte 0
+shift_1:
+ .byte 0
+shift_2:
+ .byte 0
+
+
+bioskbd_old:
+ .dword 0
+
+ .data
+kbd_ss .word 0
+kbd_sp .word 0
+ .bss 128
+kbstack:
--- /dev/null
+/*
+ * Stubs for BIOS video
+ * We need to sort out the logic for blink/underline/attributes
+ *
+ * For now we present a simple black and white console although in
+ * many cases we can actually do 8 colours plus bright plus under
+ */
+
+ .arch i8086,jumps
+ .code16
+ .att_syntax prefix
+ .text
+
+ .global bios_videomode
+ .global bios_setpage
+ .global bios_videopage
+ .global bios_setcursor
+ .global bios_setchar
+ .global bios_scrollup
+ .global bios_scrolldown
+ .global bios_clearscreen
+
+
+/* Return mode and columns */
+bios_videomode:
+ movb $0x0F,%ah
+ int $0x10
+ andb $0x7F,%al
+ movb %ah,dwidth
+ ret
+/* Set our display page */
+bios_setpage:
+ pushw %bp
+ movw %sp,%bp
+ movb 4(%bp),%al
+ movb $5,%ah
+ int $0x10
+ pop %bp
+ /* and drop through to see if it worked */
+/* Display page */
+bios_videopage:
+ movb $0x0F,%ah
+ int $0x10
+ movb %bh,%al
+ xorb %ah,%ah
+ ret
+bios_setcursor:
+ pushw %bp
+ movw %sp,%bp
+ movw 4(%bp),%dx
+ movb 6(%bp),%bh
+ int $0x10
+ popw %bp
+ ret
+bios_setchar:
+ pushw %bp
+ movw %sp,%bp
+ movw 4(%bp),%ax
+ movw 6(%bp),%bx
+ movw 8(%bp),%cx
+ movb $0x09,%ah
+ int $0x10
+ popw %bp
+ ret
+bios_scrollup:
+ pushw %ds /* Trident bug */
+ pushw %bp
+ movw %sp,%bp
+ xorw %cx,%cx
+ xorb %bh,%bh /* Until we add colour/attributes */
+ movb $24,%dh /* Hack for the moment */
+ movb dwidth,%dl
+ decb %dl
+ movw $0x0601,%ax
+ int $0x10
+ popw %bp
+ popw %ds
+ ret
+bios_scrolldown:
+ pushw %ds /* Trident bug */
+ pushw %bp
+ movw %sp,%bp
+ xorw %cx,%cx
+ xorb %bh,%bh /* Until we add colour/attributes */
+ movb $24,%dh /* Hack for the moment */
+ movb dwidth,%dl
+ decb %dl
+ movw $0x0701,%ax
+ int $0x10
+ popw %bp
+ popw %ds
+ ret
+bios_clearscreen:
+ pushw %ds /* Trident bug */
+ pushw %bp
+ movw %sp,%bp
+ xorw %cx,%cx
+ xorb %bh,%bh /* Until we add colour/attributes */
+ movb $24,%dh /* Hack for the moment */
+ xorb %al,%al
+ movb dwidth,%dl
+ decb %dl
+ movw $0x0600,%ax
+ int $0x10
+ popw %bp
+ popw %ds
+ ret
+
+ .data
+
+dwidth: .byte 0
--- /dev/null
+ .arch i8086,jumps
+ .code16
+ .att_syntax prefix
+
+ .text
+
+/*
+ * We are loaded somewhere high by the bootstrap and need
+ * to move the payload down, set up and enter it. The payload never
+ * returns to us. We are guaranteed not tbe in the payload's way
+ *
+ * On entry
+ * cs/ds are set so our address is cs:0 etc
+ * es is undefined
+ * ss:sp is a stack somewhere potentially to be overwritten
+ * We are in the BIOS environment
+ * Interrupts are *off*
+ *
+ * Tasks:
+ * Move the stack to 0x500-0x5FF
+ * Wipe 0x600-0x7FF
+ * Copy the data and code starting at 0x800 as two blocks (we skip
+ * the BSS) then jump to the code as cs:0
+ */
+
+bootstrap:
+ movb $'B',%al
+ call printchar
+ movw $0x50,%ax /* 0x500 is base, 0x600->0x7FF is the
+ udata and stack we need to clear */
+ movw %ax,%es /* Point ES: at the target */
+
+ cld
+
+ xorw %ax,%ax
+ movw $0x100,%di
+ movw $0x100,%cx
+ rep stosw /* Wipe 0x600-0x7FF */
+ movb $'o',%al
+ call printchar
+ movw $0x50,%ax
+ movw %ax,%ss /* Switch stack segment */
+ movw $0x100,%sp /* Stack pointer */
+ movb $'o',%al
+ call printchar
+ sti /* Interrupts are now safe */
+ movb $'t',%al
+ call printchar
+ movw $0x300,%di /* es: Offset to start coping image */
+ movw $end,%si /* ds: Offset of image */
+ movw end,%cx /* Length to copy (words, 16 byte pad) */
+ rep movsw /* Copy all but BSS */
+ movb $'i',%al
+ call printchar
+ movw end+2,%cx /* Code length (words) */
+ movw end+4,%di /* Code (and discard) base */
+ rep movsw /* follows on in block so si is ok */
+ movb $'n',%al
+ call printchar
+ movw end+6,%bx /* Segment value for code */
+ movw $0x50,%ax
+ movw %ax,%ds
+ pushw %bx /* Segment of code */
+ xorw %ax,%ax
+ pushw %ax
+ movb 'g',%al
+ call printchar
+ retf /* Jump to new CS:0 */
+printchar:
+ pushw %ax
+ pushw %bx
+ movb $0x0E,%ah
+ movb $7,%bl
+ int $10
+ popw %bx
+ popw %ax
+ ret
#undef CONFIG_PROFIL
#define CONFIG_MULTI
-#define CONFIG_SWAP_ONLY
+#define CONFIG_BANK_8086
#define CONFIG_USERMEM_DIRECT
#define CONFIG_BANKS 1
#define PROC_SIZE 128 /* 64K, 128 * 512 */
#define UDATA_SIZE 512
#define UDATA_BLKS 1
+#define CONFIG_VT
+#define VT_WIDTH vt_width
+#define VT_HEIGHT vt_height
+#define VT_RIGHT (vt_width - 1)
+#define VT_BOTTOM (vt_height - 1)
+extern signed char vt_width, vt_height;
+
#define PROGBASE 0x8000UL
#define PROGLOAD PROGBASE
#define PROGTOP 0xE000UL
+#if 0
#define SWAP_SIZE (130 + 2) /* 2 for the udata */
#define SWAPBASE PROGBASE
#define SWAPTOP 0xE000UL
#define MAX_SWAPS PTABSIZE /* Mandatory for swap only */
#define swap_map(x) ((uint8_t *)(x))
-
#define SWAPDEV (1)
+#endif
#define TICKSPERSEC 50 /* Ticks per second */
--- /dev/null
+/*
+ * The boot time configuration space loaded at 0x800
+ */
+
+#define NUM_SER 4
+#define NUM_PAR 4
+
+struct serconf {
+ uint8_t driver;
+#define SER_8250 0
+ uint8_t info; /* Usually IRQ for non BIOS */
+ uint16_t port;
+};
+
+struct parconf {
+ uint8_t driver
+#define PAR_BIOS 0
+ uint8_t info;
+ uint16_t port;
+};
+
+struct kconf {
+ uint16_t magic;
+#define MAGIC 0xBA10
+ uint8_t kbd_driver;
+#define KBD_BIOSHOOK 0 /* (info gives int to hook) */
+#define KBD_XTKEY 1
+ uint8_t kbd_info;
+
+ uint8_t video_driver;
+#define VID_BIOS 0 /* video_info gives mode to set or FF */
+#define VID_PC 1 /* native PC driver */
+ uint8_t video_info[3];
+
+ uint8_t xms_driver;
+#define XMS_OFF 0
+#define XMS_RAMDISK 1
+ uint8_t xms_info;
+
+ uint8_t fd_driver
+#define FD_BIOS 0
+ uint8_t fd_info;
+
+ uint8_t hd_driver
+#define HD_BIOS 0
+ uint8_t hd_info;
+
+ uint8_t js_driver;
+#define JS_BIOS 0
+ uint8_t js_info;
+
+ uint8_t ems_driver;
+#define EMS_NONE 0
+#define EMS_ABOVEBOARD 1
+#define EMS_LOTECH 2
+#define EMS_OPTI 3
+#define EMS_BIOS 4
+ uint8_t ems_ctrl;
+ uint16_t ems_port;
+ uint16_t ems_step;
+ uint16_t ems_off;
+ uint16_t ems_mem; /* KB or 0 */
+
+ struct serconf ser[NUM_SER];
+ struct lpconf par[NUM_PAR];
+
+};
void device_init(void)
{
- int i;
+/* int i;
for (i = 1; i <= MAX_SWAPS; i++)
- swapmap_init(i);
+ swapmap_init(i); */
}
+/*
+ * Just to get us going assume we have a console and keyboard and leave
+ * the PC serial ports alone as we can't sanely drive them via BIOS.
+ * We have other stuff to bring up before working on those tricky bits.
+ */
+
#include <kernel.h>
#include <kdata.h>
#include <printf.h>
#include <devtty.h>
#include <device.h>
#include <tty.h>
-
-volatile uint8_t *uart_data = (volatile uint8_t *)0xF03000; /* UART data */
-volatile uint8_t *uart_status = (volatile uint8_t *)0xF03010; /* UART status */
+#include <vt.h>
unsigned char tbuf1[TTYSIZ];
ttyready_t tty_writeready(uint8_t minor)
{
- uint8_t c = *uart_status;
- return (c & 2) ? TTY_READY_NOW : TTY_READY_SOON; /* TX DATA empty */
+ return TTY_READY_NOW;
}
void tty_putc(uint8_t minor, unsigned char c)
{
- *uart_data = c; /* Data */
+ vtoutput(&c, 1);
}
void tty_setup(uint8_t minor)
void tty_sleeping(uint8_t minor)
{
}
-
-/* Currently run off the timer */
-void tty_interrupt(void)
-{
- uint8_t r = *uart_status;
- if (r & 1) {
- r = *uart_data;
- tty_inproc(1,r);
- }
-}
-
-void platform_interrupt(void)
-{
- timer_interrupt();
- tty_interrupt();
-}
#ifndef __DEVTTY_DOT_H__
#define __DEVTTY_DOT_H__
-#define KEY_ROWS 8
-#define KEY_COLS 7
-extern uint8_t keymap[8];
-extern uint8_t keyboard[8][7];
-extern uint8_t shiftkeyboard[8][7];
-
#endif
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+
+#ifdef CONFIG_IBMPC_EMM
+
+/*
+ * Handle EMM memory space using typical implementations of the hardware
+ * with the triple ports (208/9/A or 218/9/A). Assumes only one EMM card
+ *
+ * The Intel board uses 0x258 for the port and adds 0x4000 to get higher
+ * decodes and usually maps at C0000. 0x259 controls C000/D000 base
+ * (write 128,0,128,0 for D 128,0,0,0 to 259,4259,8259,C259)
+ *
+ * For data write 0x258/4258,8258,C258 with the page number.
+ */
+
+static uint16_t emm[MAX_EMM];
+static uint16_t ems_seg;
+static uint16_t emm_ptr;
+static uint16_t emm_max;
+static uint16_t emm_over; /* EMM we couldn't use for processes but is
+ a RAMDISC candidate */
+
+static uint8_t emsport; /* Port range - usually 208/9/A */
+static uint8_t emsctrl; /* The bits we set for autoinc, base etc */
+static uint16_t emsstep; /* Step for Intel style ports */
+static uint16_t emsoff; /* Offset to add to emm */
+
+uint16_t emm_alloc_bank(struct proc_mmu *m)
+{
+ if (emm_ptr == 0) {
+ m->emm = 0;
+ return ENOMEM;
+ }
+ m->emm = emm[emm_ptr--];
+ m->dseg = ems_seg;
+ return 0;
+}
+
+void emm_free_bank(struct proc_mmu *m)
+{
+ emm[++emm_ptr] = m->emm;
+}
+
+/*
+ * Used for things like the Opti chipset support
+ */
+static void emm_select_1(uint16_t emm)
+{
+ /* Select first 16K slot, with autoincrement etc */
+ outb(emsctrl, emsport + 2);
+ for (i = 0; i < 4; i++) {
+ outb(0x80 |(emm >> 8), emsport + 2); /* A22/A23 + Enable */
+ outb(emm, emsport + 1); /* A14 - A 21 , autoincrements bank */
+ }
+}
+
+/*
+ * Intel AboveBoard,
+ */
+static void emm_select_2(uint16_t emm)
+{
+ unt16_t port = emsport;
+ for (i = 0; i < 4; i++) {
+ outb(emm + emmoff, port);
+ port += emsstep;
+ }
+}
+
+void emm_select(uint16_emm)
+{
+#ifdef CONFIG_EMM_BIOS
+ if (emm_type == 3)
+ emm_select_bios(emm);
+ else
+#endif
+ if (emm_type == 1)
+ emm_select_1(emm);
+ else
+ emm_select_2(emm);
+
+}
+
+uint16_t emm_space_used(void)
+{
+ return (emm_max - emm_ptr) * 64;
+}
+
+/* Discard for these eventually */
+
+void emm_new_bank(struct proc_mmu *m)
+{
+ if (emm_max == MAX_EMM) {
+ emm_over++;
+ return;
+ }
+ emm[++emm_ptr] = m->emm;
+ emm_max++;
+ ramsize += 64;
+}
+
+/* FIXME: always needs to run with IRQ off */
+uint8_t opti_r(uint8_t c)
+{
+ outb(c, 0x22);
+ return inb(0x23);
+}
+
+/* Need a probing version of this */
+static void do_emm_init(uint16_t base, uint16_t pages)
+{
+ uint16_t i;
+ for (i = 0; i < pages; i++)
+ emm_new_bank(base + 4 * i);
+}
+
+int opti_emm_init(void)
+{
+ uint8_t x = opti_r(0x4F);
+
+ /* EMS off */
+ if ((x & 0xC0) != 0xC0)
+ return 0;
+
+ if (x & 1)
+ emsport = 0x218;
+ else
+ emsport = 0x208;
+
+ emsctrl = 0x80; /* D0000, autoinc */
+ emstype = 1;
+ ems_seg = 0xD000;
+
+ /* Add all the memory from 1MB to the top of extended memory as we are
+ only using it in EMS mode. Don't get clever and add < 1MB shadow
+ space */
+ do_ems_init(16, xmm_kb / 64);
+ return 1;
+}
+
+/* Intel Above Board (original to 2MB) */
+int intel_emm_init(uint8_t seg, uint16_t kb)
+{
+ /* The board lives at 0x258 by default */
+ emsport = 0x258;
+ emsstep = 0x4000;
+ emstype = 2;
+ ems_seg = seg;
+ emmoff = 0;
+ if (seg != 0xC000 && seg != 0xD000)
+ return -1;
+ /* Program the base address */
+ outb(0x80, emsport);
+ outb(0x00, emsport + 0x4000);
+ outb((seg & 0x1000) >> 9, emsport + 0x8000);
+ outb(0x00, emsport + 0xC000);
+ /* Set up the pages */
+ do_ems_init(0x80, kb / 64);
+ return 1;
+}
+
+/* Not clear if writing 209 with values sets the high 3 bits for the
+ bigger ranges */
+int neat_emm_init(uint8_t seg, uint16_t kb)
+{
+ emsport = 0x208;
+ emsstep = 0x4000;
+ emstype = 2;
+ ems_seg = 0xD000;
+ emmoff = 0;
+ do_ems_init(0x80, kb / 64);
+ return 1;
+}
+
+/* Four consecutive write only ports giving each bank. About as simple as
+ it gets */
+int lotech_emm_init(uint8_t seg, uint16_t kb)
+{
+ emsport = 0x260;
+ emsstep = 1;
+ emstype = 2;
+ ems_seg = seg;
+ emmoff = -1;
+ do_ems_init(0x01, kb / 64);
+ return 1;
+}
+
+#ifdef CONFIG_EMM_BIOS
+
+/* A few emulators don't have any sane EMM interface but do have the int
+ hooks in the BIOS environment. That's annoying as **** but we need to
+ support this for development work.
+
+ We don't behave in a civilised manner we just grab all free pages knowing
+ nothing else is running */
+
+static uint16_t handle;
+
+/* This is completely unsafe on a real platform, but it's not a real one
+ so it works... */
+static void bios_emm_select(uint16_t mm)
+{
+ uint8_t i;
+ for (i = 0; i < 4; i++)
+ if (emm_map_memory(i, handle, mm - 1))
+ panic("emmfault");
+}
+
+int bios_emm_init(void)
+{
+ int num;
+ int handle;
+ /* Load the segment from 0x019E and check that :000A contains the ascii
+ EMS string */
+ if (!emm_detect())
+ return 0;
+ /* Where does it map ? */
+ ems_seg = emm_page_frame_segment();
+ if (ems_seg == 0)
+ return 0;
+ /* How much can we get */
+ num = emm_free_pages();
+ if (num == 0)
+ return 0;
+ handle = emm_allocate(num);
+ do_ems_init(0x01, num / 4);
+ return 1;
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * EMM bios crap for emulator stuff
+ */
+
+
+ .arch i8086,jumps
+ .code16
+ .att_syntax prefix
+
+ .global emm_detect
+ .global emm_page_frame_segment
+ .global emm_free_pages
+ .global emm_allocate
+ .global emm_map_memory
+
+ .data
+emm_string:
+ .byte "EMMXXXX0"
+ .even
+
+ .text
+emm_detect:
+ pushw %es
+ pushw %di
+ pushw %si
+ xorw %ax,%ax
+ movw %ax,%es ; set segment to 0
+ movw 0x19E:%ax ; read the vector
+ movw ax,%es ; segment is now the driver segment
+
+ movw $10,%di
+ movw $emm_string,%si
+ movw $4,%cx
+ repe cmpsw
+
+ cmpw $0,%cx
+ je emm_ok
+ movw %cx,%ax
+emm_det_done:
+ popw %si
+ popw %di
+ popw %es
+ ret
+emm_ok:
+ movw $1,%cx
+ jmp emm_det_done
+
+emm_page_frame_segment:
+ movb $0x41,%ah
+ int $0x67
+ movw %bx,%ax
+ ret
+
+emm_free_pages:
+ movb %0x42,%ah
+ int $0x67
+ movw %bx,%ax
+ ret
+
+emm_allocate:
+ pushw %bp
+ movw %sp,%bp
+ movw 4(%bp),%bx
+ movb $0x43,%ah
+ int $0x67
+ cmpw $0,%ax
+ jne failed_alloc
+ movw %dx,%ax
+failed_alloc:
+ popw %bp
+ ret
+
+emm_map_memory:
+ pushw %bp
+ movw %sp,%bp
+ movw 4(%bp),%al ; handle id
+ movw 6(%bp),%dx ; handle
+ movw 8(%bp),%bx ; page
+
+ movb $0x43,%ah
+ int $0x67
+ xorb %al,%al
+ popw %bp
+ ret
jmp do_irq
int3:
pushw %ax
- movb $2,%al
+ movb $3,%al
jmp do_irq
int4:
pushw %ax
- movb $2,%al
+ movb $4,%al
jmp do_irq
int5:
pushw %ax
- movb $2,%al
+ movb $5,%al
jmp do_irq
int6:
pushw %ax
- movb $2,%al
+ movb $6,%al
jmp do_irq
int7:
pushw %ax
- movb $2,%al
+ movb $7,%al
jmp do_irq
int8:
pushw %ax
- movb $2,%al
+ movb $8,%al
jmp do_irq
int9:
pushw %ax
- movb $2,%al
+ movb $9,%al
jmp do_irq
int10:
pushw %ax
- movb $2,%al
+ movb $10,%al
jmp do_irq
int11:
pushw %ax
- movb $2,%al
+ movb $11,%al
jmp do_irq
int12:
pushw %ax
- movb $2,%al
+ movb $12,%al
jmp do_irq
int13:
pushw %ax
- movb $2,%al
+ movb $13,%al
jmp do_irq
int14:
pushw %ax
- movb $2,%al
+ movb $14,%al
jmp do_irq
int15:
pushw %ax
- movb $2,%al
+ movb $15,%al
jmp do_irq
int0:
pushw %ax
xorb %al,%al
+
+ /* FIXME: we need a way to cleanly hook the schedule/signal parts
+ of this into an int handler for the BIOS timer callback */
do_irq:
/* Save base registers on current stack */
pushw %ds
movb $1,inint
movb $1,udata + U_DATA__U_ININTERRUPT
pushw %ax
- call platform_interrupt
- popw %bx
+ call do_platform_interrupt
+ popw %ax
+
+ /* This little chunk is machine specific so we'll need to work out
+ how to move most of this to lowlevel-8086 and keep the 8259A bits
+ behind */
+ cmpb $16,%al
+ jb internal /* CPU generated */
+ cmpb $8,%al
+ movb $0x20,%al
+ jb xt_int
+ outb %al,$0xA0
+ /* The 8259 is slower than the 8086 so we need to wait */
+ jmp delay
+delay: jmp xt_int
+xt_int:
+ outb %al,$0x20
+internal:
movb $0,inint
movb $0,udata + U_DATA__U_ININTERRUPT
kernel_ds:
.word 0
- .data
-equipment_word:
- .word 0
-
--- /dev/null
+typedef void (*irqvector_t)(int8_t);
+
+extern uint8_t inb(uint16_t);
+extern void outb(uint8_t, uint16_t);
+
+extern uint8_t pc_at;
+
+static inline uint8_t inb_p(uint16_t port)
+{
+ uint8_t value = inb(port);
+ inb(0x80);
+}
+
+static inline void outb_p(uint8_t value, uint16_t port)
+{
+ outb(value, port);
+ inb(0x80);
+}
+
#include <kdata.h>
#include <printf.h>
#include <devtty.h>
-#include <buddy.h>
+#include <ibmpc.h>
uint8_t kernel_flag = 1;
+uint8_t pc_at = 1;
+uint16_t equipment_word;
+uint8_t cpu_type;
+uint8_t bus_width;
+uint8_t fpu_type;
void platform_idle(void)
{
- /* FIXME: disable IRQ, run tty interrupt, re-enable ? */
+ /* Do a halt or what ? */
}
void do_beep(void)
{
}
+void pagemap_init(void)
+{
+ /* FIXME: use proper kernel _discard to correct end allowing for EBDA */
+ pagemap_init_range(64, 640);
+}
+
/*
- * MMU initialize
+ * MMU initialize. We use this to set everything up. Should move into
+ * discard
*/
void map_init(void)
{
+ static char *cpu[]={"808","80C8","NEC V","8018","8028"};
+ static char *fpu[]={"87","287+"};
+ cpu_detect();
+ kputs("Processor: ");
+ kputs(cpu[cpu_type]);
+ if (cpu_type == 2)
+ kputs(bus_width == 8 ? "20" : "30");
+ else
+ kputs(bus_width == 8 ? "8" : "6");
+ if (cpu_type == 4)
+ kputs("+");
+ if (fpu_type) {
+ kputs(" / 80");
+ kputs(fpu[fpu_type]);
+ }
+ kputs("\n");
+ /* Should we do bogomips 8) */
+// init_irq();
}
uaddr_t ramtop;
{
memset(p, 0, len);
}
-
-uint16_t irqstack[128]; /* Used for swapping only */
--- /dev/null
+/*
+ * XMS Ramdisk Driver.
+ *
+ * This allows us to use high memory on a 286 system as a RAM disk
+ *
+ * FIXME: make this use the block stuff and partitions
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devhd.h>
+#include <bios.h>
+
+static uint16_t xms_size;
+
+static int xm_transfer(bool is_read, uint8_t rawflag)
+{
+ uint16_t page = kernel_ds;
+ uint32_t dptr;
+
+ if (rawflag == 1) {
+ if (d_blkoff(9))
+ return -1;
+ page = get_segment(udata.u_page);
+#ifdef SWAPDEV
+ } else if (rawflag == 2)
+ page = swappage;
+#endif
+
+ /* dptr is effectively a far pointer */
+ dptr = (uint32_t)udata.u_dptr;
+ dptr += page << 4;
+
+ /* Should we add a simple length check to the core disk I/O ? */
+ if (udata.u_block + udata.u_nblock > xms_size ||
+ udata.u_block + udata.u_nblock < udata.u_block)
+ {
+ udata.u_error = EINVAL;
+ return -1;
+ }
+ if (is_read) {
+ os = gdt + 0x20;
+ disk = gdt + 0x30;
+ else {
+ os = gdt + 0x30;
+ disk = gdt + 0x20;
+ }
+
+ /*
+ FIXME: we should loop this with a limited transfer size because
+ 1. We can't do > 32k words at a time (not clear if can do exactly 32k)
+ 2. It runs with IRQs off
+ */
+ /* Turn the disk block into a 24 bit address remembering we start at 1MB */
+ disk[2] = 0x00; /* A0-A7 */
+ disk[3] = udata.u_block << 1; /* A8-A15 */
+ disk[4] = (udata.u_block >> 7) + 16; /* A16-A23 */
+ /* Turn the native far address into a 24bit address */
+ os[2] = dptr;
+ os[3] = dptr >> 8;
+ os[4] = dptr >> 16;
+ /* The other bytes are pre-filled */
+ /* Length is in words */
+ err = xmm_xfer(udata.u_nblock << 8);
+ if (err) {
+ /* 0x01 - parity, 0x02 exception, 0x03 gate a20 failed */
+ kprintf("xm0: error %d\n", err);
+ udata.u_error = EIO;
+ return -1;
+ }
+ return udata.u_nblock << 9;
+}
+
+int xm_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ return xm_transfer(true, rawflag);
+}
+
+int xm_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ return xm_transfer(false, rawflag);
+}
+
+int xm_open(uint8_t minor, uint16_t flag)
+{
+ if (minor || !xms_size)
+ return ENODEV;
+ return 0;
+}
+
+void xm_init(void)
+{
+ if (xm_lockout)
+ return;
+ xms_size = xmm_probe();
+ if (xms_size)
+ kprintf("xm0: %dKb extended memory RAMdisc\n", xms_size);
+ xms_size *= 2; /* Blocks */
+}
+
+/* Certain 286 systems can make memory visible as both extended and expanded.
+ On those we need to lock out the less useful extended form */
+void xm_disable(void)
+{
+ xm_lockout = 1;
+}
--- /dev/null
+ .arch i8086,jumps
+ .code16
+ .att_syntax prefix
+
+ .text
+
+ .global xmm_probe
+ .global xmm_transfer
+
+/*
+ * BIOS probe for extended memory in Kb. This doesn't work on modern
+ * systems but it does on 286 era boxes just fine.
+ */
+xmm_probe:
+ scf
+ movb %0x88,%ah
+ int $0x15
+ jnc xmm_ok
+ xorw %ax,%ax
+xmm_ok:
+ ret
+
+/*
+ * Perform an extended memory transfer
+ */
+xmm_transfer:
+ pushw %bp
+ movw %sp,%bp
+ movw 4(%bp),%cx ; count
+ pushw %si
+ movw $xmm_gdt,%si
+ movb $0x87,%ah
+ scf
+ int $0x15
+ jc no_xmm_xfer
+ popw %si
+ popw %bp
+ ret
+
+ .data
+
+xmm_gdt:
+ .byte 0,0,0,0,0,0,0,0
+ .byte 0,0,0,0,0,0,0,0
+ .byte 0xFFFF,0,0,0,0,0x93,0,0
+ .byte 0xFFFF,0,0,0,0,0x93,0,0
+ .byte 0,0,0,0,0,0,0,0
+ .byte 0,0,0,0,0,0,0,0
+ .byte 0,0,0,0,0,0,0,0
+ .byte 0,0,0,0,0,0,0,0
--- /dev/null
+/*
+ * The BIOS keyboard interface is pretty much unusable for a Unixlike
+ * OS, so sadly we have to take over the keyboard ourselves. Hopefully
+ * the early non-clones didn't do anything too weird in this space.
+ *
+ * Based on the ELKS driver by Saku Airila and Sefaan Van Dooren
+ *
+ * We need to look at the following
+ * - Some basic AT support
+ * - Nicer mapping of key codes onto ELKS standard FN etc codes
+ * - Loadable keymaps
+ *
+ * The console layer expects us to call console_queue(uint8_t x)
+ * with FUZIX codes for each key. If we see Alt-Fn we call
+ * console_switch(n) to indicate a possible console switch. Other
+ * than that we try to be blissfully ignorant of the tty layer as it's
+ * simply not our problem and we are not the only console driver.
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <vt.h>
+#include <devtty.h>
+
+#ifdef CONFIG_KBD_XT
+
+#define KBD_IO 0x60
+#define KBD_CTL 0x61
+
+#define ESC 27
+#define KB_SIZE 64
+
+static uint8_t xtkb_scan[] = {
+ 0, 033, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', '\b', '\t',
+/*10*/ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '[', ']', KEY_ENTER, /* lctrl */0x82, 'a', 's',
+/*20*/ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '#', /* lshift */0x80, '\\', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '/', /* rshift */0x81, '*',
+ /* lalt */0x83, ' ', /* capslock */0x84, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
+ KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, /* numlock */0x85, /* scrollock */0x90, KEY_HOME,
+ KEY_UP, KEY_PGUP, KEY_MINUS, KEY_LEFT, /* kb-5 ?? */0265, KEY_RIGHT, KEY_PLUS, KEY_END,
+ KEY_DOWN, KEY_PGDOWN, KEY_INSERT, KEY_DEL
+};
+
+static uint8_t xtkb_scan_shifted[] = {
+ 0, 033, '!', '"', '£', '$', '%', '^',
+ '&', '*', '(', ')', '_', '+', '\b', '\t',
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', '{', '}', KEY_ENTER, /* lctrl */0x82, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '"', '~', /* lshift */0x80, '|', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', '<', '>', '?', /* rshift */0x81, '*',
+ /* FIXME: we don't have shift- and ctrl Fx maps but need them */
+ /* lalt*/0x83, ' ', /* capslock */0x84, KEY_F1, KEY_F1, KEY_F3, KEY_F4, KEY_F5,
+ KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, /* numlock */0x84, /* scrollock */0x93, '7',
+ '8', '9', /* keypad - */'-', '4', '5', '6', '+', '1',
+ '2', '3', '0', KEY_DEL
+};
+
+static uint8_t xtkb_scan_ctrl_alt[] = {
+ 0, 033, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', KEY_BS, KEY_TAB,
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '[', ']', KEY_ENTER, /* lctrl */0x82, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '`', /* lshift */0x80, '`', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '/', /* rshift */0x81, '*',
+ /* lalt */0x83, ' ', /* capslock */0x84, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
+ KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, /* numlock */0x85, /* scrollock */0x90, KEY_HOME,
+ KEY_UP, KEY_PGUP, KEY_MINUS, KEY_LEFT, /* kb-5 ?? */0265, KEY_RIGHT, KEY_PLUS, KEY_END,
+ KEY_DOWN, KEY_PGDOWN, KEY_INSERT, KEY_DEL
+};
+
+static uint8_t xtkb_scan_caps[] = {
+ 0, 033, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', KEY_BS, KEY_TAB,
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', '[', ']', KEY_ENTER, 0x82, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '\'', '~', 0x80, '|', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', ',', '.', '/', 0x81, '*',
+ /* lalt*/0x83, ' ', /* capslock */0x84, KEY_F1, KEY_F1, KEY_F3, KEY_F4, KEY_F5,
+ KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, /* numlock */0x84, /* scrollock */0x93, '7',
+ '8', '9', /* keypad - */'-', '4', '5', '6', '+', '1',
+ '2', '3', '0', KEY_DEL
+};
+
+#define LSHIFT 1
+#define RSHIFT 2
+#define CTRL 4
+#define ALT 8
+#define CAPS 16
+#define NUM 32
+#define ALT_GR 64
+
+#define ANYSHIFT (LSHIFT | RSHIFT)
+
+#define SSC 0xC0
+
+static uint8_t tb_state[] = {
+ 0x80, CTRL, SSC, SSC, /*1C->1F */
+ SSC, SSC, SSC, SSC, SSC, SSC, SSC, SSC, /*20->27 */
+ SSC, SSC, LSHIFT, SSC, SSC, SSC, SSC, SSC, /*28->2F */
+ SSC, SSC, SSC, SSC, SSC, SSC, RSHIFT, SSC, /*30->37 */
+ SSC, SSC, CAPS, /*38->3A */
+ 'a', 'b', 'c', 'd', 'e', /*3B->3F, Function Keys */
+ 'f', 'g', 'h', 'i', 'j', /*40->44, Function Keys */
+ NUM, SSC, SSC, /*45->47 */
+ 0xB7, SSC, SSC, 0xBA, SSC, 0xB9, SSC, SSC, /*48->4F */
+ 0xB8, SSC, SSC, SSC, SSC, SSC, ALT, SSC, /*50->57 */
+};
+
+static uint8_t state_code[] = {
+ 0, /* All status are 0 */
+ 1, /* SHIFT */
+ 0, /* CTRL */
+ 1, /* SHIFT CTRL */
+ 0, /* ALT */
+ 1, /* SHIFT ALT */
+ 3, /* CTRL ALT */
+ 1, /* SHIFT CTRL ALT */
+ 2, /* CAPS */
+ 0, /* CAPS SHIFT */
+ 2, /* CAPS CTRL */
+ 0, /* CAPS SHIFT CTRL */
+ 2, /* CAPS ALT */
+ 0, /* CAPS SHIFT ALT */
+ 2, /* CAPS CTRL ALT */
+ 3, /* CAPS SHIFT CTRL ALT */
+};
+
+static uint8_t *scan_tabs[] = {
+ xtkb_scan,
+ xtkb_scan_shifted,
+ xtkb_scan_caps,
+ xtkb_scan_ctrl_alt,
+};
+
+uint8_t keymap[16]; /* 128 codes, we don't try and deal with
+ extended keys in this for now */
+
+/*
+ * XT style keyboard I/O is almost civilised compared
+ * with the monstrosity AT keyboards became.
+ */
+
+void xt_keyboard_irq(int irq)
+{
+ static uint8_t e0_prefix;
+ static unsigned int kbd_state = 0;
+ uint8_t E0;
+ uint8_t key_up;
+ uint8_t code;
+ uint8_t mode;
+ uint8_t E0 = 0;
+ uint8_t keyp;
+
+ code = inb_p((void *) KBD_IO);
+ mode = inb_p((void *) KBD_CTL);
+
+ /* Necessary for the XT. */
+ outb_p((uint8_t) (mode | 0x80), (void *) KBD_CTL);
+ outb_p((uint8_t) mode, (void *) KBD_CTL);
+
+ /* Need to put back a raw scancode mode eventually */
+
+ /* Remember this has been received */
+ if (code == 0xE0) {
+ e0_prefix = 1;
+ return;
+ }
+ e0 = e0_prefix;
+ e0_prefix = 0;
+
+ /* On an error we cross our fingers */
+ if (code == 0 || code == 0xFF)
+ return;
+
+ key_up = code & 0x80;
+ code &= 0x7F;
+
+ /* Track all the key up and down bits for the FUZIX raw keymap
+ interface. Probably nobody on x86 will use it but it's cheap */
+ if (key_up == 0)
+ key_map[code >> 3] |= 1 << (code & 7);
+ else
+ key_map[code >> 3] &= ~(1 << (code & 7));
+
+ /* Work out what table to use */
+ /* FIXME: check for over the end of the table ?? */
+ mode = (code >= 0x1C) ? tb_state[code - 0x1C] : SSC;
+
+ /* Process status keys */
+ if (!(mode & 0xC0)) {
+#if defined(CONFIG_KEYMAP_DE) || defined(CONFIG_KEYMAP_SE)
+ if ((mode == ALT) && (E0 != 0))
+ mode = ALT_GR;
+#endif
+ if (key_up)
+ kbd_state ~= ~mode;
+ else
+ kbd_state |= mode;
+ return;
+ }
+ if (key_up)
+ return;
+
+ switch (mode & 0xC0) {
+ case 0x40: /* F1 .. F10 */
+ /* Handle Function keys */
+ code -= 0x38;
+ if (kbd_mode & ALT) {
+ console_switch(code);
+ return;
+ }
+ console_queue(KEY_F1 + code);
+ return;
+
+ /* Handle extended scancodes */
+ case 0x80:
+ /* We have no idea how to map these so we don't */
+ if (E0) { /* Is extended scancode? */
+ mode &= 0x3F;
+ if (mode)
+ console_queue(ESC);
+ console_queue(mode + 0x0A);
+ return;
+ }
+ }
+
+ /* Handle CTRL-ALT-DEL */
+/* if (code == 0x53 && (kbd_mode & CTRL) && (kbd_mode & ALT))
+ ctrl_alt_del(); */
+
+ /*
+ * Pick the right keymap
+ */
+
+ mode = ((kbd_mode & ~(NUM | ALT_GR)) >> 1) | (kbd_mode & 0x01);
+ mode = state_code[mode];
+
+ if (!mode && (kbd_mode & ALT_GR))
+ mode = 3;
+ keyp = *(scan_tabs[mode] + code);
+
+ if ((kbd_mode & CTRL) && code < 14 && !(kbd_mode & ALT))
+ keyp = xtkb_scan_shifted[code];
+ if (code < 70 && (kbd_mode & NUM))
+ keyp = xtkb_scan_shifted[code];
+ /*
+ * Apply special modifiers. Needs looking at more
+ */
+ if ((kbd_mode & ALT && !(kbd_mode & CTRL)) /* Changed to support CTRL-ALT */
+ keyp |= 0x80; /* META-.. */
+ if (!keyp) /* non meta-@ is 64 */
+ keyp = '@';
+ if (kbd_mode & CTRL && !(kbd_mode & ALT)) /* Changed to support CTRL-ALT */
+ keyp &= 0x1F; /* CTRL-.. */
+ if (keyp == '\r')
+ keyp = '\n';
+ console_queue(keyp);
+}
+
+void xt_keyboard_init(void)
+{
+ request_irq(1, xt_keyboard_irq);
+}
+
+#endif