mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-06 04:32:28 +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
|
#endif
|
||||||
#include "libc/math.h"
|
#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/stdio/stdio.h"
|
||||||
|
#include "libc/sysv/consts/termios.h"
|
||||||
|
|
||||||
STATIC_YOINK("vga_console");
|
STATIC_YOINK("vga_console");
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
volatile long double x = -.5;
|
volatile long double x = -.5;
|
||||||
volatile long double y = 1.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));
|
printf("Hello World! %.19Lg\n", atan2l(x, y));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,15 +20,29 @@
|
||||||
#include "libc/calls/struct/fd.internal.h"
|
#include "libc/calls/struct/fd.internal.h"
|
||||||
#include "libc/calls/struct/iovec.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
#include "libc/calls/struct/iovec.internal.h"
|
#include "libc/calls/struct/iovec.internal.h"
|
||||||
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/errfuns.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) {
|
ssize_t sys_readv_metal(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||||
int i;
|
int i;
|
||||||
size_t got, toto;
|
size_t got, toto;
|
||||||
struct MetalFile *file;
|
struct MetalFile *file;
|
||||||
switch (fd->kind) {
|
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:
|
case kFdSerial:
|
||||||
return sys_readv_serial(fd, iov, iovlen);
|
return sys_readv_serial(fd, iov, iovlen);
|
||||||
case kFdFile:
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
if (cr && i < sizeof tty->input.p) {
|
||||||
p[i++] = '\n';
|
p[i++] = '\n';
|
||||||
}
|
}
|
||||||
|
#ifdef VGA_PERSNICKETY_STATUS
|
||||||
if (!(tty->conf & kTtyNoecho)) {
|
if (!(tty->conf & kTtyNoecho)) {
|
||||||
_TtyWrite(tty, p + tty->input.i, i - tty->input.i);
|
_TtyWrite(tty, p + tty->input.i, i - tty->input.i);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
tty->input.i = i;
|
tty->input.i = i;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -1159,6 +1164,7 @@ ssize_t _TtyRead(struct Tty *tty, void *buf, size_t size) {
|
||||||
char *p;
|
char *p;
|
||||||
size_t n;
|
size_t n;
|
||||||
n = MIN(size, tty->input.i);
|
n = MIN(size, tty->input.i);
|
||||||
|
#ifdef VGA_PERSNICKETY_STATUS
|
||||||
if (!(tty->conf & kTtyNocanon)) {
|
if (!(tty->conf & kTtyNocanon)) {
|
||||||
if ((p = memchr(tty->input.p, '\n', n))) {
|
if ((p = memchr(tty->input.p, '\n', n))) {
|
||||||
n = MIN(n, tty->input.p - p + 1);
|
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;
|
n = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
memcpy(buf, tty->input.p, n);
|
memcpy(buf, tty->input.p, n);
|
||||||
memcpy(tty->input.p, tty->input.p + n, tty->input.i - n);
|
memcpy(tty->input.p, tty->input.p + n, tty->input.i - n);
|
||||||
tty->input.i -= n;
|
tty->input.i -= n;
|
||||||
|
|
|
@ -72,3 +72,4 @@ vga_console:
|
||||||
.endobj vga_console,globl,hidden
|
.endobj vga_console,globl,hidden
|
||||||
.previous
|
.previous
|
||||||
.yoink sys_writev_vga
|
.yoink sys_writev_vga
|
||||||
|
.yoink sys_readv_vga
|
||||||
|
|
|
@ -60,6 +60,14 @@
|
||||||
* (https://www.delorie.com/djgpp/doc/rbinter/id/22/1.html)
|
* (https://www.delorie.com/djgpp/doc/rbinter/id/22/1.html)
|
||||||
*/
|
*/
|
||||||
#undef VGA_USE_BLINK
|
#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 kTtyFg 0x0001
|
||||||
#define kTtyBg 0x0002
|
#define kTtyBg 0x0002
|
||||||
|
@ -146,6 +154,9 @@ void _TtyErase(struct Tty *, size_t, size_t);
|
||||||
void _TtySetY(struct Tty *, unsigned short);
|
void _TtySetY(struct Tty *, unsigned short);
|
||||||
void _TtySetX(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);
|
ssize_t sys_writev_vga(struct Fd *, const struct iovec *, int);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -31,20 +31,21 @@
|
||||||
#include "libc/runtime/pc.internal.h"
|
#include "libc/runtime/pc.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
static struct Tty vga_tty;
|
|
||||||
#ifdef VGA_USE_WCS
|
#ifdef VGA_USE_WCS
|
||||||
static wchar_t vga_wcs[VGA_TTY_HEIGHT * VGA_TTY_WIDTH];
|
static wchar_t vga_wcs[VGA_TTY_HEIGHT * VGA_TTY_WIDTH];
|
||||||
#else
|
#else
|
||||||
static wchar_t * const vga_wcs = NULL;
|
static wchar_t * const vga_wcs = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct Tty _vga_tty;
|
||||||
|
|
||||||
ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||||
size_t i, wrote = 0;
|
size_t i, wrote = 0;
|
||||||
ssize_t res = 0;
|
ssize_t res = 0;
|
||||||
for (i = 0; i < iovlen; ++i) {
|
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;
|
size_t len = iov[i].iov_len;
|
||||||
res = _TtyWrite(&vga_tty, input, len);
|
res = _TtyWrite(&_vga_tty, output, len);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
break;
|
break;
|
||||||
wrote += res;
|
wrote += res;
|
||||||
|
@ -75,6 +76,6 @@ __attribute__((__constructor__)) static textstartup void _vga_init(void) {
|
||||||
* Initialize our tty structure from the current screen contents, current
|
* Initialize our tty structure from the current screen contents, current
|
||||||
* cursor position, & character height.
|
* 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);
|
chr_ht, vid_buf, vga_wcs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -641,15 +641,18 @@ static void PtyDeleteLines(struct Pty *pty) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PtyReportDeviceStatus(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) {
|
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) {
|
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) {
|
static void PtyBell(struct Pty *pty) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue