Changeset c072a29 in mainline for uspace/drv/char/xtkbd/xtkbd.c


Ignore:
Timestamp:
2014-09-15T15:57:32Z (10 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5c79fb5
Parents:
662ebc8
Message:

use the PAUSE / BREAK key to activate the kernel console in compositor (F15 on some strange keyboards)
this avoids issues with stuck modifier keys and other surprises
it is also unlikely that any client applications would like to use these keys

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/char/xtkbd/xtkbd.c

    r662ebc8 rc072a29  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
     28
    2829/** @addtogroup drvkbd
    2930 * @{
    3031 */
    3132/** @file
    32  * @brief XT keyboard driver;
     33 * @brief XT keyboard driver
    3334 */
    3435
     
    4041#include <ipc/kbdev.h>
    4142#include <abi/ipc/methods.h>
    42 
    4343#include "xtkbd.h"
    4444
    4545/** Scancode set 1 table. */
    46 static const int scanmap_simple[] = {
    47 
     46static const unsigned int scanmap_simple[] = {
    4847        [0x29] = KC_BACKTICK,
    49 
     48       
    5049        [0x02] = KC_1,
    5150        [0x03] = KC_2,
     
    5857        [0x0a] = KC_9,
    5958        [0x0b] = KC_0,
    60 
     59       
    6160        [0x0c] = KC_MINUS,
    6261        [0x0d] = KC_EQUALS,
    6362        [0x0e] = KC_BACKSPACE,
    64 
     63       
    6564        [0x0f] = KC_TAB,
    66 
     65       
    6766        [0x10] = KC_Q,
    6867        [0x11] = KC_W,
     
    7574        [0x18] = KC_O,
    7675        [0x19] = KC_P,
    77 
     76       
    7877        [0x1a] = KC_LBRACKET,
    7978        [0x1b] = KC_RBRACKET,
    80 
     79       
    8180        [0x3a] = KC_CAPS_LOCK,
    82 
     81       
    8382        [0x1e] = KC_A,
    8483        [0x1f] = KC_S,
     
    9089        [0x25] = KC_K,
    9190        [0x26] = KC_L,
    92 
     91       
    9392        [0x27] = KC_SEMICOLON,
    9493        [0x28] = KC_QUOTE,
    9594        [0x2b] = KC_BACKSLASH,
    96 
     95       
    9796        [0x2a] = KC_LSHIFT,
    98 
     97       
    9998        [0x2c] = KC_Z,
    10099        [0x2d] = KC_X,
     
    104103        [0x31] = KC_N,
    105104        [0x32] = KC_M,
    106 
     105       
    107106        [0x33] = KC_COMMA,
    108107        [0x34] = KC_PERIOD,
    109108        [0x35] = KC_SLASH,
    110 
     109       
    111110        [0x36] = KC_RSHIFT,
    112 
     111       
    113112        [0x1d] = KC_LCTRL,
    114113        [0x38] = KC_LALT,
    115114        [0x39] = KC_SPACE,
    116 
     115       
    117116        [0x01] = KC_ESCAPE,
    118 
     117       
    119118        [0x3b] = KC_F1,
    120119        [0x3c] = KC_F2,
     
    124123        [0x40] = KC_F6,
    125124        [0x41] = KC_F7,
    126 
     125       
    127126        [0x42] = KC_F8,
    128127        [0x43] = KC_F9,
    129128        [0x44] = KC_F10,
    130 
     129       
    131130        [0x57] = KC_F11,
    132131        [0x58] = KC_F12,
    133 
     132       
    134133        [0x46] = KC_SCROLL_LOCK,
    135 
     134       
    136135        [0x1c] = KC_ENTER,
    137 
     136       
    138137        [0x45] = KC_NUM_LOCK,
    139138        [0x37] = KC_NTIMES,
     
    153152};
    154153
    155 #define KBD_ACK   0xfa
    156 #define KBD_RESEND   0xfe
    157 #define KBD_SCANCODE_SET_EXTENDED   0xe0
     154#define KBD_ACK  0xfa
     155#define KBD_RESEND  0xfe
     156#define KBD_SCANCODE_SET_EXTENDED  0xe0
     157#define KBD_SCANCODE_SET_EXTENDED_SPECIAL  0xe1
     158
    158159/** Scancode set 1 extended codes table */
    159 static const int scanmap_e0[] = {
     160static const unsigned int scanmap_e0[] = {
    160161        [0x38] = KC_RALT,
    161162        [0x1d] = KC_RCTRL,
    162 
    163         [0x37] = KC_PRTSCR,
    164 
     163       
     164        [0x37] = KC_SYSREQ,
     165       
    165166        [0x52] = KC_INSERT,
    166167        [0x47] = KC_HOME,
    167168        [0x49] = KC_PAGE_UP,
    168 
     169       
    169170        [0x53] = KC_DELETE,
    170171        [0x4f] = KC_END,
    171172        [0x51] = KC_PAGE_DOWN,
    172 
     173       
    173174        [0x48] = KC_UP,
    174175        [0x4b] = KC_LEFT,
    175176        [0x50] = KC_DOWN,
    176177        [0x4d] = KC_RIGHT,
    177 
     178       
    178179        [0x35] = KC_NSLASH,
    179180        [0x1c] = KC_NENTER
    180181};
    181182
    182 #define KBD_CMD_SET_LEDS 0xed
     183#define KBD_CMD_SET_LEDS  0xed
     184
    183185enum led_indicators {
    184         LI_SCROLL       = 0x01,
    185         LI_NUM          = 0x02,
    186         LI_CAPS         = 0x04,
     186        LI_SCROLL = 0x01,
     187        LI_NUM    = 0x02,
     188        LI_CAPS   = 0x04
    187189};
    188190
    189 static int polling(void *);
    190 static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
    191 
    192 /** Keyboard function ops. */
    193 static ddf_dev_ops_t kbd_ops = {
    194         .default_handler = default_connection_handler
    195 };
    196 
    197 /** Initialize keyboard driver structure.
    198  * @param kbd Keyboard driver structure to initialize.
    199  * @param dev DDF device structure.
    200  *
    201  * Connects to parent, creates keyboard function, starts polling fibril.
    202  */
    203 int xt_kbd_init(xt_kbd_t *kbd, ddf_dev_t *dev)
     191static void push_event(async_sess_t *sess, kbd_event_type_t type,
     192    unsigned int key)
    204193{
     194        async_exch_t *exch = async_exchange_begin(sess);
     195        async_msg_4(exch, KBDEV_EVENT, type, key, 0, 0);
     196        async_exchange_end(exch);
     197}
     198
     199/** Get data and parse scancodes.
     200 *
     201 * @param arg Pointer to xt_kbd_t structure.
     202 *
     203 * @return EIO on error.
     204 *
     205 */
     206static int polling(void *arg)
     207{
     208        const xt_kbd_t *kbd = arg;
     209       
    205210        assert(kbd);
    206         assert(dev);
    207         kbd->client_sess = NULL;
    208         kbd->parent_sess = ddf_dev_parent_sess_create(dev, EXCHANGE_SERIALIZE);
    209         if (!kbd->parent_sess) {
    210                 ddf_msg(LVL_ERROR, "Failed creating parent session.");
    211                 return EIO;
    212         }
    213 
    214         kbd->kbd_fun = ddf_fun_create(dev, fun_exposed, "kbd");
    215         if (!kbd->kbd_fun) {
    216                 ddf_msg(LVL_ERROR, "Failed creating function 'kbd'.");
    217                 return ENOMEM;
    218         }
    219         ddf_fun_set_ops(kbd->kbd_fun, &kbd_ops);
    220 
    221         int ret = ddf_fun_bind(kbd->kbd_fun);
    222         if (ret != EOK) {
    223                 ddf_msg(LVL_ERROR, "Failed binding function 'kbd'.");
    224                 ddf_fun_destroy(kbd->kbd_fun);
    225                 return EEXIST;
    226         }
    227 
    228         ret = ddf_fun_add_to_category(kbd->kbd_fun, "keyboard");
    229         if (ret != EOK) {
    230                 ddf_msg(LVL_ERROR, "Failed adding function 'kbd' to category "
    231                     "'keyboard'.");
    232                 ddf_fun_unbind(kbd->kbd_fun);
    233                 ddf_fun_destroy(kbd->kbd_fun);
    234                 return ENOMEM;
    235         }
    236 
    237         kbd->polling_fibril = fibril_create(polling, kbd);
    238         if (!kbd->polling_fibril) {
    239                 ddf_msg(LVL_ERROR, "Failed creating polling fibril.");
    240                 ddf_fun_unbind(kbd->kbd_fun);
    241                 ddf_fun_destroy(kbd->kbd_fun);
    242                 return ENOMEM;
    243         }
    244 
    245         fibril_add_ready(kbd->polling_fibril);
    246         return EOK;
    247 }
    248 
    249 /** Get data and parse scancodes.
    250  * @param arg Pointer to xt_kbd_t structure.
    251  * @return EIO on error.
    252  */
    253 int polling(void *arg)
    254 {
    255         assert(arg);
    256         const xt_kbd_t *kbd = arg;
    257 
    258211        assert(kbd->parent_sess);
     212       
    259213        async_exch_t *parent_exch = async_exchange_begin(kbd->parent_sess);
    260         while (1) {
     214       
     215        while (true) {
    261216                if (!parent_exch)
    262217                        parent_exch = async_exchange_begin(kbd->parent_sess);
    263 
    264                 const int *map = scanmap_simple;
    265                 size_t map_size = sizeof(scanmap_simple) / sizeof(int);
    266 
     218               
     219                const unsigned int *map = scanmap_simple;
     220                size_t map_size = sizeof(scanmap_simple) / sizeof(unsigned int);
     221               
    267222                uint8_t code = 0;
    268223                ssize_t size = chardev_read(parent_exch, &code, 1);
    269224                if (size != 1)
    270225                        return EIO;
    271 
    272                 /** Ignore AT command reply */
    273                 if (code == KBD_ACK || code == KBD_RESEND) {
     226               
     227                /* Ignore AT command reply */
     228                if ((code == KBD_ACK) || (code == KBD_RESEND))
     229                        continue;
     230               
     231                /* Extended set */
     232                if (code == KBD_SCANCODE_SET_EXTENDED) {
     233                        map = scanmap_e0;
     234                        map_size = sizeof(scanmap_e0) / sizeof(unsigned int);
     235                       
     236                        size = chardev_read(parent_exch, &code, 1);
     237                        if (size != 1)
     238                                return EIO;
     239                       
     240                        /* Handle really special keys */
     241                       
     242                        if (code == 0x2a) {  /* Print Screen */
     243                                size = chardev_read(parent_exch, &code, 1);
     244                                if (size != 1)
     245                                        return EIO;
     246                               
     247                                if (code != 0xe0)
     248                                        continue;
     249                               
     250                                size = chardev_read(parent_exch, &code, 1);
     251                                if (size != 1)
     252                                        return EIO;
     253                               
     254                                if (code == 0x37)
     255                                        push_event(kbd->client_sess, KEY_PRESS, KC_PRTSCR);
     256                               
     257                                continue;
     258                        }
     259                       
     260                        if (code == 0x46) {  /* Break */
     261                                size = chardev_read(parent_exch, &code, 1);
     262                                if (size != 1)
     263                                        return EIO;
     264                               
     265                                if (code != 0xe0)
     266                                        continue;
     267                               
     268                                size = chardev_read(parent_exch, &code, 1);
     269                                if (size != 1)
     270                                        return EIO;
     271                               
     272                                if (code == 0xc6)
     273                                        push_event(kbd->client_sess, KEY_PRESS, KC_BREAK);
     274                               
     275                                continue;
     276                        }
     277                }
     278               
     279                /* Extended special set */
     280                if (code == KBD_SCANCODE_SET_EXTENDED_SPECIAL) {
     281                        size = chardev_read(parent_exch, &code, 1);
     282                        if (size != 1)
     283                                return EIO;
     284                       
     285                        if (code != 0x1d)
     286                                continue;
     287                       
     288                        size = chardev_read(parent_exch, &code, 1);
     289                        if (size != 1)
     290                                return EIO;
     291                       
     292                        if (code != 0x45)
     293                                continue;
     294                       
     295                        size = chardev_read(parent_exch, &code, 1);
     296                        if (size != 1)
     297                                return EIO;
     298                       
     299                        if (code != 0xe1)
     300                                continue;
     301                       
     302                        size = chardev_read(parent_exch, &code, 1);
     303                        if (size != 1)
     304                                return EIO;
     305                       
     306                        if (code != 0x9d)
     307                                continue;
     308                       
     309                        size = chardev_read(parent_exch, &code, 1);
     310                        if (size != 1)
     311                                return EIO;
     312                       
     313                        if (code == 0xc5)
     314                                push_event(kbd->client_sess, KEY_PRESS, KC_PAUSE);
     315                       
    274316                        continue;
    275317                }
    276 
    277                 if (code == KBD_SCANCODE_SET_EXTENDED) {
    278                         map = scanmap_e0;
    279                         map_size = sizeof(scanmap_e0) / sizeof(int);
    280                         size = chardev_read(parent_exch, &code, 1);
    281                         if (size != 1)
    282                                 return EIO;
    283 
    284                         // TODO handle print screen
    285                 }
    286 
     318               
    287319                /* Bit 7 indicates press/release */
    288320                const kbd_event_type_t type =
    289321                    (code & 0x80) ? KEY_RELEASE : KEY_PRESS;
    290322                code &= ~0x80;
    291 
    292                 const unsigned key = (code < map_size) ? map[code] : 0;
    293                 if (key != 0) {
    294                         async_exch_t *exch =
    295                             async_exchange_begin(kbd->client_sess);
    296                         if (!exch) {
    297                                 ddf_msg(LVL_ERROR,
    298                                     "Failed creating exchange.");
    299                                 continue;
    300                         }
    301                         async_msg_4(exch, KBDEV_EVENT, type, key, 0, 0);
    302                         async_exchange_end(exch);
    303                 } else {
     323               
     324                const unsigned int key = (code < map_size) ? map[code] : 0;
     325               
     326                if (key != 0)
     327                        push_event(kbd->client_sess, type, key);
     328                else
    304329                        ddf_msg(LVL_WARN, "Unknown scancode: %hhx", code);
    305                 }
    306330        }
    307331}
     
    309333/** Default handler for IPC methods not handled by DDF.
    310334 *
    311  * @param fun Device function handling the call.
     335 * @param fun     Device function handling the call.
    312336 * @param icallid Call id.
    313  * @param icall Call data.
    314  */
    315 void default_connection_handler(ddf_fun_t *fun,
     337 * @param icall   Call data.
     338 *
     339 */
     340static void default_connection_handler(ddf_fun_t *fun,
    316341    ipc_callid_t icallid, ipc_call_t *icall)
    317342{
     
    321346        switch (method) {
    322347        case KBDEV_SET_IND: {
    323                 /* XT keyboards do not support setting mods,
    324                  * assume AT keyboard with Scan Code Set 1 */
     348                /*
     349                 * XT keyboards do not support setting mods,
     350                 * assume AT keyboard with Scan Code Set 1.
     351                 */
    325352                const unsigned mods = IPC_GET_ARG1(*icall);
    326353                const uint8_t status = 0 |
     
    329356                    ((mods & KM_SCROLL_LOCK) ? LI_SCROLL : 0);
    330357                uint8_t cmds[] = { KBD_CMD_SET_LEDS, status };
     358               
    331359                async_exch_t *exch = async_exchange_begin(kbd->parent_sess);
    332360                const ssize_t size = chardev_write(exch, cmds, sizeof(cmds));
    333361                async_exchange_end(exch);
     362               
    334363                async_answer_0(icallid, size < 0 ? size : EOK);
    335364                break;
    336365        }
    337         /* This might be ugly but async_callback_receive_start makes no
    338          * difference for incorrect call and malloc failure. */
     366        /*
     367         * This might be ugly but async_callback_receive_start makes no
     368         * difference for incorrect call and malloc failure.
     369         */
    339370        case IPC_M_CONNECT_TO_ME: {
    340371                async_sess_t *sess =
    341372                    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
     373               
    342374                /* Probably ENOMEM error, try again. */
    343375                if (sess == NULL) {
     
    347379                        break;
    348380                }
     381               
    349382                if (kbd->client_sess == NULL) {
    350383                        kbd->client_sess = sess;
     
    355388                        async_answer_0(icallid, ELIMIT);
    356389                }
     390               
    357391                break;
    358392        }
    359393        default:
    360                         ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method);
    361                         async_answer_0(icallid, EINVAL);
    362                         break;
     394                ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method);
     395                async_answer_0(icallid, EINVAL);
     396                break;
    363397        }
    364398}
     399
     400/** Keyboard function ops. */
     401static ddf_dev_ops_t kbd_ops = {
     402        .default_handler = default_connection_handler
     403};
     404
     405/** Initialize keyboard driver structure.
     406 *
     407 * @param kbd Keyboard driver structure to initialize.
     408 * @param dev DDF device structure.
     409 *
     410 * Connects to parent, creates keyboard function, starts polling fibril.
     411 *
     412 */
     413int xt_kbd_init(xt_kbd_t *kbd, ddf_dev_t *dev)
     414{
     415        assert(kbd);
     416        assert(dev);
     417       
     418        kbd->client_sess = NULL;
     419        kbd->parent_sess = ddf_dev_parent_sess_create(dev, EXCHANGE_SERIALIZE);
     420       
     421        if (!kbd->parent_sess) {
     422                ddf_msg(LVL_ERROR, "Failed creating parent session.");
     423                return EIO;
     424        }
     425       
     426        kbd->kbd_fun = ddf_fun_create(dev, fun_exposed, "kbd");
     427        if (!kbd->kbd_fun) {
     428                ddf_msg(LVL_ERROR, "Failed creating function 'kbd'.");
     429                return ENOMEM;
     430        }
     431       
     432        ddf_fun_set_ops(kbd->kbd_fun, &kbd_ops);
     433       
     434        int ret = ddf_fun_bind(kbd->kbd_fun);
     435        if (ret != EOK) {
     436                ddf_msg(LVL_ERROR, "Failed binding function 'kbd'.");
     437                ddf_fun_destroy(kbd->kbd_fun);
     438                return EEXIST;
     439        }
     440       
     441        ret = ddf_fun_add_to_category(kbd->kbd_fun, "keyboard");
     442        if (ret != EOK) {
     443                ddf_msg(LVL_ERROR, "Failed adding function 'kbd' to category "
     444                    "'keyboard'.");
     445                ddf_fun_unbind(kbd->kbd_fun);
     446                ddf_fun_destroy(kbd->kbd_fun);
     447                return ENOMEM;
     448        }
     449       
     450        kbd->polling_fibril = fibril_create(polling, kbd);
     451        if (!kbd->polling_fibril) {
     452                ddf_msg(LVL_ERROR, "Failed creating polling fibril.");
     453                ddf_fun_unbind(kbd->kbd_fun);
     454                ddf_fun_destroy(kbd->kbd_fun);
     455                return ENOMEM;
     456        }
     457       
     458        fibril_add_ready(kbd->polling_fibril);
     459        return EOK;
     460}
Note: See TracChangeset for help on using the changeset viewer.