diff options
Diffstat (limited to 'drivers/hid/uhid.c')
-rw-r--r-- | drivers/hid/uhid.c | 103 |
1 files changed, 101 insertions, 2 deletions
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index cedc6da93c19..0d078c32db4f 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c | |||
@@ -244,12 +244,35 @@ static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count, | |||
244 | return count; | 244 | return count; |
245 | } | 245 | } |
246 | 246 | ||
247 | static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf, | ||
248 | size_t count) | ||
249 | { | ||
250 | return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT); | ||
251 | } | ||
252 | |||
253 | static int uhid_raw_request(struct hid_device *hid, unsigned char reportnum, | ||
254 | __u8 *buf, size_t len, unsigned char rtype, | ||
255 | int reqtype) | ||
256 | { | ||
257 | switch (reqtype) { | ||
258 | case HID_REQ_GET_REPORT: | ||
259 | return uhid_hid_get_raw(hid, reportnum, buf, len, rtype); | ||
260 | case HID_REQ_SET_REPORT: | ||
261 | /* TODO: implement proper SET_REPORT functionality */ | ||
262 | return -ENOSYS; | ||
263 | default: | ||
264 | return -EIO; | ||
265 | } | ||
266 | } | ||
267 | |||
247 | static struct hid_ll_driver uhid_hid_driver = { | 268 | static struct hid_ll_driver uhid_hid_driver = { |
248 | .start = uhid_hid_start, | 269 | .start = uhid_hid_start, |
249 | .stop = uhid_hid_stop, | 270 | .stop = uhid_hid_stop, |
250 | .open = uhid_hid_open, | 271 | .open = uhid_hid_open, |
251 | .close = uhid_hid_close, | 272 | .close = uhid_hid_close, |
252 | .parse = uhid_hid_parse, | 273 | .parse = uhid_hid_parse, |
274 | .output_report = uhid_hid_output_report, | ||
275 | .raw_request = uhid_raw_request, | ||
253 | }; | 276 | }; |
254 | 277 | ||
255 | #ifdef CONFIG_COMPAT | 278 | #ifdef CONFIG_COMPAT |
@@ -377,8 +400,6 @@ static int uhid_dev_create(struct uhid_device *uhid, | |||
377 | hid->uniq[63] = 0; | 400 | hid->uniq[63] = 0; |
378 | 401 | ||
379 | hid->ll_driver = &uhid_hid_driver; | 402 | hid->ll_driver = &uhid_hid_driver; |
380 | hid->hid_get_raw_report = uhid_hid_get_raw; | ||
381 | hid->hid_output_raw_report = uhid_hid_output_raw; | ||
382 | hid->bus = ev->u.create.bus; | 403 | hid->bus = ev->u.create.bus; |
383 | hid->vendor = ev->u.create.vendor; | 404 | hid->vendor = ev->u.create.vendor; |
384 | hid->product = ev->u.create.product; | 405 | hid->product = ev->u.create.product; |
@@ -407,6 +428,67 @@ err_free: | |||
407 | return ret; | 428 | return ret; |
408 | } | 429 | } |
409 | 430 | ||
431 | static int uhid_dev_create2(struct uhid_device *uhid, | ||
432 | const struct uhid_event *ev) | ||
433 | { | ||
434 | struct hid_device *hid; | ||
435 | int ret; | ||
436 | |||
437 | if (uhid->running) | ||
438 | return -EALREADY; | ||
439 | |||
440 | uhid->rd_size = ev->u.create2.rd_size; | ||
441 | if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE) | ||
442 | return -EINVAL; | ||
443 | |||
444 | uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL); | ||
445 | if (!uhid->rd_data) | ||
446 | return -ENOMEM; | ||
447 | |||
448 | memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size); | ||
449 | |||
450 | hid = hid_allocate_device(); | ||
451 | if (IS_ERR(hid)) { | ||
452 | ret = PTR_ERR(hid); | ||
453 | goto err_free; | ||
454 | } | ||
455 | |||
456 | strncpy(hid->name, ev->u.create2.name, 127); | ||
457 | hid->name[127] = 0; | ||
458 | strncpy(hid->phys, ev->u.create2.phys, 63); | ||
459 | hid->phys[63] = 0; | ||
460 | strncpy(hid->uniq, ev->u.create2.uniq, 63); | ||
461 | hid->uniq[63] = 0; | ||
462 | |||
463 | hid->ll_driver = &uhid_hid_driver; | ||
464 | hid->bus = ev->u.create2.bus; | ||
465 | hid->vendor = ev->u.create2.vendor; | ||
466 | hid->product = ev->u.create2.product; | ||
467 | hid->version = ev->u.create2.version; | ||
468 | hid->country = ev->u.create2.country; | ||
469 | hid->driver_data = uhid; | ||
470 | hid->dev.parent = uhid_misc.this_device; | ||
471 | |||
472 | uhid->hid = hid; | ||
473 | uhid->running = true; | ||
474 | |||
475 | ret = hid_add_device(hid); | ||
476 | if (ret) { | ||
477 | hid_err(hid, "Cannot register HID device\n"); | ||
478 | goto err_hid; | ||
479 | } | ||
480 | |||
481 | return 0; | ||
482 | |||
483 | err_hid: | ||
484 | hid_destroy_device(hid); | ||
485 | uhid->hid = NULL; | ||
486 | uhid->running = false; | ||
487 | err_free: | ||
488 | kfree(uhid->rd_data); | ||
489 | return ret; | ||
490 | } | ||
491 | |||
410 | static int uhid_dev_destroy(struct uhid_device *uhid) | 492 | static int uhid_dev_destroy(struct uhid_device *uhid) |
411 | { | 493 | { |
412 | if (!uhid->running) | 494 | if (!uhid->running) |
@@ -435,6 +517,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev) | |||
435 | return 0; | 517 | return 0; |
436 | } | 518 | } |
437 | 519 | ||
520 | static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev) | ||
521 | { | ||
522 | if (!uhid->running) | ||
523 | return -EINVAL; | ||
524 | |||
525 | hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data, | ||
526 | min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0); | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
438 | static int uhid_dev_feature_answer(struct uhid_device *uhid, | 531 | static int uhid_dev_feature_answer(struct uhid_device *uhid, |
439 | struct uhid_event *ev) | 532 | struct uhid_event *ev) |
440 | { | 533 | { |
@@ -571,12 +664,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer, | |||
571 | case UHID_CREATE: | 664 | case UHID_CREATE: |
572 | ret = uhid_dev_create(uhid, &uhid->input_buf); | 665 | ret = uhid_dev_create(uhid, &uhid->input_buf); |
573 | break; | 666 | break; |
667 | case UHID_CREATE2: | ||
668 | ret = uhid_dev_create2(uhid, &uhid->input_buf); | ||
669 | break; | ||
574 | case UHID_DESTROY: | 670 | case UHID_DESTROY: |
575 | ret = uhid_dev_destroy(uhid); | 671 | ret = uhid_dev_destroy(uhid); |
576 | break; | 672 | break; |
577 | case UHID_INPUT: | 673 | case UHID_INPUT: |
578 | ret = uhid_dev_input(uhid, &uhid->input_buf); | 674 | ret = uhid_dev_input(uhid, &uhid->input_buf); |
579 | break; | 675 | break; |
676 | case UHID_INPUT2: | ||
677 | ret = uhid_dev_input2(uhid, &uhid->input_buf); | ||
678 | break; | ||
580 | case UHID_FEATURE_ANSWER: | 679 | case UHID_FEATURE_ANSWER: |
581 | ret = uhid_dev_feature_answer(uhid, &uhid->input_buf); | 680 | ret = uhid_dev_feature_answer(uhid, &uhid->input_buf); |
582 | break; | 681 | break; |