0005-surface-sam.patch 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265
  1. From f6611d8d35d47d43b7aae454a36d69232c430958 Mon Sep 17 00:00:00 2001
  2. From: Maximilian Luz <luzmaximilian@gmail.com>
  3. Date: Thu, 28 Oct 2021 03:28:45 +0200
  4. Subject: [PATCH] platform/surface: aggregator_registry: Add initial support
  5. for Surface Pro 8
  6. Add preliminary support for the Surface Pro 8 to the Surface Aggregator
  7. registry. This includes battery/charger status and platform profile
  8. support.
  9. In contrast to earlier Surface Pro generations, the keyboard cover is
  10. now also connected via the Surface Aggregator Module (whereas it was
  11. previously connected via USB or HID-over-I2C). To properly support the
  12. HID devices of that cover, however, more changes regarding hot-removal
  13. of Surface Aggregator client devices as well as a new device hub driver
  14. are required. We will address those things in a follow-up series, so do
  15. not add any HID device IDs just yet.
  16. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  17. Link: https://lore.kernel.org/r/20211028012845.1887219-1-luzmaximilian@gmail.com
  18. Reviewed-by: Hans de Goede <hdegoede@redhat.com>
  19. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  20. Patchset: surface-sam
  21. ---
  22. .../platform/surface/surface_aggregator_registry.c | 12 ++++++++++++
  23. 1 file changed, 12 insertions(+)
  24. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  25. index 1679811eff50..e70f4c63554e 100644
  26. --- a/drivers/platform/surface/surface_aggregator_registry.c
  27. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  28. @@ -228,6 +228,15 @@ static const struct software_node *ssam_node_group_sp7[] = {
  29. NULL,
  30. };
  31. +static const struct software_node *ssam_node_group_sp8[] = {
  32. + &ssam_node_root,
  33. + &ssam_node_bat_ac,
  34. + &ssam_node_bat_main,
  35. + &ssam_node_tmp_pprof,
  36. + /* TODO: Add support for keyboard cover. */
  37. + NULL,
  38. +};
  39. +
  40. /* -- Device registry helper functions. ------------------------------------- */
  41. @@ -534,6 +543,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
  42. /* Surface Pro 7+ */
  43. { "MSHW0119", (unsigned long)ssam_node_group_sp7 },
  44. + /* Surface Pro 8 */
  45. + { "MSHW0263", (unsigned long)ssam_node_group_sp8 },
  46. +
  47. /* Surface Book 2 */
  48. { "MSHW0107", (unsigned long)ssam_node_group_gen5 },
  49. --
  50. 2.34.0
  51. From 11a1289287c02cfec4efbdd63f85dea6d68284f2 Mon Sep 17 00:00:00 2001
  52. From: Maximilian Luz <luzmaximilian@gmail.com>
  53. Date: Wed, 2 Jun 2021 03:34:06 +0200
  54. Subject: [PATCH] platform/surface: aggregator: Make client device removal more
  55. generic
  56. Currently, there are similar functions defined in the Aggregator
  57. Registry and the controller core.
  58. Make client device removal more generic and export it. We can then use
  59. this function later on to remove client devices from device hubs as well
  60. as the controller and avoid re-defining similar things.
  61. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  62. Patchset: surface-sam
  63. ---
  64. drivers/platform/surface/aggregator/bus.c | 24 ++++++++--------------
  65. drivers/platform/surface/aggregator/bus.h | 3 ---
  66. drivers/platform/surface/aggregator/core.c | 3 ++-
  67. include/linux/surface_aggregator/device.h | 9 ++++++++
  68. 4 files changed, 19 insertions(+), 20 deletions(-)
  69. diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
  70. index 0169677c243e..eaa8626baead 100644
  71. --- a/drivers/platform/surface/aggregator/bus.c
  72. +++ b/drivers/platform/surface/aggregator/bus.c
  73. @@ -376,27 +376,19 @@ static int ssam_remove_device(struct device *dev, void *_data)
  74. }
  75. /**
  76. - * ssam_controller_remove_clients() - Remove SSAM client devices registered as
  77. - * direct children under the given controller.
  78. - * @ctrl: The controller to remove all direct clients for.
  79. + * ssam_remove_clients() - Remove SSAM client devices registered as direct
  80. + * children under the given parent device.
  81. + * @dev: The (parent) device to remove all direct clients for.
  82. *
  83. - * Remove all SSAM client devices registered as direct children under the
  84. - * given controller. Note that this only accounts for direct children of the
  85. - * controller device. This does not take care of any client devices where the
  86. - * parent device has been manually set before calling ssam_device_add. Refer
  87. - * to ssam_device_add()/ssam_device_remove() for more details on those cases.
  88. - *
  89. - * To avoid new devices being added in parallel to this call, the main
  90. - * controller lock (not statelock) must be held during this (and if
  91. - * necessary, any subsequent deinitialization) call.
  92. + * Remove all SSAM client devices registered as direct children under the given
  93. + * device. Note that this only accounts for direct children of the device.
  94. + * Refer to ssam_device_add()/ssam_device_remove() for more details.
  95. */
  96. -void ssam_controller_remove_clients(struct ssam_controller *ctrl)
  97. +void ssam_remove_clients(struct device *dev)
  98. {
  99. - struct device *dev;
  100. -
  101. - dev = ssam_controller_device(ctrl);
  102. device_for_each_child_reverse(dev, NULL, ssam_remove_device);
  103. }
  104. +EXPORT_SYMBOL_GPL(ssam_remove_clients);
  105. /**
  106. * ssam_bus_register() - Register and set-up the SSAM client device bus.
  107. diff --git a/drivers/platform/surface/aggregator/bus.h b/drivers/platform/surface/aggregator/bus.h
  108. index ed032c2cbdb2..6964ee84e79c 100644
  109. --- a/drivers/platform/surface/aggregator/bus.h
  110. +++ b/drivers/platform/surface/aggregator/bus.h
  111. @@ -12,14 +12,11 @@
  112. #ifdef CONFIG_SURFACE_AGGREGATOR_BUS
  113. -void ssam_controller_remove_clients(struct ssam_controller *ctrl);
  114. -
  115. int ssam_bus_register(void);
  116. void ssam_bus_unregister(void);
  117. #else /* CONFIG_SURFACE_AGGREGATOR_BUS */
  118. -static inline void ssam_controller_remove_clients(struct ssam_controller *ctrl) {}
  119. static inline int ssam_bus_register(void) { return 0; }
  120. static inline void ssam_bus_unregister(void) {}
  121. diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
  122. index 279d9df19c01..124df0100a9f 100644
  123. --- a/drivers/platform/surface/aggregator/core.c
  124. +++ b/drivers/platform/surface/aggregator/core.c
  125. @@ -22,6 +22,7 @@
  126. #include <linux/sysfs.h>
  127. #include <linux/surface_aggregator/controller.h>
  128. +#include <linux/surface_aggregator/device.h>
  129. #include "bus.h"
  130. #include "controller.h"
  131. @@ -742,7 +743,7 @@ static void ssam_serial_hub_remove(struct serdev_device *serdev)
  132. ssam_controller_lock(ctrl);
  133. /* Remove all client devices. */
  134. - ssam_controller_remove_clients(ctrl);
  135. + ssam_remove_clients(&serdev->dev);
  136. /* Act as if suspending to silence events. */
  137. status = ssam_ctrl_notif_display_off(ctrl);
  138. diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
  139. index f636c5310321..cc257097eb05 100644
  140. --- a/include/linux/surface_aggregator/device.h
  141. +++ b/include/linux/surface_aggregator/device.h
  142. @@ -319,6 +319,15 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d);
  143. ssam_device_driver_unregister)
  144. +/* -- Helpers for controller and hub devices. ------------------------------- */
  145. +
  146. +#ifdef CONFIG_SURFACE_AGGREGATOR_BUS
  147. +void ssam_remove_clients(struct device *dev);
  148. +#else /* CONFIG_SURFACE_AGGREGATOR_BUS */
  149. +static inline void ssam_remove_clients(struct device *dev) {}
  150. +#endif /* CONFIG_SURFACE_AGGREGATOR_BUS */
  151. +
  152. +
  153. /* -- Helpers for client-device requests. ----------------------------------- */
  154. /**
  155. --
  156. 2.34.0
  157. From 4a84f3d00f6fa73d2d423f737b31e574b5a5f30a Mon Sep 17 00:00:00 2001
  158. From: Maximilian Luz <luzmaximilian@gmail.com>
  159. Date: Wed, 27 Oct 2021 02:06:38 +0200
  160. Subject: [PATCH] platform/surface: aggregator_registry: Use generic client
  161. removal function
  162. Use generic client removal function introduced in the previous commit
  163. instead of defining our own one.
  164. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  165. Patchset: surface-sam
  166. ---
  167. .../surface/surface_aggregator_registry.c | 24 ++++---------------
  168. 1 file changed, 5 insertions(+), 19 deletions(-)
  169. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  170. index e70f4c63554e..f6c639342b9d 100644
  171. --- a/drivers/platform/surface/surface_aggregator_registry.c
  172. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  173. @@ -258,20 +258,6 @@ static int ssam_uid_from_string(const char *str, struct ssam_device_uid *uid)
  174. return 0;
  175. }
  176. -static int ssam_hub_remove_devices_fn(struct device *dev, void *data)
  177. -{
  178. - if (!is_ssam_device(dev))
  179. - return 0;
  180. -
  181. - ssam_device_remove(to_ssam_device(dev));
  182. - return 0;
  183. -}
  184. -
  185. -static void ssam_hub_remove_devices(struct device *parent)
  186. -{
  187. - device_for_each_child_reverse(parent, NULL, ssam_hub_remove_devices_fn);
  188. -}
  189. -
  190. static int ssam_hub_add_device(struct device *parent, struct ssam_controller *ctrl,
  191. struct fwnode_handle *node)
  192. {
  193. @@ -317,7 +303,7 @@ static int ssam_hub_add_devices(struct device *parent, struct ssam_controller *c
  194. return 0;
  195. err:
  196. - ssam_hub_remove_devices(parent);
  197. + ssam_remove_clients(parent);
  198. return status;
  199. }
  200. @@ -414,7 +400,7 @@ static void ssam_base_hub_update_workfn(struct work_struct *work)
  201. if (hub->state == SSAM_BASE_HUB_CONNECTED)
  202. status = ssam_hub_add_devices(&hub->sdev->dev, hub->sdev->ctrl, node);
  203. else
  204. - ssam_hub_remove_devices(&hub->sdev->dev);
  205. + ssam_remove_clients(&hub->sdev->dev);
  206. if (status)
  207. dev_err(&hub->sdev->dev, "failed to update base-hub devices: %d\n", status);
  208. @@ -496,7 +482,7 @@ static int ssam_base_hub_probe(struct ssam_device *sdev)
  209. err:
  210. ssam_notifier_unregister(sdev->ctrl, &hub->notif);
  211. cancel_delayed_work_sync(&hub->update_work);
  212. - ssam_hub_remove_devices(&sdev->dev);
  213. + ssam_remove_clients(&sdev->dev);
  214. return status;
  215. }
  216. @@ -508,7 +494,7 @@ static void ssam_base_hub_remove(struct ssam_device *sdev)
  217. ssam_notifier_unregister(sdev->ctrl, &hub->notif);
  218. cancel_delayed_work_sync(&hub->update_work);
  219. - ssam_hub_remove_devices(&sdev->dev);
  220. + ssam_remove_clients(&sdev->dev);
  221. }
  222. static const struct ssam_device_id ssam_base_hub_match[] = {
  223. @@ -625,7 +611,7 @@ static int ssam_platform_hub_remove(struct platform_device *pdev)
  224. {
  225. const struct software_node **nodes = platform_get_drvdata(pdev);
  226. - ssam_hub_remove_devices(&pdev->dev);
  227. + ssam_remove_clients(&pdev->dev);
  228. set_secondary_fwnode(&pdev->dev, NULL);
  229. software_node_unregister_node_group(nodes);
  230. return 0;
  231. --
  232. 2.34.0
  233. From a801735c964f387be196a2d63d22b030667d592e Mon Sep 17 00:00:00 2001
  234. From: Maximilian Luz <luzmaximilian@gmail.com>
  235. Date: Wed, 27 Oct 2021 02:07:33 +0200
  236. Subject: [PATCH] platform/surface: aggregator_registry: Rename device
  237. registration function
  238. Rename the device registration function to better align names with the
  239. newly introduced device removal function.
  240. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  241. Patchset: surface-sam
  242. ---
  243. drivers/platform/surface/surface_aggregator_registry.c | 8 ++++----
  244. 1 file changed, 4 insertions(+), 4 deletions(-)
  245. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  246. index f6c639342b9d..ce2bd88feeaa 100644
  247. --- a/drivers/platform/surface/surface_aggregator_registry.c
  248. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  249. @@ -283,8 +283,8 @@ static int ssam_hub_add_device(struct device *parent, struct ssam_controller *ct
  250. return status;
  251. }
  252. -static int ssam_hub_add_devices(struct device *parent, struct ssam_controller *ctrl,
  253. - struct fwnode_handle *node)
  254. +static int ssam_hub_register_clients(struct device *parent, struct ssam_controller *ctrl,
  255. + struct fwnode_handle *node)
  256. {
  257. struct fwnode_handle *child;
  258. int status;
  259. @@ -398,7 +398,7 @@ static void ssam_base_hub_update_workfn(struct work_struct *work)
  260. hub->state = state;
  261. if (hub->state == SSAM_BASE_HUB_CONNECTED)
  262. - status = ssam_hub_add_devices(&hub->sdev->dev, hub->sdev->ctrl, node);
  263. + status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node);
  264. else
  265. ssam_remove_clients(&hub->sdev->dev);
  266. @@ -597,7 +597,7 @@ static int ssam_platform_hub_probe(struct platform_device *pdev)
  267. set_secondary_fwnode(&pdev->dev, root);
  268. - status = ssam_hub_add_devices(&pdev->dev, ctrl, root);
  269. + status = ssam_hub_register_clients(&pdev->dev, ctrl, root);
  270. if (status) {
  271. set_secondary_fwnode(&pdev->dev, NULL);
  272. software_node_unregister_node_group(nodes);
  273. --
  274. 2.34.0
  275. From b18657a4239bad3b786edb87311b130403a5a1fd Mon Sep 17 00:00:00 2001
  276. From: Maximilian Luz <luzmaximilian@gmail.com>
  277. Date: Tue, 8 Jun 2021 00:24:47 +0200
  278. Subject: [PATCH] platform/surface: aggregator: Allow devices to be marked as
  279. hot-removed
  280. Some SSAM devices, notably the keyboard cover (keyboard and touchpad) on
  281. the Surface Pro 8, can be hot-removed. When this occurs, communication
  282. with the device may fail and time out. This timeout can unnecessarily
  283. block and slow down device removal and even cause issues when the
  284. devices are detached and re-attached quickly. Thus, communication should
  285. generally be avoided once hot-removal is detected.
  286. While we already remove a device as soon as we detect its (hot-)removal,
  287. the corresponding device driver may still attempt to communicate with
  288. the device during teardown. This is especially critical as communication
  289. failure may also extend to disabling of events, which is typically done
  290. at that stage.
  291. Add a flag to allow marking devices as hot-removed. This can then be
  292. used during client driver teardown to check if any communication
  293. attempts should be avoided.
  294. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  295. Patchset: surface-sam
  296. ---
  297. drivers/platform/surface/aggregator/bus.c | 3 ++
  298. include/linux/surface_aggregator/device.h | 48 +++++++++++++++++++++--
  299. 2 files changed, 48 insertions(+), 3 deletions(-)
  300. diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
  301. index eaa8626baead..736cc43c9104 100644
  302. --- a/drivers/platform/surface/aggregator/bus.c
  303. +++ b/drivers/platform/surface/aggregator/bus.c
  304. @@ -390,6 +390,9 @@ void ssam_remove_clients(struct device *dev)
  305. }
  306. EXPORT_SYMBOL_GPL(ssam_remove_clients);
  307. +
  308. +/* -- Bus registration. ----------------------------------------------------- */
  309. +
  310. /**
  311. * ssam_bus_register() - Register and set-up the SSAM client device bus.
  312. */
  313. diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
  314. index cc257097eb05..491aa7e9f4bc 100644
  315. --- a/include/linux/surface_aggregator/device.h
  316. +++ b/include/linux/surface_aggregator/device.h
  317. @@ -148,17 +148,30 @@ struct ssam_device_uid {
  318. #define SSAM_SDEV(cat, tid, iid, fun) \
  319. SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, tid, iid, fun)
  320. +/*
  321. + * enum ssam_device_flags - Flags for SSAM client devices.
  322. + * @SSAM_DEVICE_HOT_REMOVED_BIT:
  323. + * The device has been hot-removed. Further communication with it may time
  324. + * out and should be avoided.
  325. + */
  326. +enum ssam_device_flags {
  327. + SSAM_DEVICE_HOT_REMOVED_BIT = 0,
  328. +};
  329. +
  330. /**
  331. * struct ssam_device - SSAM client device.
  332. - * @dev: Driver model representation of the device.
  333. - * @ctrl: SSAM controller managing this device.
  334. - * @uid: UID identifying the device.
  335. + * @dev: Driver model representation of the device.
  336. + * @ctrl: SSAM controller managing this device.
  337. + * @uid: UID identifying the device.
  338. + * @flags: Device state flags, see &enum ssam_device_flags.
  339. */
  340. struct ssam_device {
  341. struct device dev;
  342. struct ssam_controller *ctrl;
  343. struct ssam_device_uid uid;
  344. +
  345. + unsigned long flags;
  346. };
  347. /**
  348. @@ -240,6 +253,35 @@ struct ssam_device *ssam_device_alloc(struct ssam_controller *ctrl,
  349. int ssam_device_add(struct ssam_device *sdev);
  350. void ssam_device_remove(struct ssam_device *sdev);
  351. +/**
  352. + * ssam_device_mark_hot_removed() - Mark the given device as hot-removed.
  353. + * @sdev: The device to mark as hot-removed.
  354. + *
  355. + * Mark the device as having been hot-removed. This signals drivers using the
  356. + * device that communication with the device should be avoided and may lead to
  357. + * timeouts.
  358. + */
  359. +static inline void ssam_device_mark_hot_removed(struct ssam_device *sdev)
  360. +{
  361. + dev_dbg(&sdev->dev, "marking device as hot-removed\n");
  362. + set_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags);
  363. +}
  364. +
  365. +/**
  366. + * ssam_device_is_hot_removed() - Check if the given device has been
  367. + * hot-removed.
  368. + * @sdev: The device to check.
  369. + *
  370. + * Checks if the given device has been marked as hot-removed. See
  371. + * ssam_device_mark_hot_removed() for more details.
  372. + *
  373. + * Return: Returns ``true`` if the device has been marked as hot-removed.
  374. + */
  375. +static inline bool ssam_device_is_hot_removed(struct ssam_device *sdev)
  376. +{
  377. + return test_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags);
  378. +}
  379. +
  380. /**
  381. * ssam_device_get() - Increment reference count of SSAM client device.
  382. * @sdev: The device to increment the reference count of.
  383. --
  384. 2.34.0
  385. From f95d6ac5874db1bb881ffa482abc35f94bb13f5e Mon Sep 17 00:00:00 2001
  386. From: Maximilian Luz <luzmaximilian@gmail.com>
  387. Date: Tue, 8 Jun 2021 00:48:22 +0200
  388. Subject: [PATCH] platform/surface: aggregator: Allow notifiers to avoid
  389. communication on unregistering
  390. When SSAM client devices have been (physically) hot-removed,
  391. communication attempts with those devices may fail and time out. This
  392. can even extend to event notifiers, due to which timeouts may occur
  393. during device removal, slowing down that process.
  394. Add a flag to the notifier unregister function that allows skipping
  395. communication with the EC to prevent this. Furthermore, add wrappers for
  396. registering and unregistering notifiers belonging to SSAM client devices
  397. that automatically check if the device has been marked as hot-removed
  398. and communication should be avoided.
  399. Note that non-SSAM client devices can generally not be hot-removed, so
  400. also add a convenience wrapper for those, defaulting to allow
  401. communication.
  402. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  403. Patchset: surface-sam
  404. ---
  405. .../driver-api/surface_aggregator/client.rst | 6 +-
  406. .../platform/surface/aggregator/controller.c | 53 ++++++++++------
  407. include/linux/surface_aggregator/controller.h | 24 +++++++-
  408. include/linux/surface_aggregator/device.h | 60 +++++++++++++++++++
  409. 4 files changed, 122 insertions(+), 21 deletions(-)
  410. diff --git a/Documentation/driver-api/surface_aggregator/client.rst b/Documentation/driver-api/surface_aggregator/client.rst
  411. index e519d374c378..27f95abdbe99 100644
  412. --- a/Documentation/driver-api/surface_aggregator/client.rst
  413. +++ b/Documentation/driver-api/surface_aggregator/client.rst
  414. @@ -17,6 +17,8 @@
  415. .. |SSAM_DEVICE| replace:: :c:func:`SSAM_DEVICE`
  416. .. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register`
  417. .. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
  418. +.. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register`
  419. +.. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister`
  420. .. |ssam_request_sync| replace:: :c:func:`ssam_request_sync`
  421. .. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask <ssam_event_mask>`
  422. @@ -312,7 +314,9 @@ Handling Events
  423. To receive events from the SAM EC, an event notifier must be registered for
  424. the desired event via |ssam_notifier_register|. The notifier must be
  425. unregistered via |ssam_notifier_unregister| once it is not required any
  426. -more.
  427. +more. For |ssam_device| type clients, the |ssam_device_notifier_register| and
  428. +|ssam_device_notifier_unregister| wrappers should be preferred as they properly
  429. +handle hot-removal of client devices.
  430. Event notifiers are registered by providing (at minimum) a callback to call
  431. in case an event has been received, the registry specifying how the event
  432. diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
  433. index b8c377b3f932..6de834b52b63 100644
  434. --- a/drivers/platform/surface/aggregator/controller.c
  435. +++ b/drivers/platform/surface/aggregator/controller.c
  436. @@ -2199,16 +2199,26 @@ static int ssam_nf_refcount_enable(struct ssam_controller *ctrl,
  437. }
  438. /**
  439. - * ssam_nf_refcount_disable_free() - Disable event for reference count entry if it is
  440. - * no longer in use and free the corresponding entry.
  441. + * ssam_nf_refcount_disable_free() - Disable event for reference count entry if
  442. + * it is no longer in use and free the corresponding entry.
  443. * @ctrl: The controller to disable the event on.
  444. * @entry: The reference count entry for the event to be disabled.
  445. * @flags: The flags used for enabling the event on the EC.
  446. + * @ec: Flag specifying if the event should actually be disabled on the EC.
  447. *
  448. - * If the reference count equals zero, i.e. the event is no longer requested by
  449. - * any client, the event will be disabled and the corresponding reference count
  450. - * entry freed. The reference count entry must not be used any more after a
  451. - * call to this function.
  452. + * If ``ec`` equals ``true`` and the reference count equals zero (i.e. the
  453. + * event is no longer requested by any client), the specified event will be
  454. + * disabled on the EC via the corresponding request.
  455. + *
  456. + * If ``ec`` equals ``false``, no request will be sent to the EC and the event
  457. + * can be considered in a detached state (i.e. no longer used but still
  458. + * enabled). Disabling an event via this method may be required for
  459. + * hot-removable devices, where event disable requests may time out after the
  460. + * device has been physically removed.
  461. + *
  462. + * In both cases, if the reference count equals zero, the corresponding
  463. + * reference count entry will be freed. The reference count entry must not be
  464. + * used any more after a call to this function.
  465. *
  466. * Also checks if the flags used for disabling the event match the flags used
  467. * for enabling the event and warns if they do not (regardless of reference
  468. @@ -2223,7 +2233,7 @@ static int ssam_nf_refcount_enable(struct ssam_controller *ctrl,
  469. * returns the status of the event-enable EC command.
  470. */
  471. static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl,
  472. - struct ssam_nf_refcount_entry *entry, u8 flags)
  473. + struct ssam_nf_refcount_entry *entry, u8 flags, bool ec)
  474. {
  475. const struct ssam_event_registry reg = entry->key.reg;
  476. const struct ssam_event_id id = entry->key.id;
  477. @@ -2232,8 +2242,9 @@ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl,
  478. lockdep_assert_held(&nf->lock);
  479. - ssam_dbg(ctrl, "disabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n",
  480. - reg.target_category, id.target_category, id.instance, entry->refcount);
  481. + ssam_dbg(ctrl, "%s event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n",
  482. + ec ? "disabling" : "detaching", reg.target_category, id.target_category,
  483. + id.instance, entry->refcount);
  484. if (entry->flags != flags) {
  485. ssam_warn(ctrl,
  486. @@ -2242,7 +2253,7 @@ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl,
  487. id.instance);
  488. }
  489. - if (entry->refcount == 0) {
  490. + if (ec && entry->refcount == 0) {
  491. status = ssam_ssh_event_disable(ctrl, reg, id, flags);
  492. kfree(entry);
  493. }
  494. @@ -2322,20 +2333,26 @@ int ssam_notifier_register(struct ssam_controller *ctrl, struct ssam_event_notif
  495. EXPORT_SYMBOL_GPL(ssam_notifier_register);
  496. /**
  497. - * ssam_notifier_unregister() - Unregister an event notifier.
  498. - * @ctrl: The controller the notifier has been registered on.
  499. - * @n: The event notifier to unregister.
  500. + * __ssam_notifier_unregister() - Unregister an event notifier.
  501. + * @ctrl: The controller the notifier has been registered on.
  502. + * @n: The event notifier to unregister.
  503. + * @disable: Whether to disable the corresponding event on the EC.
  504. *
  505. * Unregister an event notifier. Decrement the usage counter of the associated
  506. * SAM event if the notifier is not marked as an observer. If the usage counter
  507. - * reaches zero, the event will be disabled.
  508. + * reaches zero and ``disable`` equals ``true``, the event will be disabled.
  509. + *
  510. + * Useful for hot-removable devices, where communication may fail once the
  511. + * device has been physically removed. In that case, specifying ``disable`` as
  512. + * ``false`` avoids communication with the EC.
  513. *
  514. * Return: Returns zero on success, %-ENOENT if the given notifier block has
  515. * not been registered on the controller. If the given notifier block was the
  516. * last one associated with its specific event, returns the status of the
  517. * event-disable EC-command.
  518. */
  519. -int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n)
  520. +int __ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n,
  521. + bool disable)
  522. {
  523. u16 rqid = ssh_tc_to_rqid(n->event.id.target_category);
  524. struct ssam_nf_refcount_entry *entry;
  525. @@ -2373,7 +2390,7 @@ int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_not
  526. goto remove;
  527. }
  528. - status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags);
  529. + status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags, disable);
  530. }
  531. remove:
  532. @@ -2383,7 +2400,7 @@ int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_not
  533. return status;
  534. }
  535. -EXPORT_SYMBOL_GPL(ssam_notifier_unregister);
  536. +EXPORT_SYMBOL_GPL(__ssam_notifier_unregister);
  537. /**
  538. * ssam_controller_event_enable() - Enable the specified event.
  539. @@ -2477,7 +2494,7 @@ int ssam_controller_event_disable(struct ssam_controller *ctrl,
  540. return -ENOENT;
  541. }
  542. - status = ssam_nf_refcount_disable_free(ctrl, entry, flags);
  543. + status = ssam_nf_refcount_disable_free(ctrl, entry, flags, true);
  544. mutex_unlock(&nf->lock);
  545. return status;
  546. diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h
  547. index 74bfdffaf7b0..50a2b4926c06 100644
  548. --- a/include/linux/surface_aggregator/controller.h
  549. +++ b/include/linux/surface_aggregator/controller.h
  550. @@ -835,8 +835,28 @@ struct ssam_event_notifier {
  551. int ssam_notifier_register(struct ssam_controller *ctrl,
  552. struct ssam_event_notifier *n);
  553. -int ssam_notifier_unregister(struct ssam_controller *ctrl,
  554. - struct ssam_event_notifier *n);
  555. +int __ssam_notifier_unregister(struct ssam_controller *ctrl,
  556. + struct ssam_event_notifier *n, bool disable);
  557. +
  558. +/**
  559. + * ssam_notifier_unregister() - Unregister an event notifier.
  560. + * @ctrl: The controller the notifier has been registered on.
  561. + * @n: The event notifier to unregister.
  562. + *
  563. + * Unregister an event notifier. Decrement the usage counter of the associated
  564. + * SAM event if the notifier is not marked as an observer. If the usage counter
  565. + * reaches zero, the event will be disabled.
  566. + *
  567. + * Return: Returns zero on success, %-ENOENT if the given notifier block has
  568. + * not been registered on the controller. If the given notifier block was the
  569. + * last one associated with its specific event, returns the status of the
  570. + * event-disable EC-command.
  571. + */
  572. +static inline int ssam_notifier_unregister(struct ssam_controller *ctrl,
  573. + struct ssam_event_notifier *n)
  574. +{
  575. + return __ssam_notifier_unregister(ctrl, n, true);
  576. +}
  577. int ssam_controller_event_enable(struct ssam_controller *ctrl,
  578. struct ssam_event_registry reg,
  579. diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
  580. index 491aa7e9f4bc..16816c34da3e 100644
  581. --- a/include/linux/surface_aggregator/device.h
  582. +++ b/include/linux/surface_aggregator/device.h
  583. @@ -472,4 +472,64 @@ static inline void ssam_remove_clients(struct device *dev) {}
  584. sdev->uid.instance, ret); \
  585. }
  586. +
  587. +/* -- Helpers for client-device notifiers. ---------------------------------- */
  588. +
  589. +/**
  590. + * ssam_device_notifier_register() - Register an event notifier for the
  591. + * specified client device.
  592. + * @sdev: The device the notifier should be registered on.
  593. + * @n: The event notifier to register.
  594. + *
  595. + * Register an event notifier. Increment the usage counter of the associated
  596. + * SAM event if the notifier is not marked as an observer. If the event is not
  597. + * marked as an observer and is currently not enabled, it will be enabled
  598. + * during this call. If the notifier is marked as an observer, no attempt will
  599. + * be made at enabling any event and no reference count will be modified.
  600. + *
  601. + * Notifiers marked as observers do not need to be associated with one specific
  602. + * event, i.e. as long as no event matching is performed, only the event target
  603. + * category needs to be set.
  604. + *
  605. + * Return: Returns zero on success, %-ENOSPC if there have already been
  606. + * %INT_MAX notifiers for the event ID/type associated with the notifier block
  607. + * registered, %-ENOMEM if the corresponding event entry could not be
  608. + * allocated, %-ENODEV if the device is marked as hot-removed. If this is the
  609. + * first time that a notifier block is registered for the specific associated
  610. + * event, returns the status of the event-enable EC-command.
  611. + */
  612. +static inline int ssam_device_notifier_register(struct ssam_device *sdev,
  613. + struct ssam_event_notifier *n)
  614. +{
  615. + if (ssam_device_is_hot_removed(sdev))
  616. + return -ENODEV;
  617. +
  618. + return ssam_notifier_register(sdev->ctrl, n);
  619. +}
  620. +
  621. +/**
  622. + * ssam_device_notifier_unregister() - Unregister an event notifier for the
  623. + * specified client device.
  624. + * @sdev: The device the notifier has been registered on.
  625. + * @n: The event notifier to unregister.
  626. + *
  627. + * Unregister an event notifier. Decrement the usage counter of the associated
  628. + * SAM event if the notifier is not marked as an observer. If the usage counter
  629. + * reaches zero, the event will be disabled.
  630. + *
  631. + * In case the device has been marked as hot-removed, the event will not be
  632. + * disabled on the EC, as in those cases any attempt at doing so may time out.
  633. + *
  634. + * Return: Returns zero on success, %-ENOENT if the given notifier block has
  635. + * not been registered on the controller. If the given notifier block was the
  636. + * last one associated with its specific event, returns the status of the
  637. + * event-disable EC-command.
  638. + */
  639. +static inline int ssam_device_notifier_unregister(struct ssam_device *sdev,
  640. + struct ssam_event_notifier *n)
  641. +{
  642. + return __ssam_notifier_unregister(sdev->ctrl, n,
  643. + !ssam_device_is_hot_removed(sdev));
  644. +}
  645. +
  646. #endif /* _LINUX_SURFACE_AGGREGATOR_DEVICE_H */
  647. --
  648. 2.34.0
  649. From fe2e44cf86dee61dc84b56f76d432e8b87c2710a Mon Sep 17 00:00:00 2001
  650. From: Maximilian Luz <luzmaximilian@gmail.com>
  651. Date: Tue, 8 Jun 2021 01:20:49 +0200
  652. Subject: [PATCH] platform/surface: aggregator_registry: Use client device
  653. wrappers for notifier registration
  654. Use newly introduced client device wrapper functions for notifier
  655. registration and unregistration.
  656. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  657. Patchset: surface-sam
  658. ---
  659. drivers/platform/surface/surface_aggregator_registry.c | 6 +++---
  660. 1 file changed, 3 insertions(+), 3 deletions(-)
  661. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  662. index ce2bd88feeaa..9f630e890ff7 100644
  663. --- a/drivers/platform/surface/surface_aggregator_registry.c
  664. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  665. @@ -468,7 +468,7 @@ static int ssam_base_hub_probe(struct ssam_device *sdev)
  666. ssam_device_set_drvdata(sdev, hub);
  667. - status = ssam_notifier_register(sdev->ctrl, &hub->notif);
  668. + status = ssam_device_notifier_register(sdev, &hub->notif);
  669. if (status)
  670. return status;
  671. @@ -480,7 +480,7 @@ static int ssam_base_hub_probe(struct ssam_device *sdev)
  672. return 0;
  673. err:
  674. - ssam_notifier_unregister(sdev->ctrl, &hub->notif);
  675. + ssam_device_notifier_unregister(sdev, &hub->notif);
  676. cancel_delayed_work_sync(&hub->update_work);
  677. ssam_remove_clients(&sdev->dev);
  678. return status;
  679. @@ -492,7 +492,7 @@ static void ssam_base_hub_remove(struct ssam_device *sdev)
  680. sysfs_remove_group(&sdev->dev.kobj, &ssam_base_hub_group);
  681. - ssam_notifier_unregister(sdev->ctrl, &hub->notif);
  682. + ssam_device_notifier_unregister(sdev, &hub->notif);
  683. cancel_delayed_work_sync(&hub->update_work);
  684. ssam_remove_clients(&sdev->dev);
  685. }
  686. --
  687. 2.34.0
  688. From 05ded3f8005f37297e5c47821d43c24dc243250c Mon Sep 17 00:00:00 2001
  689. From: Maximilian Luz <luzmaximilian@gmail.com>
  690. Date: Thu, 28 Oct 2021 03:37:06 +0200
  691. Subject: [PATCH] power/supply: surface_charger: Use client device wrappers for
  692. notifier registration
  693. Use newly introduced client device wrapper functions for notifier
  694. registration and unregistration.
  695. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  696. Patchset: surface-sam
  697. ---
  698. drivers/power/supply/surface_charger.c | 4 ++--
  699. 1 file changed, 2 insertions(+), 2 deletions(-)
  700. diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c
  701. index a060c36c7766..59182d55742d 100644
  702. --- a/drivers/power/supply/surface_charger.c
  703. +++ b/drivers/power/supply/surface_charger.c
  704. @@ -216,7 +216,7 @@ static int spwr_ac_register(struct spwr_ac_device *ac)
  705. if (IS_ERR(ac->psy))
  706. return PTR_ERR(ac->psy);
  707. - return ssam_notifier_register(ac->sdev->ctrl, &ac->notif);
  708. + return ssam_device_notifier_register(ac->sdev, &ac->notif);
  709. }
  710. @@ -251,7 +251,7 @@ static void surface_ac_remove(struct ssam_device *sdev)
  711. {
  712. struct spwr_ac_device *ac = ssam_device_get_drvdata(sdev);
  713. - ssam_notifier_unregister(sdev->ctrl, &ac->notif);
  714. + ssam_device_notifier_unregister(sdev, &ac->notif);
  715. }
  716. static const struct spwr_psy_properties spwr_psy_props_adp1 = {
  717. --
  718. 2.34.0
  719. From 18b5e32f9cf968307c604677143eea7dec7a8533 Mon Sep 17 00:00:00 2001
  720. From: Maximilian Luz <luzmaximilian@gmail.com>
  721. Date: Thu, 28 Oct 2021 03:38:09 +0200
  722. Subject: [PATCH] power/supply: surface_battery: Use client device wrappers for
  723. notifier registration
  724. Use newly introduced client device wrapper functions for notifier
  725. registration and unregistration.
  726. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  727. Patchset: surface-sam
  728. ---
  729. drivers/power/supply/surface_battery.c | 4 ++--
  730. 1 file changed, 2 insertions(+), 2 deletions(-)
  731. diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c
  732. index 5ec2e6bb2465..540707882bb0 100644
  733. --- a/drivers/power/supply/surface_battery.c
  734. +++ b/drivers/power/supply/surface_battery.c
  735. @@ -802,7 +802,7 @@ static int spwr_battery_register(struct spwr_battery_device *bat)
  736. if (IS_ERR(bat->psy))
  737. return PTR_ERR(bat->psy);
  738. - return ssam_notifier_register(bat->sdev->ctrl, &bat->notif);
  739. + return ssam_device_notifier_register(bat->sdev, &bat->notif);
  740. }
  741. @@ -837,7 +837,7 @@ static void surface_battery_remove(struct ssam_device *sdev)
  742. {
  743. struct spwr_battery_device *bat = ssam_device_get_drvdata(sdev);
  744. - ssam_notifier_unregister(sdev->ctrl, &bat->notif);
  745. + ssam_device_notifier_unregister(sdev, &bat->notif);
  746. cancel_delayed_work_sync(&bat->update_work);
  747. }
  748. --
  749. 2.34.0
  750. From 43c9f03affd1b3e0ecf04a370efe3ffa463a26c9 Mon Sep 17 00:00:00 2001
  751. From: Maximilian Luz <luzmaximilian@gmail.com>
  752. Date: Tue, 8 Jun 2021 01:33:02 +0200
  753. Subject: [PATCH] HID: surface-hid: Add support for hot-removal
  754. Add support for hot-removal of SSAM HID client devices.
  755. Once a device has been hot-removed, further communication with it should
  756. be avoided as it may fail and time out. While the device will be removed
  757. as soon as we detect hot-removal, communication may still occur during
  758. teardown, especially when unregistering notifiers.
  759. While hot-removal is a surprise event that can happen any time, try to
  760. avoid communication as much as possible once it has been detected to
  761. prevent timeouts that can slow down device removal and cause issues,
  762. e.g. when quickly re-attaching the device.
  763. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  764. Patchset: surface-sam
  765. ---
  766. drivers/hid/surface-hid/surface_hid_core.c | 38 +++++++++++++++++++++-
  767. 1 file changed, 37 insertions(+), 1 deletion(-)
  768. diff --git a/drivers/hid/surface-hid/surface_hid_core.c b/drivers/hid/surface-hid/surface_hid_core.c
  769. index 5571e74abe91..d2e695e942b6 100644
  770. --- a/drivers/hid/surface-hid/surface_hid_core.c
  771. +++ b/drivers/hid/surface-hid/surface_hid_core.c
  772. @@ -19,12 +19,30 @@
  773. #include "surface_hid_core.h"
  774. +/* -- Utility functions. ---------------------------------------------------- */
  775. +
  776. +static bool surface_hid_is_hot_removed(struct surface_hid_device *shid)
  777. +{
  778. + /*
  779. + * Non-ssam client devices, i.e. platform client devices, cannot be
  780. + * hot-removed.
  781. + */
  782. + if (!is_ssam_device(shid->dev))
  783. + return false;
  784. +
  785. + return ssam_device_is_hot_removed(to_ssam_device(shid->dev));
  786. +}
  787. +
  788. +
  789. /* -- Device descriptor access. --------------------------------------------- */
  790. static int surface_hid_load_hid_descriptor(struct surface_hid_device *shid)
  791. {
  792. int status;
  793. + if (surface_hid_is_hot_removed(shid))
  794. + return -ENODEV;
  795. +
  796. status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_HID,
  797. (u8 *)&shid->hid_desc, sizeof(shid->hid_desc));
  798. if (status)
  799. @@ -61,6 +79,9 @@ static int surface_hid_load_device_attributes(struct surface_hid_device *shid)
  800. {
  801. int status;
  802. + if (surface_hid_is_hot_removed(shid))
  803. + return -ENODEV;
  804. +
  805. status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_ATTRS,
  806. (u8 *)&shid->attrs, sizeof(shid->attrs));
  807. if (status)
  808. @@ -88,9 +109,18 @@ static int surface_hid_start(struct hid_device *hid)
  809. static void surface_hid_stop(struct hid_device *hid)
  810. {
  811. struct surface_hid_device *shid = hid->driver_data;
  812. + bool hot_removed;
  813. +
  814. + /*
  815. + * Communication may fail for devices that have been hot-removed. This
  816. + * also includes unregistration of HID events, so we need to check this
  817. + * here. Only if the device has not been marked as hot-removed, we can
  818. + * safely disable events.
  819. + */
  820. + hot_removed = surface_hid_is_hot_removed(shid);
  821. /* Note: This call will log errors for us, so ignore them here. */
  822. - ssam_notifier_unregister(shid->ctrl, &shid->notif);
  823. + __ssam_notifier_unregister(shid->ctrl, &shid->notif, !hot_removed);
  824. }
  825. static int surface_hid_open(struct hid_device *hid)
  826. @@ -109,6 +139,9 @@ static int surface_hid_parse(struct hid_device *hid)
  827. u8 *buf;
  828. int status;
  829. + if (surface_hid_is_hot_removed(shid))
  830. + return -ENODEV;
  831. +
  832. buf = kzalloc(len, GFP_KERNEL);
  833. if (!buf)
  834. return -ENOMEM;
  835. @@ -126,6 +159,9 @@ static int surface_hid_raw_request(struct hid_device *hid, unsigned char reportn
  836. {
  837. struct surface_hid_device *shid = hid->driver_data;
  838. + if (surface_hid_is_hot_removed(shid))
  839. + return -ENODEV;
  840. +
  841. if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT)
  842. return shid->ops.output_report(shid, reportnum, buf, len);
  843. --
  844. 2.34.0
  845. From 4b49b3f485689ddf1e9fbb4280c7ab4a8eb405ff Mon Sep 17 00:00:00 2001
  846. From: Maximilian Luz <luzmaximilian@gmail.com>
  847. Date: Sun, 31 Oct 2021 12:34:08 +0100
  848. Subject: [PATCH] platform/surface: aggregator: Add comment for KIP subsystem
  849. category
  850. The KIP subsystem (full name unknown, abbreviation has been obtained
  851. through reverse engineering) handles detachable peripherals such as the
  852. keyboard cover on the Surface Pro X and Surface Pro 8.
  853. It is currently not entirely clear what this subsystem entails, but at
  854. the very least it provides event notifications for when the keyboard
  855. cover on the Surface Pro X and Surface Pro 8 have been detached or
  856. re-attached, as well as the state that the keyboard cover is currently
  857. in (e.g. folded-back, folded laptop-like, closed, etc.).
  858. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  859. Patchset: surface-sam
  860. ---
  861. include/linux/surface_aggregator/serial_hub.h | 2 +-
  862. 1 file changed, 1 insertion(+), 1 deletion(-)
  863. diff --git a/include/linux/surface_aggregator/serial_hub.h b/include/linux/surface_aggregator/serial_hub.h
  864. index c3de43edcffa..d1efac85caf1 100644
  865. --- a/include/linux/surface_aggregator/serial_hub.h
  866. +++ b/include/linux/surface_aggregator/serial_hub.h
  867. @@ -306,7 +306,7 @@ enum ssam_ssh_tc {
  868. SSAM_SSH_TC_LPC = 0x0b,
  869. SSAM_SSH_TC_TCL = 0x0c,
  870. SSAM_SSH_TC_SFL = 0x0d,
  871. - SSAM_SSH_TC_KIP = 0x0e,
  872. + SSAM_SSH_TC_KIP = 0x0e, /* Manages detachable peripherals (Pro X/8 keyboard cover) */
  873. SSAM_SSH_TC_EXT = 0x0f,
  874. SSAM_SSH_TC_BLD = 0x10,
  875. SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */
  876. --
  877. 2.34.0
  878. From e0933caec88e7140b057a8ce85a21b9797fd567c Mon Sep 17 00:00:00 2001
  879. From: Maximilian Luz <luzmaximilian@gmail.com>
  880. Date: Sun, 10 Oct 2021 23:56:23 +0200
  881. Subject: [PATCH] platform/surface: aggregator_registry: Add KIP device hub
  882. Add a Surface System Aggregator Module (SSAM) client device hub for
  883. hot-removable devices managed via the KIP subsystem.
  884. The KIP subsystem (full name unknown, abbreviation has been obtained
  885. through reverse engineering) is a subsystem that manages hot-removable
  886. SSAM client devices. Specifically, it manages HID input devices
  887. contained in the detachable keyboard cover of the Surface Pro 8 and
  888. Surface Pro X.
  889. To properly handle detachable devices, we need to remove their kernel
  890. representation when the physical device has been detached and (re-)add
  891. and (re-)initialize said representation when the physical device has
  892. been (re-)attached. Note that we need to hot-remove those devices, as
  893. communication (especially during event notifier unregistration) may time
  894. out when the physical device is no longer present, which would lead to
  895. an unnecessary delay. This delay might become problematic when devices
  896. are detached and re-attached quickly.
  897. The KIP subsystem handles a single group of devices (e.g. all devices
  898. contained in the keyboard cover) and cannot handle devices individually.
  899. Thus we model it as a client device hub, which removes all devices
  900. contained under it once removal of the hub (e.g. keyboard cover) has
  901. been detected and (re-)adds all devices once the physical hub device has
  902. been (re-)attached.
  903. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  904. Patchset: surface-sam
  905. ---
  906. .../surface/surface_aggregator_registry.c | 247 +++++++++++++++++-
  907. 1 file changed, 245 insertions(+), 2 deletions(-)
  908. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  909. index 9f630e890ff7..4838ce6519a6 100644
  910. --- a/drivers/platform/surface/surface_aggregator_registry.c
  911. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  912. @@ -514,6 +514,237 @@ static struct ssam_device_driver ssam_base_hub_driver = {
  913. };
  914. +/* -- SSAM KIP-subsystem hub driver. ---------------------------------------- */
  915. +
  916. +/*
  917. + * Some devices may need a bit of time to be fully usable after being
  918. + * (re-)connected. This delay has been determined via experimentation.
  919. + */
  920. +#define SSAM_KIP_UPDATE_CONNECT_DELAY msecs_to_jiffies(250)
  921. +
  922. +#define SSAM_EVENT_KIP_CID_CONNECTION 0x2c
  923. +
  924. +enum ssam_kip_hub_state {
  925. + SSAM_KIP_HUB_UNINITIALIZED,
  926. + SSAM_KIP_HUB_CONNECTED,
  927. + SSAM_KIP_HUB_DISCONNECTED,
  928. +};
  929. +
  930. +struct ssam_kip_hub {
  931. + struct ssam_device *sdev;
  932. +
  933. + enum ssam_kip_hub_state state;
  934. + struct delayed_work update_work;
  935. +
  936. + struct ssam_event_notifier notif;
  937. +};
  938. +
  939. +SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_connection_state, u8, {
  940. + .target_category = SSAM_SSH_TC_KIP,
  941. + .target_id = 0x01,
  942. + .command_id = 0x2c,
  943. + .instance_id = 0x00,
  944. +});
  945. +
  946. +static int ssam_kip_get_connection_state(struct ssam_kip_hub *hub, enum ssam_kip_hub_state *state)
  947. +{
  948. + int status;
  949. + u8 connected;
  950. +
  951. + status = ssam_retry(__ssam_kip_get_connection_state, hub->sdev->ctrl, &connected);
  952. + if (status < 0) {
  953. + dev_err(&hub->sdev->dev, "failed to query KIP connection state: %d\n", status);
  954. + return status;
  955. + }
  956. +
  957. + *state = connected ? SSAM_KIP_HUB_CONNECTED : SSAM_KIP_HUB_DISCONNECTED;
  958. + return 0;
  959. +}
  960. +
  961. +static ssize_t ssam_kip_hub_state_show(struct device *dev, struct device_attribute *attr, char *buf)
  962. +{
  963. + struct ssam_kip_hub *hub = dev_get_drvdata(dev);
  964. + const char *state;
  965. +
  966. + switch (hub->state) {
  967. + case SSAM_KIP_HUB_UNINITIALIZED:
  968. + state = "uninitialized";
  969. + break;
  970. +
  971. + case SSAM_KIP_HUB_CONNECTED:
  972. + state = "connected";
  973. + break;
  974. +
  975. + case SSAM_KIP_HUB_DISCONNECTED:
  976. + state = "disconnected";
  977. + break;
  978. +
  979. + default:
  980. + /*
  981. + * Any value not handled in the above cases is invalid and
  982. + * should never have been set. Thus this case should be
  983. + * impossible to reach.
  984. + */
  985. + WARN(1, "invalid KIP hub state: %d\n", hub->state);
  986. + state = "<invalid>";
  987. + break;
  988. + }
  989. +
  990. + return sysfs_emit(buf, "%s\n", state);
  991. +}
  992. +
  993. +static struct device_attribute ssam_kip_hub_attr_state =
  994. + __ATTR(state, 0444, ssam_kip_hub_state_show, NULL);
  995. +
  996. +static struct attribute *ssam_kip_hub_attrs[] = {
  997. + &ssam_kip_hub_attr_state.attr,
  998. + NULL,
  999. +};
  1000. +
  1001. +static const struct attribute_group ssam_kip_hub_group = {
  1002. + .attrs = ssam_kip_hub_attrs,
  1003. +};
  1004. +
  1005. +static int ssam_kip_hub_mark_hot_removed(struct device *dev, void *_data)
  1006. +{
  1007. + struct ssam_device *sdev = to_ssam_device(dev);
  1008. +
  1009. + if (is_ssam_device(dev))
  1010. + ssam_device_mark_hot_removed(sdev);
  1011. +
  1012. + return 0;
  1013. +}
  1014. +
  1015. +static void ssam_kip_hub_update_workfn(struct work_struct *work)
  1016. +{
  1017. + struct ssam_kip_hub *hub = container_of(work, struct ssam_kip_hub, update_work.work);
  1018. + struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev);
  1019. + enum ssam_kip_hub_state state;
  1020. + int status = 0;
  1021. +
  1022. + status = ssam_kip_get_connection_state(hub, &state);
  1023. + if (status)
  1024. + return;
  1025. +
  1026. + if (hub->state == state)
  1027. + return;
  1028. + hub->state = state;
  1029. +
  1030. + if (hub->state == SSAM_KIP_HUB_CONNECTED)
  1031. + status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node);
  1032. + else
  1033. + ssam_remove_clients(&hub->sdev->dev);
  1034. +
  1035. + if (status)
  1036. + dev_err(&hub->sdev->dev, "failed to update KIP-hub devices: %d\n", status);
  1037. +}
  1038. +
  1039. +static u32 ssam_kip_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
  1040. +{
  1041. + struct ssam_kip_hub *hub = container_of(nf, struct ssam_kip_hub, notif);
  1042. + unsigned long delay;
  1043. +
  1044. + if (event->command_id != SSAM_EVENT_KIP_CID_CONNECTION)
  1045. + return 0; /* Return "unhandled". */
  1046. +
  1047. + if (event->length < 1) {
  1048. + dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length);
  1049. + return 0;
  1050. + }
  1051. +
  1052. + /* Mark devices as hot-removed before we remove any */
  1053. + if (!event->data[0])
  1054. + device_for_each_child_reverse(&hub->sdev->dev, NULL, ssam_kip_hub_mark_hot_removed);
  1055. +
  1056. + /*
  1057. + * Delay update when KIP devices are being connected to give devices/EC
  1058. + * some time to set up.
  1059. + */
  1060. + delay = event->data[0] ? SSAM_KIP_UPDATE_CONNECT_DELAY : 0;
  1061. +
  1062. + schedule_delayed_work(&hub->update_work, delay);
  1063. + return SSAM_NOTIF_HANDLED;
  1064. +}
  1065. +
  1066. +static int __maybe_unused ssam_kip_hub_resume(struct device *dev)
  1067. +{
  1068. + struct ssam_kip_hub *hub = dev_get_drvdata(dev);
  1069. +
  1070. + schedule_delayed_work(&hub->update_work, 0);
  1071. + return 0;
  1072. +}
  1073. +static SIMPLE_DEV_PM_OPS(ssam_kip_hub_pm_ops, NULL, ssam_kip_hub_resume);
  1074. +
  1075. +static int ssam_kip_hub_probe(struct ssam_device *sdev)
  1076. +{
  1077. + struct ssam_kip_hub *hub;
  1078. + int status;
  1079. +
  1080. + hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL);
  1081. + if (!hub)
  1082. + return -ENOMEM;
  1083. +
  1084. + hub->sdev = sdev;
  1085. + hub->state = SSAM_KIP_HUB_UNINITIALIZED;
  1086. +
  1087. + hub->notif.base.priority = INT_MAX; /* This notifier should run first. */
  1088. + hub->notif.base.fn = ssam_kip_hub_notif;
  1089. + hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM;
  1090. + hub->notif.event.id.target_category = SSAM_SSH_TC_KIP,
  1091. + hub->notif.event.id.instance = 0,
  1092. + hub->notif.event.mask = SSAM_EVENT_MASK_TARGET;
  1093. + hub->notif.event.flags = SSAM_EVENT_SEQUENCED;
  1094. +
  1095. + INIT_DELAYED_WORK(&hub->update_work, ssam_kip_hub_update_workfn);
  1096. +
  1097. + ssam_device_set_drvdata(sdev, hub);
  1098. +
  1099. + status = ssam_device_notifier_register(sdev, &hub->notif);
  1100. + if (status)
  1101. + return status;
  1102. +
  1103. + status = sysfs_create_group(&sdev->dev.kobj, &ssam_kip_hub_group);
  1104. + if (status)
  1105. + goto err;
  1106. +
  1107. + schedule_delayed_work(&hub->update_work, 0);
  1108. + return 0;
  1109. +
  1110. +err:
  1111. + ssam_device_notifier_unregister(sdev, &hub->notif);
  1112. + cancel_delayed_work_sync(&hub->update_work);
  1113. + ssam_remove_clients(&sdev->dev);
  1114. + return status;
  1115. +}
  1116. +
  1117. +static void ssam_kip_hub_remove(struct ssam_device *sdev)
  1118. +{
  1119. + struct ssam_kip_hub *hub = ssam_device_get_drvdata(sdev);
  1120. +
  1121. + sysfs_remove_group(&sdev->dev.kobj, &ssam_kip_hub_group);
  1122. +
  1123. + ssam_device_notifier_unregister(sdev, &hub->notif);
  1124. + cancel_delayed_work_sync(&hub->update_work);
  1125. + ssam_remove_clients(&sdev->dev);
  1126. +}
  1127. +
  1128. +static const struct ssam_device_id ssam_kip_hub_match[] = {
  1129. + { SSAM_SDEV(KIP, 0x01, 0x00, 0x00) },
  1130. + { },
  1131. +};
  1132. +
  1133. +static struct ssam_device_driver ssam_kip_hub_driver = {
  1134. + .probe = ssam_kip_hub_probe,
  1135. + .remove = ssam_kip_hub_remove,
  1136. + .match_table = ssam_kip_hub_match,
  1137. + .driver = {
  1138. + .name = "surface_kip_hub",
  1139. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  1140. + .pm = &ssam_kip_hub_pm_ops,
  1141. + },
  1142. +};
  1143. +
  1144. +
  1145. /* -- SSAM platform/meta-hub driver. ---------------------------------------- */
  1146. static const struct acpi_device_id ssam_platform_hub_match[] = {
  1147. @@ -636,18 +867,30 @@ static int __init ssam_device_hub_init(void)
  1148. status = platform_driver_register(&ssam_platform_hub_driver);
  1149. if (status)
  1150. - return status;
  1151. + goto err_platform;
  1152. status = ssam_device_driver_register(&ssam_base_hub_driver);
  1153. if (status)
  1154. - platform_driver_unregister(&ssam_platform_hub_driver);
  1155. + goto err_base;
  1156. +
  1157. + status = ssam_device_driver_register(&ssam_kip_hub_driver);
  1158. + if (status)
  1159. + goto err_kip;
  1160. + return 0;
  1161. +
  1162. +err_kip:
  1163. + ssam_device_driver_unregister(&ssam_base_hub_driver);
  1164. +err_base:
  1165. + platform_driver_unregister(&ssam_platform_hub_driver);
  1166. +err_platform:
  1167. return status;
  1168. }
  1169. module_init(ssam_device_hub_init);
  1170. static void __exit ssam_device_hub_exit(void)
  1171. {
  1172. + ssam_device_driver_unregister(&ssam_kip_hub_driver);
  1173. ssam_device_driver_unregister(&ssam_base_hub_driver);
  1174. platform_driver_unregister(&ssam_platform_hub_driver);
  1175. }
  1176. --
  1177. 2.34.0
  1178. From 0fc4fd278cac0d5f3274656187d706f75ef48008 Mon Sep 17 00:00:00 2001
  1179. From: Maximilian Luz <luzmaximilian@gmail.com>
  1180. Date: Wed, 27 Oct 2021 22:33:03 +0200
  1181. Subject: [PATCH] platform/surface: aggregator_registry: Add support for
  1182. keyboard cover on Surface Pro 8
  1183. Add support for the detachable keyboard cover on the Surface Pro 8.
  1184. The keyboard cover on the Surface Pro 8 is, unlike the keyboard covers
  1185. of earlier Surface Pro generations, handled via the Surface System
  1186. Aggregator Module (SSAM). The keyboard and touchpad (as well as other
  1187. HID input devices) of this cover are standard SSAM HID client devices
  1188. (just like keyboard and touchpad on e.g. the Surface Laptop 3 and 4),
  1189. however, some care needs to be taken as they can be physically detached
  1190. (similarly to the Surface Book 3). Specifically, the respective SSAM
  1191. client devices need to be removed when the keyboard cover has been
  1192. detached and (re-)initialized when the keyboard cover has been
  1193. (re-)attached.
  1194. On the Surface Pro 8, detachment of the keyboard cover (and by extension
  1195. its devices) is managed via the KIP subsystem. Therefore, said devices
  1196. need to be registered under the KIP device hub, which in turn will
  1197. remove and re-create/re-initialize those devices as needed.
  1198. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  1199. Patchset: surface-sam
  1200. ---
  1201. .../surface/surface_aggregator_registry.c | 37 ++++++++++++++++++-
  1202. 1 file changed, 36 insertions(+), 1 deletion(-)
  1203. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  1204. index 4838ce6519a6..c0e29c0514df 100644
  1205. --- a/drivers/platform/surface/surface_aggregator_registry.c
  1206. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  1207. @@ -47,6 +47,12 @@ static const struct software_node ssam_node_hub_base = {
  1208. .parent = &ssam_node_root,
  1209. };
  1210. +/* KIP device hub (connects keyboard cover devices on Surface Pro 8). */
  1211. +static const struct software_node ssam_node_hub_kip = {
  1212. + .name = "ssam:01:0e:01:00:00",
  1213. + .parent = &ssam_node_root,
  1214. +};
  1215. +
  1216. /* AC adapter. */
  1217. static const struct software_node ssam_node_bat_ac = {
  1218. .name = "ssam:01:02:01:01:01",
  1219. @@ -155,6 +161,30 @@ static const struct software_node ssam_node_hid_base_iid6 = {
  1220. .parent = &ssam_node_hub_base,
  1221. };
  1222. +/* HID keyboard (KIP hub). */
  1223. +static const struct software_node ssam_node_hid_kip_keyboard = {
  1224. + .name = "ssam:01:15:02:01:00",
  1225. + .parent = &ssam_node_hub_kip,
  1226. +};
  1227. +
  1228. +/* HID pen stash (KIP hub; pen taken / stashed away evens). */
  1229. +static const struct software_node ssam_node_hid_kip_penstash = {
  1230. + .name = "ssam:01:15:02:02:00",
  1231. + .parent = &ssam_node_hub_kip,
  1232. +};
  1233. +
  1234. +/* HID touchpad (KIP hub). */
  1235. +static const struct software_node ssam_node_hid_kip_touchpad = {
  1236. + .name = "ssam:01:15:02:03:00",
  1237. + .parent = &ssam_node_hub_kip,
  1238. +};
  1239. +
  1240. +/* HID device instance 5 (KIP hub, unknown HID device). */
  1241. +static const struct software_node ssam_node_hid_kip_iid5 = {
  1242. + .name = "ssam:01:15:02:05:00",
  1243. + .parent = &ssam_node_hub_kip,
  1244. +};
  1245. +
  1246. /*
  1247. * Devices for 5th- and 6th-generations models:
  1248. * - Surface Book 2,
  1249. @@ -230,10 +260,15 @@ static const struct software_node *ssam_node_group_sp7[] = {
  1250. static const struct software_node *ssam_node_group_sp8[] = {
  1251. &ssam_node_root,
  1252. + &ssam_node_hub_kip,
  1253. &ssam_node_bat_ac,
  1254. &ssam_node_bat_main,
  1255. &ssam_node_tmp_pprof,
  1256. - /* TODO: Add support for keyboard cover. */
  1257. + &ssam_node_hid_kip_keyboard,
  1258. + &ssam_node_hid_kip_penstash,
  1259. + &ssam_node_hid_kip_touchpad,
  1260. + &ssam_node_hid_kip_iid5,
  1261. + /* TODO: Add support for tablet mode switch. */
  1262. NULL,
  1263. };
  1264. --
  1265. 2.34.0
  1266. From 50b107f14ef9e33f8510d726630138f69f2cf480 Mon Sep 17 00:00:00 2001
  1267. From: Maximilian Luz <luzmaximilian@gmail.com>
  1268. Date: Tue, 8 Jun 2021 03:19:20 +0200
  1269. Subject: [PATCH] platform/surface: Add KIP tablet-mode switch
  1270. Add a driver providing a tablet-mode switch input device for Surface
  1271. models using the KIP subsystem to manage detachable peripherals.
  1272. The Surface Pro 8 has a detachable keyboard cover. Unlike the keyboard
  1273. covers of previous generation Surface Pro models, this cover is fully
  1274. handled by the Surface System Aggregator Module (SSAM). The SSAM KIP
  1275. subsystem (full name unknown, abbreviation found through reverse
  1276. engineering) provides notifications for mode changes of the cover.
  1277. Specifically, it allows us to know when the cover has been folded back,
  1278. detached, or whether it is in laptop mode.
  1279. The driver introduced with this change captures these events and
  1280. translates them to standard SW_TABLET_MODE input events.
  1281. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  1282. Patchset: surface-sam
  1283. ---
  1284. MAINTAINERS | 6 +
  1285. drivers/platform/surface/Kconfig | 22 ++
  1286. drivers/platform/surface/Makefile | 1 +
  1287. .../surface/surface_kip_tablet_switch.c | 245 ++++++++++++++++++
  1288. 4 files changed, 274 insertions(+)
  1289. create mode 100644 drivers/platform/surface/surface_kip_tablet_switch.c
  1290. diff --git a/MAINTAINERS b/MAINTAINERS
  1291. index d7b4f32875a9..5713585d060d 100644
  1292. --- a/MAINTAINERS
  1293. +++ b/MAINTAINERS
  1294. @@ -12357,6 +12357,12 @@ L: platform-driver-x86@vger.kernel.org
  1295. S: Maintained
  1296. F: drivers/platform/surface/surface_hotplug.c
  1297. +MICROSOFT SURFACE KIP TABLET-MODE SWITCH
  1298. +M: Maximilian Luz <luzmaximilian@gmail.com>
  1299. +L: platform-driver-x86@vger.kernel.org
  1300. +S: Maintained
  1301. +F: drivers/platform/surface/surface_kip_tablet_switch.c
  1302. +
  1303. MICROSOFT SURFACE PLATFORM PROFILE DRIVER
  1304. M: Maximilian Luz <luzmaximilian@gmail.com>
  1305. L: platform-driver-x86@vger.kernel.org
  1306. diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
  1307. index 3105f651614f..3c0ee0cdaef5 100644
  1308. --- a/drivers/platform/surface/Kconfig
  1309. +++ b/drivers/platform/surface/Kconfig
  1310. @@ -152,6 +152,28 @@ config SURFACE_HOTPLUG
  1311. Select M or Y here, if you want to (fully) support hot-plugging of
  1312. dGPU devices on the Surface Book 2 and/or 3 during D3cold.
  1313. +config SURFACE_KIP_TABLET_SWITCH
  1314. + tristate "Surface KIP Tablet-Mode Switch Driver"
  1315. + depends on SURFACE_AGGREGATOR
  1316. + depends on SURFACE_AGGREGATOR_BUS
  1317. + depends on INPUT
  1318. + help
  1319. + Provides a tablet-mode switch input device on Microsoft Surface models
  1320. + using the KIP subsystem for detachable keyboards (e.g. keyboard
  1321. + covers).
  1322. +
  1323. + The KIP subsystem is used on newer Surface generations to handle
  1324. + detachable input peripherals, specifically the keyboard cover
  1325. + (containing keyboard and touchpad) on the Surface Pro 8. This module
  1326. + provides a driver to let user-space know when the device should be
  1327. + considered in tablet-mode due to the keyboard cover being detached or
  1328. + folded back (essentially signaling when the keyboard is not available
  1329. + for input). It does so by creating a tablet-mode switch input device,
  1330. + sending the standard SW_TABLET_MODE event on mode change.
  1331. +
  1332. + Select M or Y here, if you want to provide tablet-mode switch input
  1333. + events on the Surface Pro 8.
  1334. +
  1335. config SURFACE_PLATFORM_PROFILE
  1336. tristate "Surface Platform Profile Driver"
  1337. depends on SURFACE_AGGREGATOR_REGISTRY
  1338. diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
  1339. index 32889482de55..6d9291c993c4 100644
  1340. --- a/drivers/platform/surface/Makefile
  1341. +++ b/drivers/platform/surface/Makefile
  1342. @@ -14,5 +14,6 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o
  1343. obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o
  1344. obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o
  1345. obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o
  1346. +obj-$(CONFIG_SURFACE_KIP_TABLET_SWITCH) += surface_kip_tablet_switch.o
  1347. obj-$(CONFIG_SURFACE_PLATFORM_PROFILE) += surface_platform_profile.o
  1348. obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
  1349. diff --git a/drivers/platform/surface/surface_kip_tablet_switch.c b/drivers/platform/surface/surface_kip_tablet_switch.c
  1350. new file mode 100644
  1351. index 000000000000..458470067579
  1352. --- /dev/null
  1353. +++ b/drivers/platform/surface/surface_kip_tablet_switch.c
  1354. @@ -0,0 +1,245 @@
  1355. +// SPDX-License-Identifier: GPL-2.0+
  1356. +/*
  1357. + * Surface System Aggregator Module (SSAM) tablet mode switch via KIP
  1358. + * subsystem.
  1359. + *
  1360. + * Copyright (C) 2021 Maximilian Luz <luzmaximilian@gmail.com>
  1361. + */
  1362. +
  1363. +#include <linux/input.h>
  1364. +#include <linux/kernel.h>
  1365. +#include <linux/module.h>
  1366. +#include <linux/platform_device.h>
  1367. +#include <linux/types.h>
  1368. +#include <linux/workqueue.h>
  1369. +
  1370. +#include <linux/surface_aggregator/controller.h>
  1371. +#include <linux/surface_aggregator/device.h>
  1372. +
  1373. +#define SSAM_EVENT_KIP_CID_LID_STATE 0x1d
  1374. +
  1375. +enum ssam_kip_lid_state {
  1376. + SSAM_KIP_LID_STATE_DISCONNECTED = 0x01,
  1377. + SSAM_KIP_LID_STATE_CLOSED = 0x02,
  1378. + SSAM_KIP_LID_STATE_LAPTOP = 0x03,
  1379. + SSAM_KIP_LID_STATE_FOLDED_CANVAS = 0x04,
  1380. + SSAM_KIP_LID_STATE_FOLDED_BACK = 0x05,
  1381. +};
  1382. +
  1383. +struct ssam_kip_sw {
  1384. + struct ssam_device *sdev;
  1385. +
  1386. + enum ssam_kip_lid_state state;
  1387. + struct work_struct update_work;
  1388. + struct input_dev *mode_switch;
  1389. +
  1390. + struct ssam_event_notifier notif;
  1391. +};
  1392. +
  1393. +SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_lid_state, u8, {
  1394. + .target_category = SSAM_SSH_TC_KIP,
  1395. + .target_id = 0x01,
  1396. + .command_id = 0x1d,
  1397. + .instance_id = 0x00,
  1398. +});
  1399. +
  1400. +static int ssam_kip_get_lid_state(struct ssam_kip_sw *sw, enum ssam_kip_lid_state *state)
  1401. +{
  1402. + int status;
  1403. + u8 raw;
  1404. +
  1405. + status = ssam_retry(__ssam_kip_get_lid_state, sw->sdev->ctrl, &raw);
  1406. + if (status < 0) {
  1407. + dev_err(&sw->sdev->dev, "failed to query KIP lid state: %d\n", status);
  1408. + return status;
  1409. + }
  1410. +
  1411. + *state = raw;
  1412. + return 0;
  1413. +}
  1414. +
  1415. +static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf)
  1416. +{
  1417. + struct ssam_kip_sw *sw = dev_get_drvdata(dev);
  1418. + const char *state;
  1419. +
  1420. + switch (sw->state) {
  1421. + case SSAM_KIP_LID_STATE_DISCONNECTED:
  1422. + state = "disconnected";
  1423. + break;
  1424. +
  1425. + case SSAM_KIP_LID_STATE_CLOSED:
  1426. + state = "closed";
  1427. + break;
  1428. +
  1429. + case SSAM_KIP_LID_STATE_LAPTOP:
  1430. + state = "laptop";
  1431. + break;
  1432. +
  1433. + case SSAM_KIP_LID_STATE_FOLDED_CANVAS:
  1434. + state = "folded-canvas";
  1435. + break;
  1436. +
  1437. + case SSAM_KIP_LID_STATE_FOLDED_BACK:
  1438. + state = "folded-back";
  1439. + break;
  1440. +
  1441. + default:
  1442. + state = "<unknown>";
  1443. + dev_warn(dev, "unknown KIP lid state: %d\n", sw->state);
  1444. + break;
  1445. + }
  1446. +
  1447. + return sysfs_emit(buf, "%s\n", state);
  1448. +}
  1449. +static DEVICE_ATTR_RO(state);
  1450. +
  1451. +static struct attribute *ssam_kip_sw_attrs[] = {
  1452. + &dev_attr_state.attr,
  1453. + NULL,
  1454. +};
  1455. +
  1456. +static const struct attribute_group ssam_kip_sw_group = {
  1457. + .attrs = ssam_kip_sw_attrs,
  1458. +};
  1459. +
  1460. +static void ssam_kip_sw_update_workfn(struct work_struct *work)
  1461. +{
  1462. + struct ssam_kip_sw *sw = container_of(work, struct ssam_kip_sw, update_work);
  1463. + enum ssam_kip_lid_state state;
  1464. + int tablet, status;
  1465. +
  1466. + status = ssam_kip_get_lid_state(sw, &state);
  1467. + if (status)
  1468. + return;
  1469. +
  1470. + if (sw->state == state)
  1471. + return;
  1472. + sw->state = state;
  1473. +
  1474. + /* Send SW_TABLET_MODE event. */
  1475. + tablet = state != SSAM_KIP_LID_STATE_LAPTOP;
  1476. + input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet);
  1477. + input_sync(sw->mode_switch);
  1478. +}
  1479. +
  1480. +static u32 ssam_kip_sw_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
  1481. +{
  1482. + struct ssam_kip_sw *sw = container_of(nf, struct ssam_kip_sw, notif);
  1483. +
  1484. + if (event->command_id != SSAM_EVENT_KIP_CID_LID_STATE)
  1485. + return 0; /* Return "unhandled". */
  1486. +
  1487. + if (event->length < 1) {
  1488. + dev_err(&sw->sdev->dev, "unexpected payload size: %u\n", event->length);
  1489. + return 0;
  1490. + }
  1491. +
  1492. + schedule_work(&sw->update_work);
  1493. + return SSAM_NOTIF_HANDLED;
  1494. +}
  1495. +
  1496. +static int __maybe_unused ssam_kip_sw_resume(struct device *dev)
  1497. +{
  1498. + struct ssam_kip_sw *sw = dev_get_drvdata(dev);
  1499. +
  1500. + schedule_work(&sw->update_work);
  1501. + return 0;
  1502. +}
  1503. +static SIMPLE_DEV_PM_OPS(ssam_kip_sw_pm_ops, NULL, ssam_kip_sw_resume);
  1504. +
  1505. +static int ssam_kip_sw_probe(struct ssam_device *sdev)
  1506. +{
  1507. + struct ssam_kip_sw *sw;
  1508. + int tablet, status;
  1509. +
  1510. + sw = devm_kzalloc(&sdev->dev, sizeof(*sw), GFP_KERNEL);
  1511. + if (!sw)
  1512. + return -ENOMEM;
  1513. +
  1514. + sw->sdev = sdev;
  1515. + INIT_WORK(&sw->update_work, ssam_kip_sw_update_workfn);
  1516. +
  1517. + ssam_device_set_drvdata(sdev, sw);
  1518. +
  1519. + /* Get initial state. */
  1520. + status = ssam_kip_get_lid_state(sw, &sw->state);
  1521. + if (status)
  1522. + return status;
  1523. +
  1524. + /* Set up tablet mode switch. */
  1525. + sw->mode_switch = devm_input_allocate_device(&sdev->dev);
  1526. + if (!sw->mode_switch)
  1527. + return -ENOMEM;
  1528. +
  1529. + sw->mode_switch->name = "Microsoft Surface KIP Tablet Mode Switch";
  1530. + sw->mode_switch->phys = "ssam/01:0e:01:00:01/input0";
  1531. + sw->mode_switch->id.bustype = BUS_HOST;
  1532. + sw->mode_switch->dev.parent = &sdev->dev;
  1533. +
  1534. + tablet = sw->state != SSAM_KIP_LID_STATE_LAPTOP;
  1535. + input_set_capability(sw->mode_switch, EV_SW, SW_TABLET_MODE);
  1536. + input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet);
  1537. +
  1538. + status = input_register_device(sw->mode_switch);
  1539. + if (status)
  1540. + return status;
  1541. +
  1542. + /* Set up notifier. */
  1543. + sw->notif.base.priority = 0;
  1544. + sw->notif.base.fn = ssam_kip_sw_notif;
  1545. + sw->notif.event.reg = SSAM_EVENT_REGISTRY_SAM;
  1546. + sw->notif.event.id.target_category = SSAM_SSH_TC_KIP,
  1547. + sw->notif.event.id.instance = 0,
  1548. + sw->notif.event.mask = SSAM_EVENT_MASK_TARGET;
  1549. + sw->notif.event.flags = SSAM_EVENT_SEQUENCED;
  1550. +
  1551. + status = ssam_device_notifier_register(sdev, &sw->notif);
  1552. + if (status)
  1553. + return status;
  1554. +
  1555. + status = sysfs_create_group(&sdev->dev.kobj, &ssam_kip_sw_group);
  1556. + if (status)
  1557. + goto err;
  1558. +
  1559. + /* We might have missed events during setup, so check again. */
  1560. + schedule_work(&sw->update_work);
  1561. + return 0;
  1562. +
  1563. +err:
  1564. + ssam_device_notifier_unregister(sdev, &sw->notif);
  1565. + cancel_work_sync(&sw->update_work);
  1566. + return status;
  1567. +}
  1568. +
  1569. +static void ssam_kip_sw_remove(struct ssam_device *sdev)
  1570. +{
  1571. + struct ssam_kip_sw *sw = ssam_device_get_drvdata(sdev);
  1572. +
  1573. + sysfs_remove_group(&sdev->dev.kobj, &ssam_kip_sw_group);
  1574. +
  1575. + ssam_device_notifier_unregister(sdev, &sw->notif);
  1576. + cancel_work_sync(&sw->update_work);
  1577. +}
  1578. +
  1579. +static const struct ssam_device_id ssam_kip_sw_match[] = {
  1580. + { SSAM_SDEV(KIP, 0x01, 0x00, 0x01) },
  1581. + { },
  1582. +};
  1583. +MODULE_DEVICE_TABLE(ssam, ssam_kip_sw_match);
  1584. +
  1585. +static struct ssam_device_driver ssam_kip_sw_driver = {
  1586. + .probe = ssam_kip_sw_probe,
  1587. + .remove = ssam_kip_sw_remove,
  1588. + .match_table = ssam_kip_sw_match,
  1589. + .driver = {
  1590. + .name = "surface_kip_tablet_mode_switch",
  1591. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  1592. + .pm = &ssam_kip_sw_pm_ops,
  1593. + },
  1594. +};
  1595. +module_ssam_device_driver(ssam_kip_sw_driver);
  1596. +
  1597. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  1598. +MODULE_DESCRIPTION("Tablet mode switch driver for Surface devices using KIP subsystem");
  1599. +MODULE_LICENSE("GPL");
  1600. --
  1601. 2.34.0
  1602. From 2b1685c0a906769031590c7bfc0793bcc6fb9e98 Mon Sep 17 00:00:00 2001
  1603. From: Maximilian Luz <luzmaximilian@gmail.com>
  1604. Date: Wed, 27 Oct 2021 22:33:03 +0200
  1605. Subject: [PATCH] platform/surface: aggregator_registry: Add support for tablet
  1606. mode switch on Surface Pro 8
  1607. Add a KIP subsystem tablet-mode switch device for the Surface Pro 8.
  1608. The respective driver for this device provides SW_TABLET_MODE input
  1609. events for user-space based on the state of the keyboard cover (e.g.
  1610. detached, folded-back, normal/laptop mode).
  1611. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  1612. Patchset: surface-sam
  1613. ---
  1614. drivers/platform/surface/surface_aggregator_registry.c | 8 +++++++-
  1615. 1 file changed, 7 insertions(+), 1 deletion(-)
  1616. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  1617. index c0e29c0514df..eaf0054627a5 100644
  1618. --- a/drivers/platform/surface/surface_aggregator_registry.c
  1619. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  1620. @@ -77,6 +77,12 @@ static const struct software_node ssam_node_tmp_pprof = {
  1621. .parent = &ssam_node_root,
  1622. };
  1623. +/* Tablet-mode switch via KIP subsystem. */
  1624. +static const struct software_node ssam_node_kip_tablet_switch = {
  1625. + .name = "ssam:01:0e:01:00:01",
  1626. + .parent = &ssam_node_root,
  1627. +};
  1628. +
  1629. /* DTX / detachment-system device (Surface Book 3). */
  1630. static const struct software_node ssam_node_bas_dtx = {
  1631. .name = "ssam:01:11:01:00:00",
  1632. @@ -264,11 +270,11 @@ static const struct software_node *ssam_node_group_sp8[] = {
  1633. &ssam_node_bat_ac,
  1634. &ssam_node_bat_main,
  1635. &ssam_node_tmp_pprof,
  1636. + &ssam_node_kip_tablet_switch,
  1637. &ssam_node_hid_kip_keyboard,
  1638. &ssam_node_hid_kip_penstash,
  1639. &ssam_node_hid_kip_touchpad,
  1640. &ssam_node_hid_kip_iid5,
  1641. - /* TODO: Add support for tablet mode switch. */
  1642. NULL,
  1643. };
  1644. --
  1645. 2.34.0
  1646. From fea397d2b114521a7e4cbc13998e451ebd9796ad Mon Sep 17 00:00:00 2001
  1647. From: Maximilian Luz <luzmaximilian@gmail.com>
  1648. Date: Thu, 28 Oct 2021 03:40:22 +0200
  1649. Subject: [PATCH] power/supply: surface_battery: Add support for hot-removal
  1650. In cases of hot-removal, further communication with the device should be
  1651. avoided whenever possible, as it may fail and time out.
  1652. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  1653. Patchset: surface-sam
  1654. ---
  1655. drivers/power/supply/surface_battery.c | 6 ++++++
  1656. 1 file changed, 6 insertions(+)
  1657. diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c
  1658. index 540707882bb0..ebf1f96e9a89 100644
  1659. --- a/drivers/power/supply/surface_battery.c
  1660. +++ b/drivers/power/supply/surface_battery.c
  1661. @@ -156,6 +156,9 @@ static bool spwr_battery_present(struct spwr_battery_device *bat)
  1662. {
  1663. lockdep_assert_held(&bat->lock);
  1664. + if (ssam_device_is_hot_removed(bat->sdev))
  1665. + return false;
  1666. +
  1667. return le32_to_cpu(bat->sta) & SAM_BATTERY_STA_PRESENT;
  1668. }
  1669. @@ -245,6 +248,9 @@ static int spwr_battery_update_bix_unlocked(struct spwr_battery_device *bat)
  1670. lockdep_assert_held(&bat->lock);
  1671. + if (ssam_device_is_hot_removed(bat->sdev))
  1672. + return 0;
  1673. +
  1674. status = spwr_battery_load_sta(bat);
  1675. if (status)
  1676. return status;
  1677. --
  1678. 2.34.0
  1679. From 1610b9bfd7295dfdde50ffc777a7d88c6a7e9531 Mon Sep 17 00:00:00 2001
  1680. From: Maximilian Luz <luzmaximilian@gmail.com>
  1681. Date: Sun, 31 Oct 2021 18:07:39 +0100
  1682. Subject: [PATCH] platform/surface: aggregator_registry: Use KIP hub for
  1683. Surface Book 3 base devices
  1684. It turns out that the Surface Book 3 manages the devices contained in
  1685. its detachable base via the KIP hub as well, similarly to the Surface
  1686. Pro 8 and Surface Pro X. So move them over to the KIP hub.
  1687. Right now, we (mis-)use the detachment subsystem (DTX), which is
  1688. designed for handling detachment requests and physical locking of the
  1689. base, to properly remove and re-attach Surface System Aggregator Module
  1690. (SSAM) client devices contained in the base. This system does not seem
  1691. to be intended for managing the (sub-)devices contained in the base,
  1692. which may need some time to be set up properly.
  1693. The KIP subsystem seems to be the intended subsystem for managing those
  1694. devices, thus let's use that one instead.
  1695. Note that this also changes the way in which devices on the Surface Book
  1696. 3 are removed when they have been detached, specifically from normal
  1697. removal to hot-removal (avoiding further communication with the embedded
  1698. controller). It seems that the "communication timeout after device
  1699. removal" issue does also occur on the Surface Book 3, but has so far
  1700. been missed as it does not happen reliably every time. Switching to
  1701. hot-removal fixes this issue and should not have any noticable
  1702. drawbacks.
  1703. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  1704. Patchset: surface-sam
  1705. ---
  1706. .../surface/surface_aggregator_registry.c | 56 ++++++-------------
  1707. 1 file changed, 16 insertions(+), 40 deletions(-)
  1708. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  1709. index eaf0054627a5..d17f656b2dad 100644
  1710. --- a/drivers/platform/surface/surface_aggregator_registry.c
  1711. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  1712. @@ -41,13 +41,7 @@ static const struct software_node ssam_node_root = {
  1713. .name = "ssam_platform_hub",
  1714. };
  1715. -/* Base device hub (devices attached to Surface Book 3 base). */
  1716. -static const struct software_node ssam_node_hub_base = {
  1717. - .name = "ssam:00:00:02:00:00",
  1718. - .parent = &ssam_node_root,
  1719. -};
  1720. -
  1721. -/* KIP device hub (connects keyboard cover devices on Surface Pro 8). */
  1722. +/* KIP device hub (connects detachable keyboard/touchpad on Surface Pro 8 and Book 3). */
  1723. static const struct software_node ssam_node_hub_kip = {
  1724. .name = "ssam:01:0e:01:00:00",
  1725. .parent = &ssam_node_root,
  1726. @@ -65,10 +59,10 @@ static const struct software_node ssam_node_bat_main = {
  1727. .parent = &ssam_node_root,
  1728. };
  1729. -/* Secondary battery (Surface Book 3). */
  1730. -static const struct software_node ssam_node_bat_sb3base = {
  1731. +/* Secondary battery (Surface Book 3, managed via KIP hub). */
  1732. +static const struct software_node ssam_node_bat_kip = {
  1733. .name = "ssam:01:02:02:01:00",
  1734. - .parent = &ssam_node_hub_base,
  1735. + .parent = &ssam_node_hub_kip,
  1736. };
  1737. /* Platform profile / performance-mode device. */
  1738. @@ -143,30 +137,6 @@ static const struct software_node ssam_node_hid_main_iid5 = {
  1739. .parent = &ssam_node_root,
  1740. };
  1741. -/* HID keyboard (base hub). */
  1742. -static const struct software_node ssam_node_hid_base_keyboard = {
  1743. - .name = "ssam:01:15:02:01:00",
  1744. - .parent = &ssam_node_hub_base,
  1745. -};
  1746. -
  1747. -/* HID touchpad (base hub). */
  1748. -static const struct software_node ssam_node_hid_base_touchpad = {
  1749. - .name = "ssam:01:15:02:03:00",
  1750. - .parent = &ssam_node_hub_base,
  1751. -};
  1752. -
  1753. -/* HID device instance 5 (unknown HID device, base hub). */
  1754. -static const struct software_node ssam_node_hid_base_iid5 = {
  1755. - .name = "ssam:01:15:02:05:00",
  1756. - .parent = &ssam_node_hub_base,
  1757. -};
  1758. -
  1759. -/* HID device instance 6 (unknown HID device, base hub). */
  1760. -static const struct software_node ssam_node_hid_base_iid6 = {
  1761. - .name = "ssam:01:15:02:06:00",
  1762. - .parent = &ssam_node_hub_base,
  1763. -};
  1764. -
  1765. /* HID keyboard (KIP hub). */
  1766. static const struct software_node ssam_node_hid_kip_keyboard = {
  1767. .name = "ssam:01:15:02:01:00",
  1768. @@ -191,6 +161,12 @@ static const struct software_node ssam_node_hid_kip_iid5 = {
  1769. .parent = &ssam_node_hub_kip,
  1770. };
  1771. +/* HID device instance 6 (KIP hub, unknown HID device). */
  1772. +static const struct software_node ssam_node_hid_kip_iid6 = {
  1773. + .name = "ssam:01:15:02:06:00",
  1774. + .parent = &ssam_node_hub_kip,
  1775. +};
  1776. +
  1777. /*
  1778. * Devices for 5th- and 6th-generations models:
  1779. * - Surface Book 2,
  1780. @@ -206,16 +182,16 @@ static const struct software_node *ssam_node_group_gen5[] = {
  1781. /* Devices for Surface Book 3. */
  1782. static const struct software_node *ssam_node_group_sb3[] = {
  1783. &ssam_node_root,
  1784. - &ssam_node_hub_base,
  1785. + &ssam_node_hub_kip,
  1786. &ssam_node_bat_ac,
  1787. &ssam_node_bat_main,
  1788. - &ssam_node_bat_sb3base,
  1789. + &ssam_node_bat_kip,
  1790. &ssam_node_tmp_pprof,
  1791. &ssam_node_bas_dtx,
  1792. - &ssam_node_hid_base_keyboard,
  1793. - &ssam_node_hid_base_touchpad,
  1794. - &ssam_node_hid_base_iid5,
  1795. - &ssam_node_hid_base_iid6,
  1796. + &ssam_node_hid_kip_keyboard,
  1797. + &ssam_node_hid_kip_touchpad,
  1798. + &ssam_node_hid_kip_iid5,
  1799. + &ssam_node_hid_kip_iid6,
  1800. NULL,
  1801. };
  1802. --
  1803. 2.34.0
  1804. From 236abbbef8f8a528621e839383e357f50591cb7c Mon Sep 17 00:00:00 2001
  1805. From: Maximilian Luz <luzmaximilian@gmail.com>
  1806. Date: Sun, 31 Oct 2021 18:09:53 +0100
  1807. Subject: [PATCH] platform/surface: aggregator_registry: Remove base hub driver
  1808. The base hub was a virtual device hub for Surface System Aggregator
  1809. Module (SSAM) client devices contained in the detachable Surface Book 3
  1810. base. Remove it as it is no longer needed.
  1811. In the previous change, we have moved all devices from the base hub to
  1812. the KIP hub. That change has also removed the only base-hub-device that
  1813. ever existed, as it was essentially replaced by the KIP-hub-device and
  1814. thus was no longer needed. This means that there is no remaining
  1815. hub-device against which the base hub driver can load, i.e. it is now
  1816. essentially dead code. So remove the driver as well.
  1817. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  1818. Patchset: surface-sam
  1819. ---
  1820. .../surface/surface_aggregator_registry.c | 213 ------------------
  1821. 1 file changed, 213 deletions(-)
  1822. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  1823. index d17f656b2dad..590473220e9d 100644
  1824. --- a/drivers/platform/surface/surface_aggregator_registry.c
  1825. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  1826. @@ -325,212 +325,6 @@ static int ssam_hub_register_clients(struct device *parent, struct ssam_controll
  1827. }
  1828. -/* -- SSAM base-hub driver. ------------------------------------------------- */
  1829. -
  1830. -/*
  1831. - * Some devices (especially battery) may need a bit of time to be fully usable
  1832. - * after being (re-)connected. This delay has been determined via
  1833. - * experimentation.
  1834. - */
  1835. -#define SSAM_BASE_UPDATE_CONNECT_DELAY msecs_to_jiffies(2500)
  1836. -
  1837. -enum ssam_base_hub_state {
  1838. - SSAM_BASE_HUB_UNINITIALIZED,
  1839. - SSAM_BASE_HUB_CONNECTED,
  1840. - SSAM_BASE_HUB_DISCONNECTED,
  1841. -};
  1842. -
  1843. -struct ssam_base_hub {
  1844. - struct ssam_device *sdev;
  1845. -
  1846. - enum ssam_base_hub_state state;
  1847. - struct delayed_work update_work;
  1848. -
  1849. - struct ssam_event_notifier notif;
  1850. -};
  1851. -
  1852. -SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
  1853. - .target_category = SSAM_SSH_TC_BAS,
  1854. - .target_id = 0x01,
  1855. - .command_id = 0x0d,
  1856. - .instance_id = 0x00,
  1857. -});
  1858. -
  1859. -#define SSAM_BAS_OPMODE_TABLET 0x00
  1860. -#define SSAM_EVENT_BAS_CID_CONNECTION 0x0c
  1861. -
  1862. -static int ssam_base_hub_query_state(struct ssam_base_hub *hub, enum ssam_base_hub_state *state)
  1863. -{
  1864. - u8 opmode;
  1865. - int status;
  1866. -
  1867. - status = ssam_retry(ssam_bas_query_opmode, hub->sdev->ctrl, &opmode);
  1868. - if (status < 0) {
  1869. - dev_err(&hub->sdev->dev, "failed to query base state: %d\n", status);
  1870. - return status;
  1871. - }
  1872. -
  1873. - if (opmode != SSAM_BAS_OPMODE_TABLET)
  1874. - *state = SSAM_BASE_HUB_CONNECTED;
  1875. - else
  1876. - *state = SSAM_BASE_HUB_DISCONNECTED;
  1877. -
  1878. - return 0;
  1879. -}
  1880. -
  1881. -static ssize_t ssam_base_hub_state_show(struct device *dev, struct device_attribute *attr,
  1882. - char *buf)
  1883. -{
  1884. - struct ssam_base_hub *hub = dev_get_drvdata(dev);
  1885. - bool connected = hub->state == SSAM_BASE_HUB_CONNECTED;
  1886. -
  1887. - return sysfs_emit(buf, "%d\n", connected);
  1888. -}
  1889. -
  1890. -static struct device_attribute ssam_base_hub_attr_state =
  1891. - __ATTR(state, 0444, ssam_base_hub_state_show, NULL);
  1892. -
  1893. -static struct attribute *ssam_base_hub_attrs[] = {
  1894. - &ssam_base_hub_attr_state.attr,
  1895. - NULL,
  1896. -};
  1897. -
  1898. -static const struct attribute_group ssam_base_hub_group = {
  1899. - .attrs = ssam_base_hub_attrs,
  1900. -};
  1901. -
  1902. -static void ssam_base_hub_update_workfn(struct work_struct *work)
  1903. -{
  1904. - struct ssam_base_hub *hub = container_of(work, struct ssam_base_hub, update_work.work);
  1905. - struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev);
  1906. - enum ssam_base_hub_state state;
  1907. - int status = 0;
  1908. -
  1909. - status = ssam_base_hub_query_state(hub, &state);
  1910. - if (status)
  1911. - return;
  1912. -
  1913. - if (hub->state == state)
  1914. - return;
  1915. - hub->state = state;
  1916. -
  1917. - if (hub->state == SSAM_BASE_HUB_CONNECTED)
  1918. - status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node);
  1919. - else
  1920. - ssam_remove_clients(&hub->sdev->dev);
  1921. -
  1922. - if (status)
  1923. - dev_err(&hub->sdev->dev, "failed to update base-hub devices: %d\n", status);
  1924. -}
  1925. -
  1926. -static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
  1927. -{
  1928. - struct ssam_base_hub *hub = container_of(nf, struct ssam_base_hub, notif);
  1929. - unsigned long delay;
  1930. -
  1931. - if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION)
  1932. - return 0;
  1933. -
  1934. - if (event->length < 1) {
  1935. - dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length);
  1936. - return 0;
  1937. - }
  1938. -
  1939. - /*
  1940. - * Delay update when the base is being connected to give devices/EC
  1941. - * some time to set up.
  1942. - */
  1943. - delay = event->data[0] ? SSAM_BASE_UPDATE_CONNECT_DELAY : 0;
  1944. -
  1945. - schedule_delayed_work(&hub->update_work, delay);
  1946. -
  1947. - /*
  1948. - * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and
  1949. - * consumed by the detachment system driver. We're just a (more or less)
  1950. - * silent observer.
  1951. - */
  1952. - return 0;
  1953. -}
  1954. -
  1955. -static int __maybe_unused ssam_base_hub_resume(struct device *dev)
  1956. -{
  1957. - struct ssam_base_hub *hub = dev_get_drvdata(dev);
  1958. -
  1959. - schedule_delayed_work(&hub->update_work, 0);
  1960. - return 0;
  1961. -}
  1962. -static SIMPLE_DEV_PM_OPS(ssam_base_hub_pm_ops, NULL, ssam_base_hub_resume);
  1963. -
  1964. -static int ssam_base_hub_probe(struct ssam_device *sdev)
  1965. -{
  1966. - struct ssam_base_hub *hub;
  1967. - int status;
  1968. -
  1969. - hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL);
  1970. - if (!hub)
  1971. - return -ENOMEM;
  1972. -
  1973. - hub->sdev = sdev;
  1974. - hub->state = SSAM_BASE_HUB_UNINITIALIZED;
  1975. -
  1976. - hub->notif.base.priority = INT_MAX; /* This notifier should run first. */
  1977. - hub->notif.base.fn = ssam_base_hub_notif;
  1978. - hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM;
  1979. - hub->notif.event.id.target_category = SSAM_SSH_TC_BAS,
  1980. - hub->notif.event.id.instance = 0,
  1981. - hub->notif.event.mask = SSAM_EVENT_MASK_NONE;
  1982. - hub->notif.event.flags = SSAM_EVENT_SEQUENCED;
  1983. -
  1984. - INIT_DELAYED_WORK(&hub->update_work, ssam_base_hub_update_workfn);
  1985. -
  1986. - ssam_device_set_drvdata(sdev, hub);
  1987. -
  1988. - status = ssam_device_notifier_register(sdev, &hub->notif);
  1989. - if (status)
  1990. - return status;
  1991. -
  1992. - status = sysfs_create_group(&sdev->dev.kobj, &ssam_base_hub_group);
  1993. - if (status)
  1994. - goto err;
  1995. -
  1996. - schedule_delayed_work(&hub->update_work, 0);
  1997. - return 0;
  1998. -
  1999. -err:
  2000. - ssam_device_notifier_unregister(sdev, &hub->notif);
  2001. - cancel_delayed_work_sync(&hub->update_work);
  2002. - ssam_remove_clients(&sdev->dev);
  2003. - return status;
  2004. -}
  2005. -
  2006. -static void ssam_base_hub_remove(struct ssam_device *sdev)
  2007. -{
  2008. - struct ssam_base_hub *hub = ssam_device_get_drvdata(sdev);
  2009. -
  2010. - sysfs_remove_group(&sdev->dev.kobj, &ssam_base_hub_group);
  2011. -
  2012. - ssam_device_notifier_unregister(sdev, &hub->notif);
  2013. - cancel_delayed_work_sync(&hub->update_work);
  2014. - ssam_remove_clients(&sdev->dev);
  2015. -}
  2016. -
  2017. -static const struct ssam_device_id ssam_base_hub_match[] = {
  2018. - { SSAM_VDEV(HUB, 0x02, SSAM_ANY_IID, 0x00) },
  2019. - { },
  2020. -};
  2021. -
  2022. -static struct ssam_device_driver ssam_base_hub_driver = {
  2023. - .probe = ssam_base_hub_probe,
  2024. - .remove = ssam_base_hub_remove,
  2025. - .match_table = ssam_base_hub_match,
  2026. - .driver = {
  2027. - .name = "surface_aggregator_base_hub",
  2028. - .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  2029. - .pm = &ssam_base_hub_pm_ops,
  2030. - },
  2031. -};
  2032. -
  2033. -
  2034. /* -- SSAM KIP-subsystem hub driver. ---------------------------------------- */
  2035. /*
  2036. @@ -886,10 +680,6 @@ static int __init ssam_device_hub_init(void)
  2037. if (status)
  2038. goto err_platform;
  2039. - status = ssam_device_driver_register(&ssam_base_hub_driver);
  2040. - if (status)
  2041. - goto err_base;
  2042. -
  2043. status = ssam_device_driver_register(&ssam_kip_hub_driver);
  2044. if (status)
  2045. goto err_kip;
  2046. @@ -897,8 +687,6 @@ static int __init ssam_device_hub_init(void)
  2047. return 0;
  2048. err_kip:
  2049. - ssam_device_driver_unregister(&ssam_base_hub_driver);
  2050. -err_base:
  2051. platform_driver_unregister(&ssam_platform_hub_driver);
  2052. err_platform:
  2053. return status;
  2054. @@ -908,7 +696,6 @@ module_init(ssam_device_hub_init);
  2055. static void __exit ssam_device_hub_exit(void)
  2056. {
  2057. ssam_device_driver_unregister(&ssam_kip_hub_driver);
  2058. - ssam_device_driver_unregister(&ssam_base_hub_driver);
  2059. platform_driver_unregister(&ssam_platform_hub_driver);
  2060. }
  2061. module_exit(ssam_device_hub_exit);
  2062. --
  2063. 2.34.0