/*
 * <adbkbd.c>
 *
 * Open Hack'Ware BIOS ADB keyboard support.
 * 
 *  Copyright (c) 2005 Jocelyn Mayer
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License V2
 *   as published by the Free Software Foundation
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdlib.h>
#include <stdio.h>
#include "bios.h"
#include "adb.h"
#include "kbd.h"

#ifdef DEBUG_ADB
#define ADB_DPRINTF(fmt, args...) \
do { dprintf("ADB - %s: " fmt, __func__ , ##args); } while (0)
#else
#define ADB_DPRINTF(fmt, args...) do { } while (0)
#endif

/* ADB US keyboard translation map
 * XXX: for now, only shift modifier is defined
 */
static keymap_t ADB_kbd_us[] = {
    /* 0x00 */
    { KBD_SH_CAPS, { 0x61, 0x41,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x73, 0x53,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x64, 0x44,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x66, 0x46,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x68, 0x48,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x67, 0x47,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x7A, 0x5A,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x78, 0x58,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    /* 0x08 */
    { KBD_SH_CAPS, { 0x63, 0x43,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x76, 0x56,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x60, 0x40,   -1,   -1,   -1,   -1,   -1,   -1, /* ? */
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x62, 0x42,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x71, 0x51,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x77, 0x57,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x65, 0x45,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x72, 0x52,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    /* 0x10 */
    { KBD_SH_CAPS, { 0x79, 0x59,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x74, 0x54,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x31, 0x21,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x32, 0x40,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x33, 0x23,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x34, 0x24,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x36, 0x5E,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x35, 0x25,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    /* 0x18 */
    { KBD_SH_CAPS, { 0x3D, 0x2B,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x39, 0x28,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x37, 0x26,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x2D, 0x5F,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x38, 0x2A,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x30, 0x29,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x5D, 0x7D,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x6F, 0x4F,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    /* 0x20 */
    { KBD_SH_CAPS, { 0x75, 0x55,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x5B, 0x7B,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x69, 0x49,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x70, 0x50,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_MOD_MAP(0x0D), },
    { KBD_SH_CAPS, { 0x6C, 0x4C,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x6A, 0x4A,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x27, 0x22,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    /* 0x28 */
    { KBD_SH_CAPS, { 0x6B, 0x4B,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x3B, 0x3A,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x5C, 0x7C,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x2C, 0x3C,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x2F, 0x3F,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x6E, 0x4E,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x6D, 0x4D,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_CAPS, { 0x2E, 0x3E,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    /* 0x30 : tab */
    { KBD_MOD_MAP(0x09), },
    /* 0x31 : space */
    { KBD_MOD_MAP(0x20), },
    /* 0x32 : '<' '>' */
    { KBD_SH_CAPS, { 0x3C, 0x3E,   -1,   -1,   -1,   -1,   -1,   -1, /* ? */
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    /* 0x33 : backspace */
    { KBD_MOD_MAP(0x08), },
    { KBD_MAP_NONE, },
    /* 0x35 : ESC */
    { KBD_MOD_MAP(0x1B), },
    /* 0x36 : control */
    { KBD_MOD_MAP_LCTRL, },
    /* 0x37 : command */
    { KBD_MOD_MAP_LCMD,   },
    /* 0x38 : left shift */
    { KBD_MOD_MAP_LSHIFT, },
    /* 0x39 : caps-lock */
    { KBD_MOD_MAP_CAPS,   },
    /* 0x3A : option */
    { KBD_MOD_MAP_LOPT,   },
    /* 0x3B : left */
    { KBD_MAP_NONE, },
    /* 0x3C : right */
    { KBD_MAP_NONE, },
    /* 0x3D : down */
    { KBD_MAP_NONE, },
    /* 0x3E : up */
    { KBD_MAP_NONE, },
    { KBD_MAP_NONE, },
    /* 0x40 */
    { KBD_MAP_NONE, },
    { KBD_SH_NUML, { 0x7F, 0x2E,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_MAP_NONE, },
    { KBD_SH_NONE, { 0x2A, 0x2A,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_MAP_NONE, },
    { KBD_SH_NONE, { 0x2B, 0x2B,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_MAP_NONE, },
    { KBD_MOD_MAP(0x7F), },
    /* 0x48 */
    { KBD_MAP_NONE, },
    { KBD_MAP_NONE, },
    { KBD_MAP_NONE, },
    { KBD_SH_NONE, { 0x2F, 0x2F,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_MOD_MAP(0x0D), },
    { KBD_MAP_NONE, },
    { KBD_SH_NONE, { 0x2D, 0x2D,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_MAP_NONE, },
    /* 0x50 */
    { KBD_MAP_NONE, },
    { KBD_SH_NONE, { 0x3D, 0x3D,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_NUML, {   -1, 0x30,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_NUML, {   -1, 0x31,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_NUML, {   -1, 0x32,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_NUML, {   -1, 0x33,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_NUML, {   -1, 0x34,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_NUML, {   -1, 0x35,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    /* 0x58 */
    { KBD_SH_NUML, {   -1, 0x36,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_NUML, {   -1, 0x37,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_MAP_NONE, },
    { KBD_SH_NUML, {   -1, 0x38,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_SH_NUML, {   -1, 0x39,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
    { KBD_MAP_NONE, },
    { KBD_MOD_MAP(0x2F), },
    { KBD_MAP_NONE, },
    /* 0x60 : F5 */
    { KBD_MAP_NONE, },
    /* 0x61 : F6 */
    { KBD_MAP_NONE, },
    /* 0x62 : F7 */
    { KBD_MAP_NONE, },
    /* 0x63 : F3 */
    { KBD_MAP_NONE, },
    /* 0x64 : F8 */
    { KBD_MAP_NONE, },
    /* 0x65 : F9 */
    { KBD_MAP_NONE, },
    { KBD_MAP_NONE, },
    /* 0x67 : F11 */
    { KBD_MAP_NONE, },
    /* 0x68 */
    { KBD_MAP_NONE, },
    /* 0x69 : F13 */
    { KBD_MAP_NONE, },
    { KBD_MAP_NONE, },
    /* 0x6B : F14 */
    { KBD_MAP_NONE, },
    { KBD_MAP_NONE, },
    /* 0x6D : F10 */
    { KBD_MAP_NONE, },
    { KBD_MAP_NONE, },
    /* 0x6F : F12 */
    { KBD_MAP_NONE, },
    /* 0x70 */
    { KBD_MAP_NONE, },
    /* 0x71 : F15 */
    { KBD_MAP_NONE, },
    /* 0x72 : help */
    { KBD_MAP_NONE, },
    /* 0x73 : home */
    { KBD_MAP_NONE, },
    /* 0x74 : page up */
    { KBD_MAP_NONE, },
    /* 0x75 : del */
    { KBD_MAP_NONE, },
    /* 0x76 : F4 */
    { KBD_MAP_NONE, },
    /* 0x77 : end */
    { KBD_MAP_NONE, },
    /* 0x78 : F2 */
    { KBD_MAP_NONE, },
    /* 0x79 : page down */
    { KBD_MAP_NONE, },
    /* 0x7A : F1 */
    { KBD_MAP_NONE, },
    /* 0x7B : right shift */
    { KBD_MOD_MAP_RSHIFT, },
    /* 0x7C : right option */
    { KBD_MOD_MAP_ROPT,   },
    /* 0x7D : right control */
    { KBD_MOD_MAP_RCTRL, },
    { KBD_MAP_NONE, },
    /* 0x7F : power */
    { KBD_MAP_NONE, },
};

typedef struct adb_kbd_t adb_kbd_t;
struct adb_kbd_t {
    kbd_t kbd;
    int next_key;
};

static int adb_kbd_open (unused void *private)
{
    return 0;
}

static int adb_kbd_close (unused void *private)
{
    return 0;
}

static int adb_kbd_read (void *private)
{
    uint8_t buffer[ADB_BUF_SIZE];
    adb_dev_t *dev = private;
    adb_kbd_t *kbd;
    int key;
    int ret;

    kbd = (void *)dev->state;
    ADB_DPRINTF("enter\n");
    /* Get saved state */
    ret = -1;
    for (key = -1; key == -1; ) {
        if (kbd->next_key != -1) {
            key = kbd->next_key;
            kbd->next_key = -1;
        } else {
            if (adb_reg_get(dev, 0, buffer) != 2) {
                goto out;
            }
            kbd->next_key = buffer[1] == 0xFF ? -1 : buffer[1];
            key = buffer[0];
        }
        ret = kbd_translate_key(&kbd->kbd, key & 0x7F, key >> 7);
        ADB_DPRINTF("Translated %d (%02x) into %d (%02x)\n",
                    key, key, ret, ret);
    }
 out:

    return ret;
}

static cops_t adb_kbd_ops = {
    &adb_kbd_open,
    &adb_kbd_close,
    &adb_kbd_read,
    NULL,
};

void *adb_kbd_new (void *private)
{
    adb_kbd_t *kbd;
    adb_dev_t *dev = private;

    kbd = kbd_new(sizeof(adb_kbd_t));
    if (kbd != NULL) {
        kbd_set_keymap(&kbd->kbd,
                       sizeof(ADB_kbd_us) / sizeof(keymap_t), ADB_kbd_us);
        kbd->next_key = -1;
        dev->state = (int32_t)kbd;
        chardev_register(CHARDEV_KBD, &adb_kbd_ops, private);
    }

    return kbd;
}
