|
@@ -0,0 +1,4735 @@
|
|
|
|
+From 0a7622f7cd89a2a850caab7794f6a640dee4a5e8 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:36 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator: Allow is_ssam_device() to be
|
|
|
|
+ used when CONFIG_SURFACE_AGGREGATOR_BUS is disabled
|
|
|
|
+
|
|
|
|
+In SSAM subsystem drivers that handle both ACPI and SSAM-native client
|
|
|
|
+devices, we may want to check whether we have a SSAM (native) client
|
|
|
|
+device. Further, we may want to do this even when instantiation thereof
|
|
|
|
+cannot happen due to CONFIG_SURFACE_AGGREGATOR_BUS=n. Currently, doing
|
|
|
|
+so causes an error due to an undefined reference error due to
|
|
|
|
+ssam_device_type being placed in the bus source unit.
|
|
|
|
+
|
|
|
|
+Therefore, if CONFIG_SURFACE_AGGREGATOR_BUS is not defined, simply let
|
|
|
|
+is_ssam_device() return false to prevent this error.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-2-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ include/linux/surface_aggregator/device.h | 11 +++++++++++
|
|
|
|
+ 1 file changed, 11 insertions(+)
|
|
|
|
+
|
|
|
|
+diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
|
|
|
|
+index cc257097eb05..62b38b4487eb 100644
|
|
|
|
+--- a/include/linux/surface_aggregator/device.h
|
|
|
|
++++ b/include/linux/surface_aggregator/device.h
|
|
|
|
+@@ -177,6 +177,8 @@ struct ssam_device_driver {
|
|
|
|
+ void (*remove)(struct ssam_device *sdev);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
++#ifdef CONFIG_SURFACE_AGGREGATOR_BUS
|
|
|
|
++
|
|
|
|
+ extern struct bus_type ssam_bus_type;
|
|
|
|
+ extern const struct device_type ssam_device_type;
|
|
|
|
+
|
|
|
|
+@@ -193,6 +195,15 @@ static inline bool is_ssam_device(struct device *d)
|
|
|
|
+ return d->type == &ssam_device_type;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
++#else /* CONFIG_SURFACE_AGGREGATOR_BUS */
|
|
|
|
++
|
|
|
|
++static inline bool is_ssam_device(struct device *d)
|
|
|
|
++{
|
|
|
|
++ return false;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++#endif /* CONFIG_SURFACE_AGGREGATOR_BUS */
|
|
|
|
++
|
|
|
|
+ /**
|
|
|
|
+ * to_ssam_device() - Casts the given device to a SSAM client device.
|
|
|
|
+ * @d: The device to cast.
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 59ccf6b69fdd0e03572a3e72bf5d16bb93279ab8 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:37 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator: Allow devices to be marked as
|
|
|
|
+ hot-removed
|
|
|
|
+
|
|
|
|
+Some SSAM devices, notably the keyboard cover (keyboard and touchpad) on
|
|
|
|
+the Surface Pro 8, can be hot-removed. When this occurs, communication
|
|
|
|
+with the device may fail and time out. This timeout can unnecessarily
|
|
|
|
+block and slow down device removal and even cause issues when the
|
|
|
|
+devices are detached and re-attached quickly. Thus, communication should
|
|
|
|
+generally be avoided once hot-removal is detected.
|
|
|
|
+
|
|
|
|
+While we already remove a device as soon as we detect its (hot-)removal,
|
|
|
|
+the corresponding device driver may still attempt to communicate with
|
|
|
|
+the device during teardown. This is especially critical as communication
|
|
|
|
+failure may also extend to disabling of events, which is typically done
|
|
|
|
+at that stage.
|
|
|
|
+
|
|
|
|
+Add a flag to allow marking devices as hot-removed. This can then be
|
|
|
|
+used during client driver teardown to check if any communication
|
|
|
|
+attempts should be avoided.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-3-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ include/linux/surface_aggregator/device.h | 48 +++++++++++++++++++++--
|
|
|
|
+ 1 file changed, 45 insertions(+), 3 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
|
|
|
|
+index 62b38b4487eb..6df7c8d4e50e 100644
|
|
|
|
+--- a/include/linux/surface_aggregator/device.h
|
|
|
|
++++ b/include/linux/surface_aggregator/device.h
|
|
|
|
+@@ -148,17 +148,30 @@ struct ssam_device_uid {
|
|
|
|
+ #define SSAM_SDEV(cat, tid, iid, fun) \
|
|
|
|
+ SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, tid, iid, fun)
|
|
|
|
+
|
|
|
|
++/*
|
|
|
|
++ * enum ssam_device_flags - Flags for SSAM client devices.
|
|
|
|
++ * @SSAM_DEVICE_HOT_REMOVED_BIT:
|
|
|
|
++ * The device has been hot-removed. Further communication with it may time
|
|
|
|
++ * out and should be avoided.
|
|
|
|
++ */
|
|
|
|
++enum ssam_device_flags {
|
|
|
|
++ SSAM_DEVICE_HOT_REMOVED_BIT = 0,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
+ /**
|
|
|
|
+ * struct ssam_device - SSAM client device.
|
|
|
|
+- * @dev: Driver model representation of the device.
|
|
|
|
+- * @ctrl: SSAM controller managing this device.
|
|
|
|
+- * @uid: UID identifying the device.
|
|
|
|
++ * @dev: Driver model representation of the device.
|
|
|
|
++ * @ctrl: SSAM controller managing this device.
|
|
|
|
++ * @uid: UID identifying the device.
|
|
|
|
++ * @flags: Device state flags, see &enum ssam_device_flags.
|
|
|
|
+ */
|
|
|
|
+ struct ssam_device {
|
|
|
|
+ struct device dev;
|
|
|
|
+ struct ssam_controller *ctrl;
|
|
|
|
+
|
|
|
|
+ struct ssam_device_uid uid;
|
|
|
|
++
|
|
|
|
++ unsigned long flags;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+@@ -251,6 +264,35 @@ struct ssam_device *ssam_device_alloc(struct ssam_controller *ctrl,
|
|
|
|
+ int ssam_device_add(struct ssam_device *sdev);
|
|
|
|
+ void ssam_device_remove(struct ssam_device *sdev);
|
|
|
|
+
|
|
|
|
++/**
|
|
|
|
++ * ssam_device_mark_hot_removed() - Mark the given device as hot-removed.
|
|
|
|
++ * @sdev: The device to mark as hot-removed.
|
|
|
|
++ *
|
|
|
|
++ * Mark the device as having been hot-removed. This signals drivers using the
|
|
|
|
++ * device that communication with the device should be avoided and may lead to
|
|
|
|
++ * timeouts.
|
|
|
|
++ */
|
|
|
|
++static inline void ssam_device_mark_hot_removed(struct ssam_device *sdev)
|
|
|
|
++{
|
|
|
|
++ dev_dbg(&sdev->dev, "marking device as hot-removed\n");
|
|
|
|
++ set_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++/**
|
|
|
|
++ * ssam_device_is_hot_removed() - Check if the given device has been
|
|
|
|
++ * hot-removed.
|
|
|
|
++ * @sdev: The device to check.
|
|
|
|
++ *
|
|
|
|
++ * Checks if the given device has been marked as hot-removed. See
|
|
|
|
++ * ssam_device_mark_hot_removed() for more details.
|
|
|
|
++ *
|
|
|
|
++ * Return: Returns ``true`` if the device has been marked as hot-removed.
|
|
|
|
++ */
|
|
|
|
++static inline bool ssam_device_is_hot_removed(struct ssam_device *sdev)
|
|
|
|
++{
|
|
|
|
++ return test_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
+ /**
|
|
|
|
+ * ssam_device_get() - Increment reference count of SSAM client device.
|
|
|
|
+ * @sdev: The device to increment the reference count of.
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From f245465a0ede2e4b52cf058caaf043e14065370b Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:38 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator: Allow notifiers to avoid
|
|
|
|
+ communication on unregistering
|
|
|
|
+
|
|
|
|
+When SSAM client devices have been (physically) hot-removed,
|
|
|
|
+communication attempts with those devices may fail and time out. This
|
|
|
|
+can even extend to event notifiers, due to which timeouts may occur
|
|
|
|
+during device removal, slowing down that process.
|
|
|
|
+
|
|
|
|
+Add a parameter to the notifier unregister function that allows skipping
|
|
|
|
+communication with the EC to prevent this. Furthermore, add wrappers for
|
|
|
|
+registering and unregistering notifiers belonging to SSAM client devices
|
|
|
|
+that automatically check if the device has been marked as hot-removed
|
|
|
|
+and communication should be avoided.
|
|
|
|
+
|
|
|
|
+Note that non-SSAM client devices can generally not be hot-removed, so
|
|
|
|
+also add a convenience wrapper for those, defaulting to allow
|
|
|
|
+communication.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-4-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ .../driver-api/surface_aggregator/client.rst | 6 +-
|
|
|
|
+ .../platform/surface/aggregator/controller.c | 53 ++++++++++-----
|
|
|
|
+ include/linux/surface_aggregator/controller.h | 24 ++++++-
|
|
|
|
+ include/linux/surface_aggregator/device.h | 66 +++++++++++++++++++
|
|
|
|
+ 4 files changed, 128 insertions(+), 21 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/Documentation/driver-api/surface_aggregator/client.rst b/Documentation/driver-api/surface_aggregator/client.rst
|
|
|
|
+index e519d374c378..27f95abdbe99 100644
|
|
|
|
+--- a/Documentation/driver-api/surface_aggregator/client.rst
|
|
|
|
++++ b/Documentation/driver-api/surface_aggregator/client.rst
|
|
|
|
+@@ -17,6 +17,8 @@
|
|
|
|
+ .. |SSAM_DEVICE| replace:: :c:func:`SSAM_DEVICE`
|
|
|
|
+ .. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register`
|
|
|
|
+ .. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
|
|
|
|
++.. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register`
|
|
|
|
++.. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister`
|
|
|
|
+ .. |ssam_request_sync| replace:: :c:func:`ssam_request_sync`
|
|
|
|
+ .. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask <ssam_event_mask>`
|
|
|
|
+
|
|
|
|
+@@ -312,7 +314,9 @@ Handling Events
|
|
|
|
+ To receive events from the SAM EC, an event notifier must be registered for
|
|
|
|
+ the desired event via |ssam_notifier_register|. The notifier must be
|
|
|
|
+ unregistered via |ssam_notifier_unregister| once it is not required any
|
|
|
|
+-more.
|
|
|
|
++more. For |ssam_device| type clients, the |ssam_device_notifier_register| and
|
|
|
|
++|ssam_device_notifier_unregister| wrappers should be preferred as they properly
|
|
|
|
++handle hot-removal of client devices.
|
|
|
|
+
|
|
|
|
+ Event notifiers are registered by providing (at minimum) a callback to call
|
|
|
|
+ in case an event has been received, the registry specifying how the event
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
|
|
|
|
+index b8c377b3f932..6de834b52b63 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/controller.c
|
|
|
|
++++ b/drivers/platform/surface/aggregator/controller.c
|
|
|
|
+@@ -2199,16 +2199,26 @@ static int ssam_nf_refcount_enable(struct ssam_controller *ctrl,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+- * ssam_nf_refcount_disable_free() - Disable event for reference count entry if it is
|
|
|
|
+- * no longer in use and free the corresponding entry.
|
|
|
|
++ * ssam_nf_refcount_disable_free() - Disable event for reference count entry if
|
|
|
|
++ * it is no longer in use and free the corresponding entry.
|
|
|
|
+ * @ctrl: The controller to disable the event on.
|
|
|
|
+ * @entry: The reference count entry for the event to be disabled.
|
|
|
|
+ * @flags: The flags used for enabling the event on the EC.
|
|
|
|
++ * @ec: Flag specifying if the event should actually be disabled on the EC.
|
|
|
|
+ *
|
|
|
|
+- * If the reference count equals zero, i.e. the event is no longer requested by
|
|
|
|
+- * any client, the event will be disabled and the corresponding reference count
|
|
|
|
+- * entry freed. The reference count entry must not be used any more after a
|
|
|
|
+- * call to this function.
|
|
|
|
++ * If ``ec`` equals ``true`` and the reference count equals zero (i.e. the
|
|
|
|
++ * event is no longer requested by any client), the specified event will be
|
|
|
|
++ * disabled on the EC via the corresponding request.
|
|
|
|
++ *
|
|
|
|
++ * If ``ec`` equals ``false``, no request will be sent to the EC and the event
|
|
|
|
++ * can be considered in a detached state (i.e. no longer used but still
|
|
|
|
++ * enabled). Disabling an event via this method may be required for
|
|
|
|
++ * hot-removable devices, where event disable requests may time out after the
|
|
|
|
++ * device has been physically removed.
|
|
|
|
++ *
|
|
|
|
++ * In both cases, if the reference count equals zero, the corresponding
|
|
|
|
++ * reference count entry will be freed. The reference count entry must not be
|
|
|
|
++ * used any more after a call to this function.
|
|
|
|
+ *
|
|
|
|
+ * Also checks if the flags used for disabling the event match the flags used
|
|
|
|
+ * for enabling the event and warns if they do not (regardless of reference
|
|
|
|
+@@ -2223,7 +2233,7 @@ static int ssam_nf_refcount_enable(struct ssam_controller *ctrl,
|
|
|
|
+ * returns the status of the event-enable EC command.
|
|
|
|
+ */
|
|
|
|
+ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl,
|
|
|
|
+- struct ssam_nf_refcount_entry *entry, u8 flags)
|
|
|
|
++ struct ssam_nf_refcount_entry *entry, u8 flags, bool ec)
|
|
|
|
+ {
|
|
|
|
+ const struct ssam_event_registry reg = entry->key.reg;
|
|
|
|
+ const struct ssam_event_id id = entry->key.id;
|
|
|
|
+@@ -2232,8 +2242,9 @@ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl,
|
|
|
|
+
|
|
|
|
+ lockdep_assert_held(&nf->lock);
|
|
|
|
+
|
|
|
|
+- ssam_dbg(ctrl, "disabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n",
|
|
|
|
+- reg.target_category, id.target_category, id.instance, entry->refcount);
|
|
|
|
++ ssam_dbg(ctrl, "%s event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n",
|
|
|
|
++ ec ? "disabling" : "detaching", reg.target_category, id.target_category,
|
|
|
|
++ id.instance, entry->refcount);
|
|
|
|
+
|
|
|
|
+ if (entry->flags != flags) {
|
|
|
|
+ ssam_warn(ctrl,
|
|
|
|
+@@ -2242,7 +2253,7 @@ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl,
|
|
|
|
+ id.instance);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+- if (entry->refcount == 0) {
|
|
|
|
++ if (ec && entry->refcount == 0) {
|
|
|
|
+ status = ssam_ssh_event_disable(ctrl, reg, id, flags);
|
|
|
|
+ kfree(entry);
|
|
|
|
+ }
|
|
|
|
+@@ -2322,20 +2333,26 @@ int ssam_notifier_register(struct ssam_controller *ctrl, struct ssam_event_notif
|
|
|
|
+ EXPORT_SYMBOL_GPL(ssam_notifier_register);
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+- * ssam_notifier_unregister() - Unregister an event notifier.
|
|
|
|
+- * @ctrl: The controller the notifier has been registered on.
|
|
|
|
+- * @n: The event notifier to unregister.
|
|
|
|
++ * __ssam_notifier_unregister() - Unregister an event notifier.
|
|
|
|
++ * @ctrl: The controller the notifier has been registered on.
|
|
|
|
++ * @n: The event notifier to unregister.
|
|
|
|
++ * @disable: Whether to disable the corresponding event on the EC.
|
|
|
|
+ *
|
|
|
|
+ * Unregister an event notifier. Decrement the usage counter of the associated
|
|
|
|
+ * SAM event if the notifier is not marked as an observer. If the usage counter
|
|
|
|
+- * reaches zero, the event will be disabled.
|
|
|
|
++ * reaches zero and ``disable`` equals ``true``, the event will be disabled.
|
|
|
|
++ *
|
|
|
|
++ * Useful for hot-removable devices, where communication may fail once the
|
|
|
|
++ * device has been physically removed. In that case, specifying ``disable`` as
|
|
|
|
++ * ``false`` avoids communication with the EC.
|
|
|
|
+ *
|
|
|
|
+ * Return: Returns zero on success, %-ENOENT if the given notifier block has
|
|
|
|
+ * not been registered on the controller. If the given notifier block was the
|
|
|
|
+ * last one associated with its specific event, returns the status of the
|
|
|
|
+ * event-disable EC-command.
|
|
|
|
+ */
|
|
|
|
+-int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n)
|
|
|
|
++int __ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n,
|
|
|
|
++ bool disable)
|
|
|
|
+ {
|
|
|
|
+ u16 rqid = ssh_tc_to_rqid(n->event.id.target_category);
|
|
|
|
+ struct ssam_nf_refcount_entry *entry;
|
|
|
|
+@@ -2373,7 +2390,7 @@ int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_not
|
|
|
|
+ goto remove;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+- status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags);
|
|
|
|
++ status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags, disable);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ remove:
|
|
|
|
+@@ -2383,7 +2400,7 @@ int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_not
|
|
|
|
+
|
|
|
|
+ return status;
|
|
|
|
+ }
|
|
|
|
+-EXPORT_SYMBOL_GPL(ssam_notifier_unregister);
|
|
|
|
++EXPORT_SYMBOL_GPL(__ssam_notifier_unregister);
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * ssam_controller_event_enable() - Enable the specified event.
|
|
|
|
+@@ -2477,7 +2494,7 @@ int ssam_controller_event_disable(struct ssam_controller *ctrl,
|
|
|
|
+ return -ENOENT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+- status = ssam_nf_refcount_disable_free(ctrl, entry, flags);
|
|
|
|
++ status = ssam_nf_refcount_disable_free(ctrl, entry, flags, true);
|
|
|
|
+
|
|
|
|
+ mutex_unlock(&nf->lock);
|
|
|
|
+ return status;
|
|
|
|
+diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h
|
|
|
|
+index 74bfdffaf7b0..50a2b4926c06 100644
|
|
|
|
+--- a/include/linux/surface_aggregator/controller.h
|
|
|
|
++++ b/include/linux/surface_aggregator/controller.h
|
|
|
|
+@@ -835,8 +835,28 @@ struct ssam_event_notifier {
|
|
|
|
+ int ssam_notifier_register(struct ssam_controller *ctrl,
|
|
|
|
+ struct ssam_event_notifier *n);
|
|
|
|
+
|
|
|
|
+-int ssam_notifier_unregister(struct ssam_controller *ctrl,
|
|
|
|
+- struct ssam_event_notifier *n);
|
|
|
|
++int __ssam_notifier_unregister(struct ssam_controller *ctrl,
|
|
|
|
++ struct ssam_event_notifier *n, bool disable);
|
|
|
|
++
|
|
|
|
++/**
|
|
|
|
++ * ssam_notifier_unregister() - Unregister an event notifier.
|
|
|
|
++ * @ctrl: The controller the notifier has been registered on.
|
|
|
|
++ * @n: The event notifier to unregister.
|
|
|
|
++ *
|
|
|
|
++ * Unregister an event notifier. Decrement the usage counter of the associated
|
|
|
|
++ * SAM event if the notifier is not marked as an observer. If the usage counter
|
|
|
|
++ * reaches zero, the event will be disabled.
|
|
|
|
++ *
|
|
|
|
++ * Return: Returns zero on success, %-ENOENT if the given notifier block has
|
|
|
|
++ * not been registered on the controller. If the given notifier block was the
|
|
|
|
++ * last one associated with its specific event, returns the status of the
|
|
|
|
++ * event-disable EC-command.
|
|
|
|
++ */
|
|
|
|
++static inline int ssam_notifier_unregister(struct ssam_controller *ctrl,
|
|
|
|
++ struct ssam_event_notifier *n)
|
|
|
|
++{
|
|
|
|
++ return __ssam_notifier_unregister(ctrl, n, true);
|
|
|
|
++}
|
|
|
|
+
|
|
|
|
+ int ssam_controller_event_enable(struct ssam_controller *ctrl,
|
|
|
|
+ struct ssam_event_registry reg,
|
|
|
|
+diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
|
|
|
|
+index 6df7c8d4e50e..c418f7f2732d 100644
|
|
|
|
+--- a/include/linux/surface_aggregator/device.h
|
|
|
|
++++ b/include/linux/surface_aggregator/device.h
|
|
|
|
+@@ -483,4 +483,70 @@ static inline void ssam_remove_clients(struct device *dev) {}
|
|
|
|
+ sdev->uid.instance, ret); \
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
++
|
|
|
|
++/* -- Helpers for client-device notifiers. ---------------------------------- */
|
|
|
|
++
|
|
|
|
++/**
|
|
|
|
++ * ssam_device_notifier_register() - Register an event notifier for the
|
|
|
|
++ * specified client device.
|
|
|
|
++ * @sdev: The device the notifier should be registered on.
|
|
|
|
++ * @n: The event notifier to register.
|
|
|
|
++ *
|
|
|
|
++ * Register an event notifier. Increment the usage counter of the associated
|
|
|
|
++ * SAM event if the notifier is not marked as an observer. If the event is not
|
|
|
|
++ * marked as an observer and is currently not enabled, it will be enabled
|
|
|
|
++ * during this call. If the notifier is marked as an observer, no attempt will
|
|
|
|
++ * be made at enabling any event and no reference count will be modified.
|
|
|
|
++ *
|
|
|
|
++ * Notifiers marked as observers do not need to be associated with one specific
|
|
|
|
++ * event, i.e. as long as no event matching is performed, only the event target
|
|
|
|
++ * category needs to be set.
|
|
|
|
++ *
|
|
|
|
++ * Return: Returns zero on success, %-ENOSPC if there have already been
|
|
|
|
++ * %INT_MAX notifiers for the event ID/type associated with the notifier block
|
|
|
|
++ * registered, %-ENOMEM if the corresponding event entry could not be
|
|
|
|
++ * allocated, %-ENODEV if the device is marked as hot-removed. If this is the
|
|
|
|
++ * first time that a notifier block is registered for the specific associated
|
|
|
|
++ * event, returns the status of the event-enable EC-command.
|
|
|
|
++ */
|
|
|
|
++static inline int ssam_device_notifier_register(struct ssam_device *sdev,
|
|
|
|
++ struct ssam_event_notifier *n)
|
|
|
|
++{
|
|
|
|
++ /*
|
|
|
|
++ * Note that this check does not provide any guarantees whatsoever as
|
|
|
|
++ * hot-removal could happen at any point and we can't protect against
|
|
|
|
++ * it. Nevertheless, if we can detect hot-removal, bail early to avoid
|
|
|
|
++ * communication timeouts.
|
|
|
|
++ */
|
|
|
|
++ if (ssam_device_is_hot_removed(sdev))
|
|
|
|
++ return -ENODEV;
|
|
|
|
++
|
|
|
|
++ return ssam_notifier_register(sdev->ctrl, n);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++/**
|
|
|
|
++ * ssam_device_notifier_unregister() - Unregister an event notifier for the
|
|
|
|
++ * specified client device.
|
|
|
|
++ * @sdev: The device the notifier has been registered on.
|
|
|
|
++ * @n: The event notifier to unregister.
|
|
|
|
++ *
|
|
|
|
++ * Unregister an event notifier. Decrement the usage counter of the associated
|
|
|
|
++ * SAM event if the notifier is not marked as an observer. If the usage counter
|
|
|
|
++ * reaches zero, the event will be disabled.
|
|
|
|
++ *
|
|
|
|
++ * In case the device has been marked as hot-removed, the event will not be
|
|
|
|
++ * disabled on the EC, as in those cases any attempt at doing so may time out.
|
|
|
|
++ *
|
|
|
|
++ * Return: Returns zero on success, %-ENOENT if the given notifier block has
|
|
|
|
++ * not been registered on the controller. If the given notifier block was the
|
|
|
|
++ * last one associated with its specific event, returns the status of the
|
|
|
|
++ * event-disable EC-command.
|
|
|
|
++ */
|
|
|
|
++static inline int ssam_device_notifier_unregister(struct ssam_device *sdev,
|
|
|
|
++ struct ssam_event_notifier *n)
|
|
|
|
++{
|
|
|
|
++ return __ssam_notifier_unregister(sdev->ctrl, n,
|
|
|
|
++ !ssam_device_is_hot_removed(sdev));
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
+ #endif /* _LINUX_SURFACE_AGGREGATOR_DEVICE_H */
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 75e02994d3a8b2cd245918f9e5087b17d287f17e Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:39 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Use client device
|
|
|
|
+ wrappers for notifier registration
|
|
|
|
+
|
|
|
|
+Use newly introduced client device wrapper functions for notifier
|
|
|
|
+registration and unregistration.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-5-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/platform/surface/surface_aggregator_registry.c | 6 +++---
|
|
|
|
+ 1 file changed, 3 insertions(+), 3 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index ce2bd88feeaa..9f630e890ff7 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -468,7 +468,7 @@ static int ssam_base_hub_probe(struct ssam_device *sdev)
|
|
|
|
+
|
|
|
|
+ ssam_device_set_drvdata(sdev, hub);
|
|
|
|
+
|
|
|
|
+- status = ssam_notifier_register(sdev->ctrl, &hub->notif);
|
|
|
|
++ status = ssam_device_notifier_register(sdev, &hub->notif);
|
|
|
|
+ if (status)
|
|
|
|
+ return status;
|
|
|
|
+
|
|
|
|
+@@ -480,7 +480,7 @@ static int ssam_base_hub_probe(struct ssam_device *sdev)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ err:
|
|
|
|
+- ssam_notifier_unregister(sdev->ctrl, &hub->notif);
|
|
|
|
++ ssam_device_notifier_unregister(sdev, &hub->notif);
|
|
|
|
+ cancel_delayed_work_sync(&hub->update_work);
|
|
|
|
+ ssam_remove_clients(&sdev->dev);
|
|
|
|
+ return status;
|
|
|
|
+@@ -492,7 +492,7 @@ static void ssam_base_hub_remove(struct ssam_device *sdev)
|
|
|
|
+
|
|
|
|
+ sysfs_remove_group(&sdev->dev.kobj, &ssam_base_hub_group);
|
|
|
|
+
|
|
|
|
+- ssam_notifier_unregister(sdev->ctrl, &hub->notif);
|
|
|
|
++ ssam_device_notifier_unregister(sdev, &hub->notif);
|
|
|
|
+ cancel_delayed_work_sync(&hub->update_work);
|
|
|
|
+ ssam_remove_clients(&sdev->dev);
|
|
|
|
+ }
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 47c31518e1c63bfa6d1c8dfec5db080f1ceb8749 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:40 +0200
|
|
|
|
+Subject: [PATCH] power/supply: surface_charger: Use client device wrappers for
|
|
|
|
+ notifier registration
|
|
|
|
+
|
|
|
|
+Use newly introduced client device wrapper functions for notifier
|
|
|
|
+registration and unregistration.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-6-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/power/supply/surface_charger.c | 4 ++--
|
|
|
|
+ 1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c
|
|
|
|
+index a060c36c7766..59182d55742d 100644
|
|
|
|
+--- a/drivers/power/supply/surface_charger.c
|
|
|
|
++++ b/drivers/power/supply/surface_charger.c
|
|
|
|
+@@ -216,7 +216,7 @@ static int spwr_ac_register(struct spwr_ac_device *ac)
|
|
|
|
+ if (IS_ERR(ac->psy))
|
|
|
|
+ return PTR_ERR(ac->psy);
|
|
|
|
+
|
|
|
|
+- return ssam_notifier_register(ac->sdev->ctrl, &ac->notif);
|
|
|
|
++ return ssam_device_notifier_register(ac->sdev, &ac->notif);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+@@ -251,7 +251,7 @@ static void surface_ac_remove(struct ssam_device *sdev)
|
|
|
|
+ {
|
|
|
|
+ struct spwr_ac_device *ac = ssam_device_get_drvdata(sdev);
|
|
|
|
+
|
|
|
|
+- ssam_notifier_unregister(sdev->ctrl, &ac->notif);
|
|
|
|
++ ssam_device_notifier_unregister(sdev, &ac->notif);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static const struct spwr_psy_properties spwr_psy_props_adp1 = {
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From c588c883700fd3dd5cb03de059f15746651327fa Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:41 +0200
|
|
|
|
+Subject: [PATCH] power/supply: surface_battery: Use client device wrappers for
|
|
|
|
+ notifier registration
|
|
|
|
+
|
|
|
|
+Use newly introduced client device wrapper functions for notifier
|
|
|
|
+registration and unregistration.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-7-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/power/supply/surface_battery.c | 4 ++--
|
|
|
|
+ 1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c
|
|
|
|
+index 5ec2e6bb2465..540707882bb0 100644
|
|
|
|
+--- a/drivers/power/supply/surface_battery.c
|
|
|
|
++++ b/drivers/power/supply/surface_battery.c
|
|
|
|
+@@ -802,7 +802,7 @@ static int spwr_battery_register(struct spwr_battery_device *bat)
|
|
|
|
+ if (IS_ERR(bat->psy))
|
|
|
|
+ return PTR_ERR(bat->psy);
|
|
|
|
+
|
|
|
|
+- return ssam_notifier_register(bat->sdev->ctrl, &bat->notif);
|
|
|
|
++ return ssam_device_notifier_register(bat->sdev, &bat->notif);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+@@ -837,7 +837,7 @@ static void surface_battery_remove(struct ssam_device *sdev)
|
|
|
|
+ {
|
|
|
|
+ struct spwr_battery_device *bat = ssam_device_get_drvdata(sdev);
|
|
|
|
+
|
|
|
|
+- ssam_notifier_unregister(sdev->ctrl, &bat->notif);
|
|
|
|
++ ssam_device_notifier_unregister(sdev, &bat->notif);
|
|
|
|
+ cancel_delayed_work_sync(&bat->update_work);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 678945c668057fb32298231e4c6ce14a1cbacb6b Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:42 +0200
|
|
|
|
+Subject: [PATCH] HID: surface-hid: Add support for hot-removal
|
|
|
|
+
|
|
|
|
+Add support for hot-removal of SSAM HID client devices.
|
|
|
|
+
|
|
|
|
+Once a device has been hot-removed, further communication with it should
|
|
|
|
+be avoided as it may fail and time out. While the device will be removed
|
|
|
|
+as soon as we detect hot-removal, communication may still occur during
|
|
|
|
+teardown, especially when unregistering notifiers.
|
|
|
|
+
|
|
|
|
+While hot-removal is a surprise event that can happen at any time, try
|
|
|
|
+to avoid communication as much as possible once it has been detected to
|
|
|
|
+prevent timeouts that can slow down device removal and cause issues,
|
|
|
|
+e.g. when quickly re-attaching the device.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-8-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/hid/surface-hid/surface_hid_core.c | 38 +++++++++++++++++++++-
|
|
|
|
+ 1 file changed, 37 insertions(+), 1 deletion(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/hid/surface-hid/surface_hid_core.c b/drivers/hid/surface-hid/surface_hid_core.c
|
|
|
|
+index e46330b2e561..87637f813de2 100644
|
|
|
|
+--- a/drivers/hid/surface-hid/surface_hid_core.c
|
|
|
|
++++ b/drivers/hid/surface-hid/surface_hid_core.c
|
|
|
|
+@@ -19,12 +19,30 @@
|
|
|
|
+ #include "surface_hid_core.h"
|
|
|
|
+
|
|
|
|
+
|
|
|
|
++/* -- Utility functions. ---------------------------------------------------- */
|
|
|
|
++
|
|
|
|
++static bool surface_hid_is_hot_removed(struct surface_hid_device *shid)
|
|
|
|
++{
|
|
|
|
++ /*
|
|
|
|
++ * Non-ssam client devices, i.e. platform client devices, cannot be
|
|
|
|
++ * hot-removed.
|
|
|
|
++ */
|
|
|
|
++ if (!is_ssam_device(shid->dev))
|
|
|
|
++ return false;
|
|
|
|
++
|
|
|
|
++ return ssam_device_is_hot_removed(to_ssam_device(shid->dev));
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++
|
|
|
|
+ /* -- Device descriptor access. --------------------------------------------- */
|
|
|
|
+
|
|
|
|
+ static int surface_hid_load_hid_descriptor(struct surface_hid_device *shid)
|
|
|
|
+ {
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
++ if (surface_hid_is_hot_removed(shid))
|
|
|
|
++ return -ENODEV;
|
|
|
|
++
|
|
|
|
+ status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_HID,
|
|
|
|
+ (u8 *)&shid->hid_desc, sizeof(shid->hid_desc));
|
|
|
|
+ if (status)
|
|
|
|
+@@ -61,6 +79,9 @@ static int surface_hid_load_device_attributes(struct surface_hid_device *shid)
|
|
|
|
+ {
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
++ if (surface_hid_is_hot_removed(shid))
|
|
|
|
++ return -ENODEV;
|
|
|
|
++
|
|
|
|
+ status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_ATTRS,
|
|
|
|
+ (u8 *)&shid->attrs, sizeof(shid->attrs));
|
|
|
|
+ if (status)
|
|
|
|
+@@ -88,9 +109,18 @@ static int surface_hid_start(struct hid_device *hid)
|
|
|
|
+ static void surface_hid_stop(struct hid_device *hid)
|
|
|
|
+ {
|
|
|
|
+ struct surface_hid_device *shid = hid->driver_data;
|
|
|
|
++ bool hot_removed;
|
|
|
|
++
|
|
|
|
++ /*
|
|
|
|
++ * Communication may fail for devices that have been hot-removed. This
|
|
|
|
++ * also includes unregistration of HID events, so we need to check this
|
|
|
|
++ * here. Only if the device has not been marked as hot-removed, we can
|
|
|
|
++ * safely disable events.
|
|
|
|
++ */
|
|
|
|
++ hot_removed = surface_hid_is_hot_removed(shid);
|
|
|
|
+
|
|
|
|
+ /* Note: This call will log errors for us, so ignore them here. */
|
|
|
|
+- ssam_notifier_unregister(shid->ctrl, &shid->notif);
|
|
|
|
++ __ssam_notifier_unregister(shid->ctrl, &shid->notif, !hot_removed);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static int surface_hid_open(struct hid_device *hid)
|
|
|
|
+@@ -109,6 +139,9 @@ static int surface_hid_parse(struct hid_device *hid)
|
|
|
|
+ u8 *buf;
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
++ if (surface_hid_is_hot_removed(shid))
|
|
|
|
++ return -ENODEV;
|
|
|
|
++
|
|
|
|
+ buf = kzalloc(len, GFP_KERNEL);
|
|
|
|
+ if (!buf)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+@@ -126,6 +159,9 @@ static int surface_hid_raw_request(struct hid_device *hid, unsigned char reportn
|
|
|
|
+ {
|
|
|
|
+ struct surface_hid_device *shid = hid->driver_data;
|
|
|
|
+
|
|
|
|
++ if (surface_hid_is_hot_removed(shid))
|
|
|
|
++ return -ENODEV;
|
|
|
|
++
|
|
|
|
+ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT)
|
|
|
|
+ return shid->ops.output_report(shid, reportnum, buf, len);
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 9797970d6472dec59e7cdeb112ef406e6a14a201 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:43 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator: Add comment for KIP subsystem
|
|
|
|
+ category
|
|
|
|
+
|
|
|
|
+The KIP subsystem (full name unknown, abbreviation has been obtained
|
|
|
|
+through reverse engineering) handles detachable peripherals such as the
|
|
|
|
+keyboard cover on the Surface Pro X and Surface Pro 8.
|
|
|
|
+
|
|
|
|
+It is currently not entirely clear what this subsystem entails, but at
|
|
|
|
+the very least it provides event notifications for when the keyboard
|
|
|
|
+cover on the Surface Pro X and Surface Pro 8 have been detached or
|
|
|
|
+re-attached, as well as the state that the keyboard cover is currently
|
|
|
|
+in (e.g. folded-back, folded laptop-like, closed, etc.).
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-9-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ include/linux/surface_aggregator/serial_hub.h | 2 +-
|
|
|
|
+ 1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
+
|
|
|
|
+diff --git a/include/linux/surface_aggregator/serial_hub.h b/include/linux/surface_aggregator/serial_hub.h
|
|
|
|
+index c3de43edcffa..26b95ec12733 100644
|
|
|
|
+--- a/include/linux/surface_aggregator/serial_hub.h
|
|
|
|
++++ b/include/linux/surface_aggregator/serial_hub.h
|
|
|
|
+@@ -306,7 +306,7 @@ enum ssam_ssh_tc {
|
|
|
|
+ SSAM_SSH_TC_LPC = 0x0b,
|
|
|
|
+ SSAM_SSH_TC_TCL = 0x0c,
|
|
|
|
+ SSAM_SSH_TC_SFL = 0x0d,
|
|
|
|
+- SSAM_SSH_TC_KIP = 0x0e,
|
|
|
|
++ SSAM_SSH_TC_KIP = 0x0e, /* Manages detachable peripherals (Pro X/8 keyboard cover) */
|
|
|
|
+ SSAM_SSH_TC_EXT = 0x0f,
|
|
|
|
+ SSAM_SSH_TC_BLD = 0x10,
|
|
|
|
+ SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 50b9b6d1d3d557a736d113724e4689af80510948 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:44 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Generify subsystem hub
|
|
|
|
+ functionality
|
|
|
|
+
|
|
|
|
+The Surface System Aggregator Module (SSAM) has multiple subsystems that
|
|
|
|
+can manage detachable devices. At the moment, we only support the "base"
|
|
|
|
+(BAS/0x11) subsystem, which is used on the Surface Book 3 to manage
|
|
|
|
+devices (including keyboard, touchpad, and secondary battery) connected
|
|
|
|
+to the base of the device.
|
|
|
|
+
|
|
|
|
+The Surface Pro 8 has a new type-cover with keyboard and touchpad, which
|
|
|
|
+is managed via the KIP/0x0e subsystem. The general procedure is the
|
|
|
|
+same, but with slightly different events and setup. To make
|
|
|
|
+implementation of the KIP hub easier and prevent duplication, generify
|
|
|
|
+the parts of the base hub that we can use for the KIP hub (or any
|
|
|
|
+potential future subsystem hubs).
|
|
|
|
+
|
|
|
|
+This also switches over to use the newly introduced "hot-remove"
|
|
|
|
+functionality, which should prevent communication issues when devices
|
|
|
|
+have been detached.
|
|
|
|
+
|
|
|
|
+Lastly, also drop the undocumented and unused sysfs "state" attribute of
|
|
|
|
+the base hub. It has at best been useful for debugging.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-10-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ .../surface/surface_aggregator_registry.c | 269 ++++++++++--------
|
|
|
|
+ 1 file changed, 153 insertions(+), 116 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index 9f630e890ff7..09cbeee2428b 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -308,30 +308,159 @@ static int ssam_hub_register_clients(struct device *parent, struct ssam_controll
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+-/* -- SSAM base-hub driver. ------------------------------------------------- */
|
|
|
|
++/* -- SSAM generic subsystem hub driver framework. -------------------------- */
|
|
|
|
+
|
|
|
|
+-/*
|
|
|
|
+- * Some devices (especially battery) may need a bit of time to be fully usable
|
|
|
|
+- * after being (re-)connected. This delay has been determined via
|
|
|
|
+- * experimentation.
|
|
|
|
+- */
|
|
|
|
+-#define SSAM_BASE_UPDATE_CONNECT_DELAY msecs_to_jiffies(2500)
|
|
|
|
++enum ssam_hub_state {
|
|
|
|
++ SSAM_HUB_UNINITIALIZED, /* Only set during initialization. */
|
|
|
|
++ SSAM_HUB_CONNECTED,
|
|
|
|
++ SSAM_HUB_DISCONNECTED,
|
|
|
|
++};
|
|
|
|
+
|
|
|
|
+-enum ssam_base_hub_state {
|
|
|
|
+- SSAM_BASE_HUB_UNINITIALIZED,
|
|
|
|
+- SSAM_BASE_HUB_CONNECTED,
|
|
|
|
+- SSAM_BASE_HUB_DISCONNECTED,
|
|
|
|
++enum ssam_hub_flags {
|
|
|
|
++ SSAM_HUB_HOT_REMOVED,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+-struct ssam_base_hub {
|
|
|
|
++struct ssam_hub {
|
|
|
|
+ struct ssam_device *sdev;
|
|
|
|
+
|
|
|
|
+- enum ssam_base_hub_state state;
|
|
|
|
++ enum ssam_hub_state state;
|
|
|
|
++ unsigned long flags;
|
|
|
|
++
|
|
|
|
+ struct delayed_work update_work;
|
|
|
|
++ unsigned long connect_delay;
|
|
|
|
+
|
|
|
|
+ struct ssam_event_notifier notif;
|
|
|
|
++
|
|
|
|
++ int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
++static void ssam_hub_update_workfn(struct work_struct *work)
|
|
|
|
++{
|
|
|
|
++ struct ssam_hub *hub = container_of(work, struct ssam_hub, update_work.work);
|
|
|
|
++ struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev);
|
|
|
|
++ enum ssam_hub_state state;
|
|
|
|
++ int status = 0;
|
|
|
|
++
|
|
|
|
++ status = hub->get_state(hub, &state);
|
|
|
|
++ if (status)
|
|
|
|
++ return;
|
|
|
|
++
|
|
|
|
++ /*
|
|
|
|
++ * There is a small possibility that hub devices were hot-removed and
|
|
|
|
++ * re-added before we were able to remove them here. In that case, both
|
|
|
|
++ * the state returned by get_state() and the state of the hub will
|
|
|
|
++ * equal SSAM_HUB_CONNECTED and we would bail early below, which would
|
|
|
|
++ * leave child devices without proper (re-)initialization and the
|
|
|
|
++ * hot-remove flag set.
|
|
|
|
++ *
|
|
|
|
++ * Therefore, we check whether devices have been hot-removed via an
|
|
|
|
++ * additional flag on the hub and, in this case, override the returned
|
|
|
|
++ * hub state. In case of a missed disconnect (i.e. get_state returned
|
|
|
|
++ * "connected"), we further need to re-schedule this work (with the
|
|
|
|
++ * appropriate delay) as the actual connect work submission might have
|
|
|
|
++ * been merged with this one.
|
|
|
|
++ *
|
|
|
|
++ * This then leads to one of two cases: Either we submit an unnecessary
|
|
|
|
++ * work item (which will get ignored via either the queue or the state
|
|
|
|
++ * checks) or, in the unlikely case that the work is actually required,
|
|
|
|
++ * double the normal connect delay.
|
|
|
|
++ */
|
|
|
|
++ if (test_and_clear_bit(SSAM_HUB_HOT_REMOVED, &hub->flags)) {
|
|
|
|
++ if (state == SSAM_HUB_CONNECTED)
|
|
|
|
++ schedule_delayed_work(&hub->update_work, hub->connect_delay);
|
|
|
|
++
|
|
|
|
++ state = SSAM_HUB_DISCONNECTED;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ if (hub->state == state)
|
|
|
|
++ return;
|
|
|
|
++ hub->state = state;
|
|
|
|
++
|
|
|
|
++ if (hub->state == SSAM_HUB_CONNECTED)
|
|
|
|
++ status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node);
|
|
|
|
++ else
|
|
|
|
++ ssam_remove_clients(&hub->sdev->dev);
|
|
|
|
++
|
|
|
|
++ if (status)
|
|
|
|
++ dev_err(&hub->sdev->dev, "failed to update hub child devices: %d\n", status);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int ssam_hub_mark_hot_removed(struct device *dev, void *_data)
|
|
|
|
++{
|
|
|
|
++ struct ssam_device *sdev = to_ssam_device(dev);
|
|
|
|
++
|
|
|
|
++ if (is_ssam_device(dev))
|
|
|
|
++ ssam_device_mark_hot_removed(sdev);
|
|
|
|
++
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static void ssam_hub_update(struct ssam_hub *hub, bool connected)
|
|
|
|
++{
|
|
|
|
++ unsigned long delay;
|
|
|
|
++
|
|
|
|
++ /* Mark devices as hot-removed before we remove any. */
|
|
|
|
++ if (!connected) {
|
|
|
|
++ set_bit(SSAM_HUB_HOT_REMOVED, &hub->flags);
|
|
|
|
++ device_for_each_child_reverse(&hub->sdev->dev, NULL, ssam_hub_mark_hot_removed);
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ /*
|
|
|
|
++ * Delay update when the base/keyboard cover is being connected to give
|
|
|
|
++ * devices/EC some time to set up.
|
|
|
|
++ */
|
|
|
|
++ delay = connected ? hub->connect_delay : 0;
|
|
|
|
++
|
|
|
|
++ schedule_delayed_work(&hub->update_work, delay);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int __maybe_unused ssam_hub_resume(struct device *dev)
|
|
|
|
++{
|
|
|
|
++ struct ssam_hub *hub = dev_get_drvdata(dev);
|
|
|
|
++
|
|
|
|
++ schedule_delayed_work(&hub->update_work, 0);
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++static SIMPLE_DEV_PM_OPS(ssam_hub_pm_ops, NULL, ssam_hub_resume);
|
|
|
|
++
|
|
|
|
++static int ssam_hub_setup(struct ssam_device *sdev, struct ssam_hub *hub)
|
|
|
|
++{
|
|
|
|
++ int status;
|
|
|
|
++
|
|
|
|
++ hub->sdev = sdev;
|
|
|
|
++ hub->state = SSAM_HUB_UNINITIALIZED;
|
|
|
|
++
|
|
|
|
++ INIT_DELAYED_WORK(&hub->update_work, ssam_hub_update_workfn);
|
|
|
|
++
|
|
|
|
++ ssam_device_set_drvdata(sdev, hub);
|
|
|
|
++
|
|
|
|
++ status = ssam_device_notifier_register(sdev, &hub->notif);
|
|
|
|
++ if (status)
|
|
|
|
++ return status;
|
|
|
|
++
|
|
|
|
++ schedule_delayed_work(&hub->update_work, 0);
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static void ssam_hub_remove(struct ssam_device *sdev)
|
|
|
|
++{
|
|
|
|
++ struct ssam_hub *hub = ssam_device_get_drvdata(sdev);
|
|
|
|
++
|
|
|
|
++ ssam_device_notifier_unregister(sdev, &hub->notif);
|
|
|
|
++ cancel_delayed_work_sync(&hub->update_work);
|
|
|
|
++ ssam_remove_clients(&sdev->dev);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++
|
|
|
|
++/* -- SSAM base-hub driver. ------------------------------------------------- */
|
|
|
|
++
|
|
|
|
++/*
|
|
|
|
++ * Some devices (especially battery) may need a bit of time to be fully usable
|
|
|
|
++ * after being (re-)connected. This delay has been determined via
|
|
|
|
++ * experimentation.
|
|
|
|
++ */
|
|
|
|
++#define SSAM_BASE_UPDATE_CONNECT_DELAY msecs_to_jiffies(2500)
|
|
|
|
++
|
|
|
|
+ SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
|
|
|
|
+ .target_category = SSAM_SSH_TC_BAS,
|
|
|
|
+ .target_id = 0x01,
|
|
|
|
+@@ -342,7 +471,7 @@ SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
|
|
|
|
+ #define SSAM_BAS_OPMODE_TABLET 0x00
|
|
|
|
+ #define SSAM_EVENT_BAS_CID_CONNECTION 0x0c
|
|
|
|
+
|
|
|
|
+-static int ssam_base_hub_query_state(struct ssam_base_hub *hub, enum ssam_base_hub_state *state)
|
|
|
|
++static int ssam_base_hub_query_state(struct ssam_hub *hub, enum ssam_hub_state *state)
|
|
|
|
+ {
|
|
|
|
+ u8 opmode;
|
|
|
|
+ int status;
|
|
|
|
+@@ -354,62 +483,16 @@ static int ssam_base_hub_query_state(struct ssam_base_hub *hub, enum ssam_base_h
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (opmode != SSAM_BAS_OPMODE_TABLET)
|
|
|
|
+- *state = SSAM_BASE_HUB_CONNECTED;
|
|
|
|
++ *state = SSAM_HUB_CONNECTED;
|
|
|
|
+ else
|
|
|
|
+- *state = SSAM_BASE_HUB_DISCONNECTED;
|
|
|
|
++ *state = SSAM_HUB_DISCONNECTED;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+-static ssize_t ssam_base_hub_state_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
+- char *buf)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_base_hub *hub = dev_get_drvdata(dev);
|
|
|
|
+- bool connected = hub->state == SSAM_BASE_HUB_CONNECTED;
|
|
|
|
+-
|
|
|
|
+- return sysfs_emit(buf, "%d\n", connected);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static struct device_attribute ssam_base_hub_attr_state =
|
|
|
|
+- __ATTR(state, 0444, ssam_base_hub_state_show, NULL);
|
|
|
|
+-
|
|
|
|
+-static struct attribute *ssam_base_hub_attrs[] = {
|
|
|
|
+- &ssam_base_hub_attr_state.attr,
|
|
|
|
+- NULL,
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-static const struct attribute_group ssam_base_hub_group = {
|
|
|
|
+- .attrs = ssam_base_hub_attrs,
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-static void ssam_base_hub_update_workfn(struct work_struct *work)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_base_hub *hub = container_of(work, struct ssam_base_hub, update_work.work);
|
|
|
|
+- struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev);
|
|
|
|
+- enum ssam_base_hub_state state;
|
|
|
|
+- int status = 0;
|
|
|
|
+-
|
|
|
|
+- status = ssam_base_hub_query_state(hub, &state);
|
|
|
|
+- if (status)
|
|
|
|
+- return;
|
|
|
|
+-
|
|
|
|
+- if (hub->state == state)
|
|
|
|
+- return;
|
|
|
|
+- hub->state = state;
|
|
|
|
+-
|
|
|
|
+- if (hub->state == SSAM_BASE_HUB_CONNECTED)
|
|
|
|
+- status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node);
|
|
|
|
+- else
|
|
|
|
+- ssam_remove_clients(&hub->sdev->dev);
|
|
|
|
+-
|
|
|
|
+- if (status)
|
|
|
|
+- dev_err(&hub->sdev->dev, "failed to update base-hub devices: %d\n", status);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+ static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
|
|
|
|
+ {
|
|
|
|
+- struct ssam_base_hub *hub = container_of(nf, struct ssam_base_hub, notif);
|
|
|
|
+- unsigned long delay;
|
|
|
|
++ struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif);
|
|
|
|
+
|
|
|
|
+ if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION)
|
|
|
|
+ return 0;
|
|
|
|
+@@ -419,13 +502,7 @@ static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+- /*
|
|
|
|
+- * Delay update when the base is being connected to give devices/EC
|
|
|
|
+- * some time to set up.
|
|
|
|
+- */
|
|
|
|
+- delay = event->data[0] ? SSAM_BASE_UPDATE_CONNECT_DELAY : 0;
|
|
|
|
+-
|
|
|
|
+- schedule_delayed_work(&hub->update_work, delay);
|
|
|
|
++ ssam_hub_update(hub, event->data[0]);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and
|
|
|
|
+@@ -435,27 +512,14 @@ static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+-static int __maybe_unused ssam_base_hub_resume(struct device *dev)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_base_hub *hub = dev_get_drvdata(dev);
|
|
|
|
+-
|
|
|
|
+- schedule_delayed_work(&hub->update_work, 0);
|
|
|
|
+- return 0;
|
|
|
|
+-}
|
|
|
|
+-static SIMPLE_DEV_PM_OPS(ssam_base_hub_pm_ops, NULL, ssam_base_hub_resume);
|
|
|
|
+-
|
|
|
|
+ static int ssam_base_hub_probe(struct ssam_device *sdev)
|
|
|
|
+ {
|
|
|
|
+- struct ssam_base_hub *hub;
|
|
|
|
+- int status;
|
|
|
|
++ struct ssam_hub *hub;
|
|
|
|
+
|
|
|
|
+ hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL);
|
|
|
|
+ if (!hub)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+- hub->sdev = sdev;
|
|
|
|
+- hub->state = SSAM_BASE_HUB_UNINITIALIZED;
|
|
|
|
+-
|
|
|
|
+ hub->notif.base.priority = INT_MAX; /* This notifier should run first. */
|
|
|
|
+ hub->notif.base.fn = ssam_base_hub_notif;
|
|
|
|
+ hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM;
|
|
|
|
+@@ -464,37 +528,10 @@ static int ssam_base_hub_probe(struct ssam_device *sdev)
|
|
|
|
+ hub->notif.event.mask = SSAM_EVENT_MASK_NONE;
|
|
|
|
+ hub->notif.event.flags = SSAM_EVENT_SEQUENCED;
|
|
|
|
+
|
|
|
|
+- INIT_DELAYED_WORK(&hub->update_work, ssam_base_hub_update_workfn);
|
|
|
|
+-
|
|
|
|
+- ssam_device_set_drvdata(sdev, hub);
|
|
|
|
+-
|
|
|
|
+- status = ssam_device_notifier_register(sdev, &hub->notif);
|
|
|
|
+- if (status)
|
|
|
|
+- return status;
|
|
|
|
+-
|
|
|
|
+- status = sysfs_create_group(&sdev->dev.kobj, &ssam_base_hub_group);
|
|
|
|
+- if (status)
|
|
|
|
+- goto err;
|
|
|
|
+-
|
|
|
|
+- schedule_delayed_work(&hub->update_work, 0);
|
|
|
|
+- return 0;
|
|
|
|
++ hub->connect_delay = SSAM_BASE_UPDATE_CONNECT_DELAY;
|
|
|
|
++ hub->get_state = ssam_base_hub_query_state;
|
|
|
|
+
|
|
|
|
+-err:
|
|
|
|
+- ssam_device_notifier_unregister(sdev, &hub->notif);
|
|
|
|
+- cancel_delayed_work_sync(&hub->update_work);
|
|
|
|
+- ssam_remove_clients(&sdev->dev);
|
|
|
|
+- return status;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static void ssam_base_hub_remove(struct ssam_device *sdev)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_base_hub *hub = ssam_device_get_drvdata(sdev);
|
|
|
|
+-
|
|
|
|
+- sysfs_remove_group(&sdev->dev.kobj, &ssam_base_hub_group);
|
|
|
|
+-
|
|
|
|
+- ssam_device_notifier_unregister(sdev, &hub->notif);
|
|
|
|
+- cancel_delayed_work_sync(&hub->update_work);
|
|
|
|
+- ssam_remove_clients(&sdev->dev);
|
|
|
|
++ return ssam_hub_setup(sdev, hub);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static const struct ssam_device_id ssam_base_hub_match[] = {
|
|
|
|
+@@ -504,12 +541,12 @@ static const struct ssam_device_id ssam_base_hub_match[] = {
|
|
|
|
+
|
|
|
|
+ static struct ssam_device_driver ssam_base_hub_driver = {
|
|
|
|
+ .probe = ssam_base_hub_probe,
|
|
|
|
+- .remove = ssam_base_hub_remove,
|
|
|
|
++ .remove = ssam_hub_remove,
|
|
|
|
+ .match_table = ssam_base_hub_match,
|
|
|
|
+ .driver = {
|
|
|
|
+ .name = "surface_aggregator_base_hub",
|
|
|
|
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
|
|
|
+- .pm = &ssam_base_hub_pm_ops,
|
|
|
|
++ .pm = &ssam_hub_pm_ops,
|
|
|
|
+ },
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From c74992ea392a3a93d52871413c3a2f97df2051f9 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:45 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Change device ID for
|
|
|
|
+ base hub
|
|
|
|
+
|
|
|
|
+Use the target category of the (base) hub as instance id in the
|
|
|
|
+(virtual) hub device UID. This makes association of the hub with the
|
|
|
|
+respective subsystem easier.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-11-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/platform/surface/surface_aggregator_registry.c | 4 ++--
|
|
|
|
+ 1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index 09cbeee2428b..b11ce87c7184 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -43,7 +43,7 @@ static const struct software_node ssam_node_root = {
|
|
|
|
+
|
|
|
|
+ /* Base device hub (devices attached to Surface Book 3 base). */
|
|
|
|
+ static const struct software_node ssam_node_hub_base = {
|
|
|
|
+- .name = "ssam:00:00:02:00:00",
|
|
|
|
++ .name = "ssam:00:00:02:11:00",
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+@@ -535,7 +535,7 @@ static int ssam_base_hub_probe(struct ssam_device *sdev)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static const struct ssam_device_id ssam_base_hub_match[] = {
|
|
|
|
+- { SSAM_VDEV(HUB, 0x02, SSAM_ANY_IID, 0x00) },
|
|
|
|
++ { SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00) },
|
|
|
|
+ { },
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 7fffe2d6e96ec095bd559fbc18739755f6245619 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:46 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Add KIP device hub
|
|
|
|
+
|
|
|
|
+Add a Surface System Aggregator Module (SSAM) client device hub for
|
|
|
|
+hot-removable devices managed via the KIP subsystem.
|
|
|
|
+
|
|
|
|
+The KIP subsystem (full name unknown, abbreviation has been obtained
|
|
|
|
+through reverse engineering) is a subsystem that manages hot-removable
|
|
|
|
+SSAM client devices. Specifically, it manages HID input devices
|
|
|
|
+contained in the detachable keyboard cover of the Surface Pro 8 and
|
|
|
|
+Surface Pro X.
|
|
|
|
+
|
|
|
|
+The KIP subsystem handles a single group of devices (e.g. all devices
|
|
|
|
+contained in the keyboard cover) and cannot handle devices individually.
|
|
|
|
+Thus we model it as a client device hub, which (hot-)removes all devices
|
|
|
|
+contained under it once removal of the hub (e.g. keyboard cover) has
|
|
|
|
+been detected and (re-)adds all devices once the physical hub device has
|
|
|
|
+been (re-)attached. To do this, use the previously generified SSAM
|
|
|
|
+subsystem hub framework.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-12-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ .../surface/surface_aggregator_registry.c | 103 +++++++++++++++++-
|
|
|
|
+ 1 file changed, 101 insertions(+), 2 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index b11ce87c7184..f15cef60630f 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -551,6 +551,93 @@ static struct ssam_device_driver ssam_base_hub_driver = {
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+
|
|
|
|
++/* -- SSAM KIP-subsystem hub driver. ---------------------------------------- */
|
|
|
|
++
|
|
|
|
++/*
|
|
|
|
++ * Some devices may need a bit of time to be fully usable after being
|
|
|
|
++ * (re-)connected. This delay has been determined via experimentation.
|
|
|
|
++ */
|
|
|
|
++#define SSAM_KIP_UPDATE_CONNECT_DELAY msecs_to_jiffies(250)
|
|
|
|
++
|
|
|
|
++#define SSAM_EVENT_KIP_CID_CONNECTION 0x2c
|
|
|
|
++
|
|
|
|
++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_connection_state, u8, {
|
|
|
|
++ .target_category = SSAM_SSH_TC_KIP,
|
|
|
|
++ .target_id = 0x01,
|
|
|
|
++ .command_id = 0x2c,
|
|
|
|
++ .instance_id = 0x00,
|
|
|
|
++});
|
|
|
|
++
|
|
|
|
++static int ssam_kip_get_connection_state(struct ssam_hub *hub, enum ssam_hub_state *state)
|
|
|
|
++{
|
|
|
|
++ int status;
|
|
|
|
++ u8 connected;
|
|
|
|
++
|
|
|
|
++ status = ssam_retry(__ssam_kip_get_connection_state, hub->sdev->ctrl, &connected);
|
|
|
|
++ if (status < 0) {
|
|
|
|
++ dev_err(&hub->sdev->dev, "failed to query KIP connection state: %d\n", status);
|
|
|
|
++ return status;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ *state = connected ? SSAM_HUB_CONNECTED : SSAM_HUB_DISCONNECTED;
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static u32 ssam_kip_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
|
|
|
|
++{
|
|
|
|
++ struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif);
|
|
|
|
++
|
|
|
|
++ if (event->command_id != SSAM_EVENT_KIP_CID_CONNECTION)
|
|
|
|
++ return 0; /* Return "unhandled". */
|
|
|
|
++
|
|
|
|
++ if (event->length < 1) {
|
|
|
|
++ dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length);
|
|
|
|
++ return 0;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ ssam_hub_update(hub, event->data[0]);
|
|
|
|
++ return SSAM_NOTIF_HANDLED;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int ssam_kip_hub_probe(struct ssam_device *sdev)
|
|
|
|
++{
|
|
|
|
++ struct ssam_hub *hub;
|
|
|
|
++
|
|
|
|
++ hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL);
|
|
|
|
++ if (!hub)
|
|
|
|
++ return -ENOMEM;
|
|
|
|
++
|
|
|
|
++ hub->notif.base.priority = INT_MAX; /* This notifier should run first. */
|
|
|
|
++ hub->notif.base.fn = ssam_kip_hub_notif;
|
|
|
|
++ hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM;
|
|
|
|
++ hub->notif.event.id.target_category = SSAM_SSH_TC_KIP,
|
|
|
|
++ hub->notif.event.id.instance = 0,
|
|
|
|
++ hub->notif.event.mask = SSAM_EVENT_MASK_TARGET;
|
|
|
|
++ hub->notif.event.flags = SSAM_EVENT_SEQUENCED;
|
|
|
|
++
|
|
|
|
++ hub->connect_delay = SSAM_KIP_UPDATE_CONNECT_DELAY;
|
|
|
|
++ hub->get_state = ssam_kip_get_connection_state;
|
|
|
|
++
|
|
|
|
++ return ssam_hub_setup(sdev, hub);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static const struct ssam_device_id ssam_kip_hub_match[] = {
|
|
|
|
++ { SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00) },
|
|
|
|
++ { },
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++static struct ssam_device_driver ssam_kip_hub_driver = {
|
|
|
|
++ .probe = ssam_kip_hub_probe,
|
|
|
|
++ .remove = ssam_hub_remove,
|
|
|
|
++ .match_table = ssam_kip_hub_match,
|
|
|
|
++ .driver = {
|
|
|
|
++ .name = "surface_kip_hub",
|
|
|
|
++ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
|
|
|
++ .pm = &ssam_hub_pm_ops,
|
|
|
|
++ },
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++
|
|
|
|
+ /* -- SSAM platform/meta-hub driver. ---------------------------------------- */
|
|
|
|
+
|
|
|
|
+ static const struct acpi_device_id ssam_platform_hub_match[] = {
|
|
|
|
+@@ -673,18 +760,30 @@ static int __init ssam_device_hub_init(void)
|
|
|
|
+
|
|
|
|
+ status = platform_driver_register(&ssam_platform_hub_driver);
|
|
|
|
+ if (status)
|
|
|
|
+- return status;
|
|
|
|
++ goto err_platform;
|
|
|
|
+
|
|
|
|
+ status = ssam_device_driver_register(&ssam_base_hub_driver);
|
|
|
|
+ if (status)
|
|
|
|
+- platform_driver_unregister(&ssam_platform_hub_driver);
|
|
|
|
++ goto err_base;
|
|
|
|
++
|
|
|
|
++ status = ssam_device_driver_register(&ssam_kip_hub_driver);
|
|
|
|
++ if (status)
|
|
|
|
++ goto err_kip;
|
|
|
|
+
|
|
|
|
++ return 0;
|
|
|
|
++
|
|
|
|
++err_kip:
|
|
|
|
++ ssam_device_driver_unregister(&ssam_base_hub_driver);
|
|
|
|
++err_base:
|
|
|
|
++ platform_driver_unregister(&ssam_platform_hub_driver);
|
|
|
|
++err_platform:
|
|
|
|
+ return status;
|
|
|
|
+ }
|
|
|
|
+ module_init(ssam_device_hub_init);
|
|
|
|
+
|
|
|
|
+ static void __exit ssam_device_hub_exit(void)
|
|
|
|
+ {
|
|
|
|
++ ssam_device_driver_unregister(&ssam_kip_hub_driver);
|
|
|
|
+ ssam_device_driver_unregister(&ssam_base_hub_driver);
|
|
|
|
+ platform_driver_unregister(&ssam_platform_hub_driver);
|
|
|
|
+ }
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From c0f82811a24c4a1b5efb26bb80fb0667dd5ce4d0 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 27 May 2022 04:34:47 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Add support for
|
|
|
|
+ keyboard cover on Surface Pro 8
|
|
|
|
+
|
|
|
|
+Add support for the detachable keyboard cover on the Surface Pro 8.
|
|
|
|
+
|
|
|
|
+The keyboard cover on the Surface Pro 8 is, unlike the keyboard covers
|
|
|
|
+of earlier Surface Pro generations, handled via the Surface System
|
|
|
|
+Aggregator Module (SSAM). The keyboard and touchpad (as well as other
|
|
|
|
+HID input devices) of this cover are standard SSAM HID client devices
|
|
|
|
+(just like keyboard and touchpad on e.g. the Surface Laptop 3 and 4),
|
|
|
|
+however, some care needs to be taken as they can be physically detached
|
|
|
|
+(similarly to the Surface Book 3). Specifically, the respective SSAM
|
|
|
|
+client devices need to be removed when the keyboard cover has been
|
|
|
|
+detached and (re-)initialized when the keyboard cover has been
|
|
|
|
+(re-)attached.
|
|
|
|
+
|
|
|
|
+On the Surface Pro 8, detachment of the keyboard cover (and by extension
|
|
|
|
+its devices) is managed via the KIP subsystem. Therefore, said devices
|
|
|
|
+need to be registered under the KIP device hub, which in turn will
|
|
|
|
+remove and re-create/re-initialize those devices as needed.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220527023447.2460025-13-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ .../surface/surface_aggregator_registry.c | 37 ++++++++++++++++++-
|
|
|
|
+ 1 file changed, 36 insertions(+), 1 deletion(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index f15cef60630f..bf3303f1aa71 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -41,6 +41,12 @@ static const struct software_node ssam_node_root = {
|
|
|
|
+ .name = "ssam_platform_hub",
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
++/* KIP device hub (connects keyboard cover devices on Surface Pro 8). */
|
|
|
|
++static const struct software_node ssam_node_hub_kip = {
|
|
|
|
++ .name = "ssam:00:00:01:0e:00",
|
|
|
|
++ .parent = &ssam_node_root,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
+ /* Base device hub (devices attached to Surface Book 3 base). */
|
|
|
|
+ static const struct software_node ssam_node_hub_base = {
|
|
|
|
+ .name = "ssam:00:00:02:11:00",
|
|
|
|
+@@ -155,6 +161,30 @@ static const struct software_node ssam_node_hid_base_iid6 = {
|
|
|
|
+ .parent = &ssam_node_hub_base,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
++/* HID keyboard (KIP hub). */
|
|
|
|
++static const struct software_node ssam_node_hid_kip_keyboard = {
|
|
|
|
++ .name = "ssam:01:15:02:01:00",
|
|
|
|
++ .parent = &ssam_node_hub_kip,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++/* HID pen stash (KIP hub; pen taken / stashed away evens). */
|
|
|
|
++static const struct software_node ssam_node_hid_kip_penstash = {
|
|
|
|
++ .name = "ssam:01:15:02:02:00",
|
|
|
|
++ .parent = &ssam_node_hub_kip,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++/* HID touchpad (KIP hub). */
|
|
|
|
++static const struct software_node ssam_node_hid_kip_touchpad = {
|
|
|
|
++ .name = "ssam:01:15:02:03:00",
|
|
|
|
++ .parent = &ssam_node_hub_kip,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++/* HID device instance 5 (KIP hub, unknown HID device). */
|
|
|
|
++static const struct software_node ssam_node_hid_kip_iid5 = {
|
|
|
|
++ .name = "ssam:01:15:02:05:00",
|
|
|
|
++ .parent = &ssam_node_hub_kip,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
+ /*
|
|
|
|
+ * Devices for 5th- and 6th-generations models:
|
|
|
|
+ * - Surface Book 2,
|
|
|
|
+@@ -230,10 +260,15 @@ static const struct software_node *ssam_node_group_sp7[] = {
|
|
|
|
+
|
|
|
|
+ static const struct software_node *ssam_node_group_sp8[] = {
|
|
|
|
+ &ssam_node_root,
|
|
|
|
++ &ssam_node_hub_kip,
|
|
|
|
+ &ssam_node_bat_ac,
|
|
|
|
+ &ssam_node_bat_main,
|
|
|
|
+ &ssam_node_tmp_pprof,
|
|
|
|
+- /* TODO: Add support for keyboard cover. */
|
|
|
|
++ &ssam_node_hid_kip_keyboard,
|
|
|
|
++ &ssam_node_hid_kip_penstash,
|
|
|
|
++ &ssam_node_hid_kip_touchpad,
|
|
|
|
++ &ssam_node_hid_kip_iid5,
|
|
|
|
++ /* TODO: Add support for tablet mode switch. */
|
|
|
|
+ NULL,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From ef9a5571a61a0c66a7ee9f5405fe0093e05dcd30 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
|
|
|
|
+Date: Fri, 10 Jun 2022 14:41:58 +0900
|
|
|
|
+Subject: [PATCH] platform/surface: avoid flush_scheduled_work() usage
|
|
|
|
+
|
|
|
|
+Use local wq in order to avoid flush_scheduled_work() usage.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
|
|
|
|
+Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Tested-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/63ec2d45-c67c-1134-f6d3-490c8ba67a01@I-love.SAKURA.ne.jp
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ .../platform/surface/surface_acpi_notify.c | 27 ++++++++++++++++---
|
|
|
|
+ 1 file changed, 24 insertions(+), 3 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c
|
|
|
|
+index 7b758f8cc137..c0e12f0b9b79 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_acpi_notify.c
|
|
|
|
++++ b/drivers/platform/surface/surface_acpi_notify.c
|
|
|
|
+@@ -37,6 +37,7 @@ struct san_data {
|
|
|
|
+ #define to_san_data(ptr, member) \
|
|
|
|
+ container_of(ptr, struct san_data, member)
|
|
|
|
+
|
|
|
|
++static struct workqueue_struct *san_wq;
|
|
|
|
+
|
|
|
|
+ /* -- dGPU notifier interface. ---------------------------------------------- */
|
|
|
|
+
|
|
|
|
+@@ -356,7 +357,7 @@ static u32 san_evt_bat_nf(struct ssam_event_notifier *nf,
|
|
|
|
+
|
|
|
|
+ memcpy(&work->event, event, sizeof(struct ssam_event) + event->length);
|
|
|
|
+
|
|
|
|
+- schedule_delayed_work(&work->work, delay);
|
|
|
|
++ queue_delayed_work(san_wq, &work->work, delay);
|
|
|
|
+ return SSAM_NOTIF_HANDLED;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+@@ -861,7 +862,7 @@ static int san_remove(struct platform_device *pdev)
|
|
|
|
+ * We have unregistered our event sources. Now we need to ensure that
|
|
|
|
+ * all delayed works they may have spawned are run to completion.
|
|
|
|
+ */
|
|
|
|
+- flush_scheduled_work();
|
|
|
|
++ flush_workqueue(san_wq);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+@@ -881,7 +882,27 @@ static struct platform_driver surface_acpi_notify = {
|
|
|
|
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
|
|
|
+ },
|
|
|
|
+ };
|
|
|
|
+-module_platform_driver(surface_acpi_notify);
|
|
|
|
++
|
|
|
|
++static int __init san_init(void)
|
|
|
|
++{
|
|
|
|
++ int ret;
|
|
|
|
++
|
|
|
|
++ san_wq = alloc_workqueue("san_wq", 0, 0);
|
|
|
|
++ if (!san_wq)
|
|
|
|
++ return -ENOMEM;
|
|
|
|
++ ret = platform_driver_register(&surface_acpi_notify);
|
|
|
|
++ if (ret)
|
|
|
|
++ destroy_workqueue(san_wq);
|
|
|
|
++ return ret;
|
|
|
|
++}
|
|
|
|
++module_init(san_init);
|
|
|
|
++
|
|
|
|
++static void __exit san_exit(void)
|
|
|
|
++{
|
|
|
|
++ platform_driver_unregister(&surface_acpi_notify);
|
|
|
|
++ destroy_workqueue(san_wq);
|
|
|
|
++}
|
|
|
|
++module_exit(san_exit);
|
|
|
|
+
|
|
|
|
+ MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
|
|
|
|
+ MODULE_DESCRIPTION("Surface ACPI Notify driver for Surface System Aggregator Module");
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 99089941381fc15d506ac273527e758eed824bfd Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Tue, 14 Jun 2022 21:41:17 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator: Reserve more event- and
|
|
|
|
+ target-categories
|
|
|
|
+
|
|
|
|
+With the introduction of the Surface Laptop Studio, more event- and
|
|
|
|
+target categories have been added. Therefore, increase the number of
|
|
|
|
+reserved events and extend the enum of know target categories to
|
|
|
|
+accommodate this.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220614194117.4118897-1-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/platform/surface/aggregator/trace.h | 80 +++++++++++--------
|
|
|
|
+ include/linux/surface_aggregator/serial_hub.h | 75 +++++++++--------
|
|
|
|
+ 2 files changed, 85 insertions(+), 70 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h
|
|
|
|
+index de64cf169060..cc9e73fbc18e 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/trace.h
|
|
|
|
++++ b/drivers/platform/surface/aggregator/trace.h
|
|
|
|
+@@ -76,7 +76,7 @@ TRACE_DEFINE_ENUM(SSAM_SSH_TC_HID);
|
|
|
|
+ TRACE_DEFINE_ENUM(SSAM_SSH_TC_TCH);
|
|
|
|
+ TRACE_DEFINE_ENUM(SSAM_SSH_TC_BKL);
|
|
|
|
+ TRACE_DEFINE_ENUM(SSAM_SSH_TC_TAM);
|
|
|
|
+-TRACE_DEFINE_ENUM(SSAM_SSH_TC_ACC);
|
|
|
|
++TRACE_DEFINE_ENUM(SSAM_SSH_TC_ACC0);
|
|
|
|
+ TRACE_DEFINE_ENUM(SSAM_SSH_TC_UFI);
|
|
|
|
+ TRACE_DEFINE_ENUM(SSAM_SSH_TC_USC);
|
|
|
|
+ TRACE_DEFINE_ENUM(SSAM_SSH_TC_PEN);
|
|
|
|
+@@ -85,6 +85,11 @@ TRACE_DEFINE_ENUM(SSAM_SSH_TC_AUD);
|
|
|
|
+ TRACE_DEFINE_ENUM(SSAM_SSH_TC_SMC);
|
|
|
|
+ TRACE_DEFINE_ENUM(SSAM_SSH_TC_KPD);
|
|
|
|
+ TRACE_DEFINE_ENUM(SSAM_SSH_TC_REG);
|
|
|
|
++TRACE_DEFINE_ENUM(SSAM_SSH_TC_SPT);
|
|
|
|
++TRACE_DEFINE_ENUM(SSAM_SSH_TC_SYS);
|
|
|
|
++TRACE_DEFINE_ENUM(SSAM_SSH_TC_ACC1);
|
|
|
|
++TRACE_DEFINE_ENUM(SSAM_SSH_TC_SHB);
|
|
|
|
++TRACE_DEFINE_ENUM(SSAM_SSH_TC_POS);
|
|
|
|
+
|
|
|
|
+ #define SSAM_PTR_UID_LEN 9
|
|
|
|
+ #define SSAM_U8_FIELD_NOT_APPLICABLE ((u16)-1)
|
|
|
|
+@@ -229,40 +234,45 @@ static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p)
|
|
|
|
+
|
|
|
|
+ #define ssam_show_ssh_tc(rqid) \
|
|
|
|
+ __print_symbolic(rqid, \
|
|
|
|
+- { SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \
|
|
|
|
+- { SSAM_SSH_TC_SAM, "SAM" }, \
|
|
|
|
+- { SSAM_SSH_TC_BAT, "BAT" }, \
|
|
|
|
+- { SSAM_SSH_TC_TMP, "TMP" }, \
|
|
|
|
+- { SSAM_SSH_TC_PMC, "PMC" }, \
|
|
|
|
+- { SSAM_SSH_TC_FAN, "FAN" }, \
|
|
|
|
+- { SSAM_SSH_TC_PoM, "PoM" }, \
|
|
|
|
+- { SSAM_SSH_TC_DBG, "DBG" }, \
|
|
|
|
+- { SSAM_SSH_TC_KBD, "KBD" }, \
|
|
|
|
+- { SSAM_SSH_TC_FWU, "FWU" }, \
|
|
|
|
+- { SSAM_SSH_TC_UNI, "UNI" }, \
|
|
|
|
+- { SSAM_SSH_TC_LPC, "LPC" }, \
|
|
|
|
+- { SSAM_SSH_TC_TCL, "TCL" }, \
|
|
|
|
+- { SSAM_SSH_TC_SFL, "SFL" }, \
|
|
|
|
+- { SSAM_SSH_TC_KIP, "KIP" }, \
|
|
|
|
+- { SSAM_SSH_TC_EXT, "EXT" }, \
|
|
|
|
+- { SSAM_SSH_TC_BLD, "BLD" }, \
|
|
|
|
+- { SSAM_SSH_TC_BAS, "BAS" }, \
|
|
|
|
+- { SSAM_SSH_TC_SEN, "SEN" }, \
|
|
|
|
+- { SSAM_SSH_TC_SRQ, "SRQ" }, \
|
|
|
|
+- { SSAM_SSH_TC_MCU, "MCU" }, \
|
|
|
|
+- { SSAM_SSH_TC_HID, "HID" }, \
|
|
|
|
+- { SSAM_SSH_TC_TCH, "TCH" }, \
|
|
|
|
+- { SSAM_SSH_TC_BKL, "BKL" }, \
|
|
|
|
+- { SSAM_SSH_TC_TAM, "TAM" }, \
|
|
|
|
+- { SSAM_SSH_TC_ACC, "ACC" }, \
|
|
|
|
+- { SSAM_SSH_TC_UFI, "UFI" }, \
|
|
|
|
+- { SSAM_SSH_TC_USC, "USC" }, \
|
|
|
|
+- { SSAM_SSH_TC_PEN, "PEN" }, \
|
|
|
|
+- { SSAM_SSH_TC_VID, "VID" }, \
|
|
|
|
+- { SSAM_SSH_TC_AUD, "AUD" }, \
|
|
|
|
+- { SSAM_SSH_TC_SMC, "SMC" }, \
|
|
|
|
+- { SSAM_SSH_TC_KPD, "KPD" }, \
|
|
|
|
+- { SSAM_SSH_TC_REG, "REG" } \
|
|
|
|
++ { SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \
|
|
|
|
++ { SSAM_SSH_TC_SAM, "SAM" }, \
|
|
|
|
++ { SSAM_SSH_TC_BAT, "BAT" }, \
|
|
|
|
++ { SSAM_SSH_TC_TMP, "TMP" }, \
|
|
|
|
++ { SSAM_SSH_TC_PMC, "PMC" }, \
|
|
|
|
++ { SSAM_SSH_TC_FAN, "FAN" }, \
|
|
|
|
++ { SSAM_SSH_TC_PoM, "PoM" }, \
|
|
|
|
++ { SSAM_SSH_TC_DBG, "DBG" }, \
|
|
|
|
++ { SSAM_SSH_TC_KBD, "KBD" }, \
|
|
|
|
++ { SSAM_SSH_TC_FWU, "FWU" }, \
|
|
|
|
++ { SSAM_SSH_TC_UNI, "UNI" }, \
|
|
|
|
++ { SSAM_SSH_TC_LPC, "LPC" }, \
|
|
|
|
++ { SSAM_SSH_TC_TCL, "TCL" }, \
|
|
|
|
++ { SSAM_SSH_TC_SFL, "SFL" }, \
|
|
|
|
++ { SSAM_SSH_TC_KIP, "KIP" }, \
|
|
|
|
++ { SSAM_SSH_TC_EXT, "EXT" }, \
|
|
|
|
++ { SSAM_SSH_TC_BLD, "BLD" }, \
|
|
|
|
++ { SSAM_SSH_TC_BAS, "BAS" }, \
|
|
|
|
++ { SSAM_SSH_TC_SEN, "SEN" }, \
|
|
|
|
++ { SSAM_SSH_TC_SRQ, "SRQ" }, \
|
|
|
|
++ { SSAM_SSH_TC_MCU, "MCU" }, \
|
|
|
|
++ { SSAM_SSH_TC_HID, "HID" }, \
|
|
|
|
++ { SSAM_SSH_TC_TCH, "TCH" }, \
|
|
|
|
++ { SSAM_SSH_TC_BKL, "BKL" }, \
|
|
|
|
++ { SSAM_SSH_TC_TAM, "TAM" }, \
|
|
|
|
++ { SSAM_SSH_TC_ACC0, "ACC0" }, \
|
|
|
|
++ { SSAM_SSH_TC_UFI, "UFI" }, \
|
|
|
|
++ { SSAM_SSH_TC_USC, "USC" }, \
|
|
|
|
++ { SSAM_SSH_TC_PEN, "PEN" }, \
|
|
|
|
++ { SSAM_SSH_TC_VID, "VID" }, \
|
|
|
|
++ { SSAM_SSH_TC_AUD, "AUD" }, \
|
|
|
|
++ { SSAM_SSH_TC_SMC, "SMC" }, \
|
|
|
|
++ { SSAM_SSH_TC_KPD, "KPD" }, \
|
|
|
|
++ { SSAM_SSH_TC_REG, "REG" }, \
|
|
|
|
++ { SSAM_SSH_TC_SPT, "SPT" }, \
|
|
|
|
++ { SSAM_SSH_TC_SYS, "SYS" }, \
|
|
|
|
++ { SSAM_SSH_TC_ACC1, "ACC1" }, \
|
|
|
|
++ { SSAM_SSH_TC_SHB, "SMB" }, \
|
|
|
|
++ { SSAM_SSH_TC_POS, "POS" } \
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ DECLARE_EVENT_CLASS(ssam_frame_class,
|
|
|
|
+diff --git a/include/linux/surface_aggregator/serial_hub.h b/include/linux/surface_aggregator/serial_hub.h
|
|
|
|
+index 26b95ec12733..45501b6e54e8 100644
|
|
|
|
+--- a/include/linux/surface_aggregator/serial_hub.h
|
|
|
|
++++ b/include/linux/surface_aggregator/serial_hub.h
|
|
|
|
+@@ -201,7 +201,7 @@ static inline u16 ssh_crc(const u8 *buf, size_t len)
|
|
|
|
+ * exception of zero, which is not an event ID. Thus, this is also the
|
|
|
|
+ * absolute maximum number of event handlers that can be registered.
|
|
|
|
+ */
|
|
|
|
+-#define SSH_NUM_EVENTS 34
|
|
|
|
++#define SSH_NUM_EVENTS 38
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * SSH_NUM_TARGETS - The number of communication targets used in the protocol.
|
|
|
|
+@@ -292,40 +292,45 @@ struct ssam_span {
|
|
|
|
+ * Windows driver.
|
|
|
|
+ */
|
|
|
|
+ enum ssam_ssh_tc {
|
|
|
|
+- /* Category 0x00 is invalid for EC use. */
|
|
|
|
+- SSAM_SSH_TC_SAM = 0x01, /* Generic system functionality, real-time clock. */
|
|
|
|
+- SSAM_SSH_TC_BAT = 0x02, /* Battery/power subsystem. */
|
|
|
|
+- SSAM_SSH_TC_TMP = 0x03, /* Thermal subsystem. */
|
|
|
|
+- SSAM_SSH_TC_PMC = 0x04,
|
|
|
|
+- SSAM_SSH_TC_FAN = 0x05,
|
|
|
|
+- SSAM_SSH_TC_PoM = 0x06,
|
|
|
|
+- SSAM_SSH_TC_DBG = 0x07,
|
|
|
|
+- SSAM_SSH_TC_KBD = 0x08, /* Legacy keyboard (Laptop 1/2). */
|
|
|
|
+- SSAM_SSH_TC_FWU = 0x09,
|
|
|
|
+- SSAM_SSH_TC_UNI = 0x0a,
|
|
|
|
+- SSAM_SSH_TC_LPC = 0x0b,
|
|
|
|
+- SSAM_SSH_TC_TCL = 0x0c,
|
|
|
|
+- SSAM_SSH_TC_SFL = 0x0d,
|
|
|
|
+- SSAM_SSH_TC_KIP = 0x0e, /* Manages detachable peripherals (Pro X/8 keyboard cover) */
|
|
|
|
+- SSAM_SSH_TC_EXT = 0x0f,
|
|
|
|
+- SSAM_SSH_TC_BLD = 0x10,
|
|
|
|
+- SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */
|
|
|
|
+- SSAM_SSH_TC_SEN = 0x12,
|
|
|
|
+- SSAM_SSH_TC_SRQ = 0x13,
|
|
|
|
+- SSAM_SSH_TC_MCU = 0x14,
|
|
|
|
+- SSAM_SSH_TC_HID = 0x15, /* Generic HID input subsystem. */
|
|
|
|
+- SSAM_SSH_TC_TCH = 0x16,
|
|
|
|
+- SSAM_SSH_TC_BKL = 0x17,
|
|
|
|
+- SSAM_SSH_TC_TAM = 0x18,
|
|
|
|
+- SSAM_SSH_TC_ACC = 0x19,
|
|
|
|
+- SSAM_SSH_TC_UFI = 0x1a,
|
|
|
|
+- SSAM_SSH_TC_USC = 0x1b,
|
|
|
|
+- SSAM_SSH_TC_PEN = 0x1c,
|
|
|
|
+- SSAM_SSH_TC_VID = 0x1d,
|
|
|
|
+- SSAM_SSH_TC_AUD = 0x1e,
|
|
|
|
+- SSAM_SSH_TC_SMC = 0x1f,
|
|
|
|
+- SSAM_SSH_TC_KPD = 0x20,
|
|
|
|
+- SSAM_SSH_TC_REG = 0x21, /* Extended event registry. */
|
|
|
|
++ /* Category 0x00 is invalid for EC use. */
|
|
|
|
++ SSAM_SSH_TC_SAM = 0x01, /* Generic system functionality, real-time clock. */
|
|
|
|
++ SSAM_SSH_TC_BAT = 0x02, /* Battery/power subsystem. */
|
|
|
|
++ SSAM_SSH_TC_TMP = 0x03, /* Thermal subsystem. */
|
|
|
|
++ SSAM_SSH_TC_PMC = 0x04,
|
|
|
|
++ SSAM_SSH_TC_FAN = 0x05,
|
|
|
|
++ SSAM_SSH_TC_PoM = 0x06,
|
|
|
|
++ SSAM_SSH_TC_DBG = 0x07,
|
|
|
|
++ SSAM_SSH_TC_KBD = 0x08, /* Legacy keyboard (Laptop 1/2). */
|
|
|
|
++ SSAM_SSH_TC_FWU = 0x09,
|
|
|
|
++ SSAM_SSH_TC_UNI = 0x0a,
|
|
|
|
++ SSAM_SSH_TC_LPC = 0x0b,
|
|
|
|
++ SSAM_SSH_TC_TCL = 0x0c,
|
|
|
|
++ SSAM_SSH_TC_SFL = 0x0d,
|
|
|
|
++ SSAM_SSH_TC_KIP = 0x0e, /* Manages detachable peripherals (Pro X/8 keyboard cover) */
|
|
|
|
++ SSAM_SSH_TC_EXT = 0x0f,
|
|
|
|
++ SSAM_SSH_TC_BLD = 0x10,
|
|
|
|
++ SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */
|
|
|
|
++ SSAM_SSH_TC_SEN = 0x12,
|
|
|
|
++ SSAM_SSH_TC_SRQ = 0x13,
|
|
|
|
++ SSAM_SSH_TC_MCU = 0x14,
|
|
|
|
++ SSAM_SSH_TC_HID = 0x15, /* Generic HID input subsystem. */
|
|
|
|
++ SSAM_SSH_TC_TCH = 0x16,
|
|
|
|
++ SSAM_SSH_TC_BKL = 0x17,
|
|
|
|
++ SSAM_SSH_TC_TAM = 0x18,
|
|
|
|
++ SSAM_SSH_TC_ACC0 = 0x19,
|
|
|
|
++ SSAM_SSH_TC_UFI = 0x1a,
|
|
|
|
++ SSAM_SSH_TC_USC = 0x1b,
|
|
|
|
++ SSAM_SSH_TC_PEN = 0x1c,
|
|
|
|
++ SSAM_SSH_TC_VID = 0x1d,
|
|
|
|
++ SSAM_SSH_TC_AUD = 0x1e,
|
|
|
|
++ SSAM_SSH_TC_SMC = 0x1f,
|
|
|
|
++ SSAM_SSH_TC_KPD = 0x20,
|
|
|
|
++ SSAM_SSH_TC_REG = 0x21, /* Extended event registry. */
|
|
|
|
++ SSAM_SSH_TC_SPT = 0x22,
|
|
|
|
++ SSAM_SSH_TC_SYS = 0x23,
|
|
|
|
++ SSAM_SSH_TC_ACC1 = 0x24,
|
|
|
|
++ SSAM_SSH_TC_SHB = 0x25,
|
|
|
|
++ SSAM_SSH_TC_POS = 0x26, /* For obtaining Laptop Studio screen position. */
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 318b0e7587fb5b3849089ea7bc84835383f22029 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 24 Jun 2022 20:36:39 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator: Add helper macros for requests
|
|
|
|
+ with argument and return value
|
|
|
|
+
|
|
|
|
+Add helper macros for synchronous stack-allocated Surface Aggregator
|
|
|
|
+request with both argument and return value, similar to the current
|
|
|
|
+argument-only and return-value-only ones.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220624183642.910893-2-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ include/linux/surface_aggregator/controller.h | 125 ++++++++++++++++++
|
|
|
|
+ include/linux/surface_aggregator/device.h | 36 +++++
|
|
|
|
+ 2 files changed, 161 insertions(+)
|
|
|
|
+
|
|
|
|
+diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h
|
|
|
|
+index 50a2b4926c06..d11a1c6e3186 100644
|
|
|
|
+--- a/include/linux/surface_aggregator/controller.h
|
|
|
|
++++ b/include/linux/surface_aggregator/controller.h
|
|
|
|
+@@ -469,6 +469,67 @@ struct ssam_request_spec_md {
|
|
|
|
+ return 0; \
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
++/**
|
|
|
|
++ * SSAM_DEFINE_SYNC_REQUEST_WR() - Define synchronous SAM request function with
|
|
|
|
++ * both argument and return value.
|
|
|
|
++ * @name: Name of the generated function.
|
|
|
|
++ * @atype: Type of the request's argument.
|
|
|
|
++ * @rtype: Type of the request's return value.
|
|
|
|
++ * @spec: Specification (&struct ssam_request_spec) defining the request.
|
|
|
|
++ *
|
|
|
|
++ * Defines a function executing the synchronous SAM request specified by @spec,
|
|
|
|
++ * with the request taking an argument of type @atype and having a return value
|
|
|
|
++ * of type @rtype. The generated function takes care of setting up the request
|
|
|
|
++ * and response structs, buffer allocation, as well as execution of the request
|
|
|
|
++ * itself, returning once the request has been fully completed. The required
|
|
|
|
++ * transport buffer will be allocated on the stack.
|
|
|
|
++ *
|
|
|
|
++ * The generated function is defined as ``static int name(struct
|
|
|
|
++ * ssam_controller *ctrl, const atype *arg, rtype *ret)``, returning the status
|
|
|
|
++ * of the request, which is zero on success and negative on failure. The
|
|
|
|
++ * ``ctrl`` parameter is the controller via which the request is sent. The
|
|
|
|
++ * request argument is specified via the ``arg`` pointer. The request's return
|
|
|
|
++ * value is written to the memory pointed to by the ``ret`` parameter.
|
|
|
|
++ *
|
|
|
|
++ * Refer to ssam_request_sync_onstack() for more details on the behavior of
|
|
|
|
++ * the generated function.
|
|
|
|
++ */
|
|
|
|
++#define SSAM_DEFINE_SYNC_REQUEST_WR(name, atype, rtype, spec...) \
|
|
|
|
++ static int name(struct ssam_controller *ctrl, const atype *arg, rtype *ret) \
|
|
|
|
++ { \
|
|
|
|
++ struct ssam_request_spec s = (struct ssam_request_spec)spec; \
|
|
|
|
++ struct ssam_request rqst; \
|
|
|
|
++ struct ssam_response rsp; \
|
|
|
|
++ int status; \
|
|
|
|
++ \
|
|
|
|
++ rqst.target_category = s.target_category; \
|
|
|
|
++ rqst.target_id = s.target_id; \
|
|
|
|
++ rqst.command_id = s.command_id; \
|
|
|
|
++ rqst.instance_id = s.instance_id; \
|
|
|
|
++ rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE; \
|
|
|
|
++ rqst.length = sizeof(atype); \
|
|
|
|
++ rqst.payload = (u8 *)arg; \
|
|
|
|
++ \
|
|
|
|
++ rsp.capacity = sizeof(rtype); \
|
|
|
|
++ rsp.length = 0; \
|
|
|
|
++ rsp.pointer = (u8 *)ret; \
|
|
|
|
++ \
|
|
|
|
++ status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \
|
|
|
|
++ if (status) \
|
|
|
|
++ return status; \
|
|
|
|
++ \
|
|
|
|
++ if (rsp.length != sizeof(rtype)) { \
|
|
|
|
++ struct device *dev = ssam_controller_device(ctrl); \
|
|
|
|
++ dev_err(dev, \
|
|
|
|
++ "rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \
|
|
|
|
++ sizeof(rtype), rsp.length, rqst.target_category,\
|
|
|
|
++ rqst.command_id); \
|
|
|
|
++ return -EIO; \
|
|
|
|
++ } \
|
|
|
|
++ \
|
|
|
|
++ return 0; \
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
+ /**
|
|
|
|
+ * SSAM_DEFINE_SYNC_REQUEST_MD_N() - Define synchronous multi-device SAM
|
|
|
|
+ * request function with neither argument nor return value.
|
|
|
|
+@@ -613,6 +674,70 @@ struct ssam_request_spec_md {
|
|
|
|
+ return 0; \
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
++/**
|
|
|
|
++ * SSAM_DEFINE_SYNC_REQUEST_MD_WR() - Define synchronous multi-device SAM
|
|
|
|
++ * request function with both argument and return value.
|
|
|
|
++ * @name: Name of the generated function.
|
|
|
|
++ * @atype: Type of the request's argument.
|
|
|
|
++ * @rtype: Type of the request's return value.
|
|
|
|
++ * @spec: Specification (&struct ssam_request_spec_md) defining the request.
|
|
|
|
++ *
|
|
|
|
++ * Defines a function executing the synchronous SAM request specified by @spec,
|
|
|
|
++ * with the request taking an argument of type @atype and having a return value
|
|
|
|
++ * of type @rtype. Device specifying parameters are not hard-coded, but instead
|
|
|
|
++ * must be provided to the function. The generated function takes care of
|
|
|
|
++ * setting up the request and response structs, buffer allocation, as well as
|
|
|
|
++ * execution of the request itself, returning once the request has been fully
|
|
|
|
++ * completed. The required transport buffer will be allocated on the stack.
|
|
|
|
++ *
|
|
|
|
++ * The generated function is defined as ``static int name(struct
|
|
|
|
++ * ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg, rtype *ret)``,
|
|
|
|
++ * returning the status of the request, which is zero on success and negative
|
|
|
|
++ * on failure. The ``ctrl`` parameter is the controller via which the request
|
|
|
|
++ * is sent, ``tid`` the target ID for the request, and ``iid`` the instance ID.
|
|
|
|
++ * The request argument is specified via the ``arg`` pointer. The request's
|
|
|
|
++ * return value is written to the memory pointed to by the ``ret`` parameter.
|
|
|
|
++ *
|
|
|
|
++ * Refer to ssam_request_sync_onstack() for more details on the behavior of
|
|
|
|
++ * the generated function.
|
|
|
|
++ */
|
|
|
|
++#define SSAM_DEFINE_SYNC_REQUEST_MD_WR(name, atype, rtype, spec...) \
|
|
|
|
++ static int name(struct ssam_controller *ctrl, u8 tid, u8 iid, \
|
|
|
|
++ const atype *arg, rtype *ret) \
|
|
|
|
++ { \
|
|
|
|
++ struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
|
|
|
|
++ struct ssam_request rqst; \
|
|
|
|
++ struct ssam_response rsp; \
|
|
|
|
++ int status; \
|
|
|
|
++ \
|
|
|
|
++ rqst.target_category = s.target_category; \
|
|
|
|
++ rqst.target_id = tid; \
|
|
|
|
++ rqst.command_id = s.command_id; \
|
|
|
|
++ rqst.instance_id = iid; \
|
|
|
|
++ rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE; \
|
|
|
|
++ rqst.length = sizeof(atype); \
|
|
|
|
++ rqst.payload = (u8 *)arg; \
|
|
|
|
++ \
|
|
|
|
++ rsp.capacity = sizeof(rtype); \
|
|
|
|
++ rsp.length = 0; \
|
|
|
|
++ rsp.pointer = (u8 *)ret; \
|
|
|
|
++ \
|
|
|
|
++ status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \
|
|
|
|
++ if (status) \
|
|
|
|
++ return status; \
|
|
|
|
++ \
|
|
|
|
++ if (rsp.length != sizeof(rtype)) { \
|
|
|
|
++ struct device *dev = ssam_controller_device(ctrl); \
|
|
|
|
++ dev_err(dev, \
|
|
|
|
++ "rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \
|
|
|
|
++ sizeof(rtype), rsp.length, rqst.target_category,\
|
|
|
|
++ rqst.command_id); \
|
|
|
|
++ return -EIO; \
|
|
|
|
++ } \
|
|
|
|
++ \
|
|
|
|
++ return 0; \
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
+
|
|
|
|
+ /* -- Event notifier/callbacks. --------------------------------------------- */
|
|
|
|
+
|
|
|
|
+diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
|
|
|
|
+index c418f7f2732d..6cf7e80312d5 100644
|
|
|
|
+--- a/include/linux/surface_aggregator/device.h
|
|
|
|
++++ b/include/linux/surface_aggregator/device.h
|
|
|
|
+@@ -483,6 +483,42 @@ static inline void ssam_remove_clients(struct device *dev) {}
|
|
|
|
+ sdev->uid.instance, ret); \
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
++/**
|
|
|
|
++ * SSAM_DEFINE_SYNC_REQUEST_CL_WR() - Define synchronous client-device SAM
|
|
|
|
++ * request function with argument and return value.
|
|
|
|
++ * @name: Name of the generated function.
|
|
|
|
++ * @atype: Type of the request's argument.
|
|
|
|
++ * @rtype: Type of the request's return value.
|
|
|
|
++ * @spec: Specification (&struct ssam_request_spec_md) defining the request.
|
|
|
|
++ *
|
|
|
|
++ * Defines a function executing the synchronous SAM request specified by @spec,
|
|
|
|
++ * with the request taking an argument of type @atype and having a return value
|
|
|
|
++ * of type @rtype. Device specifying parameters are not hard-coded, but instead
|
|
|
|
++ * are provided via the client device, specifically its UID, supplied when
|
|
|
|
++ * calling this function. The generated function takes care of setting up the
|
|
|
|
++ * request struct, buffer allocation, as well as execution of the request
|
|
|
|
++ * itself, returning once the request has been fully completed. The required
|
|
|
|
++ * transport buffer will be allocated on the stack.
|
|
|
|
++ *
|
|
|
|
++ * The generated function is defined as ``static int name(struct ssam_device
|
|
|
|
++ * *sdev, const atype *arg, rtype *ret)``, returning the status of the request,
|
|
|
|
++ * which is zero on success and negative on failure. The ``sdev`` parameter
|
|
|
|
++ * specifies both the target device of the request and by association the
|
|
|
|
++ * controller via which the request is sent. The request's argument is
|
|
|
|
++ * specified via the ``arg`` pointer. The request's return value is written to
|
|
|
|
++ * the memory pointed to by the ``ret`` parameter.
|
|
|
|
++ *
|
|
|
|
++ * Refer to ssam_request_sync_onstack() for more details on the behavior of
|
|
|
|
++ * the generated function.
|
|
|
|
++ */
|
|
|
|
++#define SSAM_DEFINE_SYNC_REQUEST_CL_WR(name, atype, rtype, spec...) \
|
|
|
|
++ SSAM_DEFINE_SYNC_REQUEST_MD_WR(__raw_##name, atype, rtype, spec) \
|
|
|
|
++ static int name(struct ssam_device *sdev, const atype *arg, rtype *ret) \
|
|
|
|
++ { \
|
|
|
|
++ return __raw_##name(sdev->ctrl, sdev->uid.target, \
|
|
|
|
++ sdev->uid.instance, arg, ret); \
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
+
|
|
|
|
+ /* -- Helpers for client-device notifiers. ---------------------------------- */
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 512045cafc726b6ed25380f9e8da1a03d54b468b Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 24 Jun 2022 20:36:40 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: Add KIP/POS tablet-mode switch driver
|
|
|
|
+MIME-Version: 1.0
|
|
|
|
+Content-Type: text/plain; charset=UTF-8
|
|
|
|
+Content-Transfer-Encoding: 8bit
|
|
|
|
+
|
|
|
|
+Add a driver providing a tablet-mode switch input device for Microsoft
|
|
|
|
+Surface devices using the Surface Aggregator KIP subsystem (to manage
|
|
|
|
+detachable peripherals) or POS subsystem (to obtain device posture
|
|
|
|
+information).
|
|
|
|
+
|
|
|
|
+The KIP (full name unknown, abbreviation found through reverse
|
|
|
|
+engineering) subsystem is used on the Surface Pro 8 and Surface Pro X to
|
|
|
|
+manage the keyboard cover. Among other things, it provides information
|
|
|
|
+on the positioning (posture) of the cover (closed, laptop-style,
|
|
|
|
+detached, folded-back, ...), which can be used to implement an input
|
|
|
|
+device providing the SW_TABLET_MODE event. Similarly, the POS (posture
|
|
|
|
+information) subsystem provides such information on the Surface Laptop
|
|
|
|
+Studio, with the difference being that the keyboard is not detachable.
|
|
|
|
+
|
|
|
|
+As implementing the tablet-mode switch for both subsystems is largely
|
|
|
|
+similar, the driver proposed in this commit, in large, acts as a generic
|
|
|
|
+tablet mode switch driver framework for the Surface Aggregator Module.
|
|
|
|
+Specific implementations using this framework are provided for the KIP
|
|
|
|
+and POS subsystems, adding tablet-mode switch support to the
|
|
|
|
+aforementioned devices.
|
|
|
|
+
|
|
|
|
+A few more notes on the Surface Laptop Studio:
|
|
|
|
+
|
|
|
|
+A peculiarity of the Surface Laptop Studio is its "slate/tent" mode
|
|
|
|
+(symbolized: user> _/\). In this mode, the screen covers the keyboard
|
|
|
|
+but leaves the touchpad exposed. This is essentially a mode in-between
|
|
|
|
+tablet and laptop, and it is debatable whether tablet-mode should be
|
|
|
|
+enabled in this mode. We therefore let the user decide this via a module
|
|
|
|
+parameter.
|
|
|
|
+
|
|
|
|
+In particular, tablet-mode may bring up the on-screen touch keyboard
|
|
|
|
+more easily, which would be desirable in this mode. However, some
|
|
|
|
+user-space software currently also decides to disable keyboard and, more
|
|
|
|
+importantly, touchpad input, while the touchpad is still accessible in
|
|
|
|
+the "slate/tent" mode. Furthermore, this mode shares its identifier with
|
|
|
|
+"slate/flipped" mode where the screen is flipped 180° and the keyboard
|
|
|
|
+points away from the user (symbolized: user> /_). In this mode we would
|
|
|
|
+like to enable auto-rotation, something that user-space software may
|
|
|
|
+only do when tablet-mode is enabled. We therefore default to the
|
|
|
|
+slate-mode enabling the tablet-mode switch.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220624183642.910893-3-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ .../sysfs-bus-surface_aggregator-tabletsw | 57 ++
|
|
|
|
+ MAINTAINERS | 6 +
|
|
|
|
+ drivers/platform/surface/Kconfig | 23 +
|
|
|
|
+ drivers/platform/surface/Makefile | 1 +
|
|
|
|
+ .../surface/surface_aggregator_tabletsw.c | 533 ++++++++++++++++++
|
|
|
|
+ 5 files changed, 620 insertions(+)
|
|
|
|
+ create mode 100644 Documentation/ABI/testing/sysfs-bus-surface_aggregator-tabletsw
|
|
|
|
+ create mode 100644 drivers/platform/surface/surface_aggregator_tabletsw.c
|
|
|
|
+
|
|
|
|
+diff --git a/Documentation/ABI/testing/sysfs-bus-surface_aggregator-tabletsw b/Documentation/ABI/testing/sysfs-bus-surface_aggregator-tabletsw
|
|
|
|
+new file mode 100644
|
|
|
|
+index 000000000000..74cd9d754e60
|
|
|
|
+--- /dev/null
|
|
|
|
++++ b/Documentation/ABI/testing/sysfs-bus-surface_aggregator-tabletsw
|
|
|
|
+@@ -0,0 +1,57 @@
|
|
|
|
++What: /sys/bus/surface_aggregator/devices/01:0e:01:00:01/state
|
|
|
|
++Date: July 2022
|
|
|
|
++KernelVersion: 5.20
|
|
|
|
++Contact: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++Description:
|
|
|
|
++ This attribute returns a string with the current type-cover
|
|
|
|
++ or device posture, as indicated by the embedded controller.
|
|
|
|
++ Currently returned posture states are:
|
|
|
|
++
|
|
|
|
++ - "disconnected": The type-cover has been disconnected.
|
|
|
|
++
|
|
|
|
++ - "closed": The type-cover has been folded closed and lies on
|
|
|
|
++ top of the display.
|
|
|
|
++
|
|
|
|
++ - "laptop": The type-cover is open and in laptop-mode, i.e.,
|
|
|
|
++ ready for normal use.
|
|
|
|
++
|
|
|
|
++ - "folded-canvas": The type-cover has been folded back
|
|
|
|
++ part-ways, but does not lie flush with the back side of the
|
|
|
|
++ device. In general, this means that the kick-stand is used
|
|
|
|
++ and extended atop of the cover.
|
|
|
|
++
|
|
|
|
++ - "folded-back": The type cover has been fully folded back and
|
|
|
|
++ lies flush with the back side of the device.
|
|
|
|
++
|
|
|
|
++ - "<unknown>": The current state is unknown to the driver, for
|
|
|
|
++ example due to newer as-of-yet unsupported hardware.
|
|
|
|
++
|
|
|
|
++ New states may be introduced with new hardware. Users therefore
|
|
|
|
++ must not rely on this list of states being exhaustive and
|
|
|
|
++ gracefully handle unknown states.
|
|
|
|
++
|
|
|
|
++What: /sys/bus/surface_aggregator/devices/01:26:01:00:01/state
|
|
|
|
++Date: July 2022
|
|
|
|
++KernelVersion: 5.20
|
|
|
|
++Contact: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++Description:
|
|
|
|
++ This attribute returns a string with the current device posture, as indicated by the embedded controller. Currently
|
|
|
|
++ returned posture states are:
|
|
|
|
++
|
|
|
|
++ - "closed": The lid of the device is closed.
|
|
|
|
++
|
|
|
|
++ - "laptop": The lid of the device is opened and the device
|
|
|
|
++ operates as a normal laptop.
|
|
|
|
++
|
|
|
|
++ - "slate": The screen covers the keyboard or has been flipped
|
|
|
|
++ back and the device operates mainly based on touch input.
|
|
|
|
++
|
|
|
|
++ - "tablet": The device operates as tablet and exclusively
|
|
|
|
++ relies on touch input (or external peripherals).
|
|
|
|
++
|
|
|
|
++ - "<unknown>": The current state is unknown to the driver, for
|
|
|
|
++ example due to newer as-of-yet unsupported hardware.
|
|
|
|
++
|
|
|
|
++ New states may be introduced with new hardware. Users therefore
|
|
|
|
++ must not rely on this list of states being exhaustive and
|
|
|
|
++ gracefully handle unknown states.
|
|
|
|
+diff --git a/MAINTAINERS b/MAINTAINERS
|
|
|
|
+index 64379c699903..11b84de77ab8 100644
|
|
|
|
+--- a/MAINTAINERS
|
|
|
|
++++ b/MAINTAINERS
|
|
|
|
+@@ -13304,6 +13304,12 @@ F: drivers/scsi/smartpqi/smartpqi*.[ch]
|
|
|
|
+ F: include/linux/cciss*.h
|
|
|
|
+ F: include/uapi/linux/cciss*.h
|
|
|
|
+
|
|
|
|
++MICROSOFT SURFACE AGGREGATOR TABLET-MODE SWITCH
|
|
|
|
++M: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++L: platform-driver-x86@vger.kernel.org
|
|
|
|
++S: Maintained
|
|
|
|
++F: drivers/platform/surface/surface_aggregator_tablet_switch.c
|
|
|
|
++
|
|
|
|
+ MICROSOFT SURFACE BATTERY AND AC DRIVERS
|
|
|
|
+ M: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ L: linux-pm@vger.kernel.org
|
|
|
|
+diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
|
|
|
|
+index eb79fbed8059..b152e930cc84 100644
|
|
|
|
+--- a/drivers/platform/surface/Kconfig
|
|
|
|
++++ b/drivers/platform/surface/Kconfig
|
|
|
|
+@@ -99,6 +99,29 @@ config SURFACE_AGGREGATOR_REGISTRY
|
|
|
|
+ the respective client devices. Drivers for these devices still need to
|
|
|
|
+ be selected via the other options.
|
|
|
|
+
|
|
|
|
++config SURFACE_AGGREGATOR_TABLET_SWITCH
|
|
|
|
++ tristate "Surface Aggregator Generic Tablet-Mode Switch Driver"
|
|
|
|
++ depends on SURFACE_AGGREGATOR
|
|
|
|
++ depends on SURFACE_AGGREGATOR_BUS
|
|
|
|
++ depends on INPUT
|
|
|
|
++ help
|
|
|
|
++ Provides a tablet-mode switch input device on Microsoft Surface models
|
|
|
|
++ using the KIP subsystem for detachable keyboards (e.g. keyboard covers)
|
|
|
|
++ or the POS subsystem for device/screen posture changes.
|
|
|
|
++
|
|
|
|
++ The KIP subsystem is used on newer Surface generations to handle
|
|
|
|
++ detachable input peripherals, specifically the keyboard cover (containing
|
|
|
|
++ keyboard and touchpad) on the Surface Pro 8 and Surface Pro X. The POS
|
|
|
|
++ subsystem is used for device posture change notifications on the Surface
|
|
|
|
++ Laptop Studio. This module provides a driver to let user-space know when
|
|
|
|
++ the device should be considered in tablet-mode due to the keyboard cover
|
|
|
|
++ being detached or folded back (essentially signaling when the keyboard is
|
|
|
|
++ not available for input). It does so by creating a tablet-mode switch
|
|
|
|
++ input device, sending the standard SW_TABLET_MODE event on mode change.
|
|
|
|
++
|
|
|
|
++ Select M or Y here, if you want to provide tablet-mode switch input
|
|
|
|
++ events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio.
|
|
|
|
++
|
|
|
|
+ config SURFACE_DTX
|
|
|
|
+ tristate "Surface DTX (Detachment System) Driver"
|
|
|
|
+ depends on SURFACE_AGGREGATOR
|
|
|
|
+diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
|
|
|
|
+index 0fc9cd3e4dd9..18b27898543e 100644
|
|
|
|
+--- a/drivers/platform/surface/Makefile
|
|
|
|
++++ b/drivers/platform/surface/Makefile
|
|
|
|
+@@ -10,6 +10,7 @@ obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o
|
|
|
|
+ obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/
|
|
|
|
+ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o
|
|
|
|
+ obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o
|
|
|
|
++obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o
|
|
|
|
+ obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o
|
|
|
|
+ obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o
|
|
|
|
+ obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c
|
|
|
|
+new file mode 100644
|
|
|
|
+index 000000000000..596ca6c80681
|
|
|
|
+--- /dev/null
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_tabletsw.c
|
|
|
|
+@@ -0,0 +1,533 @@
|
|
|
|
++// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
++/*
|
|
|
|
++ * Surface System Aggregator Module (SSAM) tablet mode switch driver.
|
|
|
|
++ *
|
|
|
|
++ * Copyright (C) 2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ */
|
|
|
|
++
|
|
|
|
++#include <asm/unaligned.h>
|
|
|
|
++#include <linux/input.h>
|
|
|
|
++#include <linux/kernel.h>
|
|
|
|
++#include <linux/module.h>
|
|
|
|
++#include <linux/types.h>
|
|
|
|
++#include <linux/workqueue.h>
|
|
|
|
++
|
|
|
|
++#include <linux/surface_aggregator/controller.h>
|
|
|
|
++#include <linux/surface_aggregator/device.h>
|
|
|
|
++
|
|
|
|
++
|
|
|
|
++/* -- SSAM generic tablet switch driver framework. -------------------------- */
|
|
|
|
++
|
|
|
|
++struct ssam_tablet_sw;
|
|
|
|
++
|
|
|
|
++struct ssam_tablet_sw_ops {
|
|
|
|
++ int (*get_state)(struct ssam_tablet_sw *sw, u32 *state);
|
|
|
|
++ const char *(*state_name)(struct ssam_tablet_sw *sw, u32 state);
|
|
|
|
++ bool (*state_is_tablet_mode)(struct ssam_tablet_sw *sw, u32 state);
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++struct ssam_tablet_sw {
|
|
|
|
++ struct ssam_device *sdev;
|
|
|
|
++
|
|
|
|
++ u32 state;
|
|
|
|
++ struct work_struct update_work;
|
|
|
|
++ struct input_dev *mode_switch;
|
|
|
|
++
|
|
|
|
++ struct ssam_tablet_sw_ops ops;
|
|
|
|
++ struct ssam_event_notifier notif;
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++struct ssam_tablet_sw_desc {
|
|
|
|
++ struct {
|
|
|
|
++ const char *name;
|
|
|
|
++ const char *phys;
|
|
|
|
++ } dev;
|
|
|
|
++
|
|
|
|
++ struct {
|
|
|
|
++ u32 (*notify)(struct ssam_event_notifier *nf, const struct ssam_event *event);
|
|
|
|
++ int (*get_state)(struct ssam_tablet_sw *sw, u32 *state);
|
|
|
|
++ const char *(*state_name)(struct ssam_tablet_sw *sw, u32 state);
|
|
|
|
++ bool (*state_is_tablet_mode)(struct ssam_tablet_sw *sw, u32 state);
|
|
|
|
++ } ops;
|
|
|
|
++
|
|
|
|
++ struct {
|
|
|
|
++ struct ssam_event_registry reg;
|
|
|
|
++ struct ssam_event_id id;
|
|
|
|
++ enum ssam_event_mask mask;
|
|
|
|
++ u8 flags;
|
|
|
|
++ } event;
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
++{
|
|
|
|
++ struct ssam_tablet_sw *sw = dev_get_drvdata(dev);
|
|
|
|
++ const char *state = sw->ops.state_name(sw, sw->state);
|
|
|
|
++
|
|
|
|
++ return sysfs_emit(buf, "%s\n", state);
|
|
|
|
++}
|
|
|
|
++static DEVICE_ATTR_RO(state);
|
|
|
|
++
|
|
|
|
++static struct attribute *ssam_tablet_sw_attrs[] = {
|
|
|
|
++ &dev_attr_state.attr,
|
|
|
|
++ NULL,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++static const struct attribute_group ssam_tablet_sw_group = {
|
|
|
|
++ .attrs = ssam_tablet_sw_attrs,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++static void ssam_tablet_sw_update_workfn(struct work_struct *work)
|
|
|
|
++{
|
|
|
|
++ struct ssam_tablet_sw *sw = container_of(work, struct ssam_tablet_sw, update_work);
|
|
|
|
++ int tablet, status;
|
|
|
|
++ u32 state;
|
|
|
|
++
|
|
|
|
++ status = sw->ops.get_state(sw, &state);
|
|
|
|
++ if (status)
|
|
|
|
++ return;
|
|
|
|
++
|
|
|
|
++ if (sw->state == state)
|
|
|
|
++ return;
|
|
|
|
++ sw->state = state;
|
|
|
|
++
|
|
|
|
++ /* Send SW_TABLET_MODE event. */
|
|
|
|
++ tablet = sw->ops.state_is_tablet_mode(sw, state);
|
|
|
|
++ input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet);
|
|
|
|
++ input_sync(sw->mode_switch);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int __maybe_unused ssam_tablet_sw_resume(struct device *dev)
|
|
|
|
++{
|
|
|
|
++ struct ssam_tablet_sw *sw = dev_get_drvdata(dev);
|
|
|
|
++
|
|
|
|
++ schedule_work(&sw->update_work);
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++static SIMPLE_DEV_PM_OPS(ssam_tablet_sw_pm_ops, NULL, ssam_tablet_sw_resume);
|
|
|
|
++
|
|
|
|
++static int ssam_tablet_sw_probe(struct ssam_device *sdev)
|
|
|
|
++{
|
|
|
|
++ const struct ssam_tablet_sw_desc *desc;
|
|
|
|
++ struct ssam_tablet_sw *sw;
|
|
|
|
++ int tablet, status;
|
|
|
|
++
|
|
|
|
++ desc = ssam_device_get_match_data(sdev);
|
|
|
|
++ if (!desc) {
|
|
|
|
++ WARN(1, "no driver match data specified");
|
|
|
|
++ return -EINVAL;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ sw = devm_kzalloc(&sdev->dev, sizeof(*sw), GFP_KERNEL);
|
|
|
|
++ if (!sw)
|
|
|
|
++ return -ENOMEM;
|
|
|
|
++
|
|
|
|
++ sw->sdev = sdev;
|
|
|
|
++
|
|
|
|
++ sw->ops.get_state = desc->ops.get_state;
|
|
|
|
++ sw->ops.state_name = desc->ops.state_name;
|
|
|
|
++ sw->ops.state_is_tablet_mode = desc->ops.state_is_tablet_mode;
|
|
|
|
++
|
|
|
|
++ INIT_WORK(&sw->update_work, ssam_tablet_sw_update_workfn);
|
|
|
|
++
|
|
|
|
++ ssam_device_set_drvdata(sdev, sw);
|
|
|
|
++
|
|
|
|
++ /* Get initial state. */
|
|
|
|
++ status = sw->ops.get_state(sw, &sw->state);
|
|
|
|
++ if (status)
|
|
|
|
++ return status;
|
|
|
|
++
|
|
|
|
++ /* Set up tablet mode switch. */
|
|
|
|
++ sw->mode_switch = devm_input_allocate_device(&sdev->dev);
|
|
|
|
++ if (!sw->mode_switch)
|
|
|
|
++ return -ENOMEM;
|
|
|
|
++
|
|
|
|
++ sw->mode_switch->name = desc->dev.name;
|
|
|
|
++ sw->mode_switch->phys = desc->dev.phys;
|
|
|
|
++ sw->mode_switch->id.bustype = BUS_HOST;
|
|
|
|
++ sw->mode_switch->dev.parent = &sdev->dev;
|
|
|
|
++
|
|
|
|
++ tablet = sw->ops.state_is_tablet_mode(sw, sw->state);
|
|
|
|
++ input_set_capability(sw->mode_switch, EV_SW, SW_TABLET_MODE);
|
|
|
|
++ input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet);
|
|
|
|
++
|
|
|
|
++ status = input_register_device(sw->mode_switch);
|
|
|
|
++ if (status)
|
|
|
|
++ return status;
|
|
|
|
++
|
|
|
|
++ /* Set up notifier. */
|
|
|
|
++ sw->notif.base.priority = 0;
|
|
|
|
++ sw->notif.base.fn = desc->ops.notify;
|
|
|
|
++ sw->notif.event.reg = desc->event.reg;
|
|
|
|
++ sw->notif.event.id = desc->event.id;
|
|
|
|
++ sw->notif.event.mask = desc->event.mask;
|
|
|
|
++ sw->notif.event.flags = SSAM_EVENT_SEQUENCED;
|
|
|
|
++
|
|
|
|
++ status = ssam_device_notifier_register(sdev, &sw->notif);
|
|
|
|
++ if (status)
|
|
|
|
++ return status;
|
|
|
|
++
|
|
|
|
++ status = sysfs_create_group(&sdev->dev.kobj, &ssam_tablet_sw_group);
|
|
|
|
++ if (status)
|
|
|
|
++ goto err;
|
|
|
|
++
|
|
|
|
++ /* We might have missed events during setup, so check again. */
|
|
|
|
++ schedule_work(&sw->update_work);
|
|
|
|
++ return 0;
|
|
|
|
++
|
|
|
|
++err:
|
|
|
|
++ ssam_device_notifier_unregister(sdev, &sw->notif);
|
|
|
|
++ cancel_work_sync(&sw->update_work);
|
|
|
|
++ return status;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static void ssam_tablet_sw_remove(struct ssam_device *sdev)
|
|
|
|
++{
|
|
|
|
++ struct ssam_tablet_sw *sw = ssam_device_get_drvdata(sdev);
|
|
|
|
++
|
|
|
|
++ sysfs_remove_group(&sdev->dev.kobj, &ssam_tablet_sw_group);
|
|
|
|
++
|
|
|
|
++ ssam_device_notifier_unregister(sdev, &sw->notif);
|
|
|
|
++ cancel_work_sync(&sw->update_work);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++
|
|
|
|
++/* -- SSAM KIP tablet switch implementation. -------------------------------- */
|
|
|
|
++
|
|
|
|
++#define SSAM_EVENT_KIP_CID_COVER_STATE_CHANGED 0x1d
|
|
|
|
++
|
|
|
|
++enum ssam_kip_cover_state {
|
|
|
|
++ SSAM_KIP_COVER_STATE_DISCONNECTED = 0x01,
|
|
|
|
++ SSAM_KIP_COVER_STATE_CLOSED = 0x02,
|
|
|
|
++ SSAM_KIP_COVER_STATE_LAPTOP = 0x03,
|
|
|
|
++ SSAM_KIP_COVER_STATE_FOLDED_CANVAS = 0x04,
|
|
|
|
++ SSAM_KIP_COVER_STATE_FOLDED_BACK = 0x05,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++static const char *ssam_kip_cover_state_name(struct ssam_tablet_sw *sw, u32 state)
|
|
|
|
++{
|
|
|
|
++ switch (state) {
|
|
|
|
++ case SSAM_KIP_COVER_STATE_DISCONNECTED:
|
|
|
|
++ return "disconnected";
|
|
|
|
++
|
|
|
|
++ case SSAM_KIP_COVER_STATE_CLOSED:
|
|
|
|
++ return "closed";
|
|
|
|
++
|
|
|
|
++ case SSAM_KIP_COVER_STATE_LAPTOP:
|
|
|
|
++ return "laptop";
|
|
|
|
++
|
|
|
|
++ case SSAM_KIP_COVER_STATE_FOLDED_CANVAS:
|
|
|
|
++ return "folded-canvas";
|
|
|
|
++
|
|
|
|
++ case SSAM_KIP_COVER_STATE_FOLDED_BACK:
|
|
|
|
++ return "folded-back";
|
|
|
|
++
|
|
|
|
++ default:
|
|
|
|
++ dev_warn(&sw->sdev->dev, "unknown KIP cover state: %u\n", state);
|
|
|
|
++ return "<unknown>";
|
|
|
|
++ }
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static bool ssam_kip_cover_state_is_tablet_mode(struct ssam_tablet_sw *sw, u32 state)
|
|
|
|
++{
|
|
|
|
++ switch (state) {
|
|
|
|
++ case SSAM_KIP_COVER_STATE_DISCONNECTED:
|
|
|
|
++ case SSAM_KIP_COVER_STATE_FOLDED_CANVAS:
|
|
|
|
++ case SSAM_KIP_COVER_STATE_FOLDED_BACK:
|
|
|
|
++ return true;
|
|
|
|
++
|
|
|
|
++ case SSAM_KIP_COVER_STATE_CLOSED:
|
|
|
|
++ case SSAM_KIP_COVER_STATE_LAPTOP:
|
|
|
|
++ return false;
|
|
|
|
++
|
|
|
|
++ default:
|
|
|
|
++ dev_warn(&sw->sdev->dev, "unknown KIP cover state: %d\n", sw->state);
|
|
|
|
++ return true;
|
|
|
|
++ }
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_cover_state, u8, {
|
|
|
|
++ .target_category = SSAM_SSH_TC_KIP,
|
|
|
|
++ .target_id = 0x01,
|
|
|
|
++ .command_id = 0x1d,
|
|
|
|
++ .instance_id = 0x00,
|
|
|
|
++});
|
|
|
|
++
|
|
|
|
++static int ssam_kip_get_cover_state(struct ssam_tablet_sw *sw, u32 *state)
|
|
|
|
++{
|
|
|
|
++ int status;
|
|
|
|
++ u8 raw;
|
|
|
|
++
|
|
|
|
++ status = ssam_retry(__ssam_kip_get_cover_state, sw->sdev->ctrl, &raw);
|
|
|
|
++ if (status < 0) {
|
|
|
|
++ dev_err(&sw->sdev->dev, "failed to query KIP lid state: %d\n", status);
|
|
|
|
++ return status;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ *state = raw;
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static u32 ssam_kip_sw_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
|
|
|
|
++{
|
|
|
|
++ struct ssam_tablet_sw *sw = container_of(nf, struct ssam_tablet_sw, notif);
|
|
|
|
++
|
|
|
|
++ if (event->command_id != SSAM_EVENT_KIP_CID_COVER_STATE_CHANGED)
|
|
|
|
++ return 0; /* Return "unhandled". */
|
|
|
|
++
|
|
|
|
++ if (event->length < 1)
|
|
|
|
++ dev_warn(&sw->sdev->dev, "unexpected payload size: %u\n", event->length);
|
|
|
|
++
|
|
|
|
++ schedule_work(&sw->update_work);
|
|
|
|
++ return SSAM_NOTIF_HANDLED;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static const struct ssam_tablet_sw_desc ssam_kip_sw_desc = {
|
|
|
|
++ .dev = {
|
|
|
|
++ .name = "Microsoft Surface KIP Tablet Mode Switch",
|
|
|
|
++ .phys = "ssam/01:0e:01:00:01/input0",
|
|
|
|
++ },
|
|
|
|
++ .ops = {
|
|
|
|
++ .notify = ssam_kip_sw_notif,
|
|
|
|
++ .get_state = ssam_kip_get_cover_state,
|
|
|
|
++ .state_name = ssam_kip_cover_state_name,
|
|
|
|
++ .state_is_tablet_mode = ssam_kip_cover_state_is_tablet_mode,
|
|
|
|
++ },
|
|
|
|
++ .event = {
|
|
|
|
++ .reg = SSAM_EVENT_REGISTRY_SAM,
|
|
|
|
++ .id = {
|
|
|
|
++ .target_category = SSAM_SSH_TC_KIP,
|
|
|
|
++ .instance = 0,
|
|
|
|
++ },
|
|
|
|
++ .mask = SSAM_EVENT_MASK_TARGET,
|
|
|
|
++ },
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++
|
|
|
|
++/* -- SSAM POS tablet switch implementation. -------------------------------- */
|
|
|
|
++
|
|
|
|
++static bool tablet_mode_in_slate_state = true;
|
|
|
|
++module_param(tablet_mode_in_slate_state, bool, 0644);
|
|
|
|
++MODULE_PARM_DESC(tablet_mode_in_slate_state, "Enable tablet mode in slate device posture, default is 'true'");
|
|
|
|
++
|
|
|
|
++#define SSAM_EVENT_POS_CID_POSTURE_CHANGED 0x03
|
|
|
|
++#define SSAM_POS_MAX_SOURCES 4
|
|
|
|
++
|
|
|
|
++enum ssam_pos_state {
|
|
|
|
++ SSAM_POS_POSTURE_LID_CLOSED = 0x00,
|
|
|
|
++ SSAM_POS_POSTURE_LAPTOP = 0x01,
|
|
|
|
++ SSAM_POS_POSTURE_SLATE = 0x02,
|
|
|
|
++ SSAM_POS_POSTURE_TABLET = 0x03,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++struct ssam_sources_list {
|
|
|
|
++ __le32 count;
|
|
|
|
++ __le32 id[SSAM_POS_MAX_SOURCES];
|
|
|
|
++} __packed;
|
|
|
|
++
|
|
|
|
++static const char *ssam_pos_state_name(struct ssam_tablet_sw *sw, u32 state)
|
|
|
|
++{
|
|
|
|
++ switch (state) {
|
|
|
|
++ case SSAM_POS_POSTURE_LID_CLOSED:
|
|
|
|
++ return "closed";
|
|
|
|
++
|
|
|
|
++ case SSAM_POS_POSTURE_LAPTOP:
|
|
|
|
++ return "laptop";
|
|
|
|
++
|
|
|
|
++ case SSAM_POS_POSTURE_SLATE:
|
|
|
|
++ return "slate";
|
|
|
|
++
|
|
|
|
++ case SSAM_POS_POSTURE_TABLET:
|
|
|
|
++ return "tablet";
|
|
|
|
++
|
|
|
|
++ default:
|
|
|
|
++ dev_warn(&sw->sdev->dev, "unknown device posture: %u\n", state);
|
|
|
|
++ return "<unknown>";
|
|
|
|
++ }
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static bool ssam_pos_state_is_tablet_mode(struct ssam_tablet_sw *sw, u32 state)
|
|
|
|
++{
|
|
|
|
++ switch (state) {
|
|
|
|
++ case SSAM_POS_POSTURE_LAPTOP:
|
|
|
|
++ case SSAM_POS_POSTURE_LID_CLOSED:
|
|
|
|
++ return false;
|
|
|
|
++
|
|
|
|
++ case SSAM_POS_POSTURE_SLATE:
|
|
|
|
++ return tablet_mode_in_slate_state;
|
|
|
|
++
|
|
|
|
++ case SSAM_POS_POSTURE_TABLET:
|
|
|
|
++ return true;
|
|
|
|
++
|
|
|
|
++ default:
|
|
|
|
++ dev_warn(&sw->sdev->dev, "unknown device posture: %u\n", state);
|
|
|
|
++ return true;
|
|
|
|
++ }
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sources_list *sources)
|
|
|
|
++{
|
|
|
|
++ struct ssam_request rqst;
|
|
|
|
++ struct ssam_response rsp;
|
|
|
|
++ int status;
|
|
|
|
++
|
|
|
|
++ rqst.target_category = SSAM_SSH_TC_POS;
|
|
|
|
++ rqst.target_id = 0x01;
|
|
|
|
++ rqst.command_id = 0x01;
|
|
|
|
++ rqst.instance_id = 0x00;
|
|
|
|
++ rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
|
|
|
|
++ rqst.length = 0;
|
|
|
|
++ rqst.payload = NULL;
|
|
|
|
++
|
|
|
|
++ rsp.capacity = sizeof(*sources);
|
|
|
|
++ rsp.length = 0;
|
|
|
|
++ rsp.pointer = (u8 *)sources;
|
|
|
|
++
|
|
|
|
++ status = ssam_retry(ssam_request_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0);
|
|
|
|
++ if (status)
|
|
|
|
++ return status;
|
|
|
|
++
|
|
|
|
++ /* We need at least the 'sources->count' field. */
|
|
|
|
++ if (rsp.length < sizeof(__le32)) {
|
|
|
|
++ dev_err(&sw->sdev->dev, "received source list response is too small\n");
|
|
|
|
++ return -EPROTO;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ /* Make sure 'sources->count' matches with the response length. */
|
|
|
|
++ if (get_unaligned_le32(&sources->count) * sizeof(__le32) + sizeof(__le32) != rsp.length) {
|
|
|
|
++ dev_err(&sw->sdev->dev, "mismatch between number of sources and response size\n");
|
|
|
|
++ return -EPROTO;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id)
|
|
|
|
++{
|
|
|
|
++ struct ssam_sources_list sources = {};
|
|
|
|
++ int status;
|
|
|
|
++
|
|
|
|
++ status = ssam_pos_get_sources_list(sw, &sources);
|
|
|
|
++ if (status)
|
|
|
|
++ return status;
|
|
|
|
++
|
|
|
|
++ if (sources.count == 0) {
|
|
|
|
++ dev_err(&sw->sdev->dev, "no posture sources found\n");
|
|
|
|
++ return -ENODEV;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ /*
|
|
|
|
++ * We currently don't know what to do with more than one posture
|
|
|
|
++ * source. At the moment, only one source seems to be used/provided.
|
|
|
|
++ * The WARN_ON() here should hopefully let us know quickly once there
|
|
|
|
++ * is a device that provides multiple sources, at which point we can
|
|
|
|
++ * then try to figure out how to handle them.
|
|
|
|
++ */
|
|
|
|
++ WARN_ON(sources.count > 1);
|
|
|
|
++
|
|
|
|
++ *source_id = get_unaligned_le32(&sources.id[0]);
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++SSAM_DEFINE_SYNC_REQUEST_WR(__ssam_pos_get_posture_for_source, __le32, __le32, {
|
|
|
|
++ .target_category = SSAM_SSH_TC_POS,
|
|
|
|
++ .target_id = 0x01,
|
|
|
|
++ .command_id = 0x02,
|
|
|
|
++ .instance_id = 0x00,
|
|
|
|
++});
|
|
|
|
++
|
|
|
|
++static int ssam_pos_get_posture_for_source(struct ssam_tablet_sw *sw, u32 source_id, u32 *posture)
|
|
|
|
++{
|
|
|
|
++ __le32 source_le = cpu_to_le32(source_id);
|
|
|
|
++ __le32 rspval_le = 0;
|
|
|
|
++ int status;
|
|
|
|
++
|
|
|
|
++ status = ssam_retry(__ssam_pos_get_posture_for_source, sw->sdev->ctrl,
|
|
|
|
++ &source_le, &rspval_le);
|
|
|
|
++ if (status)
|
|
|
|
++ return status;
|
|
|
|
++
|
|
|
|
++ *posture = le32_to_cpu(rspval_le);
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int ssam_pos_get_posture(struct ssam_tablet_sw *sw, u32 *state)
|
|
|
|
++{
|
|
|
|
++ u32 source_id;
|
|
|
|
++ int status;
|
|
|
|
++
|
|
|
|
++ status = ssam_pos_get_source(sw, &source_id);
|
|
|
|
++ if (status) {
|
|
|
|
++ dev_err(&sw->sdev->dev, "failed to get posture source ID: %d\n", status);
|
|
|
|
++ return status;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ status = ssam_pos_get_posture_for_source(sw, source_id, state);
|
|
|
|
++ if (status) {
|
|
|
|
++ dev_err(&sw->sdev->dev, "failed to get posture value for source %u: %d\n",
|
|
|
|
++ source_id, status);
|
|
|
|
++ return status;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static u32 ssam_pos_sw_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
|
|
|
|
++{
|
|
|
|
++ struct ssam_tablet_sw *sw = container_of(nf, struct ssam_tablet_sw, notif);
|
|
|
|
++
|
|
|
|
++ if (event->command_id != SSAM_EVENT_POS_CID_POSTURE_CHANGED)
|
|
|
|
++ return 0; /* Return "unhandled". */
|
|
|
|
++
|
|
|
|
++ if (event->length != sizeof(__le32) * 3)
|
|
|
|
++ dev_warn(&sw->sdev->dev, "unexpected payload size: %u\n", event->length);
|
|
|
|
++
|
|
|
|
++ schedule_work(&sw->update_work);
|
|
|
|
++ return SSAM_NOTIF_HANDLED;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static const struct ssam_tablet_sw_desc ssam_pos_sw_desc = {
|
|
|
|
++ .dev = {
|
|
|
|
++ .name = "Microsoft Surface POS Tablet Mode Switch",
|
|
|
|
++ .phys = "ssam/01:26:01:00:01/input0",
|
|
|
|
++ },
|
|
|
|
++ .ops = {
|
|
|
|
++ .notify = ssam_pos_sw_notif,
|
|
|
|
++ .get_state = ssam_pos_get_posture,
|
|
|
|
++ .state_name = ssam_pos_state_name,
|
|
|
|
++ .state_is_tablet_mode = ssam_pos_state_is_tablet_mode,
|
|
|
|
++ },
|
|
|
|
++ .event = {
|
|
|
|
++ .reg = SSAM_EVENT_REGISTRY_SAM,
|
|
|
|
++ .id = {
|
|
|
|
++ .target_category = SSAM_SSH_TC_POS,
|
|
|
|
++ .instance = 0,
|
|
|
|
++ },
|
|
|
|
++ .mask = SSAM_EVENT_MASK_TARGET,
|
|
|
|
++ },
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++
|
|
|
|
++/* -- Driver registration. -------------------------------------------------- */
|
|
|
|
++
|
|
|
|
++static const struct ssam_device_id ssam_tablet_sw_match[] = {
|
|
|
|
++ { SSAM_SDEV(KIP, 0x01, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc },
|
|
|
|
++ { SSAM_SDEV(POS, 0x01, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc },
|
|
|
|
++ { },
|
|
|
|
++};
|
|
|
|
++MODULE_DEVICE_TABLE(ssam, ssam_tablet_sw_match);
|
|
|
|
++
|
|
|
|
++static struct ssam_device_driver ssam_tablet_sw_driver = {
|
|
|
|
++ .probe = ssam_tablet_sw_probe,
|
|
|
|
++ .remove = ssam_tablet_sw_remove,
|
|
|
|
++ .match_table = ssam_tablet_sw_match,
|
|
|
|
++ .driver = {
|
|
|
|
++ .name = "surface_aggregator_tablet_mode_switch",
|
|
|
|
++ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
|
|
|
++ .pm = &ssam_tablet_sw_pm_ops,
|
|
|
|
++ },
|
|
|
|
++};
|
|
|
|
++module_ssam_device_driver(ssam_tablet_sw_driver);
|
|
|
|
++
|
|
|
|
++MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
|
|
|
|
++MODULE_DESCRIPTION("Tablet mode switch driver for Surface devices using the Surface Aggregator Module");
|
|
|
|
++MODULE_LICENSE("GPL");
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From b4980b9b4fea5724a15e45584f45b5d3280cc530 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 24 Jun 2022 20:36:41 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Add support for tablet
|
|
|
|
+ mode switch on Surface Pro 8
|
|
|
|
+
|
|
|
|
+Add a KIP subsystem tablet-mode switch device for the Surface Pro 8.
|
|
|
|
+The respective driver for this device provides SW_TABLET_MODE input
|
|
|
|
+events for user-space based on the state of the keyboard cover (e.g.
|
|
|
|
+detached, folded-back, normal/laptop mode).
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220624183642.910893-4-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/platform/surface/surface_aggregator_registry.c | 8 +++++++-
|
|
|
|
+ 1 file changed, 7 insertions(+), 1 deletion(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index bf3303f1aa71..8f249df673a4 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -77,6 +77,12 @@ static const struct software_node ssam_node_tmp_pprof = {
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
++/* Tablet-mode switch via KIP subsystem. */
|
|
|
|
++static const struct software_node ssam_node_kip_tablet_switch = {
|
|
|
|
++ .name = "ssam:01:0e:01:00:01",
|
|
|
|
++ .parent = &ssam_node_root,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
+ /* DTX / detachment-system device (Surface Book 3). */
|
|
|
|
+ static const struct software_node ssam_node_bas_dtx = {
|
|
|
|
+ .name = "ssam:01:11:01:00:00",
|
|
|
|
+@@ -264,11 +270,11 @@ static const struct software_node *ssam_node_group_sp8[] = {
|
|
|
|
+ &ssam_node_bat_ac,
|
|
|
|
+ &ssam_node_bat_main,
|
|
|
|
+ &ssam_node_tmp_pprof,
|
|
|
|
++ &ssam_node_kip_tablet_switch,
|
|
|
|
+ &ssam_node_hid_kip_keyboard,
|
|
|
|
+ &ssam_node_hid_kip_penstash,
|
|
|
|
+ &ssam_node_hid_kip_touchpad,
|
|
|
|
+ &ssam_node_hid_kip_iid5,
|
|
|
|
+- /* TODO: Add support for tablet mode switch. */
|
|
|
|
+ NULL,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 0961eab47ed4dce567fd3ffd8be1573f9569282d Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 24 Jun 2022 20:36:42 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Add support for tablet
|
|
|
|
+ mode switch on Surface Laptop Studio
|
|
|
|
+
|
|
|
|
+Add a POS subsystem tablet-mode switch device for the Surface Laptop
|
|
|
|
+Studio. The respective driver for this device provides SW_TABLET_MODE
|
|
|
|
+input events for user-space based on the posture of the screen.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220624183642.910893-5-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++
|
|
|
|
+ 1 file changed, 7 insertions(+)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index 8f249df673a4..f1c5905f1c16 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -191,6 +191,12 @@ static const struct software_node ssam_node_hid_kip_iid5 = {
|
|
|
|
+ .parent = &ssam_node_hub_kip,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
++/* Tablet-mode switch via POS subsystem. */
|
|
|
|
++static const struct software_node ssam_node_pos_tablet_switch = {
|
|
|
|
++ .name = "ssam:01:26:01:00:01",
|
|
|
|
++ .parent = &ssam_node_root,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
+ /*
|
|
|
|
+ * Devices for 5th- and 6th-generations models:
|
|
|
|
+ * - Surface Book 2,
|
|
|
|
+@@ -237,6 +243,7 @@ static const struct software_node *ssam_node_group_sls[] = {
|
|
|
|
+ &ssam_node_bat_ac,
|
|
|
|
+ &ssam_node_bat_main,
|
|
|
|
+ &ssam_node_tmp_pprof,
|
|
|
|
++ &ssam_node_pos_tablet_switch,
|
|
|
|
+ &ssam_node_hid_tid1_keyboard,
|
|
|
|
+ &ssam_node_hid_tid1_penstash,
|
|
|
|
+ &ssam_node_hid_tid1_touchpad,
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 725529e652ccbc578cd2f6e453cc86bb3294f2d4 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 24 Jun 2022 22:57:58 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator: Move device registry helper
|
|
|
|
+ functions to core module
|
|
|
|
+
|
|
|
|
+Move helper functions for client device registration to the core module.
|
|
|
|
+This simplifies addition of future DT/OF support and also allows us to
|
|
|
|
+split out the device hub drivers into their own module.
|
|
|
|
+
|
|
|
|
+At the same time, also improve device node validation a bit by not
|
|
|
|
+silently skipping devices with invalid device UID specifiers. Further,
|
|
|
|
+ensure proper lifetime management for the firmware/software nodes
|
|
|
|
+associated with the added devices.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220624205800.1355621-2-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/platform/surface/aggregator/bus.c | 149 ++++++++++++++++--
|
|
|
|
+ .../surface/surface_aggregator_registry.c | 75 +--------
|
|
|
|
+ include/linux/surface_aggregator/device.h | 52 ++++++
|
|
|
|
+ 3 files changed, 187 insertions(+), 89 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
|
|
|
|
+index abbbb5b08b07..e0b0381a2834 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/bus.c
|
|
|
|
++++ b/drivers/platform/surface/aggregator/bus.c
|
|
|
|
+@@ -6,6 +6,7 @@
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <linux/device.h>
|
|
|
|
++#include <linux/property.h>
|
|
|
|
+ #include <linux/slab.h>
|
|
|
|
+
|
|
|
|
+ #include <linux/surface_aggregator/controller.h>
|
|
|
|
+@@ -14,6 +15,9 @@
|
|
|
|
+ #include "bus.h"
|
|
|
|
+ #include "controller.h"
|
|
|
|
+
|
|
|
|
++
|
|
|
|
++/* -- Device and bus functions. --------------------------------------------- */
|
|
|
|
++
|
|
|
|
+ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
+ char *buf)
|
|
|
|
+ {
|
|
|
|
+@@ -46,6 +50,7 @@ static void ssam_device_release(struct device *dev)
|
|
|
|
+ struct ssam_device *sdev = to_ssam_device(dev);
|
|
|
|
+
|
|
|
|
+ ssam_controller_put(sdev->ctrl);
|
|
|
|
++ fwnode_handle_put(sdev->dev.fwnode);
|
|
|
|
+ kfree(sdev);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+@@ -363,6 +368,134 @@ void ssam_device_driver_unregister(struct ssam_device_driver *sdrv)
|
|
|
|
+ }
|
|
|
|
+ EXPORT_SYMBOL_GPL(ssam_device_driver_unregister);
|
|
|
|
+
|
|
|
|
++
|
|
|
|
++/* -- Bus registration. ----------------------------------------------------- */
|
|
|
|
++
|
|
|
|
++/**
|
|
|
|
++ * ssam_bus_register() - Register and set-up the SSAM client device bus.
|
|
|
|
++ */
|
|
|
|
++int ssam_bus_register(void)
|
|
|
|
++{
|
|
|
|
++ return bus_register(&ssam_bus_type);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++/**
|
|
|
|
++ * ssam_bus_unregister() - Unregister the SSAM client device bus.
|
|
|
|
++ */
|
|
|
|
++void ssam_bus_unregister(void)
|
|
|
|
++{
|
|
|
|
++ return bus_unregister(&ssam_bus_type);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++
|
|
|
|
++/* -- Helpers for controller and hub devices. ------------------------------- */
|
|
|
|
++
|
|
|
|
++static int ssam_device_uid_from_string(const char *str, struct ssam_device_uid *uid)
|
|
|
|
++{
|
|
|
|
++ u8 d, tc, tid, iid, fn;
|
|
|
|
++ int n;
|
|
|
|
++
|
|
|
|
++ n = sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx", &d, &tc, &tid, &iid, &fn);
|
|
|
|
++ if (n != 5)
|
|
|
|
++ return -EINVAL;
|
|
|
|
++
|
|
|
|
++ uid->domain = d;
|
|
|
|
++ uid->category = tc;
|
|
|
|
++ uid->target = tid;
|
|
|
|
++ uid->instance = iid;
|
|
|
|
++ uid->function = fn;
|
|
|
|
++
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int ssam_get_uid_for_node(struct fwnode_handle *node, struct ssam_device_uid *uid)
|
|
|
|
++{
|
|
|
|
++ const char *str = fwnode_get_name(node);
|
|
|
|
++
|
|
|
|
++ /*
|
|
|
|
++ * To simplify definitions of firmware nodes, we set the device name
|
|
|
|
++ * based on the UID of the device, prefixed with "ssam:".
|
|
|
|
++ */
|
|
|
|
++ if (strncmp(str, "ssam:", strlen("ssam:")) != 0)
|
|
|
|
++ return -ENODEV;
|
|
|
|
++
|
|
|
|
++ str += strlen("ssam:");
|
|
|
|
++ return ssam_device_uid_from_string(str, uid);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int ssam_add_client_device(struct device *parent, struct ssam_controller *ctrl,
|
|
|
|
++ struct fwnode_handle *node)
|
|
|
|
++{
|
|
|
|
++ struct ssam_device_uid uid;
|
|
|
|
++ struct ssam_device *sdev;
|
|
|
|
++ int status;
|
|
|
|
++
|
|
|
|
++ status = ssam_get_uid_for_node(node, &uid);
|
|
|
|
++ if (status)
|
|
|
|
++ return status;
|
|
|
|
++
|
|
|
|
++ sdev = ssam_device_alloc(ctrl, uid);
|
|
|
|
++ if (!sdev)
|
|
|
|
++ return -ENOMEM;
|
|
|
|
++
|
|
|
|
++ sdev->dev.parent = parent;
|
|
|
|
++ sdev->dev.fwnode = fwnode_handle_get(node);
|
|
|
|
++
|
|
|
|
++ status = ssam_device_add(sdev);
|
|
|
|
++ if (status)
|
|
|
|
++ ssam_device_put(sdev);
|
|
|
|
++
|
|
|
|
++ return status;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++/**
|
|
|
|
++ * __ssam_register_clients() - Register client devices defined under the
|
|
|
|
++ * given firmware node as children of the given device.
|
|
|
|
++ * @parent: The parent device under which clients should be registered.
|
|
|
|
++ * @ctrl: The controller with which client should be registered.
|
|
|
|
++ * @node: The firmware node holding definitions of the devices to be added.
|
|
|
|
++ *
|
|
|
|
++ * Register all clients that have been defined as children of the given root
|
|
|
|
++ * firmware node as children of the given parent device. The respective child
|
|
|
|
++ * firmware nodes will be associated with the correspondingly created child
|
|
|
|
++ * devices.
|
|
|
|
++ *
|
|
|
|
++ * The given controller will be used to instantiate the new devices. See
|
|
|
|
++ * ssam_device_add() for details.
|
|
|
|
++ *
|
|
|
|
++ * Note that, generally, the use of either ssam_device_register_clients() or
|
|
|
|
++ * ssam_register_clients() should be preferred as they directly use the
|
|
|
|
++ * firmware node and/or controller associated with the given device. This
|
|
|
|
++ * function is only intended for use when different device specifications (e.g.
|
|
|
|
++ * ACPI and firmware nodes) need to be combined (as is done in the platform hub
|
|
|
|
++ * of the device registry).
|
|
|
|
++ *
|
|
|
|
++ * Return: Returns zero on success, nonzero on failure.
|
|
|
|
++ */
|
|
|
|
++int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl,
|
|
|
|
++ struct fwnode_handle *node)
|
|
|
|
++{
|
|
|
|
++ struct fwnode_handle *child;
|
|
|
|
++ int status;
|
|
|
|
++
|
|
|
|
++ fwnode_for_each_child_node(node, child) {
|
|
|
|
++ /*
|
|
|
|
++ * Try to add the device specified in the firmware node. If
|
|
|
|
++ * this fails with -ENODEV, the node does not specify any SSAM
|
|
|
|
++ * device, so ignore it and continue with the next one.
|
|
|
|
++ */
|
|
|
|
++ status = ssam_add_client_device(parent, ctrl, child);
|
|
|
|
++ if (status && status != -ENODEV)
|
|
|
|
++ goto err;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ return 0;
|
|
|
|
++err:
|
|
|
|
++ ssam_remove_clients(parent);
|
|
|
|
++ return status;
|
|
|
|
++}
|
|
|
|
++EXPORT_SYMBOL_GPL(__ssam_register_clients);
|
|
|
|
++
|
|
|
|
+ static int ssam_remove_device(struct device *dev, void *_data)
|
|
|
|
+ {
|
|
|
|
+ struct ssam_device *sdev = to_ssam_device(dev);
|
|
|
|
+@@ -387,19 +520,3 @@ void ssam_remove_clients(struct device *dev)
|
|
|
|
+ device_for_each_child_reverse(dev, NULL, ssam_remove_device);
|
|
|
|
+ }
|
|
|
|
+ EXPORT_SYMBOL_GPL(ssam_remove_clients);
|
|
|
|
+-
|
|
|
|
+-/**
|
|
|
|
+- * ssam_bus_register() - Register and set-up the SSAM client device bus.
|
|
|
|
+- */
|
|
|
|
+-int ssam_bus_register(void)
|
|
|
|
+-{
|
|
|
|
+- return bus_register(&ssam_bus_type);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-/**
|
|
|
|
+- * ssam_bus_unregister() - Unregister the SSAM client device bus.
|
|
|
|
+- */
|
|
|
|
+-void ssam_bus_unregister(void)
|
|
|
|
+-{
|
|
|
|
+- return bus_unregister(&ssam_bus_type);
|
|
|
|
+-}
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index f1c5905f1c16..c680792a037e 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -286,76 +286,6 @@ static const struct software_node *ssam_node_group_sp8[] = {
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+-/* -- Device registry helper functions. ------------------------------------- */
|
|
|
|
+-
|
|
|
|
+-static int ssam_uid_from_string(const char *str, struct ssam_device_uid *uid)
|
|
|
|
+-{
|
|
|
|
+- u8 d, tc, tid, iid, fn;
|
|
|
|
+- int n;
|
|
|
|
+-
|
|
|
|
+- n = sscanf(str, "ssam:%hhx:%hhx:%hhx:%hhx:%hhx", &d, &tc, &tid, &iid, &fn);
|
|
|
|
+- if (n != 5)
|
|
|
|
+- return -EINVAL;
|
|
|
|
+-
|
|
|
|
+- uid->domain = d;
|
|
|
|
+- uid->category = tc;
|
|
|
|
+- uid->target = tid;
|
|
|
|
+- uid->instance = iid;
|
|
|
|
+- uid->function = fn;
|
|
|
|
+-
|
|
|
|
+- return 0;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static int ssam_hub_add_device(struct device *parent, struct ssam_controller *ctrl,
|
|
|
|
+- struct fwnode_handle *node)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_device_uid uid;
|
|
|
|
+- struct ssam_device *sdev;
|
|
|
|
+- int status;
|
|
|
|
+-
|
|
|
|
+- status = ssam_uid_from_string(fwnode_get_name(node), &uid);
|
|
|
|
+- if (status)
|
|
|
|
+- return status;
|
|
|
|
+-
|
|
|
|
+- sdev = ssam_device_alloc(ctrl, uid);
|
|
|
|
+- if (!sdev)
|
|
|
|
+- return -ENOMEM;
|
|
|
|
+-
|
|
|
|
+- sdev->dev.parent = parent;
|
|
|
|
+- sdev->dev.fwnode = node;
|
|
|
|
+-
|
|
|
|
+- status = ssam_device_add(sdev);
|
|
|
|
+- if (status)
|
|
|
|
+- ssam_device_put(sdev);
|
|
|
|
+-
|
|
|
|
+- return status;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static int ssam_hub_register_clients(struct device *parent, struct ssam_controller *ctrl,
|
|
|
|
+- struct fwnode_handle *node)
|
|
|
|
+-{
|
|
|
|
+- struct fwnode_handle *child;
|
|
|
|
+- int status;
|
|
|
|
+-
|
|
|
|
+- fwnode_for_each_child_node(node, child) {
|
|
|
|
+- /*
|
|
|
|
+- * Try to add the device specified in the firmware node. If
|
|
|
|
+- * this fails with -EINVAL, the node does not specify any SSAM
|
|
|
|
+- * device, so ignore it and continue with the next one.
|
|
|
|
+- */
|
|
|
|
+-
|
|
|
|
+- status = ssam_hub_add_device(parent, ctrl, child);
|
|
|
|
+- if (status && status != -EINVAL)
|
|
|
|
+- goto err;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- return 0;
|
|
|
|
+-err:
|
|
|
|
+- ssam_remove_clients(parent);
|
|
|
|
+- return status;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-
|
|
|
|
+ /* -- SSAM generic subsystem hub driver framework. -------------------------- */
|
|
|
|
+
|
|
|
|
+ enum ssam_hub_state {
|
|
|
|
+@@ -385,7 +315,6 @@ struct ssam_hub {
|
|
|
|
+ static void ssam_hub_update_workfn(struct work_struct *work)
|
|
|
|
+ {
|
|
|
|
+ struct ssam_hub *hub = container_of(work, struct ssam_hub, update_work.work);
|
|
|
|
+- struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev);
|
|
|
|
+ enum ssam_hub_state state;
|
|
|
|
+ int status = 0;
|
|
|
|
+
|
|
|
|
+@@ -425,7 +354,7 @@ static void ssam_hub_update_workfn(struct work_struct *work)
|
|
|
|
+ hub->state = state;
|
|
|
|
+
|
|
|
|
+ if (hub->state == SSAM_HUB_CONNECTED)
|
|
|
|
+- status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node);
|
|
|
|
++ status = ssam_device_register_clients(hub->sdev);
|
|
|
|
+ else
|
|
|
|
+ ssam_remove_clients(&hub->sdev->dev);
|
|
|
|
+
|
|
|
|
+@@ -769,7 +698,7 @@ static int ssam_platform_hub_probe(struct platform_device *pdev)
|
|
|
|
+
|
|
|
|
+ set_secondary_fwnode(&pdev->dev, root);
|
|
|
|
+
|
|
|
|
+- status = ssam_hub_register_clients(&pdev->dev, ctrl, root);
|
|
|
|
++ status = __ssam_register_clients(&pdev->dev, ctrl, root);
|
|
|
|
+ if (status) {
|
|
|
|
+ set_secondary_fwnode(&pdev->dev, NULL);
|
|
|
|
+ software_node_unregister_node_group(nodes);
|
|
|
|
+diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
|
|
|
|
+index 6cf7e80312d5..46c45d1b6368 100644
|
|
|
|
+--- a/include/linux/surface_aggregator/device.h
|
|
|
|
++++ b/include/linux/surface_aggregator/device.h
|
|
|
|
+@@ -15,6 +15,7 @@
|
|
|
|
+
|
|
|
|
+ #include <linux/device.h>
|
|
|
|
+ #include <linux/mod_devicetable.h>
|
|
|
|
++#include <linux/property.h>
|
|
|
|
+ #include <linux/types.h>
|
|
|
|
+
|
|
|
|
+ #include <linux/surface_aggregator/controller.h>
|
|
|
|
+@@ -375,11 +376,62 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d);
|
|
|
|
+ /* -- Helpers for controller and hub devices. ------------------------------- */
|
|
|
|
+
|
|
|
|
+ #ifdef CONFIG_SURFACE_AGGREGATOR_BUS
|
|
|
|
++
|
|
|
|
++int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl,
|
|
|
|
++ struct fwnode_handle *node);
|
|
|
|
+ void ssam_remove_clients(struct device *dev);
|
|
|
|
++
|
|
|
|
+ #else /* CONFIG_SURFACE_AGGREGATOR_BUS */
|
|
|
|
++
|
|
|
|
++static inline int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl,
|
|
|
|
++ struct fwnode_handle *node)
|
|
|
|
++{
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
+ static inline void ssam_remove_clients(struct device *dev) {}
|
|
|
|
++
|
|
|
|
+ #endif /* CONFIG_SURFACE_AGGREGATOR_BUS */
|
|
|
|
+
|
|
|
|
++/**
|
|
|
|
++ * ssam_register_clients() - Register all client devices defined under the
|
|
|
|
++ * given parent device.
|
|
|
|
++ * @dev: The parent device under which clients should be registered.
|
|
|
|
++ * @ctrl: The controller with which client should be registered.
|
|
|
|
++ *
|
|
|
|
++ * Register all clients that have via firmware nodes been defined as children
|
|
|
|
++ * of the given (parent) device. The respective child firmware nodes will be
|
|
|
|
++ * associated with the correspondingly created child devices.
|
|
|
|
++ *
|
|
|
|
++ * The given controller will be used to instantiate the new devices. See
|
|
|
|
++ * ssam_device_add() for details.
|
|
|
|
++ *
|
|
|
|
++ * Return: Returns zero on success, nonzero on failure.
|
|
|
|
++ */
|
|
|
|
++static inline int ssam_register_clients(struct device *dev, struct ssam_controller *ctrl)
|
|
|
|
++{
|
|
|
|
++ return __ssam_register_clients(dev, ctrl, dev_fwnode(dev));
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++/**
|
|
|
|
++ * ssam_device_register_clients() - Register all client devices defined under
|
|
|
|
++ * the given SSAM parent device.
|
|
|
|
++ * @sdev: The parent device under which clients should be registered.
|
|
|
|
++ *
|
|
|
|
++ * Register all clients that have via firmware nodes been defined as children
|
|
|
|
++ * of the given (parent) device. The respective child firmware nodes will be
|
|
|
|
++ * associated with the correspondingly created child devices.
|
|
|
|
++ *
|
|
|
|
++ * The controller used by the parent device will be used to instantiate the new
|
|
|
|
++ * devices. See ssam_device_add() for details.
|
|
|
|
++ *
|
|
|
|
++ * Return: Returns zero on success, nonzero on failure.
|
|
|
|
++ */
|
|
|
|
++static inline int ssam_device_register_clients(struct ssam_device *sdev)
|
|
|
|
++{
|
|
|
|
++ return ssam_register_clients(&sdev->dev, sdev->ctrl);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
+
|
|
|
|
+ /* -- Helpers for client-device requests. ----------------------------------- */
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From d3e38dda072f2cfa87b8074b4efe1dfc006345c9 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 24 Jun 2022 22:57:59 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator: Move subsystem hub drivers to
|
|
|
|
+ their own module
|
|
|
|
+
|
|
|
|
+Split out subsystem device hub drivers into their own module. This
|
|
|
|
+allows us to load the hub drivers separately from the registry, which
|
|
|
|
+will help future DT/OF support.
|
|
|
|
+
|
|
|
|
+While doing so, also remove a small bit of code duplication.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220624205800.1355621-3-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ MAINTAINERS | 6 +
|
|
|
|
+ drivers/platform/surface/Kconfig | 35 +-
|
|
|
|
+ drivers/platform/surface/Makefile | 1 +
|
|
|
|
+ .../platform/surface/surface_aggregator_hub.c | 371 ++++++++++++++++++
|
|
|
|
+ .../surface/surface_aggregator_registry.c | 371 +-----------------
|
|
|
|
+ 5 files changed, 410 insertions(+), 374 deletions(-)
|
|
|
|
+ create mode 100644 drivers/platform/surface/surface_aggregator_hub.c
|
|
|
|
+
|
|
|
|
+diff --git a/MAINTAINERS b/MAINTAINERS
|
|
|
|
+index 11b84de77ab8..a29042434d9e 100644
|
|
|
|
+--- a/MAINTAINERS
|
|
|
|
++++ b/MAINTAINERS
|
|
|
|
+@@ -13381,6 +13381,12 @@ F: include/linux/surface_acpi_notify.h
|
|
|
|
+ F: include/linux/surface_aggregator/
|
|
|
|
+ F: include/uapi/linux/surface_aggregator/
|
|
|
|
+
|
|
|
|
++MICROSOFT SURFACE SYSTEM AGGREGATOR HUB DRIVER
|
|
|
|
++M: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++L: platform-driver-x86@vger.kernel.org
|
|
|
|
++S: Maintained
|
|
|
|
++F: drivers/platform/surface/surface_aggregator_hub.c
|
|
|
|
++
|
|
|
|
+ MICROTEK X6 SCANNER
|
|
|
|
+ M: Oliver Neukum <oliver@neukum.org>
|
|
|
|
+ S: Maintained
|
|
|
|
+diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
|
|
|
|
+index b152e930cc84..b629e82af97c 100644
|
|
|
|
+--- a/drivers/platform/surface/Kconfig
|
|
|
|
++++ b/drivers/platform/surface/Kconfig
|
|
|
|
+@@ -72,18 +72,45 @@ config SURFACE_AGGREGATOR_CDEV
|
|
|
|
+ The provided interface is intended for debugging and development only,
|
|
|
|
+ and should not be used otherwise.
|
|
|
|
+
|
|
|
|
++config SURFACE_AGGREGATOR_HUB
|
|
|
|
++ tristate "Surface System Aggregator Module Subsystem Device Hubs"
|
|
|
|
++ depends on SURFACE_AGGREGATOR
|
|
|
|
++ depends on SURFACE_AGGREGATOR_BUS
|
|
|
|
++ help
|
|
|
|
++ Device-hub drivers for Surface System Aggregator Module (SSAM) subsystem
|
|
|
|
++ devices.
|
|
|
|
++
|
|
|
|
++ Provides subsystem hub drivers which manage client devices on various
|
|
|
|
++ SSAM subsystems. In some subsystems, notably the BAS subsystem managing
|
|
|
|
++ devices contained in the base of the Surface Book 3 and the KIP subsystem
|
|
|
|
++ managing type-cover devices in the Surface Pro 8 and Surface Pro X,
|
|
|
|
++ devices can be (hot-)removed. Hub devices and drivers are required to
|
|
|
|
++ manage these subdevices.
|
|
|
|
++
|
|
|
|
++ Devices managed via these hubs are:
|
|
|
|
++ - Battery/AC devices (Surface Book 3).
|
|
|
|
++ - HID input devices (7th-generation and later models with detachable
|
|
|
|
++ input devices).
|
|
|
|
++
|
|
|
|
++ Select M (recommended) or Y here if you want support for the above
|
|
|
|
++ mentioned devices on the corresponding Surface models. Without this
|
|
|
|
++ module, the respective devices mentioned above will not be instantiated
|
|
|
|
++ and thus any functionality provided by them will be missing, even when
|
|
|
|
++ drivers for these devices are present. This module only provides the
|
|
|
|
++ respective subsystem hubs. Both drivers and device specification (e.g.
|
|
|
|
++ via the Surface Aggregator Registry) for these devices still need to be
|
|
|
|
++ selected via other options.
|
|
|
|
++
|
|
|
|
+ config SURFACE_AGGREGATOR_REGISTRY
|
|
|
|
+ tristate "Surface System Aggregator Module Device Registry"
|
|
|
|
+ depends on SURFACE_AGGREGATOR
|
|
|
|
+ depends on SURFACE_AGGREGATOR_BUS
|
|
|
|
+ help
|
|
|
|
+- Device-registry and device-hubs for Surface System Aggregator Module
|
|
|
|
+- (SSAM) devices.
|
|
|
|
++ Device-registry for Surface System Aggregator Module (SSAM) devices.
|
|
|
|
+
|
|
|
|
+ Provides a module and driver which act as a device-registry for SSAM
|
|
|
|
+ client devices that cannot be detected automatically, e.g. via ACPI.
|
|
|
|
+- Such devices are instead provided via this registry and attached via
|
|
|
|
+- device hubs, also provided in this module.
|
|
|
|
++ Such devices are instead provided and managed via this registry.
|
|
|
|
+
|
|
|
|
+ Devices provided via this registry are:
|
|
|
|
+ - Platform profile (performance-/cooling-mode) device (5th- and later
|
|
|
|
+diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
|
|
|
|
+index 18b27898543e..53344330939b 100644
|
|
|
|
+--- a/drivers/platform/surface/Makefile
|
|
|
|
++++ b/drivers/platform/surface/Makefile
|
|
|
|
+@@ -9,6 +9,7 @@ obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o
|
|
|
|
+ obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o
|
|
|
|
+ obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/
|
|
|
|
+ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o
|
|
|
|
++obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o
|
|
|
|
+ obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o
|
|
|
|
+ obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o
|
|
|
|
+ obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_hub.c b/drivers/platform/surface/surface_aggregator_hub.c
|
|
|
|
+new file mode 100644
|
|
|
|
+index 000000000000..43061514be38
|
|
|
|
+--- /dev/null
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_hub.c
|
|
|
|
+@@ -0,0 +1,371 @@
|
|
|
|
++// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
++/*
|
|
|
|
++ * Driver for Surface System Aggregator Module (SSAM) subsystem device hubs.
|
|
|
|
++ *
|
|
|
|
++ * Provides a driver for SSAM subsystems device hubs. This driver performs
|
|
|
|
++ * instantiation of the devices managed by said hubs and takes care of
|
|
|
|
++ * (hot-)removal.
|
|
|
|
++ *
|
|
|
|
++ * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ */
|
|
|
|
++
|
|
|
|
++#include <linux/kernel.h>
|
|
|
|
++#include <linux/limits.h>
|
|
|
|
++#include <linux/module.h>
|
|
|
|
++#include <linux/types.h>
|
|
|
|
++#include <linux/workqueue.h>
|
|
|
|
++
|
|
|
|
++#include <linux/surface_aggregator/device.h>
|
|
|
|
++
|
|
|
|
++
|
|
|
|
++/* -- SSAM generic subsystem hub driver framework. -------------------------- */
|
|
|
|
++
|
|
|
|
++enum ssam_hub_state {
|
|
|
|
++ SSAM_HUB_UNINITIALIZED, /* Only set during initialization. */
|
|
|
|
++ SSAM_HUB_CONNECTED,
|
|
|
|
++ SSAM_HUB_DISCONNECTED,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++enum ssam_hub_flags {
|
|
|
|
++ SSAM_HUB_HOT_REMOVED,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++struct ssam_hub;
|
|
|
|
++
|
|
|
|
++struct ssam_hub_ops {
|
|
|
|
++ int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state);
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++struct ssam_hub {
|
|
|
|
++ struct ssam_device *sdev;
|
|
|
|
++
|
|
|
|
++ enum ssam_hub_state state;
|
|
|
|
++ unsigned long flags;
|
|
|
|
++
|
|
|
|
++ struct delayed_work update_work;
|
|
|
|
++ unsigned long connect_delay;
|
|
|
|
++
|
|
|
|
++ struct ssam_event_notifier notif;
|
|
|
|
++ struct ssam_hub_ops ops;
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++struct ssam_hub_desc {
|
|
|
|
++ struct {
|
|
|
|
++ struct ssam_event_registry reg;
|
|
|
|
++ struct ssam_event_id id;
|
|
|
|
++ enum ssam_event_mask mask;
|
|
|
|
++ } event;
|
|
|
|
++
|
|
|
|
++ struct {
|
|
|
|
++ u32 (*notify)(struct ssam_event_notifier *nf, const struct ssam_event *event);
|
|
|
|
++ int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state);
|
|
|
|
++ } ops;
|
|
|
|
++
|
|
|
|
++ unsigned long connect_delay_ms;
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++static void ssam_hub_update_workfn(struct work_struct *work)
|
|
|
|
++{
|
|
|
|
++ struct ssam_hub *hub = container_of(work, struct ssam_hub, update_work.work);
|
|
|
|
++ enum ssam_hub_state state;
|
|
|
|
++ int status = 0;
|
|
|
|
++
|
|
|
|
++ status = hub->ops.get_state(hub, &state);
|
|
|
|
++ if (status)
|
|
|
|
++ return;
|
|
|
|
++
|
|
|
|
++ /*
|
|
|
|
++ * There is a small possibility that hub devices were hot-removed and
|
|
|
|
++ * re-added before we were able to remove them here. In that case, both
|
|
|
|
++ * the state returned by get_state() and the state of the hub will
|
|
|
|
++ * equal SSAM_HUB_CONNECTED and we would bail early below, which would
|
|
|
|
++ * leave child devices without proper (re-)initialization and the
|
|
|
|
++ * hot-remove flag set.
|
|
|
|
++ *
|
|
|
|
++ * Therefore, we check whether devices have been hot-removed via an
|
|
|
|
++ * additional flag on the hub and, in this case, override the returned
|
|
|
|
++ * hub state. In case of a missed disconnect (i.e. get_state returned
|
|
|
|
++ * "connected"), we further need to re-schedule this work (with the
|
|
|
|
++ * appropriate delay) as the actual connect work submission might have
|
|
|
|
++ * been merged with this one.
|
|
|
|
++ *
|
|
|
|
++ * This then leads to one of two cases: Either we submit an unnecessary
|
|
|
|
++ * work item (which will get ignored via either the queue or the state
|
|
|
|
++ * checks) or, in the unlikely case that the work is actually required,
|
|
|
|
++ * double the normal connect delay.
|
|
|
|
++ */
|
|
|
|
++ if (test_and_clear_bit(SSAM_HUB_HOT_REMOVED, &hub->flags)) {
|
|
|
|
++ if (state == SSAM_HUB_CONNECTED)
|
|
|
|
++ schedule_delayed_work(&hub->update_work, hub->connect_delay);
|
|
|
|
++
|
|
|
|
++ state = SSAM_HUB_DISCONNECTED;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ if (hub->state == state)
|
|
|
|
++ return;
|
|
|
|
++ hub->state = state;
|
|
|
|
++
|
|
|
|
++ if (hub->state == SSAM_HUB_CONNECTED)
|
|
|
|
++ status = ssam_device_register_clients(hub->sdev);
|
|
|
|
++ else
|
|
|
|
++ ssam_remove_clients(&hub->sdev->dev);
|
|
|
|
++
|
|
|
|
++ if (status)
|
|
|
|
++ dev_err(&hub->sdev->dev, "failed to update hub child devices: %d\n", status);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int ssam_hub_mark_hot_removed(struct device *dev, void *_data)
|
|
|
|
++{
|
|
|
|
++ struct ssam_device *sdev = to_ssam_device(dev);
|
|
|
|
++
|
|
|
|
++ if (is_ssam_device(dev))
|
|
|
|
++ ssam_device_mark_hot_removed(sdev);
|
|
|
|
++
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static void ssam_hub_update(struct ssam_hub *hub, bool connected)
|
|
|
|
++{
|
|
|
|
++ unsigned long delay;
|
|
|
|
++
|
|
|
|
++ /* Mark devices as hot-removed before we remove any. */
|
|
|
|
++ if (!connected) {
|
|
|
|
++ set_bit(SSAM_HUB_HOT_REMOVED, &hub->flags);
|
|
|
|
++ device_for_each_child_reverse(&hub->sdev->dev, NULL, ssam_hub_mark_hot_removed);
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ /*
|
|
|
|
++ * Delay update when the base/keyboard cover is being connected to give
|
|
|
|
++ * devices/EC some time to set up.
|
|
|
|
++ */
|
|
|
|
++ delay = connected ? hub->connect_delay : 0;
|
|
|
|
++
|
|
|
|
++ schedule_delayed_work(&hub->update_work, delay);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static int __maybe_unused ssam_hub_resume(struct device *dev)
|
|
|
|
++{
|
|
|
|
++ struct ssam_hub *hub = dev_get_drvdata(dev);
|
|
|
|
++
|
|
|
|
++ schedule_delayed_work(&hub->update_work, 0);
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++static SIMPLE_DEV_PM_OPS(ssam_hub_pm_ops, NULL, ssam_hub_resume);
|
|
|
|
++
|
|
|
|
++static int ssam_hub_probe(struct ssam_device *sdev)
|
|
|
|
++{
|
|
|
|
++ const struct ssam_hub_desc *desc;
|
|
|
|
++ struct ssam_hub *hub;
|
|
|
|
++ int status;
|
|
|
|
++
|
|
|
|
++ desc = ssam_device_get_match_data(sdev);
|
|
|
|
++ if (!desc) {
|
|
|
|
++ WARN(1, "no driver match data specified");
|
|
|
|
++ return -EINVAL;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL);
|
|
|
|
++ if (!hub)
|
|
|
|
++ return -ENOMEM;
|
|
|
|
++
|
|
|
|
++ hub->sdev = sdev;
|
|
|
|
++ hub->state = SSAM_HUB_UNINITIALIZED;
|
|
|
|
++
|
|
|
|
++ hub->notif.base.priority = INT_MAX; /* This notifier should run first. */
|
|
|
|
++ hub->notif.base.fn = desc->ops.notify;
|
|
|
|
++ hub->notif.event.reg = desc->event.reg;
|
|
|
|
++ hub->notif.event.id = desc->event.id;
|
|
|
|
++ hub->notif.event.mask = desc->event.mask;
|
|
|
|
++ hub->notif.event.flags = SSAM_EVENT_SEQUENCED;
|
|
|
|
++
|
|
|
|
++ hub->connect_delay = msecs_to_jiffies(desc->connect_delay_ms);
|
|
|
|
++ hub->ops.get_state = desc->ops.get_state;
|
|
|
|
++
|
|
|
|
++ INIT_DELAYED_WORK(&hub->update_work, ssam_hub_update_workfn);
|
|
|
|
++
|
|
|
|
++ ssam_device_set_drvdata(sdev, hub);
|
|
|
|
++
|
|
|
|
++ status = ssam_device_notifier_register(sdev, &hub->notif);
|
|
|
|
++ if (status)
|
|
|
|
++ return status;
|
|
|
|
++
|
|
|
|
++ schedule_delayed_work(&hub->update_work, 0);
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static void ssam_hub_remove(struct ssam_device *sdev)
|
|
|
|
++{
|
|
|
|
++ struct ssam_hub *hub = ssam_device_get_drvdata(sdev);
|
|
|
|
++
|
|
|
|
++ ssam_device_notifier_unregister(sdev, &hub->notif);
|
|
|
|
++ cancel_delayed_work_sync(&hub->update_work);
|
|
|
|
++ ssam_remove_clients(&sdev->dev);
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++
|
|
|
|
++/* -- SSAM base-subsystem hub driver. --------------------------------------- */
|
|
|
|
++
|
|
|
|
++/*
|
|
|
|
++ * Some devices (especially battery) may need a bit of time to be fully usable
|
|
|
|
++ * after being (re-)connected. This delay has been determined via
|
|
|
|
++ * experimentation.
|
|
|
|
++ */
|
|
|
|
++#define SSAM_BASE_UPDATE_CONNECT_DELAY 2500
|
|
|
|
++
|
|
|
|
++SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
|
|
|
|
++ .target_category = SSAM_SSH_TC_BAS,
|
|
|
|
++ .target_id = 0x01,
|
|
|
|
++ .command_id = 0x0d,
|
|
|
|
++ .instance_id = 0x00,
|
|
|
|
++});
|
|
|
|
++
|
|
|
|
++#define SSAM_BAS_OPMODE_TABLET 0x00
|
|
|
|
++#define SSAM_EVENT_BAS_CID_CONNECTION 0x0c
|
|
|
|
++
|
|
|
|
++static int ssam_base_hub_query_state(struct ssam_hub *hub, enum ssam_hub_state *state)
|
|
|
|
++{
|
|
|
|
++ u8 opmode;
|
|
|
|
++ int status;
|
|
|
|
++
|
|
|
|
++ status = ssam_retry(ssam_bas_query_opmode, hub->sdev->ctrl, &opmode);
|
|
|
|
++ if (status < 0) {
|
|
|
|
++ dev_err(&hub->sdev->dev, "failed to query base state: %d\n", status);
|
|
|
|
++ return status;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ if (opmode != SSAM_BAS_OPMODE_TABLET)
|
|
|
|
++ *state = SSAM_HUB_CONNECTED;
|
|
|
|
++ else
|
|
|
|
++ *state = SSAM_HUB_DISCONNECTED;
|
|
|
|
++
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
|
|
|
|
++{
|
|
|
|
++ struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif);
|
|
|
|
++
|
|
|
|
++ if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION)
|
|
|
|
++ return 0;
|
|
|
|
++
|
|
|
|
++ if (event->length < 1) {
|
|
|
|
++ dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length);
|
|
|
|
++ return 0;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ ssam_hub_update(hub, event->data[0]);
|
|
|
|
++
|
|
|
|
++ /*
|
|
|
|
++ * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and
|
|
|
|
++ * consumed by the detachment system driver. We're just a (more or less)
|
|
|
|
++ * silent observer.
|
|
|
|
++ */
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static const struct ssam_hub_desc base_hub = {
|
|
|
|
++ .event = {
|
|
|
|
++ .reg = SSAM_EVENT_REGISTRY_SAM,
|
|
|
|
++ .id = {
|
|
|
|
++ .target_category = SSAM_SSH_TC_BAS,
|
|
|
|
++ .instance = 0,
|
|
|
|
++ },
|
|
|
|
++ .mask = SSAM_EVENT_MASK_NONE,
|
|
|
|
++ },
|
|
|
|
++ .ops = {
|
|
|
|
++ .notify = ssam_base_hub_notif,
|
|
|
|
++ .get_state = ssam_base_hub_query_state,
|
|
|
|
++ },
|
|
|
|
++ .connect_delay_ms = SSAM_BASE_UPDATE_CONNECT_DELAY,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++
|
|
|
|
++/* -- SSAM KIP-subsystem hub driver. ---------------------------------------- */
|
|
|
|
++
|
|
|
|
++/*
|
|
|
|
++ * Some devices may need a bit of time to be fully usable after being
|
|
|
|
++ * (re-)connected. This delay has been determined via experimentation.
|
|
|
|
++ */
|
|
|
|
++#define SSAM_KIP_UPDATE_CONNECT_DELAY 250
|
|
|
|
++
|
|
|
|
++#define SSAM_EVENT_KIP_CID_CONNECTION 0x2c
|
|
|
|
++
|
|
|
|
++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_query_state, u8, {
|
|
|
|
++ .target_category = SSAM_SSH_TC_KIP,
|
|
|
|
++ .target_id = 0x01,
|
|
|
|
++ .command_id = 0x2c,
|
|
|
|
++ .instance_id = 0x00,
|
|
|
|
++});
|
|
|
|
++
|
|
|
|
++static int ssam_kip_hub_query_state(struct ssam_hub *hub, enum ssam_hub_state *state)
|
|
|
|
++{
|
|
|
|
++ int status;
|
|
|
|
++ u8 connected;
|
|
|
|
++
|
|
|
|
++ status = ssam_retry(__ssam_kip_query_state, hub->sdev->ctrl, &connected);
|
|
|
|
++ if (status < 0) {
|
|
|
|
++ dev_err(&hub->sdev->dev, "failed to query KIP connection state: %d\n", status);
|
|
|
|
++ return status;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ *state = connected ? SSAM_HUB_CONNECTED : SSAM_HUB_DISCONNECTED;
|
|
|
|
++ return 0;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static u32 ssam_kip_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
|
|
|
|
++{
|
|
|
|
++ struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif);
|
|
|
|
++
|
|
|
|
++ if (event->command_id != SSAM_EVENT_KIP_CID_CONNECTION)
|
|
|
|
++ return 0; /* Return "unhandled". */
|
|
|
|
++
|
|
|
|
++ if (event->length < 1) {
|
|
|
|
++ dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length);
|
|
|
|
++ return 0;
|
|
|
|
++ }
|
|
|
|
++
|
|
|
|
++ ssam_hub_update(hub, event->data[0]);
|
|
|
|
++ return SSAM_NOTIF_HANDLED;
|
|
|
|
++}
|
|
|
|
++
|
|
|
|
++static const struct ssam_hub_desc kip_hub = {
|
|
|
|
++ .event = {
|
|
|
|
++ .reg = SSAM_EVENT_REGISTRY_SAM,
|
|
|
|
++ .id = {
|
|
|
|
++ .target_category = SSAM_SSH_TC_KIP,
|
|
|
|
++ .instance = 0,
|
|
|
|
++ },
|
|
|
|
++ .mask = SSAM_EVENT_MASK_TARGET,
|
|
|
|
++ },
|
|
|
|
++ .ops = {
|
|
|
|
++ .notify = ssam_kip_hub_notif,
|
|
|
|
++ .get_state = ssam_kip_hub_query_state,
|
|
|
|
++ },
|
|
|
|
++ .connect_delay_ms = SSAM_KIP_UPDATE_CONNECT_DELAY,
|
|
|
|
++};
|
|
|
|
++
|
|
|
|
++
|
|
|
|
++/* -- Driver registration. -------------------------------------------------- */
|
|
|
|
++
|
|
|
|
++static const struct ssam_device_id ssam_hub_match[] = {
|
|
|
|
++ { SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub },
|
|
|
|
++ { SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub },
|
|
|
|
++ { }
|
|
|
|
++};
|
|
|
|
++MODULE_DEVICE_TABLE(ssam, ssam_hub_match);
|
|
|
|
++
|
|
|
|
++static struct ssam_device_driver ssam_subsystem_hub_driver = {
|
|
|
|
++ .probe = ssam_hub_probe,
|
|
|
|
++ .remove = ssam_hub_remove,
|
|
|
|
++ .match_table = ssam_hub_match,
|
|
|
|
++ .driver = {
|
|
|
|
++ .name = "surface_aggregator_subsystem_hub",
|
|
|
|
++ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
|
|
|
++ .pm = &ssam_hub_pm_ops,
|
|
|
|
++ },
|
|
|
|
++};
|
|
|
|
++module_ssam_device_driver(ssam_subsystem_hub_driver);
|
|
|
|
++
|
|
|
|
++MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
|
|
|
|
++MODULE_DESCRIPTION("Subsystem device hub driver for Surface System Aggregator Module");
|
|
|
|
++MODULE_LICENSE("GPL");
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index c680792a037e..0cbb7f3a6b2d 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -11,14 +11,11 @@
|
|
|
|
+
|
|
|
|
+ #include <linux/acpi.h>
|
|
|
|
+ #include <linux/kernel.h>
|
|
|
|
+-#include <linux/limits.h>
|
|
|
|
+ #include <linux/module.h>
|
|
|
|
+ #include <linux/platform_device.h>
|
|
|
|
+ #include <linux/property.h>
|
|
|
|
+ #include <linux/types.h>
|
|
|
|
+-#include <linux/workqueue.h>
|
|
|
|
+
|
|
|
|
+-#include <linux/surface_aggregator/controller.h>
|
|
|
|
+ #include <linux/surface_aggregator/device.h>
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+@@ -286,335 +283,6 @@ static const struct software_node *ssam_node_group_sp8[] = {
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+-/* -- SSAM generic subsystem hub driver framework. -------------------------- */
|
|
|
|
+-
|
|
|
|
+-enum ssam_hub_state {
|
|
|
|
+- SSAM_HUB_UNINITIALIZED, /* Only set during initialization. */
|
|
|
|
+- SSAM_HUB_CONNECTED,
|
|
|
|
+- SSAM_HUB_DISCONNECTED,
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-enum ssam_hub_flags {
|
|
|
|
+- SSAM_HUB_HOT_REMOVED,
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-struct ssam_hub {
|
|
|
|
+- struct ssam_device *sdev;
|
|
|
|
+-
|
|
|
|
+- enum ssam_hub_state state;
|
|
|
|
+- unsigned long flags;
|
|
|
|
+-
|
|
|
|
+- struct delayed_work update_work;
|
|
|
|
+- unsigned long connect_delay;
|
|
|
|
+-
|
|
|
|
+- struct ssam_event_notifier notif;
|
|
|
|
+-
|
|
|
|
+- int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state);
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-static void ssam_hub_update_workfn(struct work_struct *work)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_hub *hub = container_of(work, struct ssam_hub, update_work.work);
|
|
|
|
+- enum ssam_hub_state state;
|
|
|
|
+- int status = 0;
|
|
|
|
+-
|
|
|
|
+- status = hub->get_state(hub, &state);
|
|
|
|
+- if (status)
|
|
|
|
+- return;
|
|
|
|
+-
|
|
|
|
+- /*
|
|
|
|
+- * There is a small possibility that hub devices were hot-removed and
|
|
|
|
+- * re-added before we were able to remove them here. In that case, both
|
|
|
|
+- * the state returned by get_state() and the state of the hub will
|
|
|
|
+- * equal SSAM_HUB_CONNECTED and we would bail early below, which would
|
|
|
|
+- * leave child devices without proper (re-)initialization and the
|
|
|
|
+- * hot-remove flag set.
|
|
|
|
+- *
|
|
|
|
+- * Therefore, we check whether devices have been hot-removed via an
|
|
|
|
+- * additional flag on the hub and, in this case, override the returned
|
|
|
|
+- * hub state. In case of a missed disconnect (i.e. get_state returned
|
|
|
|
+- * "connected"), we further need to re-schedule this work (with the
|
|
|
|
+- * appropriate delay) as the actual connect work submission might have
|
|
|
|
+- * been merged with this one.
|
|
|
|
+- *
|
|
|
|
+- * This then leads to one of two cases: Either we submit an unnecessary
|
|
|
|
+- * work item (which will get ignored via either the queue or the state
|
|
|
|
+- * checks) or, in the unlikely case that the work is actually required,
|
|
|
|
+- * double the normal connect delay.
|
|
|
|
+- */
|
|
|
|
+- if (test_and_clear_bit(SSAM_HUB_HOT_REMOVED, &hub->flags)) {
|
|
|
|
+- if (state == SSAM_HUB_CONNECTED)
|
|
|
|
+- schedule_delayed_work(&hub->update_work, hub->connect_delay);
|
|
|
|
+-
|
|
|
|
+- state = SSAM_HUB_DISCONNECTED;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- if (hub->state == state)
|
|
|
|
+- return;
|
|
|
|
+- hub->state = state;
|
|
|
|
+-
|
|
|
|
+- if (hub->state == SSAM_HUB_CONNECTED)
|
|
|
|
+- status = ssam_device_register_clients(hub->sdev);
|
|
|
|
+- else
|
|
|
|
+- ssam_remove_clients(&hub->sdev->dev);
|
|
|
|
+-
|
|
|
|
+- if (status)
|
|
|
|
+- dev_err(&hub->sdev->dev, "failed to update hub child devices: %d\n", status);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static int ssam_hub_mark_hot_removed(struct device *dev, void *_data)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_device *sdev = to_ssam_device(dev);
|
|
|
|
+-
|
|
|
|
+- if (is_ssam_device(dev))
|
|
|
|
+- ssam_device_mark_hot_removed(sdev);
|
|
|
|
+-
|
|
|
|
+- return 0;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static void ssam_hub_update(struct ssam_hub *hub, bool connected)
|
|
|
|
+-{
|
|
|
|
+- unsigned long delay;
|
|
|
|
+-
|
|
|
|
+- /* Mark devices as hot-removed before we remove any. */
|
|
|
|
+- if (!connected) {
|
|
|
|
+- set_bit(SSAM_HUB_HOT_REMOVED, &hub->flags);
|
|
|
|
+- device_for_each_child_reverse(&hub->sdev->dev, NULL, ssam_hub_mark_hot_removed);
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- /*
|
|
|
|
+- * Delay update when the base/keyboard cover is being connected to give
|
|
|
|
+- * devices/EC some time to set up.
|
|
|
|
+- */
|
|
|
|
+- delay = connected ? hub->connect_delay : 0;
|
|
|
|
+-
|
|
|
|
+- schedule_delayed_work(&hub->update_work, delay);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static int __maybe_unused ssam_hub_resume(struct device *dev)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_hub *hub = dev_get_drvdata(dev);
|
|
|
|
+-
|
|
|
|
+- schedule_delayed_work(&hub->update_work, 0);
|
|
|
|
+- return 0;
|
|
|
|
+-}
|
|
|
|
+-static SIMPLE_DEV_PM_OPS(ssam_hub_pm_ops, NULL, ssam_hub_resume);
|
|
|
|
+-
|
|
|
|
+-static int ssam_hub_setup(struct ssam_device *sdev, struct ssam_hub *hub)
|
|
|
|
+-{
|
|
|
|
+- int status;
|
|
|
|
+-
|
|
|
|
+- hub->sdev = sdev;
|
|
|
|
+- hub->state = SSAM_HUB_UNINITIALIZED;
|
|
|
|
+-
|
|
|
|
+- INIT_DELAYED_WORK(&hub->update_work, ssam_hub_update_workfn);
|
|
|
|
+-
|
|
|
|
+- ssam_device_set_drvdata(sdev, hub);
|
|
|
|
+-
|
|
|
|
+- status = ssam_device_notifier_register(sdev, &hub->notif);
|
|
|
|
+- if (status)
|
|
|
|
+- return status;
|
|
|
|
+-
|
|
|
|
+- schedule_delayed_work(&hub->update_work, 0);
|
|
|
|
+- return 0;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static void ssam_hub_remove(struct ssam_device *sdev)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_hub *hub = ssam_device_get_drvdata(sdev);
|
|
|
|
+-
|
|
|
|
+- ssam_device_notifier_unregister(sdev, &hub->notif);
|
|
|
|
+- cancel_delayed_work_sync(&hub->update_work);
|
|
|
|
+- ssam_remove_clients(&sdev->dev);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-
|
|
|
|
+-/* -- SSAM base-hub driver. ------------------------------------------------- */
|
|
|
|
+-
|
|
|
|
+-/*
|
|
|
|
+- * Some devices (especially battery) may need a bit of time to be fully usable
|
|
|
|
+- * after being (re-)connected. This delay has been determined via
|
|
|
|
+- * experimentation.
|
|
|
|
+- */
|
|
|
|
+-#define SSAM_BASE_UPDATE_CONNECT_DELAY msecs_to_jiffies(2500)
|
|
|
|
+-
|
|
|
|
+-SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
|
|
|
|
+- .target_category = SSAM_SSH_TC_BAS,
|
|
|
|
+- .target_id = 0x01,
|
|
|
|
+- .command_id = 0x0d,
|
|
|
|
+- .instance_id = 0x00,
|
|
|
|
+-});
|
|
|
|
+-
|
|
|
|
+-#define SSAM_BAS_OPMODE_TABLET 0x00
|
|
|
|
+-#define SSAM_EVENT_BAS_CID_CONNECTION 0x0c
|
|
|
|
+-
|
|
|
|
+-static int ssam_base_hub_query_state(struct ssam_hub *hub, enum ssam_hub_state *state)
|
|
|
|
+-{
|
|
|
|
+- u8 opmode;
|
|
|
|
+- int status;
|
|
|
|
+-
|
|
|
|
+- status = ssam_retry(ssam_bas_query_opmode, hub->sdev->ctrl, &opmode);
|
|
|
|
+- if (status < 0) {
|
|
|
|
+- dev_err(&hub->sdev->dev, "failed to query base state: %d\n", status);
|
|
|
|
+- return status;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- if (opmode != SSAM_BAS_OPMODE_TABLET)
|
|
|
|
+- *state = SSAM_HUB_CONNECTED;
|
|
|
|
+- else
|
|
|
|
+- *state = SSAM_HUB_DISCONNECTED;
|
|
|
|
+-
|
|
|
|
+- return 0;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif);
|
|
|
|
+-
|
|
|
|
+- if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION)
|
|
|
|
+- return 0;
|
|
|
|
+-
|
|
|
|
+- if (event->length < 1) {
|
|
|
|
+- dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length);
|
|
|
|
+- return 0;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- ssam_hub_update(hub, event->data[0]);
|
|
|
|
+-
|
|
|
|
+- /*
|
|
|
|
+- * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and
|
|
|
|
+- * consumed by the detachment system driver. We're just a (more or less)
|
|
|
|
+- * silent observer.
|
|
|
|
+- */
|
|
|
|
+- return 0;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static int ssam_base_hub_probe(struct ssam_device *sdev)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_hub *hub;
|
|
|
|
+-
|
|
|
|
+- hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL);
|
|
|
|
+- if (!hub)
|
|
|
|
+- return -ENOMEM;
|
|
|
|
+-
|
|
|
|
+- hub->notif.base.priority = INT_MAX; /* This notifier should run first. */
|
|
|
|
+- hub->notif.base.fn = ssam_base_hub_notif;
|
|
|
|
+- hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM;
|
|
|
|
+- hub->notif.event.id.target_category = SSAM_SSH_TC_BAS,
|
|
|
|
+- hub->notif.event.id.instance = 0,
|
|
|
|
+- hub->notif.event.mask = SSAM_EVENT_MASK_NONE;
|
|
|
|
+- hub->notif.event.flags = SSAM_EVENT_SEQUENCED;
|
|
|
|
+-
|
|
|
|
+- hub->connect_delay = SSAM_BASE_UPDATE_CONNECT_DELAY;
|
|
|
|
+- hub->get_state = ssam_base_hub_query_state;
|
|
|
|
+-
|
|
|
|
+- return ssam_hub_setup(sdev, hub);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static const struct ssam_device_id ssam_base_hub_match[] = {
|
|
|
|
+- { SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00) },
|
|
|
|
+- { },
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-static struct ssam_device_driver ssam_base_hub_driver = {
|
|
|
|
+- .probe = ssam_base_hub_probe,
|
|
|
|
+- .remove = ssam_hub_remove,
|
|
|
|
+- .match_table = ssam_base_hub_match,
|
|
|
|
+- .driver = {
|
|
|
|
+- .name = "surface_aggregator_base_hub",
|
|
|
|
+- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
|
|
|
+- .pm = &ssam_hub_pm_ops,
|
|
|
|
+- },
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-
|
|
|
|
+-/* -- SSAM KIP-subsystem hub driver. ---------------------------------------- */
|
|
|
|
+-
|
|
|
|
+-/*
|
|
|
|
+- * Some devices may need a bit of time to be fully usable after being
|
|
|
|
+- * (re-)connected. This delay has been determined via experimentation.
|
|
|
|
+- */
|
|
|
|
+-#define SSAM_KIP_UPDATE_CONNECT_DELAY msecs_to_jiffies(250)
|
|
|
|
+-
|
|
|
|
+-#define SSAM_EVENT_KIP_CID_CONNECTION 0x2c
|
|
|
|
+-
|
|
|
|
+-SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_connection_state, u8, {
|
|
|
|
+- .target_category = SSAM_SSH_TC_KIP,
|
|
|
|
+- .target_id = 0x01,
|
|
|
|
+- .command_id = 0x2c,
|
|
|
|
+- .instance_id = 0x00,
|
|
|
|
+-});
|
|
|
|
+-
|
|
|
|
+-static int ssam_kip_get_connection_state(struct ssam_hub *hub, enum ssam_hub_state *state)
|
|
|
|
+-{
|
|
|
|
+- int status;
|
|
|
|
+- u8 connected;
|
|
|
|
+-
|
|
|
|
+- status = ssam_retry(__ssam_kip_get_connection_state, hub->sdev->ctrl, &connected);
|
|
|
|
+- if (status < 0) {
|
|
|
|
+- dev_err(&hub->sdev->dev, "failed to query KIP connection state: %d\n", status);
|
|
|
|
+- return status;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- *state = connected ? SSAM_HUB_CONNECTED : SSAM_HUB_DISCONNECTED;
|
|
|
|
+- return 0;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static u32 ssam_kip_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif);
|
|
|
|
+-
|
|
|
|
+- if (event->command_id != SSAM_EVENT_KIP_CID_CONNECTION)
|
|
|
|
+- return 0; /* Return "unhandled". */
|
|
|
|
+-
|
|
|
|
+- if (event->length < 1) {
|
|
|
|
+- dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length);
|
|
|
|
+- return 0;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- ssam_hub_update(hub, event->data[0]);
|
|
|
|
+- return SSAM_NOTIF_HANDLED;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static int ssam_kip_hub_probe(struct ssam_device *sdev)
|
|
|
|
+-{
|
|
|
|
+- struct ssam_hub *hub;
|
|
|
|
+-
|
|
|
|
+- hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL);
|
|
|
|
+- if (!hub)
|
|
|
|
+- return -ENOMEM;
|
|
|
|
+-
|
|
|
|
+- hub->notif.base.priority = INT_MAX; /* This notifier should run first. */
|
|
|
|
+- hub->notif.base.fn = ssam_kip_hub_notif;
|
|
|
|
+- hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM;
|
|
|
|
+- hub->notif.event.id.target_category = SSAM_SSH_TC_KIP,
|
|
|
|
+- hub->notif.event.id.instance = 0,
|
|
|
|
+- hub->notif.event.mask = SSAM_EVENT_MASK_TARGET;
|
|
|
|
+- hub->notif.event.flags = SSAM_EVENT_SEQUENCED;
|
|
|
|
+-
|
|
|
|
+- hub->connect_delay = SSAM_KIP_UPDATE_CONNECT_DELAY;
|
|
|
|
+- hub->get_state = ssam_kip_get_connection_state;
|
|
|
|
+-
|
|
|
|
+- return ssam_hub_setup(sdev, hub);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static const struct ssam_device_id ssam_kip_hub_match[] = {
|
|
|
|
+- { SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00) },
|
|
|
|
+- { },
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-static struct ssam_device_driver ssam_kip_hub_driver = {
|
|
|
|
+- .probe = ssam_kip_hub_probe,
|
|
|
|
+- .remove = ssam_hub_remove,
|
|
|
|
+- .match_table = ssam_kip_hub_match,
|
|
|
|
+- .driver = {
|
|
|
|
+- .name = "surface_kip_hub",
|
|
|
|
+- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
|
|
|
+- .pm = &ssam_hub_pm_ops,
|
|
|
|
+- },
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-
|
|
|
|
+ /* -- SSAM platform/meta-hub driver. ---------------------------------------- */
|
|
|
|
+
|
|
|
|
+ static const struct acpi_device_id ssam_platform_hub_match[] = {
|
|
|
|
+@@ -727,44 +395,7 @@ static struct platform_driver ssam_platform_hub_driver = {
|
|
|
|
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
|
|
|
+ },
|
|
|
|
+ };
|
|
|
|
+-
|
|
|
|
+-
|
|
|
|
+-/* -- Module initialization. ------------------------------------------------ */
|
|
|
|
+-
|
|
|
|
+-static int __init ssam_device_hub_init(void)
|
|
|
|
+-{
|
|
|
|
+- int status;
|
|
|
|
+-
|
|
|
|
+- status = platform_driver_register(&ssam_platform_hub_driver);
|
|
|
|
+- if (status)
|
|
|
|
+- goto err_platform;
|
|
|
|
+-
|
|
|
|
+- status = ssam_device_driver_register(&ssam_base_hub_driver);
|
|
|
|
+- if (status)
|
|
|
|
+- goto err_base;
|
|
|
|
+-
|
|
|
|
+- status = ssam_device_driver_register(&ssam_kip_hub_driver);
|
|
|
|
+- if (status)
|
|
|
|
+- goto err_kip;
|
|
|
|
+-
|
|
|
|
+- return 0;
|
|
|
|
+-
|
|
|
|
+-err_kip:
|
|
|
|
+- ssam_device_driver_unregister(&ssam_base_hub_driver);
|
|
|
|
+-err_base:
|
|
|
|
+- platform_driver_unregister(&ssam_platform_hub_driver);
|
|
|
|
+-err_platform:
|
|
|
|
+- return status;
|
|
|
|
+-}
|
|
|
|
+-module_init(ssam_device_hub_init);
|
|
|
|
+-
|
|
|
|
+-static void __exit ssam_device_hub_exit(void)
|
|
|
|
+-{
|
|
|
|
+- ssam_device_driver_unregister(&ssam_kip_hub_driver);
|
|
|
|
+- ssam_device_driver_unregister(&ssam_base_hub_driver);
|
|
|
|
+- platform_driver_unregister(&ssam_platform_hub_driver);
|
|
|
|
+-}
|
|
|
|
+-module_exit(ssam_device_hub_exit);
|
|
|
|
++module_platform_driver(ssam_platform_hub_driver);
|
|
|
|
+
|
|
|
|
+ MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
|
|
|
|
+ MODULE_DESCRIPTION("Device-registry for Surface System Aggregator Module");
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 114e28179e83a80f1128056b7d91cc151b24f6ad Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 24 Jun 2022 22:58:00 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: Update copyright year of various drivers
|
|
|
|
+
|
|
|
|
+Update the copyright of various Surface drivers to the current year.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220624205800.1355621-4-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/platform/surface/aggregator/Kconfig | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/Makefile | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/bus.c | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/bus.h | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/controller.c | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/controller.h | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/core.c | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/ssh_msgb.h | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/ssh_packet_layer.c | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/ssh_packet_layer.h | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/ssh_parser.c | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/ssh_parser.h | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/ssh_request_layer.c | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/ssh_request_layer.h | 2 +-
|
|
|
|
+ drivers/platform/surface/aggregator/trace.h | 2 +-
|
|
|
|
+ drivers/platform/surface/surface_acpi_notify.c | 2 +-
|
|
|
|
+ drivers/platform/surface/surface_aggregator_cdev.c | 2 +-
|
|
|
|
+ drivers/platform/surface/surface_aggregator_registry.c | 2 +-
|
|
|
|
+ drivers/platform/surface/surface_dtx.c | 2 +-
|
|
|
|
+ drivers/platform/surface/surface_gpe.c | 2 +-
|
|
|
|
+ drivers/platform/surface/surface_hotplug.c | 2 +-
|
|
|
|
+ drivers/platform/surface/surface_platform_profile.c | 2 +-
|
|
|
|
+ 22 files changed, 22 insertions(+), 22 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/Kconfig b/drivers/platform/surface/aggregator/Kconfig
|
|
|
|
+index cab020324256..c114f9dd5fe1 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/Kconfig
|
|
|
|
++++ b/drivers/platform/surface/aggregator/Kconfig
|
|
|
|
+@@ -1,5 +1,5 @@
|
|
|
|
+ # SPDX-License-Identifier: GPL-2.0+
|
|
|
|
+-# Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++# Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+
|
|
|
|
+ menuconfig SURFACE_AGGREGATOR
|
|
|
|
+ tristate "Microsoft Surface System Aggregator Module Subsystem and Drivers"
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/Makefile b/drivers/platform/surface/aggregator/Makefile
|
|
|
|
+index c0d550eda5cd..fdf664a217f9 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/Makefile
|
|
|
|
++++ b/drivers/platform/surface/aggregator/Makefile
|
|
|
|
+@@ -1,5 +1,5 @@
|
|
|
|
+ # SPDX-License-Identifier: GPL-2.0+
|
|
|
|
+-# Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++# Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+
|
|
|
|
+ # For include/trace/define_trace.h to include trace.h
|
|
|
|
+ CFLAGS_core.o = -I$(src)
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
|
|
|
|
+index e0b0381a2834..de539938896e 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/bus.c
|
|
|
|
++++ b/drivers/platform/surface/aggregator/bus.c
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * Surface System Aggregator Module bus and device integration.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <linux/device.h>
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/bus.h b/drivers/platform/surface/aggregator/bus.h
|
|
|
|
+index 6964ee84e79c..5b4dbf21906c 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/bus.h
|
|
|
|
++++ b/drivers/platform/surface/aggregator/bus.h
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * Surface System Aggregator Module bus and device integration.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #ifndef _SURFACE_AGGREGATOR_BUS_H
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
|
|
|
|
+index 6de834b52b63..43e765199137 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/controller.c
|
|
|
|
++++ b/drivers/platform/surface/aggregator/controller.c
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * Main SSAM/SSH controller structure and functionality.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <linux/acpi.h>
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/controller.h b/drivers/platform/surface/aggregator/controller.h
|
|
|
|
+index a0963c3562ff..f0d987abc51e 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/controller.h
|
|
|
|
++++ b/drivers/platform/surface/aggregator/controller.h
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * Main SSAM/SSH controller structure and functionality.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #ifndef _SURFACE_AGGREGATOR_CONTROLLER_H
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
|
|
|
|
+index a62c5dfe42d6..1a6373dea109 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/core.c
|
|
|
|
++++ b/drivers/platform/surface/aggregator/core.c
|
|
|
|
+@@ -7,7 +7,7 @@
|
|
|
|
+ * Handles communication via requests as well as enabling, disabling, and
|
|
|
|
+ * relaying of events.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <linux/acpi.h>
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/ssh_msgb.h b/drivers/platform/surface/aggregator/ssh_msgb.h
|
|
|
|
+index e562958ffdf0..f3ecad92eefd 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/ssh_msgb.h
|
|
|
|
++++ b/drivers/platform/surface/aggregator/ssh_msgb.h
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * SSH message builder functions.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
|
|
|
|
+index 8a4451c1ffe5..6748fe4ac5d5 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
|
|
|
|
++++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * SSH packet transport layer.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <asm/unaligned.h>
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.h b/drivers/platform/surface/aggregator/ssh_packet_layer.h
|
|
|
|
+index 2eb329f0b91a..64633522f971 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/ssh_packet_layer.h
|
|
|
|
++++ b/drivers/platform/surface/aggregator/ssh_packet_layer.h
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * SSH packet transport layer.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #ifndef _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/ssh_parser.c b/drivers/platform/surface/aggregator/ssh_parser.c
|
|
|
|
+index b77912f8f13b..a6f668694365 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/ssh_parser.c
|
|
|
|
++++ b/drivers/platform/surface/aggregator/ssh_parser.c
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * SSH message parser.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <asm/unaligned.h>
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/ssh_parser.h b/drivers/platform/surface/aggregator/ssh_parser.h
|
|
|
|
+index 3bd6e180fd16..801d8fa69fb5 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/ssh_parser.h
|
|
|
|
++++ b/drivers/platform/surface/aggregator/ssh_parser.h
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * SSH message parser.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #ifndef _SURFACE_AGGREGATOR_SSH_PARSER_H
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
|
|
|
|
+index 790f7f0eee98..f5565570f16c 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/ssh_request_layer.c
|
|
|
|
++++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * SSH request transport layer.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <asm/unaligned.h>
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.h b/drivers/platform/surface/aggregator/ssh_request_layer.h
|
|
|
|
+index 9c3cbae2d4bd..4e387a031351 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/ssh_request_layer.h
|
|
|
|
++++ b/drivers/platform/surface/aggregator/ssh_request_layer.h
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * SSH request transport layer.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #ifndef _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H
|
|
|
|
+diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h
|
|
|
|
+index cc9e73fbc18e..2a2c17771d01 100644
|
|
|
|
+--- a/drivers/platform/surface/aggregator/trace.h
|
|
|
|
++++ b/drivers/platform/surface/aggregator/trace.h
|
|
|
|
+@@ -2,7 +2,7 @@
|
|
|
|
+ /*
|
|
|
|
+ * Trace points for SSAM/SSH.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #undef TRACE_SYSTEM
|
|
|
|
+diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c
|
|
|
|
+index c0e12f0b9b79..44e317970557 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_acpi_notify.c
|
|
|
|
++++ b/drivers/platform/surface/surface_acpi_notify.c
|
|
|
|
+@@ -8,7 +8,7 @@
|
|
|
|
+ * notifications sent from ACPI via the SAN interface by providing them to any
|
|
|
|
+ * registered external driver.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <asm/unaligned.h>
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c
|
|
|
|
+index 30fb50fde450..492c82e69182 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_cdev.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_cdev.c
|
|
|
|
+@@ -3,7 +3,7 @@
|
|
|
|
+ * Provides user-space access to the SSAM EC via the /dev/surface/aggregator
|
|
|
|
+ * misc device. Intended for debugging and development.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <linux/fs.h>
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index 0cbb7f3a6b2d..d5655f6a4a41 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -6,7 +6,7 @@
|
|
|
|
+ * cannot be auto-detected. Provides device-hubs and performs instantiation
|
|
|
|
+ * for these devices.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <linux/acpi.h>
|
|
|
|
+diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c
|
|
|
|
+index 1203b9a82993..ed36944467f9 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_dtx.c
|
|
|
|
++++ b/drivers/platform/surface/surface_dtx.c
|
|
|
|
+@@ -8,7 +8,7 @@
|
|
|
|
+ * acknowledge (to speed things up), abort (e.g. in case the dGPU is still in
|
|
|
|
+ * use), or request detachment via user-space.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <linux/fs.h>
|
|
|
|
+diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c
|
|
|
|
+index ec66fde28e75..27365cbe1ee9 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_gpe.c
|
|
|
|
++++ b/drivers/platform/surface/surface_gpe.c
|
|
|
|
+@@ -4,7 +4,7 @@
|
|
|
|
+ * properly configuring the respective GPEs. Required for wakeup via lid on
|
|
|
|
+ * newer Intel-based Microsoft Surface devices.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
+diff --git a/drivers/platform/surface/surface_hotplug.c b/drivers/platform/surface/surface_hotplug.c
|
|
|
|
+index cfcc15cfbacb..f004a2495201 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_hotplug.c
|
|
|
|
++++ b/drivers/platform/surface/surface_hotplug.c
|
|
|
|
+@@ -10,7 +10,7 @@
|
|
|
|
+ * Event signaling is handled via ACPI, which will generate the appropriate
|
|
|
|
+ * device-check notifications to be picked up by the PCIe hot-plug driver.
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <linux/acpi.h>
|
|
|
|
+diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c
|
|
|
|
+index 6373d3b5eb7f..fbf2e11fd6ce 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_platform_profile.c
|
|
|
|
++++ b/drivers/platform/surface/surface_platform_profile.c
|
|
|
|
+@@ -3,7 +3,7 @@
|
|
|
|
+ * Surface Platform Profile / Performance Mode driver for Surface System
|
|
|
|
+ * Aggregator Module (thermal subsystem).
|
|
|
|
+ *
|
|
|
|
+- * Copyright (C) 2021 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
++ * Copyright (C) 2021-2022 Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ #include <asm/unaligned.h>
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From a73e0c964ed06bc1294ab0862a6b795fcf73911d Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Lukas Bulwahn <lukas.bulwahn@gmail.com>
|
|
|
|
+Date: Wed, 13 Jul 2022 06:09:16 +0200
|
|
|
|
+Subject: [PATCH] MAINTAINERS: repair file entry in MICROSOFT SURFACE
|
|
|
|
+ AGGREGATOR TABLET-MODE SWITCH
|
|
|
|
+
|
|
|
|
+Commit 9f794056db5b ("platform/surface: Add KIP/POS tablet-mode switch
|
|
|
|
+driver") adds the section MICROSOFT SURFACE AGGREGATOR TABLET-MODE SWITCH
|
|
|
|
+with a file entry, but the file that is added with this commit is actually
|
|
|
|
+named slightly differently.
|
|
|
|
+
|
|
|
|
+ file entry name: drivers/platform/surface/surface_aggregator_tablet_switch.c
|
|
|
|
+ added file name: drivers/platform/surface/surface_aggregator_tabletsw.c
|
|
|
|
+
|
|
|
|
+Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about a
|
|
|
|
+broken reference.
|
|
|
|
+
|
|
|
|
+Repair this file entry to the actual file name added with the commit above.
|
|
|
|
+
|
|
|
|
+Fixes: 9f794056db5b ("platform/surface: Add KIP/POS tablet-mode switch driver")
|
|
|
|
+Signed-off-by: Lukas Bulwahn <lukas.bulwahn@gmail.com>
|
|
|
|
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
|
|
|
|
+Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220713040916.1767-1-lukas.bulwahn@gmail.com
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ MAINTAINERS | 2 +-
|
|
|
|
+ 1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
+
|
|
|
|
+diff --git a/MAINTAINERS b/MAINTAINERS
|
|
|
|
+index a29042434d9e..c967eb4675b7 100644
|
|
|
|
+--- a/MAINTAINERS
|
|
|
|
++++ b/MAINTAINERS
|
|
|
|
+@@ -13308,7 +13308,7 @@ MICROSOFT SURFACE AGGREGATOR TABLET-MODE SWITCH
|
|
|
|
+ M: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+ L: platform-driver-x86@vger.kernel.org
|
|
|
|
+ S: Maintained
|
|
|
|
+-F: drivers/platform/surface/surface_aggregator_tablet_switch.c
|
|
|
|
++F: drivers/platform/surface/surface_aggregator_tabletsw.c
|
|
|
|
+
|
|
|
|
+ MICROSOFT SURFACE BATTERY AND AC DRIVERS
|
|
|
|
+ M: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 0ba68391040ba804f381cf1e80fed98ff9810016 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Sun, 17 Jul 2022 14:07:35 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: tabletsw: Fix __le32 integer access
|
|
|
|
+
|
|
|
|
+The sources.count field is a __le32 inside a packed struct. So use the
|
|
|
|
+proper functions to access it.
|
|
|
|
+
|
|
|
|
+Reported-by: kernel test robot <lkp@intel.com>
|
|
|
|
+Fixes: 9f794056db5b ("platform/surface: Add KIP/POS tablet-mode switch driver")
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Link: https://lore.kernel.org/r/20220717120735.2052160-1-luzmaximilian@gmail.com
|
|
|
|
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/platform/surface/surface_aggregator_tabletsw.c | 4 ++--
|
|
|
|
+ 1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c
|
|
|
|
+index 596ca6c80681..27d95a6a7851 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_tabletsw.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_tabletsw.c
|
|
|
|
+@@ -410,7 +410,7 @@ static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id)
|
|
|
|
+ if (status)
|
|
|
|
+ return status;
|
|
|
|
+
|
|
|
|
+- if (sources.count == 0) {
|
|
|
|
++ if (get_unaligned_le32(&sources.count) == 0) {
|
|
|
|
+ dev_err(&sw->sdev->dev, "no posture sources found\n");
|
|
|
|
+ return -ENODEV;
|
|
|
|
+ }
|
|
|
|
+@@ -422,7 +422,7 @@ static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id)
|
|
|
|
+ * is a device that provides multiple sources, at which point we can
|
|
|
|
+ * then try to figure out how to handle them.
|
|
|
|
+ */
|
|
|
|
+- WARN_ON(sources.count > 1);
|
|
|
|
++ WARN_ON(get_unaligned_le32(&sources.count) > 1);
|
|
|
|
+
|
|
|
|
+ *source_id = get_unaligned_le32(&sources.id[0]);
|
|
|
|
+ return 0;
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From ff91dba8ef6eab54f9025cd35d52028cb75cbf3e Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Fri, 8 Jul 2022 03:34:44 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Add support for
|
|
|
|
+ Surface Laptop Go 2
|
|
|
|
+
|
|
|
|
+The Surface Laptop Go 2 seems to have the same SAM client devices as the
|
|
|
|
+Surface Laptop Go 1, so re-use its node group.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/platform/surface/surface_aggregator_registry.c | 3 +++
|
|
|
|
+ 1 file changed, 3 insertions(+)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index d5655f6a4a41..93ab62eb393d 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -325,6 +325,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
|
|
|
|
+ /* Surface Laptop Go 1 */
|
|
|
|
+ { "MSHW0118", (unsigned long)ssam_node_group_slg1 },
|
|
|
|
+
|
|
|
|
++ /* Surface Laptop Go 2 */
|
|
|
|
++ { "MSHW0290", (unsigned long)ssam_node_group_slg1 },
|
|
|
|
++
|
|
|
|
+ /* Surface Laptop Studio */
|
|
|
|
+ { "MSHW0123", (unsigned long)ssam_node_group_sls },
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From e399ffd43d7419256f29b8834211ed6685f6ca2d Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Sat, 25 Jun 2022 20:42:00 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Rename HID device
|
|
|
|
+ nodes based on their function
|
|
|
|
+
|
|
|
|
+Rename HID device nodes based on their function. In particular, these
|
|
|
|
+are nodes for firmware updates via the CFU mechanism (component firmware
|
|
|
|
+update), HID based sensors, and a USB-C UCSI client.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ .../surface/surface_aggregator_registry.c | 18 +++++++++---------
|
|
|
|
+ 1 file changed, 9 insertions(+), 9 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index 93ab62eb393d..7d82398f55b1 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -104,14 +104,14 @@ static const struct software_node ssam_node_hid_tid1_touchpad = {
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+-/* HID device instance 6 (TID1, unknown HID device). */
|
|
|
|
+-static const struct software_node ssam_node_hid_tid1_iid6 = {
|
|
|
|
++/* HID device instance 6 (TID1, HID sensor collection). */
|
|
|
|
++static const struct software_node ssam_node_hid_tid1_sensors = {
|
|
|
|
+ .name = "ssam:01:15:01:06:00",
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+-/* HID device instance 7 (TID1, unknown HID device). */
|
|
|
|
+-static const struct software_node ssam_node_hid_tid1_iid7 = {
|
|
|
|
++/* HID device instance 7 (TID1, UCM UCSI HID client). */
|
|
|
|
++static const struct software_node ssam_node_hid_tid1_ucm_ucsi = {
|
|
|
|
+ .name = "ssam:01:15:01:07:00",
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+@@ -182,8 +182,8 @@ static const struct software_node ssam_node_hid_kip_touchpad = {
|
|
|
|
+ .parent = &ssam_node_hub_kip,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+-/* HID device instance 5 (KIP hub, unknown HID device). */
|
|
|
|
+-static const struct software_node ssam_node_hid_kip_iid5 = {
|
|
|
|
++/* HID device instance 5 (KIP hub, type-cover firmware update). */
|
|
|
|
++static const struct software_node ssam_node_hid_kip_fwupd = {
|
|
|
|
+ .name = "ssam:01:15:02:05:00",
|
|
|
|
+ .parent = &ssam_node_hub_kip,
|
|
|
|
+ };
|
|
|
|
+@@ -244,8 +244,8 @@ static const struct software_node *ssam_node_group_sls[] = {
|
|
|
|
+ &ssam_node_hid_tid1_keyboard,
|
|
|
|
+ &ssam_node_hid_tid1_penstash,
|
|
|
|
+ &ssam_node_hid_tid1_touchpad,
|
|
|
|
+- &ssam_node_hid_tid1_iid6,
|
|
|
|
+- &ssam_node_hid_tid1_iid7,
|
|
|
|
++ &ssam_node_hid_tid1_sensors,
|
|
|
|
++ &ssam_node_hid_tid1_ucm_ucsi,
|
|
|
|
+ &ssam_node_hid_tid1_sysctrl,
|
|
|
|
+ NULL,
|
|
|
|
+ };
|
|
|
|
+@@ -278,7 +278,7 @@ static const struct software_node *ssam_node_group_sp8[] = {
|
|
|
|
+ &ssam_node_hid_kip_keyboard,
|
|
|
|
+ &ssam_node_hid_kip_penstash,
|
|
|
|
+ &ssam_node_hid_kip_touchpad,
|
|
|
|
+- &ssam_node_hid_kip_iid5,
|
|
|
|
++ &ssam_node_hid_kip_fwupd,
|
|
|
|
+ NULL,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 1d687b69d2e5eadb47710d4cc2b811a130787120 Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Sat, 25 Jun 2022 20:52:47 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Rename HID device
|
|
|
|
+ nodes based on new findings
|
|
|
|
+
|
|
|
|
+On Windows, the HID devices with target ID 1 are grouped as "Surface Hot
|
|
|
|
+Plug - SAM". Rename their device nodes in the registry to reflect that
|
|
|
|
+and update the comments accordingly.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ .../surface/surface_aggregator_registry.c | 36 +++++++++----------
|
|
|
|
+ 1 file changed, 18 insertions(+), 18 deletions(-)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index 7d82398f55b1..9970f89b1411 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -86,38 +86,38 @@ static const struct software_node ssam_node_bas_dtx = {
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+-/* HID keyboard (TID1). */
|
|
|
|
+-static const struct software_node ssam_node_hid_tid1_keyboard = {
|
|
|
|
++/* HID keyboard (SAM, TID=1). */
|
|
|
|
++static const struct software_node ssam_node_hid_sam_keyboard = {
|
|
|
|
+ .name = "ssam:01:15:01:01:00",
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+-/* HID pen stash (TID1; pen taken / stashed away evens). */
|
|
|
|
+-static const struct software_node ssam_node_hid_tid1_penstash = {
|
|
|
|
++/* HID pen stash (SAM, TID=1; pen taken / stashed away evens). */
|
|
|
|
++static const struct software_node ssam_node_hid_sam_penstash = {
|
|
|
|
+ .name = "ssam:01:15:01:02:00",
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+-/* HID touchpad (TID1). */
|
|
|
|
+-static const struct software_node ssam_node_hid_tid1_touchpad = {
|
|
|
|
++/* HID touchpad (SAM, TID=1). */
|
|
|
|
++static const struct software_node ssam_node_hid_sam_touchpad = {
|
|
|
|
+ .name = "ssam:01:15:01:03:00",
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+-/* HID device instance 6 (TID1, HID sensor collection). */
|
|
|
|
+-static const struct software_node ssam_node_hid_tid1_sensors = {
|
|
|
|
++/* HID device instance 6 (SAM, TID=1, HID sensor collection). */
|
|
|
|
++static const struct software_node ssam_node_hid_sam_sensors = {
|
|
|
|
+ .name = "ssam:01:15:01:06:00",
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+-/* HID device instance 7 (TID1, UCM UCSI HID client). */
|
|
|
|
+-static const struct software_node ssam_node_hid_tid1_ucm_ucsi = {
|
|
|
|
++/* HID device instance 7 (SAM, TID=1, UCM UCSI HID client). */
|
|
|
|
++static const struct software_node ssam_node_hid_sam_ucm_ucsi = {
|
|
|
|
+ .name = "ssam:01:15:01:07:00",
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+-/* HID system controls (TID1). */
|
|
|
|
+-static const struct software_node ssam_node_hid_tid1_sysctrl = {
|
|
|
|
++/* HID system controls (SAM, TID=1). */
|
|
|
|
++static const struct software_node ssam_node_hid_sam_sysctrl = {
|
|
|
|
+ .name = "ssam:01:15:01:08:00",
|
|
|
|
+ .parent = &ssam_node_root,
|
|
|
|
+ };
|
|
|
|
+@@ -241,12 +241,12 @@ static const struct software_node *ssam_node_group_sls[] = {
|
|
|
|
+ &ssam_node_bat_main,
|
|
|
|
+ &ssam_node_tmp_pprof,
|
|
|
|
+ &ssam_node_pos_tablet_switch,
|
|
|
|
+- &ssam_node_hid_tid1_keyboard,
|
|
|
|
+- &ssam_node_hid_tid1_penstash,
|
|
|
|
+- &ssam_node_hid_tid1_touchpad,
|
|
|
|
+- &ssam_node_hid_tid1_sensors,
|
|
|
|
+- &ssam_node_hid_tid1_ucm_ucsi,
|
|
|
|
+- &ssam_node_hid_tid1_sysctrl,
|
|
|
|
++ &ssam_node_hid_sam_keyboard,
|
|
|
|
++ &ssam_node_hid_sam_penstash,
|
|
|
|
++ &ssam_node_hid_sam_touchpad,
|
|
|
|
++ &ssam_node_hid_sam_sensors,
|
|
|
|
++ &ssam_node_hid_sam_ucm_ucsi,
|
|
|
|
++ &ssam_node_hid_sam_sysctrl,
|
|
|
|
+ NULL,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|
|
|
|
+From 89fac2c107f3738bb8a67144827d35ab3e2d92eb Mon Sep 17 00:00:00 2001
|
|
|
|
+From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Date: Sat, 25 Jun 2022 20:54:59 +0200
|
|
|
|
+Subject: [PATCH] platform/surface: aggregator_registry: Add HID devices for
|
|
|
|
+ sensors and UCSI client to SP8
|
|
|
|
+
|
|
|
|
+Add software nodes for the HID sensor collection and the UCM UCSI HID
|
|
|
|
+client to the Surface Pro 8. In contrast to the type-cover devices,
|
|
|
|
+these devices are directly attached to the SAM controller, without any
|
|
|
|
+hub.
|
|
|
|
+
|
|
|
|
+This enables support for HID-based sensors, including the ones used for
|
|
|
|
+automatic screen rotation, on the Surface Pro 8.
|
|
|
|
+
|
|
|
|
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
+Patchset: surface-sam
|
|
|
|
+---
|
|
|
|
+ drivers/platform/surface/surface_aggregator_registry.c | 2 ++
|
|
|
|
+ 1 file changed, 2 insertions(+)
|
|
|
|
+
|
|
|
|
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+index 9970f89b1411..585911020cea 100644
|
|
|
|
+--- a/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
++++ b/drivers/platform/surface/surface_aggregator_registry.c
|
|
|
|
+@@ -279,6 +279,8 @@ static const struct software_node *ssam_node_group_sp8[] = {
|
|
|
|
+ &ssam_node_hid_kip_penstash,
|
|
|
|
+ &ssam_node_hid_kip_touchpad,
|
|
|
|
+ &ssam_node_hid_kip_fwupd,
|
|
|
|
++ &ssam_node_hid_sam_sensors,
|
|
|
|
++ &ssam_node_hid_sam_ucm_ucsi,
|
|
|
|
+ NULL,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+--
|
|
|
|
+2.37.1
|
|
|
|
+
|