mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-02 23:18:44 +00:00
Bare metal VGA: implement "status report" escape codes (#613)
* Bare metal VGA: implement "status report" escape codes * Minor fix to pseudoteletypewriter code Co-authored-by: tkchia <tkchia-cosmo@gmx.com>
This commit is contained in:
parent
e0fabd1d49
commit
df08b541af
8 changed files with 113 additions and 10 deletions
|
@ -8,13 +8,30 @@
|
|||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/math.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/isystem/unistd.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
STATIC_YOINK("vga_console");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
volatile long double x = -.5;
|
||||
volatile long double y = 1.5;
|
||||
struct termios tio;
|
||||
char buf[4];
|
||||
ssize_t res;
|
||||
if (tcgetattr(0, &tio) != -1) {
|
||||
tio.c_lflag &= ~(ECHO | ICANON);
|
||||
tcsetattr(0, TCSANOW, &tio);
|
||||
}
|
||||
write(1, "\e[5n", 4);
|
||||
res = read(0, buf, 4);
|
||||
if (res != 4 || memcmp(buf, "\e[0n", 4) != 0) {
|
||||
printf("res = %d?\n", res);
|
||||
return -1;
|
||||
}
|
||||
printf("Hello World! %.19Lg\n", atan2l(x, y));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -20,15 +20,29 @@
|
|||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/vga/vga.internal.h"
|
||||
|
||||
ssize_t sys_readv_metal(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||
int i;
|
||||
size_t got, toto;
|
||||
struct MetalFile *file;
|
||||
switch (fd->kind) {
|
||||
case kFdConsole:
|
||||
/*
|
||||
* The VGA teletypewriter code may wish to send out "status report"
|
||||
* escape sequences, in response to requests sent to it via write().
|
||||
* Read & return these if they are available.
|
||||
*/
|
||||
if (weaken(sys_readv_vga)) {
|
||||
ssize_t res = weaken(sys_readv_vga)(fd, iov, iovlen);
|
||||
if (res > 0)
|
||||
return res;
|
||||
}
|
||||
/* fall through */
|
||||
case kFdSerial:
|
||||
return sys_readv_serial(fd, iov, iovlen);
|
||||
case kFdFile:
|
||||
|
|
49
libc/vga/readv-vga.c
Normal file
49
libc/vga/readv-vga.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ This is free and unencumbered software released into the public domain. │
|
||||
│ │
|
||||
│ Anyone is free to copy, modify, publish, use, compile, sell, or │
|
||||
│ distribute this software, either in source code form or as a compiled │
|
||||
│ binary, for any purpose, commercial or non-commercial, and by any │
|
||||
│ means. │
|
||||
│ │
|
||||
│ In jurisdictions that recognize copyright laws, the author or authors │
|
||||
│ of this software dedicate any and all copyright interest in the │
|
||||
│ software to the public domain. We make this dedication for the benefit │
|
||||
│ of the public at large and to the detriment of our heirs and │
|
||||
│ successors. We intend this dedication to be an overt act of │
|
||||
│ relinquishment in perpetuity of all present and future rights to this │
|
||||
│ software under copyright law. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||
│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │
|
||||
│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
||||
│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │
|
||||
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/vga/vga.internal.h"
|
||||
|
||||
ssize_t sys_readv_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||
/* NOTE: this routine is always non-blocking. */
|
||||
size_t i, redd = 0;
|
||||
ssize_t res = 0;
|
||||
for (i = 0; i < iovlen; ++i) {
|
||||
void *input = iov[i].iov_base;
|
||||
size_t len = iov[i].iov_len;
|
||||
res = _TtyRead(&_vga_tty, input, len);
|
||||
if (res < 0)
|
||||
break;
|
||||
redd += res;
|
||||
if (redd != len)
|
||||
return redd;
|
||||
}
|
||||
if (!redd)
|
||||
return res;
|
||||
return redd;
|
||||
}
|
|
@ -536,15 +536,18 @@ static void TtyDeleteLines(struct Tty *tty) {
|
|||
}
|
||||
|
||||
static void TtyReportDeviceStatus(struct Tty *tty) {
|
||||
_TtyWriteInput(tty, "\e[0n", 4);
|
||||
static const char report[] = "\e[0n";
|
||||
_TtyWriteInput(tty, report, strlen(report));
|
||||
}
|
||||
|
||||
static void TtyReportPreferredVtType(struct Tty *tty) {
|
||||
_TtyWriteInput(tty, "\e[?1;0c", 4);
|
||||
static const char report[] = "\e[?1;0c";
|
||||
_TtyWriteInput(tty, report, strlen(report));
|
||||
}
|
||||
|
||||
static void TtyReportPreferredVtIdentity(struct Tty *tty) {
|
||||
_TtyWriteInput(tty, "\e/Z", 4);
|
||||
static const char report[] = "\e/Z";
|
||||
_TtyWriteInput(tty, report, strlen(report));
|
||||
}
|
||||
|
||||
static void TtyBell(struct Tty *tty) {
|
||||
|
@ -1148,9 +1151,11 @@ ssize_t _TtyWriteInput(struct Tty *tty, const void *data, size_t n) {
|
|||
if (cr && i < sizeof tty->input.p) {
|
||||
p[i++] = '\n';
|
||||
}
|
||||
#ifdef VGA_PERSNICKETY_STATUS
|
||||
if (!(tty->conf & kTtyNoecho)) {
|
||||
_TtyWrite(tty, p + tty->input.i, i - tty->input.i);
|
||||
}
|
||||
#endif
|
||||
tty->input.i = i;
|
||||
return n;
|
||||
}
|
||||
|
@ -1159,6 +1164,7 @@ ssize_t _TtyRead(struct Tty *tty, void *buf, size_t size) {
|
|||
char *p;
|
||||
size_t n;
|
||||
n = MIN(size, tty->input.i);
|
||||
#ifdef VGA_PERSNICKETY_STATUS
|
||||
if (!(tty->conf & kTtyNocanon)) {
|
||||
if ((p = memchr(tty->input.p, '\n', n))) {
|
||||
n = MIN(n, tty->input.p - p + 1);
|
||||
|
@ -1166,6 +1172,7 @@ ssize_t _TtyRead(struct Tty *tty, void *buf, size_t size) {
|
|||
n = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
memcpy(buf, tty->input.p, n);
|
||||
memcpy(tty->input.p, tty->input.p + n, tty->input.i - n);
|
||||
tty->input.i -= n;
|
||||
|
|
|
@ -72,3 +72,4 @@ vga_console:
|
|||
.endobj vga_console,globl,hidden
|
||||
.previous
|
||||
.yoink sys_writev_vga
|
||||
.yoink sys_readv_vga
|
||||
|
|
|
@ -60,6 +60,14 @@
|
|||
* (https://www.delorie.com/djgpp/doc/rbinter/id/22/1.html)
|
||||
*/
|
||||
#undef VGA_USE_BLINK
|
||||
/**
|
||||
* If VGA_PERSNICKETY_STATUS is defined, then when deciding how to return
|
||||
* status response codes (e.g. "\e[0n"), the tty code will pay attention to
|
||||
* the terminal's termios mode (TODO). If undefined, the tty code will
|
||||
* simply return any response strings immediately, & will not echo them —
|
||||
* per the common use case.
|
||||
*/
|
||||
#undef VGA_PERSNICKETY_STATUS
|
||||
|
||||
#define kTtyFg 0x0001
|
||||
#define kTtyBg 0x0002
|
||||
|
@ -146,6 +154,9 @@ void _TtyErase(struct Tty *, size_t, size_t);
|
|||
void _TtySetY(struct Tty *, unsigned short);
|
||||
void _TtySetX(struct Tty *, unsigned short);
|
||||
|
||||
extern struct Tty _vga_tty;
|
||||
|
||||
ssize_t sys_readv_vga(struct Fd *, const struct iovec *, int);
|
||||
ssize_t sys_writev_vga(struct Fd *, const struct iovec *, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -31,20 +31,21 @@
|
|||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static struct Tty vga_tty;
|
||||
#ifdef VGA_USE_WCS
|
||||
static wchar_t vga_wcs[VGA_TTY_HEIGHT * VGA_TTY_WIDTH];
|
||||
#else
|
||||
static wchar_t * const vga_wcs = NULL;
|
||||
#endif
|
||||
|
||||
struct Tty _vga_tty;
|
||||
|
||||
ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||
size_t i, wrote = 0;
|
||||
ssize_t res = 0;
|
||||
for (i = 0; i < iovlen; ++i) {
|
||||
void *input = iov[i].iov_base;
|
||||
void *output = iov[i].iov_base;
|
||||
size_t len = iov[i].iov_len;
|
||||
res = _TtyWrite(&vga_tty, input, len);
|
||||
res = _TtyWrite(&_vga_tty, output, len);
|
||||
if (res < 0)
|
||||
break;
|
||||
wrote += res;
|
||||
|
@ -75,6 +76,6 @@ __attribute__((__constructor__)) static textstartup void _vga_init(void) {
|
|||
* Initialize our tty structure from the current screen contents, current
|
||||
* cursor position, & character height.
|
||||
*/
|
||||
_StartTty(&vga_tty, VGA_TTY_HEIGHT, VGA_TTY_WIDTH, pos.row, pos.col,
|
||||
_StartTty(&_vga_tty, VGA_TTY_HEIGHT, VGA_TTY_WIDTH, pos.row, pos.col,
|
||||
chr_ht, vid_buf, vga_wcs);
|
||||
}
|
||||
|
|
|
@ -641,15 +641,18 @@ static void PtyDeleteLines(struct Pty *pty) {
|
|||
}
|
||||
|
||||
static void PtyReportDeviceStatus(struct Pty *pty) {
|
||||
PtyWriteInput(pty, "\e[0n", 4);
|
||||
static const char report[] = "\e[0n";
|
||||
PtyWriteInput(pty, report, strlen(report));
|
||||
}
|
||||
|
||||
static void PtyReportPreferredVtType(struct Pty *pty) {
|
||||
PtyWriteInput(pty, "\e[?1;0c", 4);
|
||||
static const char report[] = "\e[?1;0c";
|
||||
PtyWriteInput(pty, report, strlen(report));
|
||||
}
|
||||
|
||||
static void PtyReportPreferredVtIdentity(struct Pty *pty) {
|
||||
PtyWriteInput(pty, "\e/Z", 4);
|
||||
static const char report[] = "\e/Z";
|
||||
PtyWriteInput(pty, report, strlen(report));
|
||||
}
|
||||
|
||||
static void PtyBell(struct Pty *pty) {
|
||||
|
|
Loading…
Add table
Reference in a new issue