Ignore:
File:
1 edited

Legend:

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

    rf9b2cb4c r56fd7cf  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 
    2928/** @addtogroup drvkbd
    3029 * @{
    3130 */
    3231/** @file
    33  * @brief XT keyboard driver
     32 * @brief XT keyboard driver;
    3433 */
    3534
     
    3736#include <ddf/log.h>
    3837#include <io/keycode.h>
    39 #include <io/chardev.h>
    4038#include <io/console.h>
    4139#include <ipc/kbdev.h>
    4240#include <abi/ipc/methods.h>
     41
     42#include "chardev.h"
    4343#include "xtkbd.h"
    4444
    4545/** Scancode set 1 table. */
    46 static const unsigned int scanmap_simple[] = {
     46static const int scanmap_simple[] = {
     47
    4748        [0x29] = KC_BACKTICK,
    48        
     49
    4950        [0x02] = KC_1,
    5051        [0x03] = KC_2,
     
    5758        [0x0a] = KC_9,
    5859        [0x0b] = KC_0,
    59        
     60
    6061        [0x0c] = KC_MINUS,
    6162        [0x0d] = KC_EQUALS,
    6263        [0x0e] = KC_BACKSPACE,
    63        
     64
    6465        [0x0f] = KC_TAB,
    65        
     66
    6667        [0x10] = KC_Q,
    6768        [0x11] = KC_W,
     
    7475        [0x18] = KC_O,
    7576        [0x19] = KC_P,
    76        
     77
    7778        [0x1a] = KC_LBRACKET,
    7879        [0x1b] = KC_RBRACKET,
    79        
     80
    8081        [0x3a] = KC_CAPS_LOCK,
    81        
     82
    8283        [0x1e] = KC_A,
    8384        [0x1f] = KC_S,
     
    8990        [0x25] = KC_K,
    9091        [0x26] = KC_L,
    91        
     92
    9293        [0x27] = KC_SEMICOLON,
    9394        [0x28] = KC_QUOTE,
    9495        [0x2b] = KC_BACKSLASH,
    95        
     96
    9697        [0x2a] = KC_LSHIFT,
    97        
     98
    9899        [0x2c] = KC_Z,
    99100        [0x2d] = KC_X,
     
    103104        [0x31] = KC_N,
    104105        [0x32] = KC_M,
    105        
     106
    106107        [0x33] = KC_COMMA,
    107108        [0x34] = KC_PERIOD,
    108109        [0x35] = KC_SLASH,
    109        
     110
    110111        [0x36] = KC_RSHIFT,
    111        
     112
    112113        [0x1d] = KC_LCTRL,
    113114        [0x38] = KC_LALT,
    114115        [0x39] = KC_SPACE,
    115        
     116
    116117        [0x01] = KC_ESCAPE,
    117        
     118
    118119        [0x3b] = KC_F1,
    119120        [0x3c] = KC_F2,
     
    123124        [0x40] = KC_F6,
    124125        [0x41] = KC_F7,
    125        
     126
    126127        [0x42] = KC_F8,
    127128        [0x43] = KC_F9,
    128129        [0x44] = KC_F10,
    129        
     130
    130131        [0x57] = KC_F11,
    131132        [0x58] = KC_F12,
    132        
     133
    133134        [0x46] = KC_SCROLL_LOCK,
    134        
     135
    135136        [0x1c] = KC_ENTER,
    136        
     137
    137138        [0x45] = KC_NUM_LOCK,
    138139        [0x37] = KC_NTIMES,
     
    152153};
    153154
    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 
     155#define KBD_ACK   0xfa
     156#define KBD_RESEND   0xfe
     157#define KBD_SCANCODE_SET_EXTENDED   0xe0
    159158/** Scancode set 1 extended codes table */
    160 static const unsigned int scanmap_e0[] = {
     159static const int scanmap_e0[] = {
    161160        [0x38] = KC_RALT,
    162         [0x1d] = KC_RCTRL,
    163        
    164         [0x37] = KC_SYSREQ,
    165        
     161        [0x1d] = KC_RSHIFT,
     162
     163        [0x37] = KC_PRTSCR,
     164
    166165        [0x52] = KC_INSERT,
    167166        [0x47] = KC_HOME,
    168167        [0x49] = KC_PAGE_UP,
    169        
     168
    170169        [0x53] = KC_DELETE,
    171170        [0x4f] = KC_END,
    172171        [0x51] = KC_PAGE_DOWN,
    173        
     172
    174173        [0x48] = KC_UP,
    175174        [0x4b] = KC_LEFT,
    176175        [0x50] = KC_DOWN,
    177176        [0x4d] = KC_RIGHT,
    178        
     177
    179178        [0x35] = KC_NSLASH,
    180179        [0x1c] = KC_NENTER
    181180};
    182181
    183 #define KBD_CMD_SET_LEDS  0xed
    184 
     182#define KBD_CMD_SET_LEDS 0xed
    185183enum led_indicators {
    186         LI_SCROLL = 0x01,
    187         LI_NUM    = 0x02,
    188         LI_CAPS   = 0x04
     184        LI_SCROLL       = 0x01,
     185        LI_NUM          = 0x02,
     186        LI_CAPS         = 0x04,
    189187};
    190188
    191 static void push_event(async_sess_t *sess, kbd_event_type_t type,
    192     unsigned int key)
     189static int polling(void *);
     190static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
     191
     192/** Keyboard function ops. */
     193static 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 */
     203int xt_kbd_init(xt_kbd_t *kbd, ddf_dev_t *dev)
    193204{
    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);
     205        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;
    197239}
    198240
    199241/** Get data and parse scancodes.
    200  *
    201242 * @param arg Pointer to xt_kbd_t structure.
    202  *
    203  * @return EIO on error.
    204  *
    205  */
    206 static int polling(void *arg)
     243 * @return Never.
     244 */
     245int polling(void *arg)
    207246{
     247        assert(arg);
    208248        const xt_kbd_t *kbd = arg;
    209        
    210         assert(kbd);
     249
    211250        assert(kbd->parent_sess);
    212        
    213251        async_exch_t *parent_exch = async_exchange_begin(kbd->parent_sess);
    214        
    215         while (true) {
     252        while (1) {
    216253                if (!parent_exch)
    217254                        parent_exch = async_exchange_begin(kbd->parent_sess);
    218                
    219                 const unsigned int *map = scanmap_simple;
    220                 size_t map_size = sizeof(scanmap_simple) / sizeof(unsigned int);
    221                
     255
     256                const int *map = scanmap_simple;
     257                size_t map_size = sizeof(scanmap_simple) / sizeof(int);
     258
    222259                uint8_t code = 0;
    223260                ssize_t size = chardev_read(parent_exch, &code, 1);
    224                 if (size != 1)
    225                         return EIO;
    226                
    227                 /* Ignore AT command reply */
    228                 if ((code == KBD_ACK) || (code == KBD_RESEND))
     261
     262                /** Ignore AT command reply */
     263                if (code == KBD_ACK || code == KBD_RESEND) {
    229264                        continue;
    230                
    231                 /* Extended set */
     265                }
     266
    232267                if (code == KBD_SCANCODE_SET_EXTENDED) {
    233268                        map = scanmap_e0;
    234                         map_size = sizeof(scanmap_e0) / sizeof(unsigned int);
    235                        
     269                        map_size = sizeof(scanmap_e0) / sizeof(int);
    236270                        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                        
     271                        // TODO handle print screen
     272                }
     273
     274                /* Invalid read. */
     275                if (size != 1) {
    316276                        continue;
    317277                }
    318                
     278
     279
    319280                /* Bit 7 indicates press/release */
    320281                const kbd_event_type_t type =
    321282                    (code & 0x80) ? KEY_RELEASE : KEY_PRESS;
    322283                code &= ~0x80;
    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
     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 {
    329297                        ddf_msg(LVL_WARN, "Unknown scancode: %hhx", code);
     298                }
    330299        }
    331300}
     
    333302/** Default handler for IPC methods not handled by DDF.
    334303 *
    335  * @param fun     Device function handling the call.
     304 * @param fun Device function handling the call.
    336305 * @param icallid Call id.
    337  * @param icall   Call data.
    338  *
    339  */
    340 static void default_connection_handler(ddf_fun_t *fun,
     306 * @param icall Call data.
     307 */
     308void default_connection_handler(ddf_fun_t *fun,
    341309    ipc_callid_t icallid, ipc_call_t *icall)
    342310{
     
    346314        switch (method) {
    347315        case KBDEV_SET_IND: {
    348                 /*
    349                  * XT keyboards do not support setting mods,
    350                  * assume AT keyboard with Scan Code Set 1.
    351                  */
     316                /* XT keyboards do not support setting mods,
     317                 * assume AT keyboard with Scan Code Set 1 */
    352318                const unsigned mods = IPC_GET_ARG1(*icall);
    353319                const uint8_t status = 0 |
     
    356322                    ((mods & KM_SCROLL_LOCK) ? LI_SCROLL : 0);
    357323                uint8_t cmds[] = { KBD_CMD_SET_LEDS, status };
    358                
    359324                async_exch_t *exch = async_exchange_begin(kbd->parent_sess);
    360325                const ssize_t size = chardev_write(exch, cmds, sizeof(cmds));
    361326                async_exchange_end(exch);
    362                
    363327                async_answer_0(icallid, size < 0 ? size : EOK);
    364328                break;
    365329        }
    366         /*
    367          * This might be ugly but async_callback_receive_start makes no
    368          * difference for incorrect call and malloc failure.
    369          */
     330        /* This might be ugly but async_callback_receive_start makes no
     331         * difference for incorrect call and malloc failure. */
    370332        case IPC_M_CONNECT_TO_ME: {
    371333                async_sess_t *sess =
    372334                    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
    373                
    374335                /* Probably ENOMEM error, try again. */
    375336                if (sess == NULL) {
     
    379340                        break;
    380341                }
    381                
    382342                if (kbd->client_sess == NULL) {
    383343                        kbd->client_sess = sess;
     
    388348                        async_answer_0(icallid, ELIMIT);
    389349                }
    390                
    391350                break;
    392351        }
    393352        default:
    394                 ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method);
    395                 async_answer_0(icallid, EINVAL);
    396                 break;
     353                        ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method);
     354                        async_answer_0(icallid, EINVAL);
     355                        break;
    397356        }
    398357}
    399 
    400 /** Keyboard function ops. */
    401 static 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  */
    413 int 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.