-CSRCS = devlpr.c devtty.c devrd.c
+CSRCS = devlpr.c devtty.c devrd.c devaudio.c devgfx.c
CSRCS += devices.c main.c
ASRCS = nc100.s crt0.s
#define MAX_MAPS 16
/* We want the 4x6 font */
#define CONFIG_FONT_4X6
+/* We have audio (just about) */
+#define CONFIG_AUDIO
/* As reported to user space - 4 banks, 16K page size */
#define CONFIG_BANKS 4
#define CMDLINE NULL /* Location of root dev name */
/* Device parameters */
-#define NUM_DEV_TTY 3
+#define NUM_DEV_TTY 2
#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */
#define NBUFS 10 /* Number of block buffers */
#ifdef CONFIG_NC200
#define NMOUNTS 2 /* Floppy can also be mounted */
#else
#define NMOUNTS 1 /* Number of mounts at a time - nothing mountable! */
+#define BOOTDEVICE 0x0100 /* Only one possible option */
#endif
--- /dev/null
+/*
+ * Audio support for the NC100. Pretty minimal
+ */
+
+#include <kernel.h>
+#include <audio.h>
+
+/* Simple two channel beeper style ton generator with no volume control */
+const struct audio audio_info = {
+ AUDIO_BEEPER,
+ 2,
+ 0
+};
+
+static uint8_t audio_count[2];
+
+static inline uint16_t devaudio_map(uint16_t hz)
+{
+ /* The given equation is freq = 1000000/(rate * 2 * 1.6276) */
+ /* ie rate = 307201/freq */
+ return 307201UL/hz;
+}
+
+/* The sound core will call this when it wants to stop a sound */
+void devaudio_stop(uint8_t channel)
+{
+ out(0x51 + 2 * channel, 0xFF);
+ audio_count[channel] = 0;
+ wakeup(&audio_count[channel]);
+}
+
+/* The NC100 has two tone generators, no volume control, nothing fancy
+ at all */
+int devaudio_play(void)
+{
+ uint16_t rate;
+ audio_count[sound.channel] = sound.time;
+ rate = devaudio_map(sound.freq);
+ if (sound.volume > 32) { /* Arbitrary low = off */
+ out(0x50 + 2 * sound.channel, rate & 0xFF);
+ out(0x51 + 2 * sound.channel, rate >> 8);
+ }
+ return 0;
+}
+
+int devaudio_ioctl(uarg_t op, void *val)
+{
+ used(op);
+ used(val);
+ return -EINVAL;
+}
+
+void devaudio_tick(void)
+{
+ if (audio_count[0]) {
+ if (!--audio_count[0]) {
+ out(0x51, 0xFF);
+ wakeup(&audio_count[0]);
+ }
+ }
+ if (audio_count[1]) {
+ if (!--audio_count[1]) {
+ out(0x53, 0xFF);
+ wakeup(&audio_count[1]);
+ }
+ }
+}
+
+/* FIXME? - worth making a pwait_irq or similar 'wait for an IRQ to clear
+ a flag' function ? */
+int devaudio_wait(uint8_t channel)
+{
+ uint8_t *p = &audio_count[channel];
+ irqflags_t irq = di();
+
+ while(*p) {
+ if (psleep_flags(p,0) == -1) {
+ irqrestore(irq);
+ return -1;
+ }
+ }
+ irqrestore(irq);
+ return 0;
+}
--- /dev/null
+/*
+ * Graphics logic for the NC100/200
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <vt.h>
+#include <graphics.h>
+#include <devgfx.h>
+
+#ifdef CONFIG_NC100
+static struct display ncdisplay = {
+ 480, 64,
+ 512, 64,
+ 0xFF, 0xFF, /* For now */
+ FMT_MONO_WB,
+ HW_UNACCEL,
+ 0,
+ 0,
+ GFX_SETPIXEL|GFX_RAW|GFX_RAWCOPY,
+ 0
+};
+#else
+static struct display ncdisplay = {
+ 480, 128,
+ 512, 128,
+ 0xFF, 0xFF, /* For now */
+ FMT_MONO_WB,
+ HW_UNACCEL,
+ 0,
+ 0,
+ GFX_SETPIXEL|GFX_RAW|GFX_RAWCOPY,
+ 0
+};
+#endif
+
+extern uint16_t video_op[GFX_BUFLEN];
+
+extern struct attribute video_attr; /* Shared with asm code */
+
+int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr)
+{
+ if (arg >> 8 != 0x03)
+ return vt_ioctl(minor, arg, ptr);
+ if (arg == GFXIOC_GETINFO)
+ return uput(&ncdisplay, ptr, sizeof(ncdisplay));
+ if (arg == GFXIOC_SETATTR)
+ return uget(&video_attr, ptr, sizeof(video_attr));
+ if (uget(&video_op, ptr, sizeof(video_op)))
+ return -1;
+ switch(arg) {
+ case GFXIOC_SETPIXEL:
+ video_setpixel();
+ return 0;
+ case GFXIOC_CMD:
+ video_cmd();
+ return 0;
+ default:
+ udata.u_error = EINVAL;
+ return -1;
+ }
+}
--- /dev/null
+#ifndef _DEV_GFX_H
+#define _DEV_GFX_H
+
+#include <graphics.h>
+
+extern int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr);
+extern struct attribute video_attr;
+extern uint16_t video_op[GFX_BUFLEN];
+
+extern void video_setpixel(void);
+extern void video_cmd(void);
+
+#endif
#include <tty.h>
#include <vt.h>
#include <devtty.h>
+#include <devgfx.h>
struct devsw dev_tab[] = /* The device driver switch table */
{
/* 1: /dev/hd Hard disc block devices (Really PCMCIA) */
{ rd_open, no_close, rd_read, rd_write, no_ioctl },
/* 2: /dev/tty TTY devices */
- { nc100_tty_open, nc100_tty_close, tty_read, tty_write, vt_ioctl },
+ { nc100_tty_open, nc100_tty_close, tty_read, tty_write, gfx_ioctl },
/* 3: /dev/lpr Printer devices */
{ lpr_open, lpr_close, no_rdwr, lpr_write, no_ioctl },
/* 4: /dev/mem etc System devices (one offs) */
tty.rel
vt.rel
devsys.rel
+audio.rel
usermem.rel
usermem_std-z80.rel
platform-nc100/devlpr.rel
platform-nc100/devtty.rel
+platform-nc100/devaudio.rel
+platform-nc100/devgfx.rel
font4x6.rel
-e
VIDEO_BASEH .equ 0x70
+VIDEO_END .equ 0x80
VIDEO_BASE .equ 0x7000
VIDEO_SIZE .equ 0x1000
.globl _font4x6
.globl _vtinit
.globl platform_interrupt_all
+ .globl _video_setpixel
+ .globl _video_cmd
+ .globl _video_attr
+ .globl _video_op
; exported debugging tools
.globl _trap_monitor
; -----------------------------------------------------------------------------
.area _COMMONMEM
-trapmsg: .ascii "Trapdoor: SP="
- .db 0
-trapmsg2: .ascii ", PC="
- .db 0
-tm_user_sp: .dw 0
-
-tm_stack:
- .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-tm_stack_top:
-
_trap_monitor:
di
halt
jr _trap_monitor
-
_trap_reboot:
xor a
out (0x70), a
ld de, (_cursorpos)
jr cursor_do
+;
+; Entered with HL pointing to the co-ordinates
+; Returns with HL pointing to the byte address of the pixel
+; A holding the pixel mask
+; C holding the bit number
+; DE holding the screen byte address
+;
+coords:
+ ld a, (hl) ; low bits of X
+ and #7 ; pixel
+ ld c, a
+ ld a, (hl)
+ ld de, #0 ; clear D - and keep D at zero
+ rra
+ rra
+ rra ; A is the byte offset
+ inc hl
+ bit 0, (hl)
+ jr z, xonleft
+ set 5,a ; right hand side
+xonleft:
+ inc hl
+ ld a, (hl) ; y low (no y high needed) 0-63 or 0-127 */
+ add a ; x 2
+ ld l, a
+ ld h, d ; zero
+ add hl, hl ; x 4
+ add hl, hl ; x 8
+ add hl, hl ; x 16
+ add hl, hl ; x 32
+ add hl, hl ; x 64 lines into bytes offset
+ add hl, de ; pixel in this byte
+ ex de, hl
+ ld hl, #setpixel_bittab
+ ld b, d ; zero
+ add hl, bc
+ ld a, (hl) ; our pixel mask
+ ex de, hl
+ ret
+
+setpixel_optab:
+ nop ;
+ or (hl) ; COPY
+ nop
+ or (hl) ; SET
+ cpl ; complement pixel mask
+ and (hl) ; CLEAR by anding with mask
+ nop
+ xor (hl) ; INVERT
+setpixel_bittab:
+ .db 128,64,32,16,8,4,2,1
+
+_video_setpixel:
+ in a, (0x11)
+ push af
+ ld a, #0x43 ; Map the display
+ out (0x11), a
+ call video_setpixel
+ pop af
+ out (0x11), a
+ ret
+
+video_setpixel:
+ ld a, (_video_attr + 2) ; mode
+ or a ; copy ?
+ jr nz, setpixel_notdraw
+ ld a, (_video_attr) ; ink
+ or a ; white ?
+ jr nz, setpixel_notdraw ; a = 1 = set so good
+ ld a, #2 ; clear
+setpixel_notdraw:
+ ld e, a
+ ld d, #0
+ ld hl, #setpixel_optab
+ add hl, de
+ ld a, (hl)
+ ld (setpixel_opcode), a ; Self modifying
+ inc hl
+ ld a, (hl)
+ ld (setpixel_opcode+1), a ; Self modifying
+ ld bc, (_video_op) ; B is the count
+ ld a, b
+ and #0x1f ; max 31 pixels per op
+ ret z
+ push bc
+ ld hl, #_video_op + 2 ; co-ordinate pairs
+setpixel_loop:
+ push hl
+ call coords
+setpixel_opcode:
+ nop ; nop or cpl
+ ld a, (hl) ; screen
+ ld (hl), a ; store back to display
+ pop hl
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ pop bc
+ djnz setpixel_loop
+ ret
+
+;
+; Need different logic for NC200 ?
+;
+_video_cmd:
+ in a, (0x11)
+ push af
+ ld a, #0x43 ; Map the display
+ out (0x11), a
+ call video_cmd
+ pop af
+ out (0x11), a
+ ret
+
+video_cmd:
+ ld hl, #_video_op
+ ld e, (hl) ; offset
+ inc hl
+ ld a, (hl)
+ cp #0x10
+ ret nc ; over end
+ ld d, a
+ inc hl
+ ld a, (hl) ; count
+ cp #124 ; 2 bytes offset, 2 bytes length, 124 data
+ ret nc
+ ld c, a
+ inc hl
+ ld a, (hl)
+ or a
+ ret nz ; too big
+ ld b, a
+ push hl
+ ld l, e
+ ld h, d
+ add hl, bc ; end offset
+ ld a, h
+ cp #0x10
+ jr c, cmd_over ; doesn't fit
+ ld hl, #VIDEO_BASE
+ add hl, de ; offset
+ ex de, hl
+ pop hl ; input buffer
+ ldir
+ ret
+cmd_over: pop hl
+ ret
+
+;
+; Needed here so they don't vanish when we map the screen
+;
+_video_op:
+ .ds 128
+_video_attr:
+ .ds 4