Changes in uspace/drv/bus/usb/usbhid/mouse/mousedev.c [1dc4a5e:5cc9eba] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhid/mouse/mousedev.c
r1dc4a5e r5cc9eba 42 42 #include <errno.h> 43 43 #include <async.h> 44 #include <async_obsolete.h>45 44 #include <str_error.h> 46 45 #include <ipc/mouseev.h> … … 53 52 #include "../usbhid.h" 54 53 55 /** Number of simulated arrow-key presses for singel wheel step. */56 #define ARROWS_PER_SINGLE_WHEEL 357 58 // FIXME: remove this header59 #include <abi/ipc/methods.h>60 61 54 #define NAME "mouse" 62 55 63 56 /*----------------------------------------------------------------------------*/ 64 57 65 usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {58 const usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = { 66 59 .transfer_type = USB_TRANSFER_INTERRUPT, 67 60 .direction = USB_DIRECTION_IN, … … 73 66 74 67 const char *HID_MOUSE_FUN_NAME = "mouse"; 75 const char *HID_MOUSE_WHEEL_FUN_NAME = "mouse-wheel";76 68 const char *HID_MOUSE_CATEGORY = "mouse"; 77 const char *HID_MOUSE_WHEEL_CATEGORY = "keyboard";78 69 79 70 /** Default idle rate for mouses. */ 80 71 static const uint8_t IDLE_RATE = 0; 81 static const size_t USB_MOUSE_BUTTON_COUNT = 3; 82 83 /*----------------------------------------------------------------------------*/ 84 85 enum { 86 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE = 63 87 }; 88 89 static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[ 90 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE] = { 72 73 /*----------------------------------------------------------------------------*/ 74 static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[] = { 91 75 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 92 76 0x09, 0x02, // USAGE (Mouse) … … 128 112 ipc_callid_t icallid, ipc_call_t *icall) 129 113 { 130 sysarg_t method = IPC_GET_IMETHOD(*icall); 131 132 usb_mouse_t *mouse_dev = (usb_mouse_t *)fun->driver_data; 133 114 usb_mouse_t *mouse_dev = fun->driver_data; 115 134 116 if (mouse_dev == NULL) { 135 usb_log_debug("default_connection_handler: Missing " 136 "parameters.\n"); 117 usb_log_debug("%s: Missing parameters.\n", __FUNCTION__); 137 118 async_answer_0(icallid, EINVAL); 138 119 return; 139 120 } 140 141 usb_log_debug("default_connection_handler: fun->name: %s\n", 142 fun->name); 143 usb_log_debug("default_connection_handler: mouse_phone: %d, wheel " 144 "phone: %d\n", mouse_dev->mouse_phone, mouse_dev->wheel_phone); 145 146 int *phone = (str_cmp(fun->name, HID_MOUSE_FUN_NAME) == 0) 147 ? &mouse_dev->mouse_phone : &mouse_dev->wheel_phone; 148 149 if (method == IPC_M_CONNECT_TO_ME) { 150 int callback = IPC_GET_ARG5(*icall); 151 152 if (*phone != -1) { 153 usb_log_debug("default_connection_handler: Console " 154 "phone to mouse already set.\n"); 121 122 usb_log_debug("%s: fun->name: %s\n", __FUNCTION__, fun->name); 123 usb_log_debug("%s: mouse_sess: %p\n", 124 __FUNCTION__, mouse_dev->mouse_sess); 125 126 async_sess_t *sess = 127 async_callback_receive_start(EXCHANGE_SERIALIZE, icall); 128 if (sess != NULL) { 129 if (mouse_dev->mouse_sess == NULL) { 130 mouse_dev->mouse_sess = sess; 131 usb_log_debug("Console session to %s set ok (%p).\n", 132 fun->name, sess); 133 async_answer_0(icallid, EOK); 134 } else { 135 usb_log_error("Console session to %s already set.\n", 136 fun->name); 155 137 async_answer_0(icallid, ELIMIT); 156 return;138 async_hangup(sess); 157 139 } 158 159 *phone = callback; 160 usb_log_debug("Console phone to mouse set ok (%d).\n", *phone); 161 async_answer_0(icallid, EOK); 162 return; 163 } 164 165 usb_log_debug("default_connection_handler: Invalid function.\n"); 166 async_answer_0(icallid, EINVAL); 167 } 168 169 /*----------------------------------------------------------------------------*/ 170 171 static usb_mouse_t *usb_mouse_new(void) 172 { 173 usb_mouse_t *mouse = calloc(1, sizeof(usb_mouse_t)); 174 if (mouse == NULL) { 175 return NULL; 176 } 177 mouse->mouse_phone = -1; 178 mouse->wheel_phone = -1; 179 180 return mouse; 181 } 182 183 /*----------------------------------------------------------------------------*/ 184 185 static void usb_mouse_free(usb_mouse_t **mouse_dev) 186 { 187 assert(mouse_dev != NULL && *mouse_dev != NULL); 188 189 // hangup phone to the console 190 if ((*mouse_dev)->mouse_phone >= 0) { 191 async_obsolete_hangup((*mouse_dev)->mouse_phone); 192 } 193 194 if ((*mouse_dev)->wheel_phone >= 0) { 195 async_obsolete_hangup((*mouse_dev)->wheel_phone); 196 } 197 198 free(*mouse_dev); 199 *mouse_dev = NULL; 200 } 201 202 /*----------------------------------------------------------------------------*/ 203 204 static void usb_mouse_send_wheel(const usb_mouse_t *mouse_dev, int wheel) 205 { 206 unsigned int key = (wheel > 0) ? KC_UP : KC_DOWN; 207 208 if (mouse_dev->wheel_phone < 0) { 209 usb_log_warning( 210 "Connection to console not ready, wheel roll discarded.\n"); 211 return; 212 } 213 214 int count = ((wheel < 0) ? -wheel : wheel) * ARROWS_PER_SINGLE_WHEEL; 215 int i; 216 217 for (i = 0; i < count; i++) { 218 /* Send arrow press and release. */ 219 usb_log_debug2("Sending key %d to the console\n", key); 220 async_obsolete_msg_4(mouse_dev->wheel_phone, KBDEV_EVENT, 221 KEY_PRESS, key, 0, 0); 222 async_obsolete_msg_4(mouse_dev->wheel_phone, KBDEV_EVENT, 223 KEY_RELEASE, key, 0, 0); 224 } 225 } 226 227 /*----------------------------------------------------------------------------*/ 228 140 } else { 141 usb_log_debug("%s: Invalid function.\n", __FUNCTION__); 142 async_answer_0(icallid, EINVAL); 143 } 144 } 145 /*----------------------------------------------------------------------------*/ 229 146 static int get_mouse_axis_move_value(uint8_t rid, usb_hid_report_t *report, 230 147 int32_t usage) … … 255 172 { 256 173 assert(mouse_dev != NULL); 257 258 if (mouse_dev->mouse_ phone < 0) {259 usb_log_warning(NAME " No console phone.\n");174 175 if (mouse_dev->mouse_sess == NULL) { 176 usb_log_warning(NAME " No console session.\n"); 260 177 return true; 261 178 } 262 179 263 int shift_x = get_mouse_axis_move_value(hid_dev->report_id, 264 hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_X); 265 int shift_y = get_mouse_axis_move_value(hid_dev->report_id, 266 hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_Y); 267 int wheel = get_mouse_axis_move_value(hid_dev->report_id, 268 hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL); 269 270 if ((shift_x != 0) || (shift_y != 0)) { 271 async_obsolete_req_2_0(mouse_dev->mouse_phone, 272 MOUSEEV_MOVE_EVENT, shift_x, shift_y); 273 } 274 275 if (wheel != 0) { 276 usb_mouse_send_wheel(mouse_dev, wheel); 277 } 278 279 /* 280 * Buttons 281 */ 180 const int shift_x = get_mouse_axis_move_value(hid_dev->report_id, 181 &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_X); 182 const int shift_y = get_mouse_axis_move_value(hid_dev->report_id, 183 &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_Y); 184 const int wheel = get_mouse_axis_move_value(hid_dev->report_id, 185 &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL); 186 187 if (shift_x || shift_y || wheel) { 188 async_exch_t *exch = 189 async_exchange_begin(mouse_dev->mouse_sess); 190 if (exch != NULL) { 191 async_msg_3(exch, MOUSEEV_MOVE_EVENT, 192 shift_x, shift_y, wheel); 193 async_exchange_end(exch); 194 } 195 } 196 197 /* Buttons */ 282 198 usb_hid_report_path_t *path = usb_hid_report_path(); 283 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0); 199 if (path == NULL) { 200 usb_log_warning("Failed to create USB HID report path.\n"); 201 return true; 202 } 203 int ret = 204 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0); 205 if (ret != EOK) { 206 usb_hid_report_path_free(path); 207 usb_log_warning("Failed to add buttons to report path.\n"); 208 return true; 209 } 284 210 usb_hid_report_path_set_report_id(path, hid_dev->report_id); 285 211 286 212 usb_hid_report_field_t *field = usb_hid_report_get_sibling( 287 hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END 288 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 289 USB_HID_REPORT_TYPE_INPUT); 213 &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END 214 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, USB_HID_REPORT_TYPE_INPUT); 290 215 291 216 while (field != NULL) { 292 217 usb_log_debug2(NAME " VALUE(%X) USAGE(%X)\n", field->value, 293 218 field->usage); 294 295 if (mouse_dev->buttons[field->usage - field->usage_minimum] == 0 296 && field->value != 0) { 297 async_obsolete_req_2_0(mouse_dev->mouse_phone, 298 MOUSEEV_BUTTON_EVENT, field->usage, 1); 299 mouse_dev->buttons[field->usage - field->usage_minimum] 300 = field->value; 301 } else if (mouse_dev->buttons[field->usage - field->usage_minimum] != 0 302 && field->value == 0) { 303 async_obsolete_req_2_0(mouse_dev->mouse_phone, 304 MOUSEEV_BUTTON_EVENT, field->usage, 0); 305 mouse_dev->buttons[field->usage - field->usage_minimum] = 306 field->value; 219 assert(field->usage > field->usage_minimum); 220 const unsigned index = field->usage - field->usage_minimum; 221 assert(index < mouse_dev->buttons_count); 222 223 if (mouse_dev->buttons[index] == 0 && field->value != 0) { 224 async_exch_t *exch = 225 async_exchange_begin(mouse_dev->mouse_sess); 226 if (exch != NULL) { 227 async_req_2_0(exch, MOUSEEV_BUTTON_EVENT, 228 field->usage, 1); 229 async_exchange_end(exch); 230 mouse_dev->buttons[index] = field->value; 231 } 232 233 } else if (mouse_dev->buttons[index] != 0 && field->value == 0) { 234 async_exch_t *exch = 235 async_exchange_begin(mouse_dev->mouse_sess); 236 if (exch != NULL) { 237 async_req_2_0(exch, MOUSEEV_BUTTON_EVENT, 238 field->usage, 0); 239 async_exchange_end(exch); 240 mouse_dev->buttons[index] = field->value; 241 } 307 242 } 308 243 309 244 field = usb_hid_report_get_sibling( 310 hid_dev->report, field, path, USB_HID_PATH_COMPARE_END311 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 245 &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END 246 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 312 247 USB_HID_REPORT_TYPE_INPUT); 313 248 } 314 249 315 250 usb_hid_report_path_free(path); 316 251 317 252 return true; 318 253 } 319 320 /*----------------------------------------------------------------------------*/ 321 254 /*----------------------------------------------------------------------------*/ 255 #define FUN_UNBIND_DESTROY(fun) \ 256 if (fun) { \ 257 if (ddf_fun_unbind((fun)) == EOK) { \ 258 (fun)->driver_data = NULL; \ 259 ddf_fun_destroy((fun)); \ 260 } else { \ 261 usb_log_error("Could not unbind function `%s', it " \ 262 "will not be destroyed.\n", (fun)->name); \ 263 } \ 264 } else (void)0 265 /*----------------------------------------------------------------------------*/ 322 266 static int usb_mouse_create_function(usb_hid_dev_t *hid_dev, usb_mouse_t *mouse) 323 267 { 324 268 assert(hid_dev != NULL); 325 269 assert(mouse != NULL); 326 270 327 271 /* Create the exposed function. */ 328 272 usb_log_debug("Creating DDF function %s...\n", HID_MOUSE_FUN_NAME); 329 ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 273 ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 330 274 HID_MOUSE_FUN_NAME); 331 275 if (fun == NULL) { 332 usb_log_error("Could not create DDF function node.\n"); 276 usb_log_error("Could not create DDF function node `%s'.\n", 277 HID_MOUSE_FUN_NAME); 333 278 return ENOMEM; 334 279 } 335 280 336 281 fun->ops = &mouse->ops; 337 282 fun->driver_data = mouse; … … 339 284 int rc = ddf_fun_bind(fun); 340 285 if (rc != EOK) { 341 usb_log_error("Could not bind DDF function: %s.\n", 342 str_error(rc)); 286 usb_log_error("Could not bind DDF function `%s': %s.\n", 287 fun->name, str_error(rc)); 288 fun->driver_data = NULL; 343 289 ddf_fun_destroy(fun); 344 290 return rc; 345 291 } 346 347 usb_log_debug("Adding DDF function to category %s...\n",348 HID_MOUSE_CATEGORY);292 293 usb_log_debug("Adding DDF function `%s' to category %s...\n", 294 fun->name, HID_MOUSE_CATEGORY); 349 295 rc = ddf_fun_add_to_category(fun, HID_MOUSE_CATEGORY); 350 296 if (rc != EOK) { … … 352 298 "Could not add DDF function to category %s: %s.\n", 353 299 HID_MOUSE_CATEGORY, str_error(rc)); 354 ddf_fun_destroy(fun);300 FUN_UNBIND_DESTROY(fun); 355 301 return rc; 356 302 } 357 358 /* 359 * Special function for acting as keyboard (wheel) 360 */ 361 usb_log_debug("Creating DDF function %s...\n", 362 HID_MOUSE_WHEEL_FUN_NAME); 363 fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 364 HID_MOUSE_WHEEL_FUN_NAME); 365 if (fun == NULL) { 366 usb_log_error("Could not create DDF function node.\n"); 367 return ENOMEM; 368 } 369 370 /* 371 * Store the initialized HID device and HID ops 372 * to the DDF function. 373 */ 374 fun->ops = &mouse->ops; 375 fun->driver_data = mouse; 376 377 rc = ddf_fun_bind(fun); 378 if (rc != EOK) { 379 usb_log_error("Could not bind DDF function: %s.\n", 380 str_error(rc)); 381 ddf_fun_destroy(fun); 382 return rc; 383 } 384 385 usb_log_debug("Adding DDF function to category %s...\n", 386 HID_MOUSE_WHEEL_CATEGORY); 387 rc = ddf_fun_add_to_category(fun, HID_MOUSE_WHEEL_CATEGORY); 388 if (rc != EOK) { 389 usb_log_error( 390 "Could not add DDF function to category %s: %s.\n", 391 HID_MOUSE_WHEEL_CATEGORY, str_error(rc)); 392 ddf_fun_destroy(fun); 393 return rc; 394 } 395 303 mouse->mouse_fun = fun; 304 396 305 return EOK; 397 306 } 398 307 399 /*----------------------------------------------------------------------------*/ 400 308 /** Get highest index of a button mentioned in given report. 309 * 310 * @param report HID report. 311 * @param report_id Report id we are interested in. 312 * @return Highest button mentioned in the report. 313 * @retval 1 No button was mentioned. 314 * 315 */ 316 static size_t usb_mouse_get_highest_button(usb_hid_report_t *report, uint8_t report_id) 317 { 318 size_t highest_button = 0; 319 320 usb_hid_report_path_t *path = usb_hid_report_path(); 321 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0); 322 usb_hid_report_path_set_report_id(path, report_id); 323 324 usb_hid_report_field_t *field = NULL; 325 326 /* Break from within. */ 327 while (1) { 328 field = usb_hid_report_get_sibling( 329 report, field, path, 330 USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 331 USB_HID_REPORT_TYPE_INPUT); 332 /* No more buttons? */ 333 if (field == NULL) { 334 break; 335 } 336 337 size_t current_button = field->usage - field->usage_minimum; 338 if (current_button > highest_button) { 339 highest_button = current_button; 340 } 341 } 342 343 usb_hid_report_path_free(path); 344 345 return highest_button; 346 } 347 /*----------------------------------------------------------------------------*/ 401 348 int usb_mouse_init(usb_hid_dev_t *hid_dev, void **data) 402 349 { 403 350 usb_log_debug("Initializing HID/Mouse structure...\n"); 404 351 405 352 if (hid_dev == NULL) { 406 353 usb_log_error("Failed to init keyboard structure: no structure" … … 408 355 return EINVAL; 409 356 } 410 411 usb_mouse_t *mouse_dev = usb_mouse_new();357 358 usb_mouse_t *mouse_dev = calloc(1, sizeof(usb_mouse_t)); 412 359 if (mouse_dev == NULL) { 413 360 usb_log_error("Error while creating USB/HID Mouse device " … … 415 362 return ENOMEM; 416 363 } 417 418 mouse_dev->buttons = (int32_t *)calloc(USB_MOUSE_BUTTON_COUNT, 419 sizeof(int32_t)); 420 364 365 // FIXME: This may not be optimal since stupid hardware vendor may 366 // use buttons 1, 2, 3 and 6000 and we would allocate array of 367 // 6001*4B and use only 4 items in it. 368 // Since I doubt that hardware producers would do that, I think 369 // that the current solution is good enough. 370 /* Adding 1 because we will be accessing buttons[highest]. */ 371 mouse_dev->buttons_count = 1 + usb_mouse_get_highest_button( 372 &hid_dev->report, hid_dev->report_id); 373 mouse_dev->buttons = calloc(mouse_dev->buttons_count, sizeof(int32_t)); 374 421 375 if (mouse_dev->buttons == NULL) { 422 usb_log_ fatal("No memory!\n");376 usb_log_error(NAME ": out of memory, giving up on device!\n"); 423 377 free(mouse_dev); 424 378 return ENOMEM; 425 379 } 426 427 // save the Mouse device structure into the HID device structure 428 *data = mouse_dev; 429 380 430 381 // set handler for incoming calls 431 382 mouse_dev->ops.default_handler = default_connection_handler; 432 383 433 384 // TODO: how to know if the device supports the request??? 434 usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 385 usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 435 386 hid_dev->usb_dev->interface_no, IDLE_RATE); 436 387 437 388 int rc = usb_mouse_create_function(hid_dev, mouse_dev); 438 389 if (rc != EOK) { 439 usb_mouse_free(&mouse_dev); 390 free(mouse_dev->buttons); 391 free(mouse_dev); 440 392 return rc; 441 393 } 442 394 395 /* Save the Mouse device structure into the HID device structure. */ 396 *data = mouse_dev; 397 443 398 return EOK; 444 399 } 445 446 /*----------------------------------------------------------------------------*/ 447 400 /*----------------------------------------------------------------------------*/ 448 401 bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, void *data) 449 402 { 450 403 if (hid_dev == NULL || data == NULL) { 451 usb_log_error( "Missing argument to the mouse polling callback."452 " \n");404 usb_log_error( 405 "Missing argument to the mouse polling callback.\n"); 453 406 return false; 454 407 } 455 456 usb_mouse_t *mouse_dev = (usb_mouse_t *)data;457 408 409 usb_mouse_t *mouse_dev = data; 410 458 411 return usb_mouse_process_report(hid_dev, mouse_dev); 459 412 } 460 461 /*----------------------------------------------------------------------------*/ 462 413 /*----------------------------------------------------------------------------*/ 463 414 void usb_mouse_deinit(usb_hid_dev_t *hid_dev, void *data) 464 415 { 465 if (data != NULL) { 466 usb_mouse_free((usb_mouse_t **)&data); 467 } 468 } 469 470 /*----------------------------------------------------------------------------*/ 471 416 if (data == NULL) 417 return; 418 419 usb_mouse_t *mouse_dev = data; 420 421 /* Hangup session to the console */ 422 if (mouse_dev->mouse_sess != NULL) { 423 const int ret = async_hangup(mouse_dev->mouse_sess); 424 if (ret != EOK) 425 usb_log_warning("Failed to hang up mouse session: " 426 "%p, %s.\n", mouse_dev->mouse_sess, str_error(ret)); 427 } 428 429 FUN_UNBIND_DESTROY(mouse_dev->mouse_fun); 430 431 free(mouse_dev->buttons); 432 free(mouse_dev); 433 } 434 /*----------------------------------------------------------------------------*/ 472 435 int usb_mouse_set_boot_protocol(usb_hid_dev_t *hid_dev) 473 436 { 474 int rc = usb_hid_parse_report_descriptor( hid_dev->report,475 USB_MOUSE_BOOT_REPORT_DESCRIPTOR,476 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE);477 437 int rc = usb_hid_parse_report_descriptor( 438 &hid_dev->report, USB_MOUSE_BOOT_REPORT_DESCRIPTOR, 439 sizeof(USB_MOUSE_BOOT_REPORT_DESCRIPTOR)); 440 478 441 if (rc != EOK) { 479 442 usb_log_error("Failed to parse boot report descriptor: %s\n", … … 481 444 return rc; 482 445 } 483 484 rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 446 447 rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 485 448 hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT); 486 449 487 450 if (rc != EOK) { 488 451 usb_log_warning("Failed to set boot protocol to the device: " … … 490 453 return rc; 491 454 } 492 455 493 456 return EOK; 494 457 }
Note:
See TracChangeset
for help on using the changeset viewer.