Changes in uspace/drv/char/xtkbd/xtkbd.c [56fd7cf:f9b2cb4c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/char/xtkbd/xtkbd.c
r56fd7cf rf9b2cb4c 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 28 29 /** @addtogroup drvkbd 29 30 * @{ 30 31 */ 31 32 /** @file 32 * @brief XT keyboard driver ;33 * @brief XT keyboard driver 33 34 */ 34 35 … … 36 37 #include <ddf/log.h> 37 38 #include <io/keycode.h> 39 #include <io/chardev.h> 38 40 #include <io/console.h> 39 41 #include <ipc/kbdev.h> 40 42 #include <abi/ipc/methods.h> 41 42 #include "chardev.h"43 43 #include "xtkbd.h" 44 44 45 45 /** Scancode set 1 table. */ 46 static const int scanmap_simple[] = { 47 46 static const unsigned int scanmap_simple[] = { 48 47 [0x29] = KC_BACKTICK, 49 48 50 49 [0x02] = KC_1, 51 50 [0x03] = KC_2, … … 58 57 [0x0a] = KC_9, 59 58 [0x0b] = KC_0, 60 59 61 60 [0x0c] = KC_MINUS, 62 61 [0x0d] = KC_EQUALS, 63 62 [0x0e] = KC_BACKSPACE, 64 63 65 64 [0x0f] = KC_TAB, 66 65 67 66 [0x10] = KC_Q, 68 67 [0x11] = KC_W, … … 75 74 [0x18] = KC_O, 76 75 [0x19] = KC_P, 77 76 78 77 [0x1a] = KC_LBRACKET, 79 78 [0x1b] = KC_RBRACKET, 80 79 81 80 [0x3a] = KC_CAPS_LOCK, 82 81 83 82 [0x1e] = KC_A, 84 83 [0x1f] = KC_S, … … 90 89 [0x25] = KC_K, 91 90 [0x26] = KC_L, 92 91 93 92 [0x27] = KC_SEMICOLON, 94 93 [0x28] = KC_QUOTE, 95 94 [0x2b] = KC_BACKSLASH, 96 95 97 96 [0x2a] = KC_LSHIFT, 98 97 99 98 [0x2c] = KC_Z, 100 99 [0x2d] = KC_X, … … 104 103 [0x31] = KC_N, 105 104 [0x32] = KC_M, 106 105 107 106 [0x33] = KC_COMMA, 108 107 [0x34] = KC_PERIOD, 109 108 [0x35] = KC_SLASH, 110 109 111 110 [0x36] = KC_RSHIFT, 112 111 113 112 [0x1d] = KC_LCTRL, 114 113 [0x38] = KC_LALT, 115 114 [0x39] = KC_SPACE, 116 115 117 116 [0x01] = KC_ESCAPE, 118 117 119 118 [0x3b] = KC_F1, 120 119 [0x3c] = KC_F2, … … 124 123 [0x40] = KC_F6, 125 124 [0x41] = KC_F7, 126 125 127 126 [0x42] = KC_F8, 128 127 [0x43] = KC_F9, 129 128 [0x44] = KC_F10, 130 129 131 130 [0x57] = KC_F11, 132 131 [0x58] = KC_F12, 133 132 134 133 [0x46] = KC_SCROLL_LOCK, 135 134 136 135 [0x1c] = KC_ENTER, 137 136 138 137 [0x45] = KC_NUM_LOCK, 139 138 [0x37] = KC_NTIMES, … … 153 152 }; 154 153 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 158 159 /** Scancode set 1 extended codes table */ 159 static const int scanmap_e0[] = {160 static const unsigned int scanmap_e0[] = { 160 161 [0x38] = KC_RALT, 161 [0x1d] = KC_R SHIFT,162 163 [0x37] = KC_ PRTSCR,164 162 [0x1d] = KC_RCTRL, 163 164 [0x37] = KC_SYSREQ, 165 165 166 [0x52] = KC_INSERT, 166 167 [0x47] = KC_HOME, 167 168 [0x49] = KC_PAGE_UP, 168 169 169 170 [0x53] = KC_DELETE, 170 171 [0x4f] = KC_END, 171 172 [0x51] = KC_PAGE_DOWN, 172 173 173 174 [0x48] = KC_UP, 174 175 [0x4b] = KC_LEFT, 175 176 [0x50] = KC_DOWN, 176 177 [0x4d] = KC_RIGHT, 177 178 178 179 [0x35] = KC_NSLASH, 179 180 [0x1c] = KC_NENTER 180 181 }; 181 182 182 #define KBD_CMD_SET_LEDS 0xed 183 #define KBD_CMD_SET_LEDS 0xed 184 183 185 enum led_indicators { 184 LI_SCROLL 185 LI_NUM 186 LI_CAPS = 0x04,186 LI_SCROLL = 0x01, 187 LI_NUM = 0x02, 188 LI_CAPS = 0x04 187 189 }; 188 190 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) 191 static void push_event(async_sess_t *sess, kbd_event_type_t type, 192 unsigned int key) 204 193 { 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 */ 206 static int polling(void *arg) 207 { 208 const xt_kbd_t *kbd = arg; 209 205 210 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 250 211 assert(kbd->parent_sess); 212 251 213 async_exch_t *parent_exch = async_exchange_begin(kbd->parent_sess); 252 while (1) { 214 215 while (true) { 253 216 if (!parent_exch) 254 217 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 259 222 uint8_t code = 0; 260 223 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 264 316 continue; 265 317 } 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 280 319 /* Bit 7 indicates press/release */ 281 320 const kbd_event_type_t type = 282 321 (code & 0x80) ? KEY_RELEASE : KEY_PRESS; 283 322 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 297 329 ddf_msg(LVL_WARN, "Unknown scancode: %hhx", code); 298 }299 330 } 300 331 } … … 302 333 /** Default handler for IPC methods not handled by DDF. 303 334 * 304 * @param fun Device function handling the call.335 * @param fun Device function handling the call. 305 336 * @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 */ 340 static void default_connection_handler(ddf_fun_t *fun, 309 341 ipc_callid_t icallid, ipc_call_t *icall) 310 342 { … … 314 346 switch (method) { 315 347 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 */ 318 352 const unsigned mods = IPC_GET_ARG1(*icall); 319 353 const uint8_t status = 0 | … … 322 356 ((mods & KM_SCROLL_LOCK) ? LI_SCROLL : 0); 323 357 uint8_t cmds[] = { KBD_CMD_SET_LEDS, status }; 358 324 359 async_exch_t *exch = async_exchange_begin(kbd->parent_sess); 325 360 const ssize_t size = chardev_write(exch, cmds, sizeof(cmds)); 326 361 async_exchange_end(exch); 362 327 363 async_answer_0(icallid, size < 0 ? size : EOK); 328 364 break; 329 365 } 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 */ 332 370 case IPC_M_CONNECT_TO_ME: { 333 371 async_sess_t *sess = 334 372 async_callback_receive_start(EXCHANGE_SERIALIZE, icall); 373 335 374 /* Probably ENOMEM error, try again. */ 336 375 if (sess == NULL) { … … 340 379 break; 341 380 } 381 342 382 if (kbd->client_sess == NULL) { 343 383 kbd->client_sess = sess; … … 348 388 async_answer_0(icallid, ELIMIT); 349 389 } 390 350 391 break; 351 392 } 352 393 default: 353 354 355 394 ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method); 395 async_answer_0(icallid, EINVAL); 396 break; 356 397 } 357 398 } 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.