Lines Matching +full:misc +full:- +full:latch

1 // SPDX-License-Identifier: GPL-2.0+
5 * Provides a user-space interface to properly handle clipboard/tablet
9 * use), or request detachment via user-space.
11 * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
34 /* -- SSAM interface. ------------------------------------------------------- */
136 /* -- Main structures. ------------------------------------------------------ */
191 mutex_destroy(&ddev->write_lock); in __sdtx_device_release()
198 kref_get(&ddev->kref); in sdtx_device_get()
206 kref_put(&ddev->kref, __sdtx_device_release); in sdtx_device_put()
210 /* -- Firmware value translations. ------------------------------------------ */
225 dev_err(ddev->dev, "unknown base state: %#04x\n", state); in sdtx_translate_base_state()
249 dev_err(ddev->dev, "unknown latch status: %#04x\n", status); in sdtx_translate_latch_status()
273 dev_err(ddev->dev, "unknown cancel reason: %#04x\n", reason); in sdtx_translate_cancel_reason()
279 /* -- IOCTLs. --------------------------------------------------------------- */
288 lockdep_assert_held_read(&ddev->lock); in sdtx_ioctl_get_base_info()
290 status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &raw); in sdtx_ioctl_get_base_info()
298 return -EFAULT; in sdtx_ioctl_get_base_info()
308 lockdep_assert_held_read(&ddev->lock); in sdtx_ioctl_get_device_mode()
310 status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode); in sdtx_ioctl_get_device_mode()
319 u8 latch; in sdtx_ioctl_get_latch_status() local
322 lockdep_assert_held_read(&ddev->lock); in sdtx_ioctl_get_latch_status()
324 status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &latch); in sdtx_ioctl_get_latch_status()
328 return put_user(sdtx_translate_latch_status(ddev, latch), buf); in sdtx_ioctl_get_latch_status()
333 struct sdtx_device *ddev = client->ddev; in __surface_dtx_ioctl()
335 lockdep_assert_held_read(&ddev->lock); in __surface_dtx_ioctl()
339 set_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags); in __surface_dtx_ioctl()
343 clear_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags); in __surface_dtx_ioctl()
347 return ssam_retry(ssam_bas_latch_lock, ddev->ctrl); in __surface_dtx_ioctl()
350 return ssam_retry(ssam_bas_latch_unlock, ddev->ctrl); in __surface_dtx_ioctl()
353 return ssam_retry(ssam_bas_latch_request, ddev->ctrl); in __surface_dtx_ioctl()
356 return ssam_retry(ssam_bas_latch_confirm, ddev->ctrl); in __surface_dtx_ioctl()
359 return ssam_retry(ssam_bas_latch_heartbeat, ddev->ctrl); in __surface_dtx_ioctl()
362 return ssam_retry(ssam_bas_latch_cancel, ddev->ctrl); in __surface_dtx_ioctl()
374 return -EINVAL; in __surface_dtx_ioctl()
380 struct sdtx_client *client = file->private_data; in surface_dtx_ioctl()
383 if (down_read_killable(&client->ddev->lock)) in surface_dtx_ioctl()
384 return -ERESTARTSYS; in surface_dtx_ioctl()
386 if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &client->ddev->flags)) { in surface_dtx_ioctl()
387 up_read(&client->ddev->lock); in surface_dtx_ioctl()
388 return -ENODEV; in surface_dtx_ioctl()
393 up_read(&client->ddev->lock); in surface_dtx_ioctl()
398 /* -- File operations. ------------------------------------------------------ */
402 struct sdtx_device *ddev = container_of(file->private_data, struct sdtx_device, mdev); in surface_dtx_open()
408 return -ENOMEM; in surface_dtx_open()
410 client->ddev = sdtx_device_get(ddev); in surface_dtx_open()
412 INIT_LIST_HEAD(&client->node); in surface_dtx_open()
414 mutex_init(&client->read_lock); in surface_dtx_open()
415 INIT_KFIFO(client->buffer); in surface_dtx_open()
417 file->private_data = client; in surface_dtx_open()
420 down_write(&ddev->client_lock); in surface_dtx_open()
428 if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) { in surface_dtx_open()
429 up_write(&ddev->client_lock); in surface_dtx_open()
430 mutex_destroy(&client->read_lock); in surface_dtx_open()
431 sdtx_device_put(client->ddev); in surface_dtx_open()
433 return -ENODEV; in surface_dtx_open()
436 list_add_tail(&client->node, &ddev->client_list); in surface_dtx_open()
437 up_write(&ddev->client_lock); in surface_dtx_open()
445 struct sdtx_client *client = file->private_data; in surface_dtx_release()
448 down_write(&client->ddev->client_lock); in surface_dtx_release()
449 list_del(&client->node); in surface_dtx_release()
450 up_write(&client->ddev->client_lock); in surface_dtx_release()
453 sdtx_device_put(client->ddev); in surface_dtx_release()
454 mutex_destroy(&client->read_lock); in surface_dtx_release()
462 struct sdtx_client *client = file->private_data; in surface_dtx_read()
463 struct sdtx_device *ddev = client->ddev; in surface_dtx_read()
467 if (down_read_killable(&ddev->lock)) in surface_dtx_read()
468 return -ERESTARTSYS; in surface_dtx_read()
471 if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) { in surface_dtx_read()
472 up_read(&ddev->lock); in surface_dtx_read()
473 return -ENODEV; in surface_dtx_read()
478 if (kfifo_is_empty(&client->buffer)) { in surface_dtx_read()
479 up_read(&ddev->lock); in surface_dtx_read()
481 if (file->f_flags & O_NONBLOCK) in surface_dtx_read()
482 return -EAGAIN; in surface_dtx_read()
484 status = wait_event_interruptible(ddev->waitq, in surface_dtx_read()
485 !kfifo_is_empty(&client->buffer) || in surface_dtx_read()
487 &ddev->flags)); in surface_dtx_read()
491 if (down_read_killable(&ddev->lock)) in surface_dtx_read()
492 return -ERESTARTSYS; in surface_dtx_read()
495 if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) { in surface_dtx_read()
496 up_read(&ddev->lock); in surface_dtx_read()
497 return -ENODEV; in surface_dtx_read()
502 if (mutex_lock_interruptible(&client->read_lock)) { in surface_dtx_read()
503 up_read(&ddev->lock); in surface_dtx_read()
504 return -ERESTARTSYS; in surface_dtx_read()
507 status = kfifo_to_user(&client->buffer, buf, count, &copied); in surface_dtx_read()
508 mutex_unlock(&client->read_lock); in surface_dtx_read()
511 up_read(&ddev->lock); in surface_dtx_read()
516 if (copied == 0 && (file->f_flags & O_NONBLOCK)) { in surface_dtx_read()
517 up_read(&ddev->lock); in surface_dtx_read()
518 return -EAGAIN; in surface_dtx_read()
522 up_read(&ddev->lock); in surface_dtx_read()
528 struct sdtx_client *client = file->private_data; in surface_dtx_poll()
531 if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &client->ddev->flags)) in surface_dtx_poll()
534 poll_wait(file, &client->ddev->waitq, pt); in surface_dtx_poll()
536 if (!kfifo_is_empty(&client->buffer)) in surface_dtx_poll()
544 struct sdtx_client *client = file->private_data; in surface_dtx_fasync()
546 return fasync_helper(fd, file, on, &client->fasync); in surface_dtx_fasync()
562 /* -- Event handling/forwarding. -------------------------------------------- */
568 * determine the new tablet-mode switch and device mode values after some
596 /* Must be executed with ddev->write_lock held. */
599 const size_t len = sizeof(struct sdtx_event) + evt->length; in sdtx_push_event()
602 lockdep_assert_held(&ddev->write_lock); in sdtx_push_event()
604 down_read(&ddev->client_lock); in sdtx_push_event()
605 list_for_each_entry(client, &ddev->client_list, node) { in sdtx_push_event()
606 if (!test_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags)) in sdtx_push_event()
609 if (likely(kfifo_avail(&client->buffer) >= len)) in sdtx_push_event()
610 kfifo_in(&client->buffer, (const u8 *)evt, len); in sdtx_push_event()
612 dev_warn(ddev->dev, "event buffer overrun\n"); in sdtx_push_event()
614 kill_fasync(&client->fasync, SIGIO, POLL_IN); in sdtx_push_event()
616 up_read(&ddev->client_lock); in sdtx_push_event()
618 wake_up_interruptible(&ddev->waitq); in sdtx_push_event()
628 switch (in->command_id) { in sdtx_notifier()
649 if (in->length != len) { in sdtx_notifier()
650 dev_err(ddev->dev, in sdtx_notifier()
652 in->command_id, in->length, len); in sdtx_notifier()
656 mutex_lock(&ddev->write_lock); in sdtx_notifier()
659 switch (in->command_id) { in sdtx_notifier()
661 clear_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags); in sdtx_notifier()
664 if (ddev->state.base.state == in->data[0] && in sdtx_notifier()
665 ddev->state.base.base_id == in->data[1]) in sdtx_notifier()
668 ddev->state.base.state = in->data[0]; in sdtx_notifier()
669 ddev->state.base.base_id = in->data[1]; in sdtx_notifier()
673 event.base.v.state = sdtx_translate_base_state(ddev, in->data[0]); in sdtx_notifier()
674 event.base.v.base_id = SDTX_BASE_TYPE_SSH(in->data[1]); in sdtx_notifier()
685 event.status.v = sdtx_translate_cancel_reason(ddev, in->data[0]); in sdtx_notifier()
689 clear_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags); in sdtx_notifier()
692 if (ddev->state.latch_status == in->data[0]) in sdtx_notifier()
695 ddev->state.latch_status = in->data[0]; in sdtx_notifier()
699 event.status.v = sdtx_translate_latch_status(ddev, in->data[0]); in sdtx_notifier()
706 if (in->command_id == SAM_EVENT_CID_DTX_CONNECTION) { in sdtx_notifier()
709 delay = in->data[0] ? SDTX_DEVICE_MODE_DELAY_CONNECT : 0; in sdtx_notifier()
714 mutex_unlock(&ddev->write_lock); in sdtx_notifier()
719 /* -- State update functions. ----------------------------------------------- */
738 status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode); in sdtx_device_mode_workfn()
740 dev_err(ddev->dev, "failed to get device mode: %d\n", status); in sdtx_device_mode_workfn()
745 status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &base); in sdtx_device_mode_workfn()
747 dev_err(ddev->dev, "failed to get base info: %d\n", status); in sdtx_device_mode_workfn()
758 dev_dbg(ddev->dev, "device mode is invalid, trying again\n"); in sdtx_device_mode_workfn()
763 mutex_lock(&ddev->write_lock); in sdtx_device_mode_workfn()
764 clear_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags); in sdtx_device_mode_workfn()
766 /* Avoid sending duplicate device-mode events. */ in sdtx_device_mode_workfn()
767 if (ddev->state.device_mode == mode) { in sdtx_device_mode_workfn()
768 mutex_unlock(&ddev->write_lock); in sdtx_device_mode_workfn()
772 ddev->state.device_mode = mode; in sdtx_device_mode_workfn()
782 input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet); in sdtx_device_mode_workfn()
783 input_sync(ddev->mode_switch); in sdtx_device_mode_workfn()
785 mutex_unlock(&ddev->write_lock); in sdtx_device_mode_workfn()
790 schedule_delayed_work(&ddev->mode_work, delay); in sdtx_update_device_mode()
793 /* Must be executed with ddev->write_lock held. */
799 lockdep_assert_held(&ddev->write_lock); in __sdtx_device_state_update_base()
802 if (ddev->state.base.state == info.state && in __sdtx_device_state_update_base()
803 ddev->state.base.base_id == info.base_id) in __sdtx_device_state_update_base()
806 ddev->state.base = info; in __sdtx_device_state_update_base()
816 /* Must be executed with ddev->write_lock held. */
828 lockdep_assert_held(&ddev->write_lock); in __sdtx_device_state_update_mode()
830 if (sdtx_device_mode_invalid(mode, ddev->state.base.state)) { in __sdtx_device_state_update_mode()
831 dev_dbg(ddev->dev, "device mode is invalid, trying again\n"); in __sdtx_device_state_update_mode()
837 if (ddev->state.device_mode == mode) in __sdtx_device_state_update_mode()
840 ddev->state.device_mode = mode; in __sdtx_device_state_update_mode()
851 input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet); in __sdtx_device_state_update_mode()
852 input_sync(ddev->mode_switch); in __sdtx_device_state_update_mode()
855 /* Must be executed with ddev->write_lock held. */
860 lockdep_assert_held(&ddev->write_lock); in __sdtx_device_state_update_latch()
863 if (ddev->state.latch_status == status) in __sdtx_device_state_update_latch()
866 ddev->state.latch_status = status; in __sdtx_device_state_update_latch()
879 u8 mode, latch; in sdtx_device_state_workfn() local
883 set_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags); in sdtx_device_state_workfn()
884 set_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags); in sdtx_device_state_workfn()
885 set_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags); in sdtx_device_state_workfn()
895 status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &base); in sdtx_device_state_workfn()
897 dev_err(ddev->dev, "failed to get base state: %d\n", status); in sdtx_device_state_workfn()
901 status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode); in sdtx_device_state_workfn()
903 dev_err(ddev->dev, "failed to get device mode: %d\n", status); in sdtx_device_state_workfn()
907 status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &latch); in sdtx_device_state_workfn()
909 dev_err(ddev->dev, "failed to get latch status: %d\n", status); in sdtx_device_state_workfn()
913 mutex_lock(&ddev->write_lock); in sdtx_device_state_workfn()
916 * If the respective dirty-bit has been cleared, an event has been in sdtx_device_state_workfn()
923 if (test_and_clear_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags)) in sdtx_device_state_workfn()
926 if (test_and_clear_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags)) in sdtx_device_state_workfn()
929 if (test_and_clear_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags)) in sdtx_device_state_workfn()
930 __sdtx_device_state_update_latch(ddev, latch); in sdtx_device_state_workfn()
932 mutex_unlock(&ddev->write_lock); in sdtx_device_state_workfn()
937 schedule_delayed_work(&ddev->state_work, delay); in sdtx_update_device_state()
941 /* -- Common device initialization. ----------------------------------------- */
949 kref_init(&ddev->kref); in sdtx_device_init()
950 init_rwsem(&ddev->lock); in sdtx_device_init()
951 ddev->dev = dev; in sdtx_device_init()
952 ddev->ctrl = ctrl; in sdtx_device_init()
954 ddev->mdev.minor = MISC_DYNAMIC_MINOR; in sdtx_device_init()
955 ddev->mdev.name = "surface_dtx"; in sdtx_device_init()
956 ddev->mdev.nodename = "surface/dtx"; in sdtx_device_init()
957 ddev->mdev.fops = &surface_dtx_fops; in sdtx_device_init()
959 ddev->notif.base.priority = 1; in sdtx_device_init()
960 ddev->notif.base.fn = sdtx_notifier; in sdtx_device_init()
961 ddev->notif.event.reg = SSAM_EVENT_REGISTRY_SAM; in sdtx_device_init()
962 ddev->notif.event.id.target_category = SSAM_SSH_TC_BAS; in sdtx_device_init()
963 ddev->notif.event.id.instance = 0; in sdtx_device_init()
964 ddev->notif.event.mask = SSAM_EVENT_MASK_NONE; in sdtx_device_init()
965 ddev->notif.event.flags = SSAM_EVENT_SEQUENCED; in sdtx_device_init()
967 init_waitqueue_head(&ddev->waitq); in sdtx_device_init()
968 mutex_init(&ddev->write_lock); in sdtx_device_init()
969 init_rwsem(&ddev->client_lock); in sdtx_device_init()
970 INIT_LIST_HEAD(&ddev->client_list); in sdtx_device_init()
972 INIT_DELAYED_WORK(&ddev->mode_work, sdtx_device_mode_workfn); in sdtx_device_init()
973 INIT_DELAYED_WORK(&ddev->state_work, sdtx_device_state_workfn); in sdtx_device_init()
986 status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &ddev->state.base); in sdtx_device_init()
990 status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &ddev->state.device_mode); in sdtx_device_init()
994 status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &ddev->state.latch_status); in sdtx_device_init()
999 ddev->mode_switch = input_allocate_device(); in sdtx_device_init()
1000 if (!ddev->mode_switch) in sdtx_device_init()
1001 return -ENOMEM; in sdtx_device_init()
1003 ddev->mode_switch->name = "Microsoft Surface DTX Device Mode Switch"; in sdtx_device_init()
1004 ddev->mode_switch->phys = "ssam/01:11:01:00:00/input0"; in sdtx_device_init()
1005 ddev->mode_switch->id.bustype = BUS_HOST; in sdtx_device_init()
1006 ddev->mode_switch->dev.parent = ddev->dev; in sdtx_device_init()
1008 tablet_mode = (ddev->state.device_mode != SDTX_DEVICE_MODE_LAPTOP); in sdtx_device_init()
1009 input_set_capability(ddev->mode_switch, EV_SW, SW_TABLET_MODE); in sdtx_device_init()
1010 input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet_mode); in sdtx_device_init()
1012 status = input_register_device(ddev->mode_switch); in sdtx_device_init()
1014 input_free_device(ddev->mode_switch); in sdtx_device_init()
1019 status = ssam_notifier_register(ddev->ctrl, &ddev->notif); in sdtx_device_init()
1024 status = misc_register(&ddev->mdev); in sdtx_device_init()
1036 ssam_notifier_unregister(ddev->ctrl, &ddev->notif); in sdtx_device_init()
1037 cancel_delayed_work_sync(&ddev->mode_work); in sdtx_device_init()
1039 input_unregister_device(ddev->mode_switch); in sdtx_device_init()
1050 return ERR_PTR(-ENOMEM); in sdtx_device_create()
1066 * Mark device as shut-down. Prevent new clients from being added and in sdtx_device_destroy()
1069 set_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags); in sdtx_device_destroy()
1072 ssam_notifier_unregister(ddev->ctrl, &ddev->notif); in sdtx_device_destroy()
1075 cancel_delayed_work_sync(&ddev->mode_work); in sdtx_device_destroy()
1078 cancel_delayed_work_sync(&ddev->state_work); in sdtx_device_destroy()
1081 input_unregister_device(ddev->mode_switch); in sdtx_device_destroy()
1084 down_write(&ddev->client_lock); in sdtx_device_destroy()
1085 list_for_each_entry(client, &ddev->client_list, node) { in sdtx_device_destroy()
1086 kill_fasync(&client->fasync, SIGIO, POLL_HUP); in sdtx_device_destroy()
1088 up_write(&ddev->client_lock); in sdtx_device_destroy()
1091 wake_up_interruptible(&ddev->waitq); in sdtx_device_destroy()
1098 down_write(&ddev->lock); in sdtx_device_destroy()
1099 ddev->dev = NULL; in sdtx_device_destroy()
1100 ddev->ctrl = NULL; in sdtx_device_destroy()
1101 up_write(&ddev->lock); in sdtx_device_destroy()
1103 /* Finally remove the misc-device. */ in sdtx_device_destroy()
1104 misc_deregister(&ddev->mdev); in sdtx_device_destroy()
1114 /* -- PM ops. --------------------------------------------------------------- */
1124 * display-off state) and release them when resumed (i.e. transitioned in surface_dtx_pm_complete()
1125 * to display-on state). During hibernation, however, the EC will be in surface_dtx_pm_complete()
1151 /* -- Platform driver. ------------------------------------------------------ */
1159 ctrl = ssam_client_bind(&pdev->dev); in surface_dtx_platform_probe()
1161 return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); in surface_dtx_platform_probe()
1163 ddev = sdtx_device_create(&pdev->dev, ctrl); in surface_dtx_platform_probe()
1195 /* -- SSAM device driver. --------------------------------------------------- */
1203 ddev = sdtx_device_create(&sdev->dev, sdev->ctrl); in surface_dtx_ssam_probe()
1257 /* -- Module setup. --------------------------------------------------------- */
1283 MODULE_DESCRIPTION("Detachment-system driver for Surface System Aggregator Module");