From 7905dd209976516b4a348cd30a975e989b8a6ed4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 4 Oct 2015 22:16:02 +0100 Subject: [PATCH] dragon-nx32: first cut at adding draw/read/write methods Strictly speaking we don't need them, but this probably won't be true on all the 6809 variants (eg COCO3) so we should support them to make portable code easier. It's not as if they are very much code space. --- Kernel/platform-dragon-nx32/devtty.c | 68 ++++++++++++++++++++-- Kernel/platform-dragon-nx32/devtty.h | 4 ++ Kernel/platform-dragon-nx32/video.s | 86 +++++++++++++++++++++++++++- 3 files changed, 153 insertions(+), 5 deletions(-) diff --git a/Kernel/platform-dragon-nx32/devtty.c b/Kernel/platform-dragon-nx32/devtty.c index ebbba438..b5643193 100644 --- a/Kernel/platform-dragon-nx32/devtty.c +++ b/Kernel/platform-dragon-nx32/devtty.c @@ -311,6 +311,45 @@ static uint8_t piabits[] = { 0xF0, 0xF8, 0xE0, 0xE8}; #define pia1b ((volatile uint8_t *)0xFF22) #define sam_v ((volatile uint8_t *)0xFFC0) +static int gfx_draw_op(uarg_t arg, char *ptr, uint8_t *buf) +{ + int l; + int c = 8; /* 4 x uint16_t */ + uint16_t *p = (uint16_t *)buf; + l = ugetw(ptr); + if (l < 6 || l > 512) + return EINVAL; + if (arg != GFXIOC_READ) + c = l; + if (uget(buf, ptr + 2, c)) + return EFAULT; + switch(arg) { + case GFXIOC_DRAW: + /* TODO + if (draw_validate(ptr, l, 256, 192)) - or 128! + return EINVAL */ + video_cmd(buf); + break; + case GFXIOC_WRITE: + case GFXIOC_READ: + if (l < 8) + return EINVAL; + l -= 8; + if (p[0] > 31 || p[1] > 191 || p[2] > 31 || p[3] > 191 || + p[0] + p[2] > 32 || p[1] + p[3] > 192 || + (p[2] * p[3]) > l) + return -EFAULT; + if (arg == GFXIOC_READ) { + video_read(buf); + if (uput(buf + 8, ptr, l)) + return EFAULT; + return 0; + } + video_write(buf); + } + return 0; +} + /* * Start by just reporting the 256x192 mode which is memory mapped * (it's effectively always in our address space). Should really @@ -320,11 +359,16 @@ 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) + switch(arg) { + case GFXIOC_GETINFO: return uput(&display[vmode], ptr, sizeof(struct display)); - if (arg == GFXIOC_MAP) + case GFXIOC_MAP: return uput(&displaymap, ptr, sizeof(displaymap)); - if (arg == GFXIOC_GETMODE || arg == GFXIOC_SETMODE) { + case GFXIOC_UNMAP: + return 0; + case GFXIOC_GETMODE: + case GFXIOC_SETMODE: + { uint8_t m = ugetc(ptr); // uint8_t b; if (m > 3) { @@ -341,6 +385,22 @@ int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr) // sam_v[(b & 4)?5:4] = 0; return 0; } - udata.u_error = ENOTTY; + case GFXIOC_DRAW: + case GFXIOC_READ: + case GFXIOC_WRITE: + { + uint8_t *tmp; + int err; + + tmp = (uint8_t *)tmpbuf(); + err = gfx_draw_op(arg, ptr, tmp); + brelse((bufptr) tmp); + if (err) { + udata.u_error = err; + err = -1; + } + return err; + } + } return -1; } diff --git a/Kernel/platform-dragon-nx32/devtty.h b/Kernel/platform-dragon-nx32/devtty.h index 2d6f8735..89b1ac06 100644 --- a/Kernel/platform-dragon-nx32/devtty.h +++ b/Kernel/platform-dragon-nx32/devtty.h @@ -9,4 +9,8 @@ extern uint8_t shiftkeyboard[8][7]; extern int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr); +extern void video_cmd(uint8_t *ptr); +extern void video_read(uint8_t *ptr); +extern void video_write(uint8_t *ptr); + #endif diff --git a/Kernel/platform-dragon-nx32/video.s b/Kernel/platform-dragon-nx32/video.s index a4b8646c..da68bdd3 100644 --- a/Kernel/platform-dragon-nx32/video.s +++ b/Kernel/platform-dragon-nx32/video.s @@ -9,6 +9,11 @@ .globl _clear_lines .globl _cursor_on .globl _cursor_off + + .globl _video_read + .globl _video_write + .globl _video_cmd + ; ; Imports ; @@ -329,9 +334,88 @@ _cursor_off: com 224,x nocursor: rts +; +; These routines wortk in both 256x192x2 and 128x192x4 modes +; because everything in the X plane is bytewide. +; +_video_write: + pshs u + bsr vidptr + tfr x,y ; So we can use y to get at the w/h + leax 4,x ; Move on to data space +vwnext: + lda 2,y + pshs u +vwline: + ldb ,x+ + stb ,u+ + deca + bne vwline + puls u + leau 32,u + dec ,y + bne vwnext + puls u,pc +; +; Find the address we need on a pixel row basis +; +vidptr: + ldu #VIDEO_BASE + ldd ,x++ ; Y into B + lda #32 + mul + leau d,u + ldd ,x++ ; X + leau d,u + rts +; +; FIXME - fold read/write into one self modifier +; +_video_read: + pshs u + bsr vidptr + tfr x,y ; So we can use y to get at the w/h + leax 4,x ; Move on to data space +vrnext: + lda 2,y ; a counts our copy along the scan line + pshs u +vrline: + ldb ,u+ ; b does our data + stb ,x+ + deca + bne vrline + puls u ; step down a line + leau 32,u + dec ,y ; use the buffer directly for line count + bne vrnext + puls u,pc ; and done + +_video_cmd: + pshs u + bsr vidptr ; u now points to the screen +nextline: + pshs u ; save it for the next line +nextop: + ldb ,x+ ; op code, 0 = end of line + beq endline +oploop: + lda ,u ; do one screen byte + anda ,x + eora 1,x + sta ,u+ + decb + bne oploop ; keep going for run + leax 2,x + bra nextop ; next triplet +endline: + puls u ; get position back + leau 32,u ; down one scan line + ldb ,x+ ; get next op - 0,0 means end and done + bne oploop + puls u,pc .area .data cursor_save: .dw 0 _vtrow: - .db 0 \ No newline at end of file + .db 0 -- 2.34.1