nc100: first draft graphics and audio support
authorAlan Cox <alan@linux.intel.com>
Tue, 31 Mar 2015 21:54:38 +0000 (22:54 +0100)
committerAlan Cox <alan@linux.intel.com>
Tue, 31 Mar 2015 21:54:38 +0000 (22:54 +0100)
Kernel/platform-nc100/Makefile
Kernel/platform-nc100/config.h
Kernel/platform-nc100/devaudio.c [new file with mode: 0644]
Kernel/platform-nc100/devgfx.c [new file with mode: 0644]
Kernel/platform-nc100/devgfx.h [new file with mode: 0644]
Kernel/platform-nc100/devices.c
Kernel/platform-nc100/fuzix.lnk
Kernel/platform-nc100/nc100.def
Kernel/platform-nc100/nc100.s

index 148d521..1b25006 100644 (file)
@@ -1,5 +1,5 @@
 
-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
index fa0b23a..9fe41a6 100644 (file)
@@ -22,6 +22,8 @@
 #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
diff --git a/Kernel/platform-nc100/devaudio.c b/Kernel/platform-nc100/devaudio.c
new file mode 100644 (file)
index 0000000..05bfc9f
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *     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;
+}
diff --git a/Kernel/platform-nc100/devgfx.c b/Kernel/platform-nc100/devgfx.c
new file mode 100644 (file)
index 0000000..41bd351
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *     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;
+  }
+}
diff --git a/Kernel/platform-nc100/devgfx.h b/Kernel/platform-nc100/devgfx.h
new file mode 100644 (file)
index 0000000..f495778
--- /dev/null
@@ -0,0 +1,13 @@
+#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
index bad73e1..6fb58e2 100644 (file)
@@ -7,6 +7,7 @@
 #include <tty.h>
 #include <vt.h>
 #include <devtty.h>
+#include <devgfx.h>
 
 struct devsw dev_tab[] =  /* The device driver switch table */
 {
@@ -15,7 +16,7 @@ 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) */
index b141730..1c92985 100644 (file)
@@ -31,9 +31,12 @@ bank16k.rel
 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
index 5d27681..297710f 100644 (file)
@@ -1,3 +1,4 @@
 VIDEO_BASEH    .equ    0x70
+VIDEO_END      .equ    0x80
 VIDEO_BASE     .equ    0x7000
 VIDEO_SIZE     .equ    0x1000
index 267057e..fec413e 100644 (file)
            .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
@@ -590,3 +583,159 @@ _cursor_off:
            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