Changes in uspace/drv/usbhid/lgtch-ultrax/lgtch-ultrax.c [e3b5129:b20de1d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/usbhid/lgtch-ultrax/lgtch-ultrax.c
re3b5129 rb20de1d 38 38 #include "lgtch-ultrax.h" 39 39 #include "../usbhid.h" 40 #include "keymap.h" 40 41 41 42 #include <usb/classes/hidparser.h> 42 43 #include <usb/debug.h> 44 #include <usb/classes/hidut.h> 45 43 46 #include <errno.h> 44 47 #include <str_error.h> 45 48 49 #include <ipc/kbd.h> 50 #include <io/console.h> 51 46 52 #define NAME "lgtch-ultrax" 47 53 48 /*----------------------------------------------------------------------------*/ 49 50 static void usb_lgtch_process_keycodes(const uint8_t *key_codes, size_t count, 51 uint8_t report_id, void *arg); 52 53 static const usb_hid_report_in_callbacks_t usb_lgtch_parser_callbacks = { 54 .keyboard = usb_lgtch_process_keycodes 54 typedef enum usb_lgtch_flags { 55 USB_LGTCH_STATUS_UNINITIALIZED = 0, 56 USB_LGTCH_STATUS_INITIALIZED = 1, 57 USB_LGTCH_STATUS_TO_DESTROY = -1 58 } usb_lgtch_flags; 59 60 61 /*----------------------------------------------------------------------------*/ 62 /** 63 * Default handler for IPC methods not handled by DDF. 64 * 65 * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it 66 * assumes the caller is the console and thus it stores IPC phone to it for 67 * later use by the driver to notify about key events. 68 * 69 * @param fun Device function handling the call. 70 * @param icallid Call id. 71 * @param icall Call data. 72 */ 73 static void default_connection_handler(ddf_fun_t *fun, 74 ipc_callid_t icallid, ipc_call_t *icall) 75 { 76 usb_log_debug(NAME " default_connection_handler()\n"); 77 78 sysarg_t method = IPC_GET_IMETHOD(*icall); 79 80 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data; 81 82 if (hid_dev == NULL || hid_dev->data == NULL) { 83 async_answer_0(icallid, EINVAL); 84 return; 85 } 86 87 assert(hid_dev != NULL); 88 assert(hid_dev->data != NULL); 89 usb_lgtch_ultrax_t *lgtch_dev = (usb_lgtch_ultrax_t *)hid_dev->data; 90 91 if (method == IPC_M_CONNECT_TO_ME) { 92 int callback = IPC_GET_ARG5(*icall); 93 94 if (lgtch_dev->console_phone != -1) { 95 async_answer_0(icallid, ELIMIT); 96 return; 97 } 98 99 lgtch_dev->console_phone = callback; 100 usb_log_debug(NAME " Saved phone to console: %d\n", callback); 101 async_answer_0(icallid, EOK); 102 return; 103 } 104 105 async_answer_0(icallid, EINVAL); 106 } 107 108 /*----------------------------------------------------------------------------*/ 109 110 static ddf_dev_ops_t lgtch_ultrax_ops = { 111 .default_handler = default_connection_handler 55 112 }; 56 113 57 114 /*----------------------------------------------------------------------------*/ 58 115 59 static void usb_lgtch_process_keycodes(const uint8_t *key_codes, size_t count, 60 uint8_t report_id, void *arg) 61 { 62 // TODO: checks 63 64 usb_log_debug(NAME " Got keys from parser (report id: %u): %s\n", 65 report_id, usb_debug_str_buffer(key_codes, count, 0)); 116 //static void usb_lgtch_process_keycodes(const uint8_t *key_codes, size_t count, 117 // uint8_t report_id, void *arg); 118 119 //static const usb_hid_report_in_callbacks_t usb_lgtch_parser_callbacks = { 120 // .keyboard = usb_lgtch_process_keycodes 121 //}; 122 123 ///*----------------------------------------------------------------------------*/ 124 125 //static void usb_lgtch_process_keycodes(const uint8_t *key_codes, size_t count, 126 // uint8_t report_id, void *arg) 127 //{ 128 // // TODO: checks 129 130 // usb_log_debug(NAME " Got keys from parser (report id: %u): %s\n", 131 // report_id, usb_debug_str_buffer(key_codes, count, 0)); 132 //} 133 134 /*----------------------------------------------------------------------------*/ 135 /** 136 * Processes key events. 137 * 138 * @note This function was copied from AT keyboard driver and modified to suit 139 * USB keyboard. 140 * 141 * @note Lock keys are not sent to the console, as they are completely handled 142 * in the driver. It may, however, be required later that the driver 143 * sends also these keys to application (otherwise it cannot use those 144 * keys at all). 145 * 146 * @param hid_dev 147 * @param lgtch_dev 148 * @param type Type of the event (press / release). Recognized values: 149 * KEY_PRESS, KEY_RELEASE 150 * @param key Key code of the key according to HID Usage Tables. 151 */ 152 static void usb_lgtch_push_ev(usb_hid_dev_t *hid_dev, int type, 153 unsigned int key) 154 { 155 assert(hid_dev != NULL); 156 assert(hid_dev->data != NULL); 157 158 usb_lgtch_ultrax_t *lgtch_dev = (usb_lgtch_ultrax_t *)hid_dev->data; 159 160 console_event_t ev; 161 162 ev.type = type; 163 ev.key = key; 164 ev.mods = 0; 165 166 ev.c = 0; 167 168 usb_log_debug2(NAME " Sending key %d to the console\n", ev.key); 169 if (lgtch_dev->console_phone < 0) { 170 usb_log_warning( 171 "Connection to console not ready, key discarded.\n"); 172 return; 173 } 174 175 async_msg_4(lgtch_dev->console_phone, KBD_EVENT, ev.type, ev.key, 176 ev.mods, ev.c); 177 } 178 179 /*----------------------------------------------------------------------------*/ 180 181 static void usb_lgtch_free(usb_lgtch_ultrax_t **lgtch_dev) 182 { 183 if (lgtch_dev == NULL || *lgtch_dev == NULL) { 184 return; 185 } 186 187 // hangup phone to the console 188 async_hangup((*lgtch_dev)->console_phone); 189 190 // if ((*lgtch_dev)->repeat_mtx != NULL) { 191 // /* TODO: replace by some check and wait */ 192 // assert(!fibril_mutex_is_locked((*lgtch_dev)->repeat_mtx)); 193 // free((*lgtch_dev)->repeat_mtx); 194 // } 195 196 // free all buffers 197 if ((*lgtch_dev)->keys != NULL) { 198 free((*lgtch_dev)->keys); 199 } 200 if ((*lgtch_dev)->keys_old != NULL) { 201 free((*lgtch_dev)->keys_old); 202 } 203 204 free(*lgtch_dev); 205 *lgtch_dev = NULL; 206 } 207 208 /*----------------------------------------------------------------------------*/ 209 210 int usb_lgtch_init(struct usb_hid_dev *hid_dev) 211 { 212 if (hid_dev == NULL || hid_dev->usb_dev == NULL) { 213 return EINVAL; /*! @todo Other return code? */ 214 } 215 216 usb_log_debug(NAME " Initializing HID/lgtch_ultrax structure...\n"); 217 218 usb_lgtch_ultrax_t *lgtch_dev = (usb_lgtch_ultrax_t *)malloc( 219 sizeof(usb_lgtch_ultrax_t)); 220 if (lgtch_dev == NULL) { 221 return ENOMEM; 222 } 223 224 lgtch_dev->console_phone = -1; 225 226 usb_hid_report_path_t *path = usb_hid_report_path(); 227 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0); 228 229 usb_hid_report_path_set_report_id(path, 1); 230 231 lgtch_dev->key_count = usb_hid_report_input_length( 232 hid_dev->report, path, 233 USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY); 234 usb_hid_report_path_free(path); 235 236 usb_log_debug(NAME " Size of the input report: %zu\n", 237 lgtch_dev->key_count); 238 239 lgtch_dev->keys = (int32_t *)calloc(lgtch_dev->key_count, 240 sizeof(int32_t)); 241 242 if (lgtch_dev->keys == NULL) { 243 usb_log_fatal("No memory!\n"); 244 free(lgtch_dev); 245 return ENOMEM; 246 } 247 248 lgtch_dev->keys_old = 249 (int32_t *)calloc(lgtch_dev->key_count, sizeof(int32_t)); 250 251 if (lgtch_dev->keys_old == NULL) { 252 usb_log_fatal("No memory!\n"); 253 free(lgtch_dev->keys); 254 free(lgtch_dev); 255 return ENOMEM; 256 } 257 258 /*! @todo Autorepeat */ 259 260 // save the KBD device structure into the HID device structure 261 hid_dev->data = lgtch_dev; 262 263 /* Create the function exposed under /dev/devices. */ 264 ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 265 NAME); 266 if (fun == NULL) { 267 usb_log_error("Could not create DDF function node.\n"); 268 return ENOMEM; 269 } 270 271 lgtch_dev->initialized = USB_LGTCH_STATUS_INITIALIZED; 272 usb_log_debug(NAME " HID/lgtch_ultrax device structure initialized.\n"); 273 274 /* 275 * Store the initialized HID device and HID ops 276 * to the DDF function. 277 */ 278 fun->ops = &lgtch_ultrax_ops; 279 fun->driver_data = hid_dev; // TODO: maybe change to hid_dev->data 280 281 /* 282 * 1) subdriver vytvori vlastnu ddf_fun, vlastne ddf_dev_ops, ktore da 283 * do nej. 284 * 2) do tych ops do .interfaces[DEV_IFACE_USBHID (asi)] priradi 285 * vyplnenu strukturu usbhid_iface_t. 286 * 3) klientska aplikacia - musi si rucne vytvorit telefon 287 * (devman_device_connect() - cesta k zariadeniu (/hw/pci0/...) az 288 * k tej fcii. 289 * pouzit usb/classes/hid/iface.h - prvy int je telefon 290 */ 291 292 int rc = ddf_fun_bind(fun); 293 if (rc != EOK) { 294 usb_log_error("Could not bind DDF function: %s.\n", 295 str_error(rc)); 296 // TODO: Can / should I destroy the DDF function? 297 ddf_fun_destroy(fun); 298 usb_lgtch_free(&lgtch_dev); 299 return rc; 300 } 301 302 rc = ddf_fun_add_to_class(fun, "keyboard"); 303 if (rc != EOK) { 304 usb_log_error( 305 "Could not add DDF function to class 'keyboard': %s.\n", 306 str_error(rc)); 307 // TODO: Can / should I destroy the DDF function? 308 ddf_fun_destroy(fun); 309 usb_lgtch_free(&lgtch_dev); 310 return rc; 311 } 312 313 usb_log_debug(NAME " HID/lgtch_ultrax structure initialized.\n"); 314 315 return EOK; 316 } 317 318 /*----------------------------------------------------------------------------*/ 319 320 void usb_lgtch_deinit(struct usb_hid_dev *hid_dev) 321 { 322 if (hid_dev == NULL) { 323 return; 324 } 325 326 if (hid_dev->data != NULL) { 327 usb_lgtch_ultrax_t *lgtch_dev = 328 (usb_lgtch_ultrax_t *)hid_dev->data; 329 // if (usb_kbd_is_initialized(kbd_dev)) { 330 // usb_kbd_mark_unusable(kbd_dev); 331 // } else { 332 usb_lgtch_free(&lgtch_dev); 333 hid_dev->data = NULL; 334 // } 335 } 66 336 } 67 337 … … 81 351 usb_hid_report_path_t *path = usb_hid_report_path(); 82 352 usb_hid_report_path_append_item(path, 0xc, 0); 83 usb_hid_report_path_set_report_id(path, 1); 84 85 int rc = usb_hid_parse_report(hid_dev->parser, buffer, 86 buffer_size, path, 87 USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 88 &usb_lgtch_parser_callbacks, hid_dev); 353 354 uint8_t report_id; 355 356 int rc = usb_hid_parse_report(hid_dev->report, buffer, buffer_size, 357 &report_id); 358 usb_hid_report_path_set_report_id(path, report_id); 359 360 usb_hid_report_field_t *field = usb_hid_report_get_sibling( 361 hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END 362 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 363 USB_HID_REPORT_TYPE_INPUT); 364 365 unsigned int key; 366 367 /*! @todo Is this iterating OK if done multiple times? 368 * @todo The parsing is not OK 369 */ 370 while (field != NULL) { 371 usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n", field->value, 372 field->usage); 373 374 key = usb_lgtch_map_usage(field->usage); 375 usb_lgtch_push_ev(hid_dev, KEY_PRESS, key); 376 377 field = usb_hid_report_get_sibling( 378 hid_dev->report, field, path, USB_HID_PATH_COMPARE_END 379 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 380 USB_HID_REPORT_TYPE_INPUT); 381 } 89 382 90 383 usb_hid_report_path_free(path); 91 384 92 385 if (rc != EOK) { 93 usb_log_warning( "Error in usb_hid_boot_keyboard_input_report():"386 usb_log_warning(NAME "Error in usb_hid_boot_keyboard_input_report():" 94 387 "%s\n", str_error(rc)); 95 388 }
Note:
See TracChangeset
for help on using the changeset viewer.