mirror of
https://gitlab.com/qemu-project/openbios.git
synced 2024-02-13 08:34:06 +08:00
blueswirl's latest console-nographic.diff.bz2
git-svn-id: svn://coreboot.org/openbios/openbios-devel@71 f158a5a8-5612-0410-a976-696ce0be7e32
This commit is contained in:
@@ -51,7 +51,8 @@ static int check_mem_ranges(struct sys_info *info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aout_load(struct sys_info *info, const char *filename, const char *cmdline)
|
||||
int aout_load(struct sys_info *info, const char *filename, const char *cmdline,
|
||||
const void *romvec)
|
||||
{
|
||||
int retval = -1;
|
||||
int image_retval;
|
||||
@@ -126,14 +127,8 @@ int aout_load(struct sys_info *info, const char *filename, const char *cmdline)
|
||||
|
||||
#if 1
|
||||
{
|
||||
extern unsigned int qemu_mem_size;
|
||||
extern char boot_device;
|
||||
void *init_openprom(unsigned long memsize, const char *cmdline, char boot_device);
|
||||
|
||||
int (*entry)(const void *romvec, int p2, int p3, int p4, int p5);
|
||||
const void *romvec;
|
||||
|
||||
romvec = init_openprom(qemu_mem_size, cmdline, boot_device);
|
||||
entry = (void *) addr_fixup(start);
|
||||
image_retval = entry(romvec, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
#include "openbios/nvram.h"
|
||||
#include "libc/diskio.h"
|
||||
#include "sys_info.h"
|
||||
#include "openprom.h"
|
||||
|
||||
int elf_load(struct sys_info *, const char *filename, const char *cmdline);
|
||||
int aout_load(struct sys_info *, const char *filename, const char *cmdline);
|
||||
int linux_load(struct sys_info *, const char *filename, const char *cmdline);
|
||||
int elf_load(struct sys_info *, const char *filename, const char *cmdline, const void *romvec);
|
||||
int aout_load(struct sys_info *, const char *filename, const char *cmdline, const void *romvec);
|
||||
int linux_load(struct sys_info *, const char *filename, const char *cmdline, const void *romvec);
|
||||
|
||||
void boot(void);
|
||||
|
||||
@@ -21,43 +22,54 @@ uint32_t kernel_size;
|
||||
uint32_t cmdline;
|
||||
uint32_t cmdline_size;
|
||||
char boot_device;
|
||||
extern unsigned int qemu_mem_size;
|
||||
void *init_openprom(unsigned long memsize);
|
||||
extern struct linux_arguments_v0 obp_arg;
|
||||
|
||||
void boot(void)
|
||||
{
|
||||
char *path=pop_fstr_copy(), *param;
|
||||
char *path = pop_fstr_copy(), *param, *oldpath;
|
||||
char altpath[256];
|
||||
|
||||
if (kernel_size) {
|
||||
extern unsigned int qemu_mem_size;
|
||||
void *init_openprom(unsigned long memsize, const char *cmdline, char boot_device);
|
||||
|
||||
int (*entry)(const void *romvec, int p2, int p3, int p4, int p5);
|
||||
int unit;
|
||||
const void *romvec;
|
||||
|
||||
printk("[sparc] Kernel already loaded\n");
|
||||
romvec = init_openprom(qemu_mem_size, (void *)cmdline, boot_device);
|
||||
entry = (void *) kernel_image;
|
||||
entry(romvec, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
if(!path) {
|
||||
switch(boot_device) {
|
||||
case 'a':
|
||||
path = "/obio/SUNW,fdtwo";
|
||||
oldpath = "fd()";
|
||||
unit = 0;
|
||||
break;
|
||||
case 'c':
|
||||
path = "disk";
|
||||
oldpath = "sd(0,0,0):d";
|
||||
unit = 0;
|
||||
break;
|
||||
default:
|
||||
case 'd':
|
||||
path = "cdrom";
|
||||
// FIXME: hardcoding this looks almost definitely wrong.
|
||||
// With sd(0,2,0):b we get to see the solaris kernel though
|
||||
//oldpath = "sd(0,2,0):d";
|
||||
oldpath = "sd(0,2,0):b";
|
||||
unit = 2;
|
||||
break;
|
||||
case 'n':
|
||||
path = "net";
|
||||
oldpath = "le()";
|
||||
unit = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
obp_arg.boot_dev_ctrl = 0;
|
||||
obp_arg.boot_dev_unit = unit;
|
||||
obp_arg.dev_partition = 0;
|
||||
obp_arg.boot_dev[0] = oldpath[0];
|
||||
obp_arg.boot_dev[1] = oldpath[1];
|
||||
obp_arg.argv[0] = oldpath;
|
||||
obp_arg.argv[1] = cmdline;
|
||||
|
||||
param = strchr(path, ' ');
|
||||
if(param) {
|
||||
*param = '\0';
|
||||
@@ -66,22 +78,31 @@ void boot(void)
|
||||
param = (char *)cmdline;
|
||||
}
|
||||
|
||||
romvec = init_openprom(qemu_mem_size);
|
||||
|
||||
if (kernel_size) {
|
||||
int (*entry)(const void *romvec, int p2, int p3, int p4, int p5);
|
||||
|
||||
printk("[sparc] Kernel already loaded\n");
|
||||
entry = (void *) kernel_image;
|
||||
entry(romvec, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
printk("[sparc] Booting file '%s' ", path);
|
||||
if(param)
|
||||
printk("with parameters '%s'\n", param);
|
||||
else
|
||||
printk("without parameters.\n");
|
||||
|
||||
|
||||
if (elf_load(&sys_info, path, param) == LOADER_NOT_SUPPORT)
|
||||
if (linux_load(&sys_info, path, param) == LOADER_NOT_SUPPORT)
|
||||
if (aout_load(&sys_info, path, param) == LOADER_NOT_SUPPORT) {
|
||||
if (elf_load(&sys_info, path, param, romvec) == LOADER_NOT_SUPPORT)
|
||||
if (linux_load(&sys_info, path, param, romvec) == LOADER_NOT_SUPPORT)
|
||||
if (aout_load(&sys_info, path, param, romvec) == LOADER_NOT_SUPPORT) {
|
||||
|
||||
sprintf(altpath, "%s:d", path);
|
||||
|
||||
if (elf_load(&sys_info, altpath, param) == LOADER_NOT_SUPPORT)
|
||||
if (linux_load(&sys_info, altpath, param) == LOADER_NOT_SUPPORT)
|
||||
if (aout_load(&sys_info, altpath, param) == LOADER_NOT_SUPPORT)
|
||||
if (elf_load(&sys_info, altpath, param, romvec) == LOADER_NOT_SUPPORT)
|
||||
if (linux_load(&sys_info, altpath, param, romvec) == LOADER_NOT_SUPPORT)
|
||||
if (aout_load(&sys_info, altpath, param, romvec) == LOADER_NOT_SUPPORT)
|
||||
printk("Unsupported image format\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
*/
|
||||
|
||||
int forth_load(struct sys_info *info, const char *filename, const char *cmdline);
|
||||
int elf_load(struct sys_info *info, const char *filename, const char *cmdline);
|
||||
int linux_load(struct sys_info *info, const char *file, const char *cmdline);
|
||||
int elf_load(struct sys_info *, const char *filename, const char *cmdline,
|
||||
const void *romvec);
|
||||
int aout_load(struct sys_info *, const char *filename, const char *cmdline,
|
||||
const void *romvec);
|
||||
int linux_load(struct sys_info *, const char *filename, const char *cmdline,
|
||||
const void *romvec);
|
||||
|
||||
unsigned int start_elf(unsigned long entry_point, unsigned long param);
|
||||
|
||||
|
||||
@@ -192,13 +192,13 @@ static const unsigned char sunkbd_keycode_shifted[128] = {
|
||||
|
||||
static int shiftstate;
|
||||
|
||||
static int
|
||||
int
|
||||
keyboard_dataready(void)
|
||||
{
|
||||
return ((inb(KBD_BASE) & 1) == 1);
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
unsigned char
|
||||
keyboard_readdata(void)
|
||||
{
|
||||
unsigned char ch;
|
||||
|
||||
@@ -302,7 +302,8 @@ static Elf_Bhdr *build_boot_notes(struct sys_info *info, const char *cmdline)
|
||||
return bhdr;
|
||||
}
|
||||
|
||||
int elf_load(struct sys_info *info, const char *filename, const char *cmdline)
|
||||
int elf_load(struct sys_info *info, const char *filename, const char *cmdline,
|
||||
const void *romvec)
|
||||
{
|
||||
Elf_ehdr ehdr;
|
||||
Elf_phdr *phdr = NULL;
|
||||
@@ -383,14 +384,8 @@ int elf_load(struct sys_info *info, const char *filename, const char *cmdline)
|
||||
|
||||
#if 1
|
||||
{
|
||||
extern unsigned int qemu_mem_size;
|
||||
extern char boot_device;
|
||||
void *init_openprom(unsigned long memsize, const char *cmdline, char boot_device);
|
||||
|
||||
int (*entry)(const void *romvec, int p2, int p3, int p4, int p5);
|
||||
const void *romvec;
|
||||
|
||||
romvec = init_openprom(qemu_mem_size, cmdline, boot_device);
|
||||
entry = (void *) addr_fixup(ehdr.e_entry);
|
||||
image_retval = entry(romvec, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@@ -578,7 +578,8 @@ static int start_linux(uint32_t kern_addr, struct linux_params *params)
|
||||
return ctx->regs[REG_O0];
|
||||
}
|
||||
|
||||
int linux_load(struct sys_info *info, const char *file, const char *cmdline)
|
||||
int linux_load(struct sys_info *info, const char *file, const char *cmdline,
|
||||
const void *romvec)
|
||||
{
|
||||
struct linux_header hdr;
|
||||
struct linux_params *params;
|
||||
|
||||
@@ -33,8 +33,9 @@ static struct linux_mlist_v0 totavail[1];
|
||||
static struct linux_mlist_v0 *ptphys;
|
||||
static struct linux_mlist_v0 *ptmap;
|
||||
static struct linux_mlist_v0 *ptavail;
|
||||
static char obp_stdin, obp_stdout;
|
||||
char obp_stdin, obp_stdout;
|
||||
static int obp_fd_stdin, obp_fd_stdout;
|
||||
const char *obp_stdin_path, *obp_stdout_path;
|
||||
|
||||
static int obp_nextnode(int node);
|
||||
static int obp_child(int node);
|
||||
@@ -45,7 +46,7 @@ static const char *obp_nextprop(int node, char *name);
|
||||
static int obp_devread(int dev_desc, char *buf, int nbytes);
|
||||
static int obp_devseek(int dev_desc, int hi, int lo);
|
||||
|
||||
static struct linux_arguments_v0 obp_arg;
|
||||
struct linux_arguments_v0 obp_arg;
|
||||
static const struct linux_arguments_v0 * const obp_argp = &obp_arg;
|
||||
|
||||
static void (*sync_hook)(void);
|
||||
@@ -444,7 +445,7 @@ static void obp_fortheval_v2(char *str)
|
||||
}
|
||||
|
||||
void *
|
||||
init_openprom(unsigned long memsize, const char *cmdline, char boot_device)
|
||||
init_openprom(unsigned long memsize)
|
||||
{
|
||||
free_ram = va2pa((int)&_data) - PAGE_SIZE;
|
||||
|
||||
@@ -503,51 +504,18 @@ init_openprom(unsigned long memsize, const char *cmdline, char boot_device)
|
||||
romvec0.pv_v2devops.v2_dev_read = obp_devread;
|
||||
romvec0.pv_v2devops.v2_dev_write = obp_devwrite;
|
||||
romvec0.pv_v2devops.v2_dev_seek = obp_devseek;
|
||||
obp_arg.boot_dev_ctrl = 0;
|
||||
obp_arg.boot_dev_unit = 0;
|
||||
obp_arg.dev_partition = 0;
|
||||
obp_arg.argv[0] = "sd(0,0,0):d";
|
||||
|
||||
switch(boot_device) {
|
||||
default:
|
||||
case 'a':
|
||||
obp_arg.argv[0] = "fd()";
|
||||
obp_arg.boot_dev[0] = 'f';
|
||||
obp_arg.boot_dev[1] = 'd';
|
||||
break;
|
||||
case 'd':
|
||||
obp_arg.boot_dev_unit = 2;
|
||||
// FIXME: hardcoding this looks almost definitely wrong.
|
||||
// With sd(0,2,0):b we get to see the solaris kernel though
|
||||
//obp_arg.argv[0] = "sd(0,2,0):d";
|
||||
obp_arg.argv[0] = "sd(0,2,0):b";
|
||||
// Fall through
|
||||
case 'c':
|
||||
obp_arg.boot_dev[0] = 's';
|
||||
obp_arg.boot_dev[1] = 'd';
|
||||
break;
|
||||
case 'n':
|
||||
obp_arg.argv[0] = "le()";
|
||||
obp_arg.boot_dev[0] = 'l';
|
||||
obp_arg.boot_dev[1] = 'e';
|
||||
break;
|
||||
}
|
||||
obp_arg.argv[1] = cmdline;
|
||||
romvec0.pv_v2bootargs.bootpath = &obp_arg.argv[0];
|
||||
romvec0.pv_v2bootargs.bootargs = &obp_arg.argv[1];
|
||||
romvec0.pv_v2bootargs.fd_stdin = &obp_fd_stdin;
|
||||
romvec0.pv_v2bootargs.fd_stdout = &obp_fd_stdout;
|
||||
|
||||
push_str("/builtin/console");
|
||||
push_str(obp_stdin_path);
|
||||
fword("open-dev");
|
||||
obp_fd_stdin = POP();
|
||||
push_str("/builtin/console");
|
||||
push_str(obp_stdout_path);
|
||||
fword("open-dev");
|
||||
obp_fd_stdout = POP();
|
||||
|
||||
obp_stdin = PROMDEV_TTYA;
|
||||
obp_stdout = PROMDEV_TTYA;
|
||||
|
||||
romvec0.v3_cpustart = obp_cpustart;
|
||||
romvec0.v3_cpustop = obp_cpustop;
|
||||
romvec0.v3_cpuidle = obp_cpuidle;
|
||||
|
||||
@@ -9,10 +9,6 @@
|
||||
" SUNW,501-3059" encode-string " model" property
|
||||
h# 0a21fe80 encode-int " clock-frequency" property
|
||||
|
||||
" /obio/zs@0,100000:a" encode-string " stdin-path" property
|
||||
" /obio/zs@0,100000:a" encode-string " stdout-path" property
|
||||
|
||||
|
||||
: encode-unit encode-unit-sbus ;
|
||||
: decode-unit decode-unit-sbus ;
|
||||
|
||||
|
||||
187
drivers/obio.c
187
drivers/obio.c
@@ -25,6 +25,17 @@
|
||||
path, name##_m, sizeof(name##_m)/sizeof(method_t)); \
|
||||
} while(0)
|
||||
|
||||
#define REGISTER_NODE_METHODS( name, path ) do { \
|
||||
const char *paths[1]; \
|
||||
\
|
||||
paths[0] = path; \
|
||||
bind_node( name##_flags_, name##_size_, \
|
||||
paths, 1, name##_m, sizeof(name##_m)/sizeof(method_t)); \
|
||||
} while(0)
|
||||
|
||||
#define PROMDEV_KBD 0 /* input from keyboard */
|
||||
#define PROMDEV_SCREEN 0 /* output to screen */
|
||||
#define PROMDEV_TTYA 1 /* in/out to ttya */
|
||||
|
||||
/* DECLARE data structures for the nodes. */
|
||||
DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) );
|
||||
@@ -88,10 +99,145 @@ ob_intr(int intr)
|
||||
fword("property");
|
||||
}
|
||||
|
||||
// XXX move all arch/sparc32/console.c stuff here
|
||||
#define CTRL(addr) (*(char *)(addr))
|
||||
#define DATA(addr) (*(char *)(addr + 2))
|
||||
|
||||
/* Read Register 0 */
|
||||
#define Rx_CH_AV 0x1 /* Rx Character Available */
|
||||
#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
|
||||
|
||||
static int uart_charav(int port)
|
||||
{
|
||||
return (CTRL(port) & Rx_CH_AV) != 0;
|
||||
}
|
||||
|
||||
static char uart_getchar(int port)
|
||||
{
|
||||
while (!uart_charav(port));
|
||||
|
||||
return DATA(port) & 0177;
|
||||
}
|
||||
|
||||
static void uart_putchar(int port, unsigned char c)
|
||||
{
|
||||
if (c == '\n')
|
||||
uart_putchar(port, '\r');
|
||||
while (!(CTRL(port) & Tx_BUF_EMP));
|
||||
|
||||
DATA(port) = c;
|
||||
}
|
||||
|
||||
/* ( addr len -- actual ) */
|
||||
static void
|
||||
zs_read(unsigned long *address)
|
||||
{
|
||||
char *addr;
|
||||
int len;
|
||||
|
||||
len = POP();
|
||||
addr = (char *)POP();
|
||||
|
||||
if (len != 1)
|
||||
printk("zs_read: bad len, addr %x len %x\n", (unsigned int)addr, len);
|
||||
|
||||
if (uart_charav(*address)) {
|
||||
*addr = (char)uart_getchar(*address);
|
||||
PUSH(1);
|
||||
} else {
|
||||
PUSH(0);
|
||||
}
|
||||
}
|
||||
|
||||
int keyboard_dataready(void);
|
||||
unsigned char keyboard_readdata(void);
|
||||
|
||||
/* ( addr len -- actual ) */
|
||||
static void
|
||||
zs_read_keyboard(unsigned long *address)
|
||||
{
|
||||
unsigned char *addr;
|
||||
int len;
|
||||
|
||||
len = POP();
|
||||
addr = (unsigned char *)POP();
|
||||
|
||||
if (len != 1)
|
||||
printk("zs_read: bad len, addr %x len %x\n", (unsigned int)addr, len);
|
||||
|
||||
if (keyboard_dataready()) {
|
||||
*addr = keyboard_readdata();
|
||||
PUSH(1);
|
||||
} else {
|
||||
PUSH(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ( addr len -- actual ) */
|
||||
static void
|
||||
zs_write(unsigned long *address)
|
||||
{
|
||||
unsigned char *addr;
|
||||
int i, len;
|
||||
|
||||
len = POP();
|
||||
addr = (unsigned char *)POP();
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
uart_putchar(*address, addr[i]);
|
||||
}
|
||||
PUSH(len);
|
||||
}
|
||||
|
||||
static void
|
||||
zs_close(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
zs_open(unsigned long *address)
|
||||
{
|
||||
int len;
|
||||
phandle_t ph;
|
||||
unsigned long *prop;
|
||||
char *args;
|
||||
|
||||
fword("my-self");
|
||||
fword("ihandle>phandle");
|
||||
ph = (phandle_t)POP();
|
||||
prop = (unsigned long *)get_property(ph, "address", &len);
|
||||
*address = *prop;
|
||||
fword("my-args");
|
||||
args = pop_fstr_copy();
|
||||
if (args && args[0] == 'a')
|
||||
*address += 4;
|
||||
|
||||
//printk("zs_open: address %lx, args %s\n", *address, args);
|
||||
RET ( -1 );
|
||||
}
|
||||
|
||||
DECLARE_UNNAMED_NODE(zs, INSTALL_OPEN, sizeof(unsigned long));
|
||||
|
||||
NODE_METHODS(zs) = {
|
||||
{ "open", zs_open },
|
||||
{ "close", zs_close },
|
||||
{ "read", zs_read },
|
||||
{ "write", zs_write },
|
||||
};
|
||||
|
||||
DECLARE_UNNAMED_NODE(zs_keyboard, INSTALL_OPEN, sizeof(unsigned long));
|
||||
|
||||
NODE_METHODS(zs_keyboard) = {
|
||||
{ "open", zs_open },
|
||||
{ "close", zs_close },
|
||||
{ "read", zs_read_keyboard },
|
||||
};
|
||||
|
||||
static void
|
||||
ob_zs_init(unsigned long base, unsigned long offset, int intr, int slave, int keyboard)
|
||||
{
|
||||
char nodebuff[256];
|
||||
|
||||
ob_new_obio_device("zs", "serial");
|
||||
|
||||
ob_reg(base, offset, ZS_REGS, 1);
|
||||
@@ -116,6 +262,13 @@ ob_zs_init(unsigned long base, unsigned long offset, int intr, int slave, int ke
|
||||
ob_intr(intr);
|
||||
|
||||
fword("finish-device");
|
||||
|
||||
sprintf(nodebuff, "/obio/zs@0,%x", offset);
|
||||
if (keyboard) {
|
||||
REGISTER_NODE_METHODS(zs_keyboard, nodebuff);
|
||||
} else {
|
||||
REGISTER_NODE_METHODS(zs, nodebuff);
|
||||
}
|
||||
}
|
||||
|
||||
static char *nvram;
|
||||
@@ -147,8 +300,12 @@ ob_nvram_init(unsigned long base, unsigned long offset)
|
||||
extern uint32_t cmdline;
|
||||
extern uint32_t cmdline_size;
|
||||
extern char boot_device;
|
||||
extern char obp_stdin, obp_stdout;
|
||||
extern const char *obp_stdin_path, *obp_stdout_path;
|
||||
|
||||
const char *stdin, *stdout;
|
||||
unsigned int i;
|
||||
char nographic;
|
||||
|
||||
ob_new_obio_device("eeprom", NULL);
|
||||
|
||||
@@ -171,6 +328,7 @@ ob_nvram_init(unsigned long base, unsigned long offset)
|
||||
cmdline = nv_info.cmdline;
|
||||
cmdline_size = nv_info.cmdline_size;
|
||||
boot_device = nv_info.boot_device;
|
||||
nographic = nv_info.nographic;
|
||||
|
||||
push_str("mk48t08");
|
||||
fword("model");
|
||||
@@ -301,6 +459,35 @@ ob_nvram_init(unsigned long base, unsigned long offset)
|
||||
|
||||
fword("finish-device");
|
||||
}
|
||||
|
||||
if (nographic) {
|
||||
obp_stdin = PROMDEV_TTYA;
|
||||
obp_stdout = PROMDEV_TTYA;
|
||||
stdin = "/obio/zs@0,100000:a";
|
||||
stdout = "/obio/zs@0,100000:a";
|
||||
} else {
|
||||
obp_stdin = PROMDEV_KBD;
|
||||
obp_stdout = PROMDEV_SCREEN;
|
||||
stdin = "/obio/zs@0,0:a";
|
||||
stdout = "/iommu/sbus/SUNW,tcx";
|
||||
}
|
||||
|
||||
push_str("/");
|
||||
fword("find-device");
|
||||
push_str(stdin);
|
||||
fword("encode-string");
|
||||
push_str("stdin-path");
|
||||
fword("encode-string");
|
||||
fword("property");
|
||||
|
||||
push_str(stdout);
|
||||
fword("encode-string");
|
||||
push_str("stdout-path");
|
||||
fword("encode-string");
|
||||
fword("property");
|
||||
|
||||
obp_stdin_path = stdin;
|
||||
obp_stdout_path = stdout;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -242,11 +242,32 @@ video_fill_rect( void )
|
||||
fill_rect( color_ind, x, y, w, h );
|
||||
}
|
||||
|
||||
/* ( addr len -- actual ) */
|
||||
static void
|
||||
video_write(void)
|
||||
{
|
||||
char *addr;
|
||||
int i, len;
|
||||
|
||||
len = GETTOS();
|
||||
addr = pop_fstr_copy();
|
||||
|
||||
console_draw_str(addr);
|
||||
PUSH(len);
|
||||
}
|
||||
|
||||
static void
|
||||
video_open(void)
|
||||
{
|
||||
}
|
||||
|
||||
NODE_METHODS( video ) = {
|
||||
{"open", video_open },
|
||||
{"dimensions", video_dimensions },
|
||||
{"set-colors", video_set_colors },
|
||||
{"fill-rectangle", video_fill_rect },
|
||||
{"color!", video_color_bang },
|
||||
{"write", video_write },
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user