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