Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/vt/vt_accessibility.c
- This file was added.
/*- | |||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||||
* | |||||
* Copyright (c) 2022 Hans Petter Selasky | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
*/ | |||||
#include <sys/param.h> | |||||
#include <sys/systm.h> | |||||
#include <sys/kernel.h> | |||||
#include <sys/lock.h> | |||||
#include <sys/sx.h> | |||||
#include <sys/malloc.h> | |||||
#include <sys/mutex.h> | |||||
#include <sys/reboot.h> | |||||
#include <dev/vt/vt.h> | |||||
#define VT_ACCESS_UTF8_DATA_MAX 1000 /* bytes */ | |||||
#define VT_ACCESS_CHATTY_CHAR_MAX 32 /* bytes */ | |||||
#define VT_ACCESS_CHATTY_DATA_MAX (VT_ACCESS_UTF8_DATA_MAX * VT_ACCESS_CHATTY_CHAR_MAX) | |||||
static MALLOC_DEFINE(M_VTACCESS, "vtaccess", "VT accessibility"); | |||||
static SYSCTL_NODE(_kern_vt, OID_AUTO, accessibility, | |||||
CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "Accessibility parameters"); | |||||
static int vt_access_text_utf8(SYSCTL_HANDLER_ARGS); | |||||
static int vt_access_text_chatty(SYSCTL_HANDLER_ARGS); | |||||
static int vt_access_feed(SYSCTL_HANDLER_ARGS); | |||||
static term_pos_t vt_access_cursor; | |||||
static char *vt_access_utf8_data; | |||||
static size_t vt_access_utf8_length; | |||||
static char *vt_access_chatty_data; | |||||
static size_t vt_access_chatty_length; | |||||
static struct sx vt_access_sx; | |||||
SX_SYSINIT(vt_access_sx, &vt_access_sx, "VT accessibility"); | |||||
#define VT_ACCESS_LOCK() sx_xlock(&vt_access_sx) | |||||
#define VT_ACCESS_UNLOCK() sx_xunlock(&vt_access_sx) | |||||
static unsigned vt_access_lines = 1; /* default value */ | |||||
SYSCTL_UINT(_kern_vt_accessibility, OID_AUTO, lines, CTLFLAG_RWTUN | CTLFLAG_MPSAFE, | |||||
&vt_access_lines, 0, "Number of lines the VT accessibility module will feed, between 1 and 1000"); | |||||
SYSCTL_U16(_kern_vt_accessibility, OID_AUTO, row, CTLFLAG_RD | CTLFLAG_MPSAFE, | |||||
&vt_access_cursor.tp_row, 0, "Current VT accessibility row number, between 0 and 65535 inclusivly"); | |||||
SYSCTL_U16(_kern_vt_accessibility, OID_AUTO, col, CTLFLAG_RD | CTLFLAG_MPSAFE, | |||||
&vt_access_cursor.tp_col, 0, "Current VT accessibility column number, between 0 and 65535 inclusivly"); | |||||
SYSCTL_PROC(_kern_vt_accessibility, OID_AUTO, text_utf8, CTLTYPE_STRING | CTLFLAG_RD | | |||||
CTLFLAG_MPSAFE, NULL, 0, &vt_access_text_utf8, "A", "Current VT accessibility buffer in UTF-8 format"); | |||||
SYSCTL_PROC(_kern_vt_accessibility, OID_AUTO, text_chatty, CTLTYPE_STRING | CTLFLAG_RD | | |||||
CTLFLAG_MPSAFE, NULL, 0, &vt_access_text_chatty, "A", "Current VT accessibility buffer in chatty 7-bit ASCII format"); | |||||
SYSCTL_PROC(_kern_vt_accessibility, OID_AUTO, feed, | |||||
CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, NULL, | |||||
0, &vt_access_feed, "IU", "Set to non-zero to feed a new VT accessibility buffer"); | |||||
static void | |||||
vt_access_to_chatty(char ch, char *buffer, size_t *ppos, size_t size) | |||||
{ | |||||
char temp[VT_ACCESS_CHATTY_CHAR_MAX]; | |||||
imp: please construct the messages using sbuf. | |||||
Done Inline ActionsSure, but devd has its limits on the message size including headers (1Kbyte I think) hselasky: Sure, but devd has its limits on the message size including headers (1Kbyte I think) | |||||
size_t len; | |||||
switch (ch) { | |||||
case 'a' ... 'z': | |||||
case 'A' ... 'Z': | |||||
case '0' ... '9': | |||||
temp[0] = (char)ch; | |||||
temp[1] = 0; | |||||
break; | |||||
case '~': | |||||
strlcpy(temp, " tilde ", sizeof(temp)); | |||||
break; | |||||
case '#': | |||||
strlcpy(temp, " hash ", sizeof(temp)); | |||||
break; | |||||
case '+': | |||||
strlcpy(temp, " plus ", sizeof(temp)); | |||||
break; | |||||
case '-': | |||||
strlcpy(temp, " minus ", sizeof(temp)); | |||||
break; | |||||
case '_': | |||||
strlcpy(temp, " underscore ", sizeof(temp)); | |||||
break; | |||||
case '*': | |||||
strlcpy(temp, " multiply ", sizeof(temp)); | |||||
break; | |||||
case '/': | |||||
strlcpy(temp, " divide ", sizeof(temp)); | |||||
break; | |||||
case '\\': | |||||
strlcpy(temp, " backslash ", sizeof(temp)); | |||||
break; | |||||
case '=': | |||||
strlcpy(temp, " equal ", sizeof(temp)); | |||||
break; | |||||
case '@': | |||||
strlcpy(temp, " at ", sizeof(temp)); | |||||
break; | |||||
case '^': | |||||
strlcpy(temp, " xor ", sizeof(temp)); | |||||
break; | |||||
case '|': | |||||
strlcpy(temp, " pipe ", sizeof(temp)); | |||||
break; | |||||
case '&': | |||||
strlcpy(temp, " and ", sizeof(temp)); | |||||
break; | |||||
case '(': | |||||
strlcpy(temp, " opening parenthesis ", sizeof(temp)); | |||||
break; | |||||
case ')': | |||||
strlcpy(temp, " closing parenthesis ", sizeof(temp)); | |||||
break; | |||||
case '[': | |||||
strlcpy(temp, " opening bracket ", sizeof(temp)); | |||||
break; | |||||
case ']': | |||||
strlcpy(temp, " closing bracket ", sizeof(temp)); | |||||
break; | |||||
case '{': | |||||
strlcpy(temp, " opening curlybracket ", sizeof(temp)); | |||||
break; | |||||
case '}': | |||||
strlcpy(temp, " closing curlybracket ", sizeof(temp)); | |||||
break; | |||||
case '.': | |||||
strlcpy(temp, " period ", sizeof(temp)); | |||||
break; | |||||
case ',': | |||||
strlcpy(temp, " comma ", sizeof(temp)); | |||||
break; | |||||
case ':': | |||||
strlcpy(temp, " colon ", sizeof(temp)); | |||||
break; | |||||
case ';': | |||||
strlcpy(temp, " semicolon ", sizeof(temp)); | |||||
break; | |||||
case '!': | |||||
strlcpy(temp, " not ", sizeof(temp)); | |||||
break; | |||||
case '$': | |||||
strlcpy(temp, " dollar ", sizeof(temp)); | |||||
break; | |||||
case '?': | |||||
strlcpy(temp, " questionmark ", sizeof(temp)); | |||||
break; | |||||
case '>': | |||||
strlcpy(temp, " greaterthan ", sizeof(temp)); | |||||
break; | |||||
case '<': | |||||
strlcpy(temp, " lessthan ", sizeof(temp)); | |||||
break; | |||||
case '"': | |||||
strlcpy(temp, " quote ", sizeof(temp)); | |||||
break; | |||||
case '\'': | |||||
strlcpy(temp, " apostrophe ", sizeof(temp)); | |||||
break; | |||||
case '%': | |||||
strlcpy(temp, " percent ", sizeof(temp)); | |||||
break; | |||||
case ' ': | |||||
temp[0] = ' '; | |||||
temp[1] = 0; | |||||
break; | |||||
default: | |||||
snprintf(temp, sizeof(temp), " byte %u ", (uint8_t)ch); | |||||
break; | |||||
} | |||||
len = strlen(temp); | |||||
if (*ppos + len > size) | |||||
return; | |||||
if (buffer != NULL) | |||||
memcpy(buffer + *ppos, temp, len); | |||||
*ppos += len; | |||||
} | |||||
static int | |||||
vt_access_text_utf8(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
int error; | |||||
VT_ACCESS_LOCK(); | |||||
if (vt_access_utf8_data != NULL) | |||||
error = SYSCTL_OUT(req, vt_access_utf8_data, vt_access_utf8_length); | |||||
else | |||||
error = 0; | |||||
VT_ACCESS_UNLOCK(); | |||||
return (error); | |||||
} | |||||
static int | |||||
vt_access_text_chatty(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
int error; | |||||
VT_ACCESS_LOCK(); | |||||
if (vt_access_chatty_data != NULL) | |||||
error = SYSCTL_OUT(req, vt_access_chatty_data, vt_access_chatty_length); | |||||
else | |||||
error = 0; | |||||
VT_ACCESS_UNLOCK(); | |||||
return (error); | |||||
} | |||||
static int | |||||
vt_access_feed(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
unsigned max_ln; | |||||
unsigned val; | |||||
size_t off; | |||||
int error; | |||||
VT_ACCESS_LOCK(); | |||||
val = 0; | |||||
error = SYSCTL_OUT(req, &val, sizeof(val)); | |||||
if (error || !req->newptr) | |||||
goto done; | |||||
error = SYSCTL_IN(req, &val, sizeof(val)); | |||||
if (error || val == 0) | |||||
goto done; | |||||
if (vt_access_utf8_data == NULL) { | |||||
vt_access_utf8_data = | |||||
malloc(VT_ACCESS_UTF8_DATA_MAX, M_VTACCESS, M_WAITOK | M_ZERO); | |||||
} else { | |||||
/* Re-use the UTF-8 buffer */ | |||||
} | |||||
max_ln = vt_access_lines; | |||||
if (max_ln < 1) | |||||
max_ln = 1; | |||||
else if (max_ln > 1000) | |||||
max_ln = 1000; | |||||
vt_access_utf8_length = 0; | |||||
/* Update the accessibility buffer: */ | |||||
if (vtbuf_extract_accessibility(vt_access_utf8_data, | |||||
&vt_access_utf8_length, &vt_access_cursor, max_ln, VT_ACCESS_UTF8_DATA_MAX) != 0) | |||||
vt_access_utf8_length = 0; | |||||
free(vt_access_chatty_data, M_VTACCESS); | |||||
vt_access_chatty_data = NULL; | |||||
vt_access_chatty_length = 0; | |||||
/* Compute size of chatty buffer: */ | |||||
for (size_t x = 0; x != vt_access_utf8_length; x++) { | |||||
vt_access_to_chatty(vt_access_utf8_data[x], NULL, | |||||
&vt_access_chatty_length, VT_ACCESS_CHATTY_DATA_MAX); | |||||
} | |||||
if (vt_access_chatty_length != 0) { | |||||
vt_access_chatty_data = | |||||
malloc(vt_access_chatty_length, M_VTACCESS, M_WAITOK); | |||||
off = 0; | |||||
for (size_t x = 0; x != vt_access_utf8_length; x++) { | |||||
vt_access_to_chatty(vt_access_utf8_data[x], vt_access_chatty_data, | |||||
&off, vt_access_chatty_length); | |||||
} | |||||
MPASS(off == vt_access_chatty_length); | |||||
} | |||||
done: | |||||
VT_ACCESS_UNLOCK(); | |||||
return (error); | |||||
} |
please construct the messages using sbuf.