Lines Matching +full:min +full:- +full:len

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * User-space I/O driver support for HID subsystem
73 ret = hid_add_device(uhid->hid); in uhid_device_add_worker()
75 hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret); in uhid_device_add_worker()
80 * of using uhid->hid. in uhid_device_add_worker()
81 * Just leave uhid->hid as-is for now, and clean it up when in uhid_device_add_worker()
84 * However, we do have to clear the ->running flag and do a in uhid_device_add_worker()
87 WRITE_ONCE(uhid->running, false); in uhid_device_add_worker()
88 wake_up_interruptible(&uhid->report_wait); in uhid_device_add_worker()
96 newhead = (uhid->head + 1) % UHID_BUFSIZE; in uhid_queue()
98 if (newhead != uhid->tail) { in uhid_queue()
99 uhid->outq[uhid->head] = ev; in uhid_queue()
100 uhid->head = newhead; in uhid_queue()
101 wake_up_interruptible(&uhid->waitq); in uhid_queue()
103 hid_warn(uhid->hid, "Output queue is full\n"); in uhid_queue()
115 return -ENOMEM; in uhid_queue_event()
117 ev->type = event; in uhid_queue_event()
119 spin_lock_irqsave(&uhid->qlock, flags); in uhid_queue_event()
121 spin_unlock_irqrestore(&uhid->qlock, flags); in uhid_queue_event()
128 struct uhid_device *uhid = hid->driver_data; in uhid_hid_start()
134 return -ENOMEM; in uhid_hid_start()
136 ev->type = UHID_START; in uhid_hid_start()
138 if (hid->report_enum[HID_FEATURE_REPORT].numbered) in uhid_hid_start()
139 ev->u.start.dev_flags |= UHID_DEV_NUMBERED_FEATURE_REPORTS; in uhid_hid_start()
140 if (hid->report_enum[HID_OUTPUT_REPORT].numbered) in uhid_hid_start()
141 ev->u.start.dev_flags |= UHID_DEV_NUMBERED_OUTPUT_REPORTS; in uhid_hid_start()
142 if (hid->report_enum[HID_INPUT_REPORT].numbered) in uhid_hid_start()
143 ev->u.start.dev_flags |= UHID_DEV_NUMBERED_INPUT_REPORTS; in uhid_hid_start()
145 spin_lock_irqsave(&uhid->qlock, flags); in uhid_hid_start()
147 spin_unlock_irqrestore(&uhid->qlock, flags); in uhid_hid_start()
154 struct uhid_device *uhid = hid->driver_data; in uhid_hid_stop()
156 hid->claimed = 0; in uhid_hid_stop()
162 struct uhid_device *uhid = hid->driver_data; in uhid_hid_open()
169 struct uhid_device *uhid = hid->driver_data; in uhid_hid_close()
176 struct uhid_device *uhid = hid->driver_data; in uhid_hid_parse()
178 return hid_parse_report(hid, uhid->rd_data, uhid->rd_size); in uhid_hid_parse()
189 spin_lock_irqsave(&uhid->qlock, flags); in __uhid_report_queue_and_wait()
190 *report_id = ++uhid->report_id; in __uhid_report_queue_and_wait()
191 uhid->report_type = ev->type + 1; in __uhid_report_queue_and_wait()
192 uhid->report_running = true; in __uhid_report_queue_and_wait()
194 spin_unlock_irqrestore(&uhid->qlock, flags); in __uhid_report_queue_and_wait()
196 ret = wait_event_interruptible_timeout(uhid->report_wait, in __uhid_report_queue_and_wait()
197 !uhid->report_running || !READ_ONCE(uhid->running), in __uhid_report_queue_and_wait()
199 if (!ret || !READ_ONCE(uhid->running) || uhid->report_running) in __uhid_report_queue_and_wait()
200 ret = -EIO; in __uhid_report_queue_and_wait()
202 ret = -ERESTARTSYS; in __uhid_report_queue_and_wait()
206 uhid->report_running = false; in __uhid_report_queue_and_wait()
216 spin_lock_irqsave(&uhid->qlock, flags); in uhid_report_wake_up()
219 if (uhid->report_type != ev->type || uhid->report_id != id) in uhid_report_wake_up()
221 if (!uhid->report_running) in uhid_report_wake_up()
224 memcpy(&uhid->report_buf, ev, sizeof(*ev)); in uhid_report_wake_up()
225 uhid->report_running = false; in uhid_report_wake_up()
226 wake_up_interruptible(&uhid->report_wait); in uhid_report_wake_up()
229 spin_unlock_irqrestore(&uhid->qlock, flags); in uhid_report_wake_up()
235 struct uhid_device *uhid = hid->driver_data; in uhid_hid_get_report()
240 if (!READ_ONCE(uhid->running)) in uhid_hid_get_report()
241 return -EIO; in uhid_hid_get_report()
245 return -ENOMEM; in uhid_hid_get_report()
247 ev->type = UHID_GET_REPORT; in uhid_hid_get_report()
248 ev->u.get_report.rnum = rnum; in uhid_hid_get_report()
249 ev->u.get_report.rtype = rtype; in uhid_hid_get_report()
251 ret = mutex_lock_interruptible(&uhid->report_lock); in uhid_hid_get_report()
258 ret = __uhid_report_queue_and_wait(uhid, ev, &ev->u.get_report.id); in uhid_hid_get_report()
262 req = &uhid->report_buf.u.get_report_reply; in uhid_hid_get_report()
263 if (req->err) { in uhid_hid_get_report()
264 ret = -EIO; in uhid_hid_get_report()
266 ret = min3(count, (size_t)req->size, (size_t)UHID_DATA_MAX); in uhid_hid_get_report()
267 memcpy(buf, req->data, ret); in uhid_hid_get_report()
271 mutex_unlock(&uhid->report_lock); in uhid_hid_get_report()
278 struct uhid_device *uhid = hid->driver_data; in uhid_hid_set_report()
282 if (!READ_ONCE(uhid->running) || count > UHID_DATA_MAX) in uhid_hid_set_report()
283 return -EIO; in uhid_hid_set_report()
287 return -ENOMEM; in uhid_hid_set_report()
289 ev->type = UHID_SET_REPORT; in uhid_hid_set_report()
290 ev->u.set_report.rnum = rnum; in uhid_hid_set_report()
291 ev->u.set_report.rtype = rtype; in uhid_hid_set_report()
292 ev->u.set_report.size = count; in uhid_hid_set_report()
293 memcpy(ev->u.set_report.data, buf, count); in uhid_hid_set_report()
295 ret = mutex_lock_interruptible(&uhid->report_lock); in uhid_hid_set_report()
302 ret = __uhid_report_queue_and_wait(uhid, ev, &ev->u.set_report.id); in uhid_hid_set_report()
306 if (uhid->report_buf.u.set_report_reply.err) in uhid_hid_set_report()
307 ret = -EIO; in uhid_hid_set_report()
312 mutex_unlock(&uhid->report_lock); in uhid_hid_set_report()
317 __u8 *buf, size_t len, unsigned char rtype, in uhid_hid_raw_request() argument
333 return -EINVAL; in uhid_hid_raw_request()
338 return uhid_hid_get_report(hid, reportnum, buf, len, u_rtype); in uhid_hid_raw_request()
340 return uhid_hid_set_report(hid, reportnum, buf, len, u_rtype); in uhid_hid_raw_request()
342 return -EIO; in uhid_hid_raw_request()
349 struct uhid_device *uhid = hid->driver_data; in uhid_hid_output_raw()
362 return -EINVAL; in uhid_hid_output_raw()
366 return -EINVAL; in uhid_hid_output_raw()
370 return -ENOMEM; in uhid_hid_output_raw()
372 ev->type = UHID_OUTPUT; in uhid_hid_output_raw()
373 ev->u.output.size = count; in uhid_hid_output_raw()
374 ev->u.output.rtype = rtype; in uhid_hid_output_raw()
375 memcpy(ev->u.output.data, buf, count); in uhid_hid_output_raw()
377 spin_lock_irqsave(&uhid->qlock, flags); in uhid_hid_output_raw()
379 spin_unlock_irqrestore(&uhid->qlock, flags); in uhid_hid_output_raw()
419 static int uhid_event_from_user(const char __user *buffer, size_t len, in uhid_event_from_user() argument
426 return -EFAULT; in uhid_event_from_user()
438 return -ENOMEM; in uhid_event_from_user()
441 len -= sizeof(type); in uhid_event_from_user()
443 min(len, sizeof(*compat)))) { in uhid_event_from_user()
445 return -EFAULT; in uhid_event_from_user()
449 event->type = type; in uhid_event_from_user()
451 memcpy(event->u.create.name, compat->name, in uhid_event_from_user()
452 sizeof(compat->name)); in uhid_event_from_user()
453 memcpy(event->u.create.phys, compat->phys, in uhid_event_from_user()
454 sizeof(compat->phys)); in uhid_event_from_user()
455 memcpy(event->u.create.uniq, compat->uniq, in uhid_event_from_user()
456 sizeof(compat->uniq)); in uhid_event_from_user()
458 event->u.create.rd_data = compat_ptr(compat->rd_data); in uhid_event_from_user()
459 event->u.create.rd_size = compat->rd_size; in uhid_event_from_user()
461 event->u.create.bus = compat->bus; in uhid_event_from_user()
462 event->u.create.vendor = compat->vendor; in uhid_event_from_user()
463 event->u.create.product = compat->product; in uhid_event_from_user()
464 event->u.create.version = compat->version; in uhid_event_from_user()
465 event->u.create.country = compat->country; in uhid_event_from_user()
473 if (copy_from_user(event, buffer, min(len, sizeof(*event)))) in uhid_event_from_user()
474 return -EFAULT; in uhid_event_from_user()
479 static int uhid_event_from_user(const char __user *buffer, size_t len, in uhid_event_from_user() argument
482 if (copy_from_user(event, buffer, min(len, sizeof(*event)))) in uhid_event_from_user()
483 return -EFAULT; in uhid_event_from_user()
493 size_t rd_size, len; in uhid_dev_create2() local
497 if (uhid->hid) in uhid_dev_create2()
498 return -EALREADY; in uhid_dev_create2()
500 rd_size = ev->u.create2.rd_size; in uhid_dev_create2()
502 return -EINVAL; in uhid_dev_create2()
504 rd_data = kmemdup(ev->u.create2.rd_data, rd_size, GFP_KERNEL); in uhid_dev_create2()
506 return -ENOMEM; in uhid_dev_create2()
508 uhid->rd_size = rd_size; in uhid_dev_create2()
509 uhid->rd_data = rd_data; in uhid_dev_create2()
517 /* @hid is zero-initialized, strncpy() is correct, strlcpy() not */ in uhid_dev_create2()
518 len = min(sizeof(hid->name), sizeof(ev->u.create2.name)) - 1; in uhid_dev_create2()
519 strncpy(hid->name, ev->u.create2.name, len); in uhid_dev_create2()
520 len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys)) - 1; in uhid_dev_create2()
521 strncpy(hid->phys, ev->u.create2.phys, len); in uhid_dev_create2()
522 len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq)) - 1; in uhid_dev_create2()
523 strncpy(hid->uniq, ev->u.create2.uniq, len); in uhid_dev_create2()
525 hid->ll_driver = &uhid_hid_driver; in uhid_dev_create2()
526 hid->bus = ev->u.create2.bus; in uhid_dev_create2()
527 hid->vendor = ev->u.create2.vendor; in uhid_dev_create2()
528 hid->product = ev->u.create2.product; in uhid_dev_create2()
529 hid->version = ev->u.create2.version; in uhid_dev_create2()
530 hid->country = ev->u.create2.country; in uhid_dev_create2()
531 hid->driver_data = uhid; in uhid_dev_create2()
532 hid->dev.parent = uhid_misc.this_device; in uhid_dev_create2()
534 uhid->hid = hid; in uhid_dev_create2()
535 uhid->running = true; in uhid_dev_create2()
541 schedule_work(&uhid->worker); in uhid_dev_create2()
546 kfree(uhid->rd_data); in uhid_dev_create2()
547 uhid->rd_data = NULL; in uhid_dev_create2()
548 uhid->rd_size = 0; in uhid_dev_create2()
557 orig = ev->u.create; in uhid_dev_create()
560 return -EINVAL; in uhid_dev_create()
561 if (copy_from_user(&ev->u.create2.rd_data, orig.rd_data, orig.rd_size)) in uhid_dev_create()
562 return -EFAULT; in uhid_dev_create()
564 memcpy(ev->u.create2.name, orig.name, sizeof(orig.name)); in uhid_dev_create()
565 memcpy(ev->u.create2.phys, orig.phys, sizeof(orig.phys)); in uhid_dev_create()
566 memcpy(ev->u.create2.uniq, orig.uniq, sizeof(orig.uniq)); in uhid_dev_create()
567 ev->u.create2.rd_size = orig.rd_size; in uhid_dev_create()
568 ev->u.create2.bus = orig.bus; in uhid_dev_create()
569 ev->u.create2.vendor = orig.vendor; in uhid_dev_create()
570 ev->u.create2.product = orig.product; in uhid_dev_create()
571 ev->u.create2.version = orig.version; in uhid_dev_create()
572 ev->u.create2.country = orig.country; in uhid_dev_create()
579 if (!uhid->hid) in uhid_dev_destroy()
580 return -EINVAL; in uhid_dev_destroy()
582 WRITE_ONCE(uhid->running, false); in uhid_dev_destroy()
583 wake_up_interruptible(&uhid->report_wait); in uhid_dev_destroy()
585 cancel_work_sync(&uhid->worker); in uhid_dev_destroy()
587 hid_destroy_device(uhid->hid); in uhid_dev_destroy()
588 uhid->hid = NULL; in uhid_dev_destroy()
589 kfree(uhid->rd_data); in uhid_dev_destroy()
596 if (!READ_ONCE(uhid->running)) in uhid_dev_input()
597 return -EINVAL; in uhid_dev_input()
599 hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data, in uhid_dev_input()
600 min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0); in uhid_dev_input()
607 if (!READ_ONCE(uhid->running)) in uhid_dev_input2()
608 return -EINVAL; in uhid_dev_input2()
610 hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data, in uhid_dev_input2()
611 min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0); in uhid_dev_input2()
619 if (!READ_ONCE(uhid->running)) in uhid_dev_get_report_reply()
620 return -EINVAL; in uhid_dev_get_report_reply()
622 uhid_report_wake_up(uhid, ev->u.get_report_reply.id, ev); in uhid_dev_get_report_reply()
629 if (!READ_ONCE(uhid->running)) in uhid_dev_set_report_reply()
630 return -EINVAL; in uhid_dev_set_report_reply()
632 uhid_report_wake_up(uhid, ev->u.set_report_reply.id, ev); in uhid_dev_set_report_reply()
642 return -ENOMEM; in uhid_char_open()
644 mutex_init(&uhid->devlock); in uhid_char_open()
645 mutex_init(&uhid->report_lock); in uhid_char_open()
646 spin_lock_init(&uhid->qlock); in uhid_char_open()
647 init_waitqueue_head(&uhid->waitq); in uhid_char_open()
648 init_waitqueue_head(&uhid->report_wait); in uhid_char_open()
649 uhid->running = false; in uhid_char_open()
650 INIT_WORK(&uhid->worker, uhid_device_add_worker); in uhid_char_open()
652 file->private_data = uhid; in uhid_char_open()
660 struct uhid_device *uhid = file->private_data; in uhid_char_release()
666 kfree(uhid->outq[i]); in uhid_char_release()
676 struct uhid_device *uhid = file->private_data; in uhid_char_read()
679 size_t len; in uhid_char_read() local
683 return -EINVAL; in uhid_char_read()
686 if (file->f_flags & O_NONBLOCK) { in uhid_char_read()
687 if (uhid->head == uhid->tail) in uhid_char_read()
688 return -EAGAIN; in uhid_char_read()
690 ret = wait_event_interruptible(uhid->waitq, in uhid_char_read()
691 uhid->head != uhid->tail); in uhid_char_read()
696 ret = mutex_lock_interruptible(&uhid->devlock); in uhid_char_read()
700 if (uhid->head == uhid->tail) { in uhid_char_read()
701 mutex_unlock(&uhid->devlock); in uhid_char_read()
704 len = min(count, sizeof(**uhid->outq)); in uhid_char_read()
705 if (copy_to_user(buffer, uhid->outq[uhid->tail], len)) { in uhid_char_read()
706 ret = -EFAULT; in uhid_char_read()
708 kfree(uhid->outq[uhid->tail]); in uhid_char_read()
709 uhid->outq[uhid->tail] = NULL; in uhid_char_read()
711 spin_lock_irqsave(&uhid->qlock, flags); in uhid_char_read()
712 uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE; in uhid_char_read()
713 spin_unlock_irqrestore(&uhid->qlock, flags); in uhid_char_read()
717 mutex_unlock(&uhid->devlock); in uhid_char_read()
718 return ret ? ret : len; in uhid_char_read()
724 struct uhid_device *uhid = file->private_data; in uhid_char_write()
726 size_t len; in uhid_char_write() local
730 return -EINVAL; in uhid_char_write()
732 ret = mutex_lock_interruptible(&uhid->devlock); in uhid_char_write()
736 memset(&uhid->input_buf, 0, sizeof(uhid->input_buf)); in uhid_char_write()
737 len = min(count, sizeof(uhid->input_buf)); in uhid_char_write()
739 ret = uhid_event_from_user(buffer, len, &uhid->input_buf); in uhid_char_write()
743 switch (uhid->input_buf.type) { in uhid_char_write()
750 if (file->f_cred != current_cred()) { in uhid_char_write()
752 task_tgid_vnr(current), current->comm); in uhid_char_write()
753 ret = -EACCES; in uhid_char_write()
756 ret = uhid_dev_create(uhid, &uhid->input_buf); in uhid_char_write()
759 ret = uhid_dev_create2(uhid, &uhid->input_buf); in uhid_char_write()
765 ret = uhid_dev_input(uhid, &uhid->input_buf); in uhid_char_write()
768 ret = uhid_dev_input2(uhid, &uhid->input_buf); in uhid_char_write()
771 ret = uhid_dev_get_report_reply(uhid, &uhid->input_buf); in uhid_char_write()
774 ret = uhid_dev_set_report_reply(uhid, &uhid->input_buf); in uhid_char_write()
777 ret = -EOPNOTSUPP; in uhid_char_write()
781 mutex_unlock(&uhid->devlock); in uhid_char_write()
783 /* return "count" not "len" to not confuse the caller */ in uhid_char_write()
789 struct uhid_device *uhid = file->private_data; in uhid_char_poll()
792 poll_wait(file, &uhid->waitq, wait); in uhid_char_poll()
794 if (uhid->head != uhid->tail) in uhid_char_poll()
819 MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");