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()
561 /* -- Event handling/forwarding. -------------------------------------------- */
567 * determine the new tablet-mode switch and device mode values after some
595 /* Must be executed with ddev->write_lock held. */
598 const size_t len = sizeof(struct sdtx_event) + evt->length; in sdtx_push_event()
601 lockdep_assert_held(&ddev->write_lock); in sdtx_push_event()
603 down_read(&ddev->client_lock); in sdtx_push_event()
604 list_for_each_entry(client, &ddev->client_list, node) { in sdtx_push_event()
605 if (!test_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags)) in sdtx_push_event()
608 if (likely(kfifo_avail(&client->buffer) >= len)) in sdtx_push_event()
609 kfifo_in(&client->buffer, (const u8 *)evt, len); in sdtx_push_event()
611 dev_warn(ddev->dev, "event buffer overrun\n"); in sdtx_push_event()
613 kill_fasync(&client->fasync, SIGIO, POLL_IN); in sdtx_push_event()
615 up_read(&ddev->client_lock); in sdtx_push_event()
617 wake_up_interruptible(&ddev->waitq); in sdtx_push_event()
627 switch (in->command_id) { in sdtx_notifier()
648 if (in->length != len) { in sdtx_notifier()
649 dev_err(ddev->dev, in sdtx_notifier()
651 in->command_id, in->length, len); in sdtx_notifier()
655 mutex_lock(&ddev->write_lock); in sdtx_notifier()
658 switch (in->command_id) { in sdtx_notifier()
660 clear_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags); in sdtx_notifier()
663 if (ddev->state.base.state == in->data[0] && in sdtx_notifier()
664 ddev->state.base.base_id == in->data[1]) in sdtx_notifier()
667 ddev->state.base.state = in->data[0]; in sdtx_notifier()
668 ddev->state.base.base_id = in->data[1]; in sdtx_notifier()
672 event.base.v.state = sdtx_translate_base_state(ddev, in->data[0]); in sdtx_notifier()
673 event.base.v.base_id = SDTX_BASE_TYPE_SSH(in->data[1]); in sdtx_notifier()
684 event.status.v = sdtx_translate_cancel_reason(ddev, in->data[0]); in sdtx_notifier()
688 clear_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags); in sdtx_notifier()
691 if (ddev->state.latch_status == in->data[0]) in sdtx_notifier()
694 ddev->state.latch_status = in->data[0]; in sdtx_notifier()
698 event.status.v = sdtx_translate_latch_status(ddev, in->data[0]); in sdtx_notifier()
705 if (in->command_id == SAM_EVENT_CID_DTX_CONNECTION) { in sdtx_notifier()
708 delay = in->data[0] ? SDTX_DEVICE_MODE_DELAY_CONNECT : 0; in sdtx_notifier()
713 mutex_unlock(&ddev->write_lock); in sdtx_notifier()
718 /* -- State update functions. ----------------------------------------------- */
737 status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode); in sdtx_device_mode_workfn()
739 dev_err(ddev->dev, "failed to get device mode: %d\n", status); in sdtx_device_mode_workfn()
744 status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &base); in sdtx_device_mode_workfn()
746 dev_err(ddev->dev, "failed to get base info: %d\n", status); in sdtx_device_mode_workfn()
757 dev_dbg(ddev->dev, "device mode is invalid, trying again\n"); in sdtx_device_mode_workfn()
762 mutex_lock(&ddev->write_lock); in sdtx_device_mode_workfn()
763 clear_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags); in sdtx_device_mode_workfn()
765 /* Avoid sending duplicate device-mode events. */ in sdtx_device_mode_workfn()
766 if (ddev->state.device_mode == mode) { in sdtx_device_mode_workfn()
767 mutex_unlock(&ddev->write_lock); in sdtx_device_mode_workfn()
771 ddev->state.device_mode = mode; in sdtx_device_mode_workfn()
781 input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet); in sdtx_device_mode_workfn()
782 input_sync(ddev->mode_switch); in sdtx_device_mode_workfn()
784 mutex_unlock(&ddev->write_lock); in sdtx_device_mode_workfn()
789 schedule_delayed_work(&ddev->mode_work, delay); in sdtx_update_device_mode()
792 /* Must be executed with ddev->write_lock held. */
798 lockdep_assert_held(&ddev->write_lock); in __sdtx_device_state_update_base()
801 if (ddev->state.base.state == info.state && in __sdtx_device_state_update_base()
802 ddev->state.base.base_id == info.base_id) in __sdtx_device_state_update_base()
805 ddev->state.base = info; in __sdtx_device_state_update_base()
815 /* Must be executed with ddev->write_lock held. */
827 lockdep_assert_held(&ddev->write_lock); in __sdtx_device_state_update_mode()
829 if (sdtx_device_mode_invalid(mode, ddev->state.base.state)) { in __sdtx_device_state_update_mode()
830 dev_dbg(ddev->dev, "device mode is invalid, trying again\n"); in __sdtx_device_state_update_mode()
836 if (ddev->state.device_mode == mode) in __sdtx_device_state_update_mode()
839 ddev->state.device_mode = mode; in __sdtx_device_state_update_mode()
850 input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet); in __sdtx_device_state_update_mode()
851 input_sync(ddev->mode_switch); in __sdtx_device_state_update_mode()
854 /* Must be executed with ddev->write_lock held. */
859 lockdep_assert_held(&ddev->write_lock); in __sdtx_device_state_update_latch()
862 if (ddev->state.latch_status == status) in __sdtx_device_state_update_latch()
865 ddev->state.latch_status = status; in __sdtx_device_state_update_latch()
878 u8 mode, latch; in sdtx_device_state_workfn() local
882 set_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags); in sdtx_device_state_workfn()
883 set_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags); in sdtx_device_state_workfn()
884 set_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags); in sdtx_device_state_workfn()
894 status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &base); in sdtx_device_state_workfn()
896 dev_err(ddev->dev, "failed to get base state: %d\n", status); in sdtx_device_state_workfn()
900 status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode); in sdtx_device_state_workfn()
902 dev_err(ddev->dev, "failed to get device mode: %d\n", status); in sdtx_device_state_workfn()
906 status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &latch); in sdtx_device_state_workfn()
908 dev_err(ddev->dev, "failed to get latch status: %d\n", status); in sdtx_device_state_workfn()
912 mutex_lock(&ddev->write_lock); in sdtx_device_state_workfn()
915 * If the respective dirty-bit has been cleared, an event has been in sdtx_device_state_workfn()
922 if (test_and_clear_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags)) in sdtx_device_state_workfn()
925 if (test_and_clear_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags)) in sdtx_device_state_workfn()
928 if (test_and_clear_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags)) in sdtx_device_state_workfn()
929 __sdtx_device_state_update_latch(ddev, latch); in sdtx_device_state_workfn()
931 mutex_unlock(&ddev->write_lock); in sdtx_device_state_workfn()
936 schedule_delayed_work(&ddev->state_work, delay); in sdtx_update_device_state()
940 /* -- Common device initialization. ----------------------------------------- */
948 kref_init(&ddev->kref); in sdtx_device_init()
949 init_rwsem(&ddev->lock); in sdtx_device_init()
950 ddev->dev = dev; in sdtx_device_init()
951 ddev->ctrl = ctrl; in sdtx_device_init()
953 ddev->mdev.minor = MISC_DYNAMIC_MINOR; in sdtx_device_init()
954 ddev->mdev.name = "surface_dtx"; in sdtx_device_init()
955 ddev->mdev.nodename = "surface/dtx"; in sdtx_device_init()
956 ddev->mdev.fops = &surface_dtx_fops; in sdtx_device_init()
958 ddev->notif.base.priority = 1; in sdtx_device_init()
959 ddev->notif.base.fn = sdtx_notifier; in sdtx_device_init()
960 ddev->notif.event.reg = SSAM_EVENT_REGISTRY_SAM; in sdtx_device_init()
961 ddev->notif.event.id.target_category = SSAM_SSH_TC_BAS; in sdtx_device_init()
962 ddev->notif.event.id.instance = 0; in sdtx_device_init()
963 ddev->notif.event.mask = SSAM_EVENT_MASK_NONE; in sdtx_device_init()
964 ddev->notif.event.flags = SSAM_EVENT_SEQUENCED; in sdtx_device_init()
966 init_waitqueue_head(&ddev->waitq); in sdtx_device_init()
967 mutex_init(&ddev->write_lock); in sdtx_device_init()
968 init_rwsem(&ddev->client_lock); in sdtx_device_init()
969 INIT_LIST_HEAD(&ddev->client_list); in sdtx_device_init()
971 INIT_DELAYED_WORK(&ddev->mode_work, sdtx_device_mode_workfn); in sdtx_device_init()
972 INIT_DELAYED_WORK(&ddev->state_work, sdtx_device_state_workfn); in sdtx_device_init()
985 status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &ddev->state.base); in sdtx_device_init()
989 status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &ddev->state.device_mode); in sdtx_device_init()
993 status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &ddev->state.latch_status); in sdtx_device_init()
998 ddev->mode_switch = input_allocate_device(); in sdtx_device_init()
999 if (!ddev->mode_switch) in sdtx_device_init()
1000 return -ENOMEM; in sdtx_device_init()
1002 ddev->mode_switch->name = "Microsoft Surface DTX Device Mode Switch"; in sdtx_device_init()
1003 ddev->mode_switch->phys = "ssam/01:11:01:00:00/input0"; in sdtx_device_init()
1004 ddev->mode_switch->id.bustype = BUS_HOST; in sdtx_device_init()
1005 ddev->mode_switch->dev.parent = ddev->dev; in sdtx_device_init()
1007 tablet_mode = (ddev->state.device_mode != SDTX_DEVICE_MODE_LAPTOP); in sdtx_device_init()
1008 input_set_capability(ddev->mode_switch, EV_SW, SW_TABLET_MODE); in sdtx_device_init()
1009 input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet_mode); in sdtx_device_init()
1011 status = input_register_device(ddev->mode_switch); in sdtx_device_init()
1013 input_free_device(ddev->mode_switch); in sdtx_device_init()
1018 status = ssam_notifier_register(ddev->ctrl, &ddev->notif); in sdtx_device_init()
1023 status = misc_register(&ddev->mdev); in sdtx_device_init()
1035 ssam_notifier_unregister(ddev->ctrl, &ddev->notif); in sdtx_device_init()
1036 cancel_delayed_work_sync(&ddev->mode_work); in sdtx_device_init()
1038 input_unregister_device(ddev->mode_switch); in sdtx_device_init()
1049 return ERR_PTR(-ENOMEM); in sdtx_device_create()
1065 * Mark device as shut-down. Prevent new clients from being added and in sdtx_device_destroy()
1068 set_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags); in sdtx_device_destroy()
1071 ssam_notifier_unregister(ddev->ctrl, &ddev->notif); in sdtx_device_destroy()
1074 cancel_delayed_work_sync(&ddev->mode_work); in sdtx_device_destroy()
1077 cancel_delayed_work_sync(&ddev->state_work); in sdtx_device_destroy()
1080 input_unregister_device(ddev->mode_switch); in sdtx_device_destroy()
1083 down_write(&ddev->client_lock); in sdtx_device_destroy()
1084 list_for_each_entry(client, &ddev->client_list, node) { in sdtx_device_destroy()
1085 kill_fasync(&client->fasync, SIGIO, POLL_HUP); in sdtx_device_destroy()
1087 up_write(&ddev->client_lock); in sdtx_device_destroy()
1090 wake_up_interruptible(&ddev->waitq); in sdtx_device_destroy()
1097 down_write(&ddev->lock); in sdtx_device_destroy()
1098 ddev->dev = NULL; in sdtx_device_destroy()
1099 ddev->ctrl = NULL; in sdtx_device_destroy()
1100 up_write(&ddev->lock); in sdtx_device_destroy()
1102 /* Finally remove the misc-device. */ in sdtx_device_destroy()
1103 misc_deregister(&ddev->mdev); in sdtx_device_destroy()
1113 /* -- PM ops. --------------------------------------------------------------- */
1123 * display-off state) and release them when resumed (i.e. transitioned in surface_dtx_pm_complete()
1124 * to display-on state). During hibernation, however, the EC will be in surface_dtx_pm_complete()
1150 /* -- Platform driver. ------------------------------------------------------ */
1158 ctrl = ssam_client_bind(&pdev->dev); in surface_dtx_platform_probe()
1160 return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); in surface_dtx_platform_probe()
1162 ddev = sdtx_device_create(&pdev->dev, ctrl); in surface_dtx_platform_probe()
1193 /* -- SSAM device driver. --------------------------------------------------- */
1201 ddev = sdtx_device_create(&sdev->dev, sdev->ctrl); in surface_dtx_ssam_probe()
1255 /* -- Module setup. --------------------------------------------------------- */
1281 MODULE_DESCRIPTION("Detachment-system driver for Surface System Aggregator Module");