Ignore:
File:
1 edited

Legend:

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

    r56fd7cf rf9b2cb4c  
    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
     
    3637#include <ddf/log.h>
    3738#include <io/keycode.h>
     39#include <io/chardev.h>
    3840#include <io/console.h>
    3941#include <ipc/kbdev.h>
    4042#include <abi/ipc/methods.h>
    41 
    42 #include "chardev.h"
    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,
    161         [0x1d] = KC_RSHIFT,
    162 
    163         [0x37] = KC_PRTSCR,
    164 
     162        [0x1d] = KC_RCTRL,
     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 mouse 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                 return ENOMEM;
    211 
    212         kbd->kbd_fun = ddf_fun_create(dev, fun_exposed, "kbd");
    213         if (!kbd->kbd_fun) {
    214                 return ENOMEM;
    215         }
    216         ddf_fun_set_ops(kbd->kbd_fun, &kbd_ops);
    217 
    218         int ret = ddf_fun_bind(kbd->kbd_fun);
    219         if (ret != EOK) {
    220                 ddf_fun_destroy(kbd->kbd_fun);
    221                 return ENOMEM;
    222         }
    223 
    224         ret = ddf_fun_add_to_category(kbd->kbd_fun, "keyboard");
    225         if (ret != EOK) {
    226                 ddf_fun_unbind(kbd->kbd_fun);
    227                 ddf_fun_destroy(kbd->kbd_fun);
    228                 return ENOMEM;
    229         }
    230 
    231         kbd->polling_fibril = fibril_create(polling, kbd);
    232         if (!kbd->polling_fibril) {
    233                 ddf_fun_unbind(kbd->kbd_fun);
    234                 ddf_fun_destroy(kbd->kbd_fun);
    235                 return ENOMEM;
    236         }
    237         fibril_add_ready(kbd->polling_fibril);
    238         return EOK;
    239 }
    240 
    241 /** Get data and parse scancodes.
    242  * @param arg Pointer to xt_kbd_t structure.
    243  * @return Never.
    244  */
    245 int polling(void *arg)
    246 {
    247         assert(arg);
    248         const xt_kbd_t *kbd = arg;
    249 
    250211        assert(kbd->parent_sess);
     212       
    251213        async_exch_t *parent_exch = async_exchange_begin(kbd->parent_sess);
    252         while (1) {
     214       
     215        while (true) {
    253216                if (!parent_exch)
    254217                        parent_exch = async_exchange_begin(kbd->parent_sess);
    255 
    256                 const int *map = scanmap_simple;
    257                 size_t map_size = sizeof(scanmap_simple) / sizeof(int);
    258 
     218               
     219                const unsigned int *map = scanmap_simple;
     220                size_t map_size = sizeof(scanmap_simple) / sizeof(unsigned int);
     221               
    259222                uint8_t code = 0;
    260223                ssize_t size = chardev_read(parent_exch, &code, 1);
    261 
    262                 /** Ignore AT command reply */
    263                 if (code == KBD_ACK || code == KBD_RESEND) {
     224                if (size != 1)
     225                        return EIO;
     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                       
    264316                        continue;
    265317                }
    266 
    267                 if (code == KBD_SCANCODE_SET_EXTENDED) {
    268                         map = scanmap_e0;
    269                         map_size = sizeof(scanmap_e0) / sizeof(int);
    270                         size = chardev_read(parent_exch, &code, 1);
    271                         // TODO handle print screen
    272                 }
    273 
    274                 /* Invalid read. */
    275                 if (size != 1) {
    276                         continue;
    277                 }
    278 
    279 
     318               
    280319                /* Bit 7 indicates press/release */
    281320                const kbd_event_type_t type =
    282321                    (code & 0x80) ? KEY_RELEASE : KEY_PRESS;
    283322                code &= ~0x80;
    284 
    285                 const unsigned key = (code < map_size) ? map[code] : 0;
    286                 if (key != 0) {
    287                         async_exch_t *exch =
    288                             async_exchange_begin(kbd->client_sess);
    289                         if (!exch) {
    290                                 ddf_msg(LVL_ERROR,
    291                                     "Failed creating exchange.");
    292                                 continue;
    293                         }
    294                         async_msg_4(exch, KBDEV_EVENT, type, key, 0, 0);
    295                         async_exchange_end(exch);
    296                 } 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
    297329                        ddf_msg(LVL_WARN, "Unknown scancode: %hhx", code);
    298                 }
    299330        }
    300331}
     
    302333/** Default handler for IPC methods not handled by DDF.
    303334 *
    304  * @param fun Device function handling the call.
     335 * @param fun     Device function handling the call.
    305336 * @param icallid Call id.
    306  * @param icall Call data.
    307  */
    308 void default_connection_handler(ddf_fun_t *fun,
     337 * @param icall   Call data.
     338 *
     339 */
     340static void default_connection_handler(ddf_fun_t *fun,
    309341    ipc_callid_t icallid, ipc_call_t *icall)
    310342{
     
    314346        switch (method) {
    315347        case KBDEV_SET_IND: {
    316                 /* XT keyboards do not support setting mods,
    317                  * 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                 */
    318352                const unsigned mods = IPC_GET_ARG1(*icall);
    319353                const uint8_t status = 0 |
     
    322356                    ((mods & KM_SCROLL_LOCK) ? LI_SCROLL : 0);
    323357                uint8_t cmds[] = { KBD_CMD_SET_LEDS, status };
     358               
    324359                async_exch_t *exch = async_exchange_begin(kbd->parent_sess);
    325360                const ssize_t size = chardev_write(exch, cmds, sizeof(cmds));
    326361                async_exchange_end(exch);
     362               
    327363                async_answer_0(icallid, size < 0 ? size : EOK);
    328364                break;
    329365        }
    330         /* This might be ugly but async_callback_receive_start makes no
    331          * 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         */
    332370        case IPC_M_CONNECT_TO_ME: {
    333371                async_sess_t *sess =
    334372                    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
     373               
    335374                /* Probably ENOMEM error, try again. */
    336375                if (sess == NULL) {
     
    340379                        break;
    341380                }
     381               
    342382                if (kbd->client_sess == NULL) {
    343383                        kbd->client_sess = sess;
     
    348388                        async_answer_0(icallid, ELIMIT);
    349389                }
     390               
    350391                break;
    351392        }
    352393        default:
    353                         ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method);
    354                         async_answer_0(icallid, EINVAL);
    355                         break;
     394                ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method);
     395                async_answer_0(icallid, EINVAL);
     396                break;
    356397        }
    357398}
     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);
     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.