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