Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/ps2kbd.c
Show All 25 Lines | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/stat.h> | |||||
#include <machine/vmm_snapshot.h> | #include <machine/vmm_snapshot.h> | ||||
#include <assert.h> | #include <assert.h> | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <strings.h> | #include <strings.h> | ||||
#include <pthread.h> | #include <pthread.h> | ||||
#include <pthread_np.h> | #include <pthread_np.h> | ||||
#include <unistd.h> | |||||
#include <fcntl.h> | |||||
#include "bhyverun.h" | |||||
#include "atkbdc.h" | #include "atkbdc.h" | ||||
#include "debug.h" | #include "debug.h" | ||||
#include "console.h" | #include "console.h" | ||||
/* keyboard device commands */ | /* keyboard device commands */ | ||||
#define PS2KC_RESET_DEV 0xff | #define PS2KC_RESET_DEV 0xff | ||||
#define PS2KC_DISABLE 0xf5 | #define PS2KC_DISABLE 0xf5 | ||||
#define PS2KC_ENABLE 0xf4 | #define PS2KC_ENABLE 0xf4 | ||||
#define PS2KC_SET_TYPEMATIC 0xf3 | #define PS2KC_SET_TYPEMATIC 0xf3 | ||||
#define PS2KC_SEND_DEV_ID 0xf2 | #define PS2KC_SEND_DEV_ID 0xf2 | ||||
#define PS2KC_SET_SCANCODE_SET 0xf0 | #define PS2KC_SET_SCANCODE_SET 0xf0 | ||||
#define PS2KC_ECHO 0xee | #define PS2KC_ECHO 0xee | ||||
#define PS2KC_SET_LEDS 0xed | #define PS2KC_SET_LEDS 0xed | ||||
#define PS2KC_BAT_SUCCESS 0xaa | #define PS2KC_BAT_SUCCESS 0xaa | ||||
#define PS2KC_ACK 0xfa | #define PS2KC_ACK 0xfa | ||||
#define PS2KBD_FIFOSZ 16 | #define PS2KBD_FIFOSZ 16 | ||||
#define PS2KBD_LAYOUT_BASEDIR "/usr/share/bhyve/kbdlayout/" | |||||
struct fifo { | struct fifo { | ||||
uint8_t buf[PS2KBD_FIFOSZ]; | uint8_t buf[PS2KBD_FIFOSZ]; | ||||
int rindex; /* index to read from */ | int rindex; /* index to read from */ | ||||
int windex; /* index to write to */ | int windex; /* index to write to */ | ||||
int num; /* number of bytes in the fifo */ | int num; /* number of bytes in the fifo */ | ||||
int size; /* size of the fifo */ | int size; /* size of the fifo */ | ||||
}; | }; | ||||
Show All 12 Lines | struct extended_translation { | ||||
uint32_t keysym; | uint32_t keysym; | ||||
uint8_t scancode; | uint8_t scancode; | ||||
int flags; | int flags; | ||||
}; | }; | ||||
/* | /* | ||||
* FIXME: Pause/break and Print Screen/SysRq require special handling. | * FIXME: Pause/break and Print Screen/SysRq require special handling. | ||||
*/ | */ | ||||
static const struct extended_translation extended_translations[] = { | static struct extended_translation extended_translations[128] = { | ||||
{0xff08, 0x66}, /* Back space */ | {0xff08, 0x66}, /* Back space */ | ||||
{0xff09, 0x0d}, /* Tab */ | {0xff09, 0x0d}, /* Tab */ | ||||
{0xff0d, 0x5a}, /* Return */ | {0xff0d, 0x5a}, /* Return */ | ||||
{0xff1b, 0x76}, /* Escape */ | {0xff1b, 0x76}, /* Escape */ | ||||
{0xff50, 0x6c, SCANCODE_E0_PREFIX}, /* Home */ | {0xff50, 0x6c, SCANCODE_E0_PREFIX}, /* Home */ | ||||
{0xff51, 0x6b, SCANCODE_E0_PREFIX}, /* Left arrow */ | {0xff51, 0x6b, SCANCODE_E0_PREFIX}, /* Left arrow */ | ||||
{0xff52, 0x75, SCANCODE_E0_PREFIX}, /* Up arrow */ | {0xff52, 0x75, SCANCODE_E0_PREFIX}, /* Up arrow */ | ||||
{0xff53, 0x74, SCANCODE_E0_PREFIX}, /* Right arrow */ | {0xff53, 0x74, SCANCODE_E0_PREFIX}, /* Right arrow */ | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | static struct extended_translation extended_translations[128] = { | ||||
{0xffb0, 0x70}, /* Keypad 0 */ | {0xffb0, 0x70}, /* Keypad 0 */ | ||||
{0xff9e, 0x70}, /* Keypad ins */ | {0xff9e, 0x70}, /* Keypad ins */ | ||||
{0xffae, 0x71}, /* Keypad . */ | {0xffae, 0x71}, /* Keypad . */ | ||||
{0xff9f, 0x71}, /* Keypad del */ | {0xff9f, 0x71}, /* Keypad del */ | ||||
{0, 0, 0} /* Terminator */ | {0, 0, 0} /* Terminator */ | ||||
}; | }; | ||||
/* ASCII to type 2 scancode lookup table */ | /* ASCII to type 2 scancode lookup table */ | ||||
static const uint8_t ascii_translations[128] = { | static uint8_t ascii_translations[128] = { | ||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52, | 0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52, | ||||
0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a, | 0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a, | ||||
0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d, | 0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d, | ||||
0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a, | 0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a, | ||||
▲ Show 20 Lines • Show All 161 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static void | static void | ||||
ps2kbd_keysym_queue(struct ps2kbd_softc *sc, | ps2kbd_keysym_queue(struct ps2kbd_softc *sc, | ||||
int down, uint32_t keysym, uint32_t keycode) | int down, uint32_t keysym, uint32_t keycode) | ||||
{ | { | ||||
assert(pthread_mutex_isowned_np(&sc->mtx)); | assert(pthread_mutex_isowned_np(&sc->mtx)); | ||||
int e0_prefix, found; | int e0_prefix, found; | ||||
uint8_t code; | uint8_t code; | ||||
const struct extended_translation *trans; | struct extended_translation *trans; | ||||
if (keycode) { | if (keycode) { | ||||
code = keyset1to2_translations[(uint8_t)(keycode & 0x7f)]; | code = keyset1to2_translations[(uint8_t)(keycode & 0x7f)]; | ||||
e0_prefix = ((keycode & 0x80) ? SCANCODE_E0_PREFIX : 0); | e0_prefix = ((keycode & 0x80) ? SCANCODE_E0_PREFIX : 0); | ||||
found = 1; | found = 1; | ||||
} else { | } else { | ||||
found = 0; | found = 0; | ||||
if (keysym < 0x80) { | if (keysym < 0x80) { | ||||
Show All 39 Lines | ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg) | ||||
fifo_full = sc->fifo.num == PS2KBD_FIFOSZ; | fifo_full = sc->fifo.num == PS2KBD_FIFOSZ; | ||||
ps2kbd_keysym_queue(sc, down, keysym, keycode); | ps2kbd_keysym_queue(sc, down, keysym, keycode); | ||||
pthread_mutex_unlock(&sc->mtx); | pthread_mutex_unlock(&sc->mtx); | ||||
if (!fifo_full) | if (!fifo_full) | ||||
atkbdc_event(sc->atkbdc_sc, 1); | atkbdc_event(sc->atkbdc_sc, 1); | ||||
} | } | ||||
static void | |||||
ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix) | |||||
{ | |||||
int i = 0; | |||||
do { | |||||
if (extended_translations[i].keysym == keycode) | |||||
break; | |||||
} while(extended_translations[++i].keysym); | |||||
if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1)) | |||||
return; | |||||
if (!extended_translations[i].keysym) { | |||||
extended_translations[i].keysym = keycode; | |||||
extended_translations[i+1].keysym = 0; | |||||
extended_translations[i+1].scancode = 0; | |||||
extended_translations[i+1].flags = 0; | |||||
} | |||||
extended_translations[i].scancode = (uint8_t)(scancode & 0xff); | |||||
extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0); | |||||
} | |||||
static void | |||||
ps2kbd_setkbdlayout(void) | |||||
{ | |||||
int err; | |||||
int fd; | |||||
char path[256]; | |||||
jhb: Use MAX_PATHNAME (or whatever the right constant is) | |||||
char *buf, *next, *line; | |||||
struct stat sb; | |||||
size_t sz; | |||||
uint8_t ascii; | |||||
uint32_t keycode, scancode, prefix; | |||||
strcpy(path, PS2KBD_LAYOUT_BASEDIR); | |||||
strncat(path, kbdlayout_name, (sizeof(path) - strlen(PS2KBD_LAYOUT_BASEDIR) - 1)); | |||||
Not Done Inline ActionsThis is probably simpler as a single call to snprintf(). strlcat would let you avoid the complicated length expression, but using snprintf() is even simpler. jhb: This is probably simpler as a single call to snprintf(). strlcat would let you avoid the… | |||||
err = stat(path, &sb); | |||||
if (err) | |||||
return; | |||||
buf = (char *)malloc(sizeof(char) * sb.st_size); | |||||
if (buf == NULL) | |||||
return; | |||||
fd = open(path, O_RDONLY); | |||||
if (fd == -1) | |||||
goto out; | |||||
sz = read(fd, buf, sb.st_size ); | |||||
close(fd); | |||||
if (sz != sb.st_size ) | |||||
goto out; | |||||
next = buf; | |||||
while ((line = strsep(&next, "\n")) != NULL) { | |||||
if (sscanf(line, "'%c',%x;", &ascii, &scancode) == 2) { | |||||
if (ascii < 0x80) | |||||
ascii_translations[ascii] = (uint8_t)(scancode & 0xff); | |||||
} else if (sscanf(line, "%x,%x,%x;", &keycode, &scancode, &prefix) == 3 ) { | |||||
ps2kbd_update_extended_translation(keycode, scancode, prefix); | |||||
} else if (sscanf(line, "%x,%x;", &keycode, &scancode) == 2) { | |||||
if (keycode < 0x80) | |||||
ascii_translations[(uint8_t)(keycode & 0xff)] = (uint8_t)(scancode & 0xff); | |||||
else | |||||
ps2kbd_update_extended_translation(keycode, scancode, 0); | |||||
} | |||||
} | |||||
out: | |||||
free(buf); | |||||
} | |||||
struct ps2kbd_softc * | struct ps2kbd_softc * | ||||
ps2kbd_init(struct atkbdc_softc *atkbdc_sc) | ps2kbd_init(struct atkbdc_softc *atkbdc_sc) | ||||
{ | { | ||||
struct ps2kbd_softc *sc; | struct ps2kbd_softc *sc; | ||||
if (kbdlayout_name != NULL) | |||||
ps2kbd_setkbdlayout(); | |||||
sc = calloc(1, sizeof (struct ps2kbd_softc)); | sc = calloc(1, sizeof (struct ps2kbd_softc)); | ||||
pthread_mutex_init(&sc->mtx, NULL); | pthread_mutex_init(&sc->mtx, NULL); | ||||
fifo_init(sc); | fifo_init(sc); | ||||
sc->atkbdc_sc = atkbdc_sc; | sc->atkbdc_sc = atkbdc_sc; | ||||
console_kbd_register(ps2kbd_event, sc, 1); | console_kbd_register(ps2kbd_event, sc, 1); | ||||
Show All 17 Lines |
Use MAX_PATHNAME (or whatever the right constant is)