/*
* Graphics logic for the TRS80 graphics add on board
*
- * FIXME: GETPIXEL, direct raw I/O access, scrolling, rects and
- * aligned blit are probably the basic set we should go for
+ * FIXME: - turn the gfx on/off when we switch tty
+ * - tie gfx to one tty and report EBUSY for the other on enable
*/
#include <kernel.h>
#include <devgfx.h>
static const struct display trsdisplay = {
+ 0,
640, 240,
1024, 256,
1, 1, /* Need adding to ioctls */
HW_TRS80GFX,
GFX_ENABLE|GFX_MAPPABLE|GFX_OFFSCREEN, /* Can in theory do pans */
32,
- GFX_DRAW /* FIXME: do GFX_READ */
+ GFX_DRAW|GFX_READ|GFX_WRITE
};
/* Assumes a Tandy board */
__sfr __at 0x83 gfx_ctrl;
+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, 1024, 256))
+ return EINVAL */
+ video_cmd(buf);
+ break;
+ case GFXIOC_WRITE:
+ case GFXIOC_READ:
+ if (l < 8)
+ return EINVAL;
+ l -= 8;
+ if (p[0] > 128 || p[1] > 255 || p[2] > 128 || p[3] > 255 ||
+ p[0] + p[2] > 128 || p[1] + p[3] > 255 ||
+ (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;
+}
+
int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr)
{
uint8_t *tmp;
- uint16_t l;
+ int err;
if (arg >> 8 != 0x03)
return vt_ioctl(minor, arg, ptr);
case GFXIOC_MAP:
return uput(&trsmap, ptr, sizeof(trsmap));
case GFXIOC_DRAW:
+ case GFXIOC_READ:
+ case GFXIOC_WRITE:
tmp = (uint8_t *)tmpbuf();
- l = ugetw(ptr);
- if (l < 2 || l > 512)
- goto bad;
- if (uget(tmp, ptr + 2, l))
- goto bad2;
- /* TODO
- if (draw_validate(ptr, l, 1024, 256))
- goto bad; */
- video_cmd(tmp);
+ err = gfx_draw_op(arg, ptr, tmp);
brelse((bufptr) tmp);
- return 0;
+ if (err) {
+ udata.u_error = err;
+ err = -1;
+ }
+ return err;
default:
udata.u_error = EINVAL;
return -1;
}
-bad:
- udata.u_error = EINVAL;
-bad2:
- brelse((bufptr) tmp);
- return -1;
}
; video
.globl _video_cmd
+ .globl _video_read
+ .globl _video_write
; exported debugging tools
.globl _trap_monitor
push de
ld e,(hl) ; X byte, Y line
inc hl ; The hardware does the conversion
+ inc hl
ld d,(hl) ; for us
+ inc hl ; skip high bytes
+ inc hl
ld a, #0x43 ; auto incremeent X on write only
out (0x83), a ; set the register up
nextline:
inc hl
jr nextop
endline: pop de
- inc d ; down a scan line (easy peasy)
+ inc d ; down a scan line (easy peasy)
inc hl
xor a
cp (hl) ; 0 0 = end (for blank lines just do 01 ff 00)
jr nz, nextline
ret
+
+_video_write:
+ ld a, #0xB3
+ ld (patch_io + 1), a ; OTIR
+ ld a, #0x43
+video_do:
+ out (0x83), a ; autoincrement on write
+ pop de
+ pop iy
+ push iy
+ push de
+ push iy
+ pop hl
+ ld de, #8
+ add hl, de ; Data start into HL
+ ld e, (iy) ; x
+ ld d, 2(iy) ; y
+next_rw:
+ ld c, #0x80
+ out (c), e ; x
+ inc c
+ out (c), d ; y
+ inc c ; to data
+ ld b, 4(iy) ; count of bytes per line
+patch_io:
+ otir ; wheee...
+ inc d ; next line
+ dec 6(iy) ; height
+ jr nz, next_rw
+ ret
+
+_video_read:
+ ld a, #0xB2 ; inir
+ ld (patch_io + 1), a
+ ld a, #0x13 ; autoincrement on read
+ jr video_do