0008-surface-typecover.patch 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. From faaa02f3a030264f021373f9f83e29d34b2e5497 Mon Sep 17 00:00:00 2001
  2. From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
  3. Date: Thu, 5 Nov 2020 13:09:45 +0100
  4. Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when
  5. suspending
  6. The Type Cover for Microsoft Surface devices supports a special usb
  7. control request to disable or enable the built-in keyboard backlight.
  8. On Windows, this request happens when putting the device into suspend or
  9. resuming it, without it the backlight of the Type Cover will remain
  10. enabled for some time even though the computer is suspended, which looks
  11. weird to the user.
  12. So add support for this special usb control request to hid-multitouch,
  13. which is the driver that's handling the Type Cover.
  14. The reason we have to use a pm_notifier for this instead of the usual
  15. suspend/resume methods is that those won't get called in case the usb
  16. device is already autosuspended.
  17. Also, if the device is autosuspended, we have to briefly autoresume it
  18. in order to send the request. Doing that should be fine, the usb-core
  19. driver does something similar during suspend inside choose_wakeup().
  20. To make sure we don't send that request to every device but only to
  21. devices which support it, add a new quirk
  22. MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk
  23. is only enabled for the usb id of the Surface Pro 2017 Type Cover, which
  24. is where I confirmed that it's working.
  25. Patchset: surface-typecover
  26. ---
  27. drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++-
  28. 1 file changed, 98 insertions(+), 2 deletions(-)
  29. diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
  30. index 91a4d3fc30e0..458537bf4a8e 100644
  31. --- a/drivers/hid/hid-multitouch.c
  32. +++ b/drivers/hid/hid-multitouch.c
  33. @@ -34,7 +34,10 @@
  34. #include <linux/device.h>
  35. #include <linux/hid.h>
  36. #include <linux/module.h>
  37. +#include <linux/pm_runtime.h>
  38. #include <linux/slab.h>
  39. +#include <linux/suspend.h>
  40. +#include <linux/usb.h>
  41. #include <linux/input/mt.h>
  42. #include <linux/jiffies.h>
  43. #include <linux/string.h>
  44. @@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels");
  45. MODULE_LICENSE("GPL");
  46. #include "hid-ids.h"
  47. +#include "usbhid/usbhid.h"
  48. /* quirks to control the device */
  49. #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0)
  50. @@ -71,12 +75,15 @@ MODULE_LICENSE("GPL");
  51. #define MT_QUIRK_SEPARATE_APP_REPORT BIT(19)
  52. #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
  53. #define MT_QUIRK_DISABLE_WAKEUP BIT(21)
  54. +#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(22)
  55. #define MT_INPUTMODE_TOUCHSCREEN 0x02
  56. #define MT_INPUTMODE_TOUCHPAD 0x03
  57. #define MT_BUTTONTYPE_CLICKPAD 0
  58. +#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086
  59. +
  60. enum latency_mode {
  61. HID_LATENCY_NORMAL = 0,
  62. HID_LATENCY_HIGH = 1,
  63. @@ -168,6 +175,8 @@ struct mt_device {
  64. struct list_head applications;
  65. struct list_head reports;
  66. +
  67. + struct notifier_block pm_notifier;
  68. };
  69. static void mt_post_parse_default_settings(struct mt_device *td,
  70. @@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
  71. #define MT_CLS_GOOGLE 0x0111
  72. #define MT_CLS_RAZER_BLADE_STEALTH 0x0112
  73. #define MT_CLS_SMART_TECH 0x0113
  74. +#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114
  75. #define MT_DEFAULT_MAXCONTACT 10
  76. #define MT_MAX_MAXCONTACT 250
  77. @@ -396,6 +406,16 @@ static const struct mt_class mt_classes[] = {
  78. MT_QUIRK_CONTACT_CNT_ACCURATE |
  79. MT_QUIRK_SEPARATE_APP_REPORT,
  80. },
  81. + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER,
  82. + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT |
  83. + MT_QUIRK_ALWAYS_VALID |
  84. + MT_QUIRK_IGNORE_DUPLICATES |
  85. + MT_QUIRK_HOVERING |
  86. + MT_QUIRK_CONTACT_CNT_ACCURATE |
  87. + MT_QUIRK_STICKY_FINGERS |
  88. + MT_QUIRK_WIN8_PTP_BUTTONS,
  89. + .export_all_inputs = true
  90. + },
  91. { }
  92. };
  93. @@ -1706,6 +1726,69 @@ static void mt_expired_timeout(struct timer_list *t)
  94. clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
  95. }
  96. +static void get_type_cover_backlight_field(struct hid_device *hdev,
  97. + struct hid_field **field)
  98. +{
  99. + struct hid_report_enum *rep_enum;
  100. + struct hid_report *rep;
  101. + struct hid_field *cur_field;
  102. + int i, j;
  103. +
  104. + rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
  105. + list_for_each_entry(rep, &rep_enum->report_list, list) {
  106. + for (i = 0; i < rep->maxfield; i++) {
  107. + cur_field = rep->field[i];
  108. +
  109. + for (j = 0; j < cur_field->maxusage; j++) {
  110. + if (cur_field->usage[j].hid
  111. + == MS_TYPE_COVER_FEATURE_REPORT_USAGE) {
  112. + *field = cur_field;
  113. + return;
  114. + }
  115. + }
  116. + }
  117. + }
  118. +}
  119. +
  120. +static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
  121. +{
  122. + struct usb_device *udev = hid_to_usb_dev(hdev);
  123. + struct hid_field *field = NULL;
  124. +
  125. + /* Wake up the device in case it's already suspended */
  126. + pm_runtime_get_sync(&udev->dev);
  127. +
  128. + get_type_cover_backlight_field(hdev, &field);
  129. + if (!field) {
  130. + hid_err(hdev, "couldn't find backlight field\n");
  131. + goto out;
  132. + }
  133. +
  134. + field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff;
  135. + hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT);
  136. +
  137. +out:
  138. + pm_runtime_put_sync(&udev->dev);
  139. +}
  140. +
  141. +static int mt_pm_notifier(struct notifier_block *notifier,
  142. + unsigned long pm_event,
  143. + void *unused)
  144. +{
  145. + struct mt_device *td =
  146. + container_of(notifier, struct mt_device, pm_notifier);
  147. + struct hid_device *hdev = td->hdev;
  148. +
  149. + if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) {
  150. + if (pm_event == PM_SUSPEND_PREPARE)
  151. + update_keyboard_backlight(hdev, 0);
  152. + else if (pm_event == PM_POST_SUSPEND)
  153. + update_keyboard_backlight(hdev, 1);
  154. + }
  155. +
  156. + return NOTIFY_DONE;
  157. +}
  158. +
  159. static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
  160. {
  161. int ret, i;
  162. @@ -1729,6 +1812,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
  163. td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
  164. hid_set_drvdata(hdev, td);
  165. + td->pm_notifier.notifier_call = mt_pm_notifier;
  166. + register_pm_notifier(&td->pm_notifier);
  167. +
  168. INIT_LIST_HEAD(&td->applications);
  169. INIT_LIST_HEAD(&td->reports);
  170. @@ -1758,15 +1844,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
  171. timer_setup(&td->release_timer, mt_expired_timeout, 0);
  172. ret = hid_parse(hdev);
  173. - if (ret != 0)
  174. + if (ret != 0) {
  175. + unregister_pm_notifier(&td->pm_notifier);
  176. return ret;
  177. + }
  178. if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID)
  179. mt_fix_const_fields(hdev, HID_DG_CONTACTID);
  180. ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
  181. - if (ret)
  182. + if (ret) {
  183. + unregister_pm_notifier(&td->pm_notifier);
  184. return ret;
  185. + }
  186. ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
  187. if (ret)
  188. @@ -1818,6 +1908,7 @@ static void mt_remove(struct hid_device *hdev)
  189. {
  190. struct mt_device *td = hid_get_drvdata(hdev);
  191. + unregister_pm_notifier(&td->pm_notifier);
  192. del_timer_sync(&td->release_timer);
  193. sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
  194. @@ -2191,6 +2282,11 @@ static const struct hid_device_id mt_devices[] = {
  195. MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
  196. USB_DEVICE_ID_XIROKU_CSR2) },
  197. + /* Microsoft Surface type cover */
  198. + { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER,
  199. + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
  200. + USB_VENDOR_ID_MICROSOFT, 0x09c0) },
  201. +
  202. /* Google MT devices */
  203. { .driver_data = MT_CLS_GOOGLE,
  204. HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
  205. --
  206. 2.38.1
  207. From 219e89d9c3d57bc998ed6aafde09c96105a80dad Mon Sep 17 00:00:00 2001
  208. From: PJungkamp <p.jungkamp@gmail.com>
  209. Date: Fri, 25 Feb 2022 12:04:25 +0100
  210. Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet
  211. switch
  212. The Surface Pro Type Cover has several non standard HID usages in it's
  213. hid report descriptor.
  214. I noticed that, upon folding the typecover back, a vendor specific range
  215. of 4 32 bit integer hid usages is transmitted.
  216. Only the first byte of the message seems to convey reliable information
  217. about the keyboard state.
  218. 0x22 => Normal (keys enabled)
  219. 0x33 => Folded back (keys disabled)
  220. 0x53 => Rotated left/right side up (keys disabled)
  221. 0x13 => Cover closed (keys disabled)
  222. 0x43 => Folded back and Tablet upside down (keys disabled)
  223. This list may not be exhaustive.
  224. The tablet mode switch will be disabled for a value of 0x22 and enabled
  225. on any other value.
  226. Patchset: surface-typecover
  227. ---
  228. drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------
  229. 1 file changed, 122 insertions(+), 26 deletions(-)
  230. diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
  231. index 458537bf4a8e..3d7d002a662f 100644
  232. --- a/drivers/hid/hid-multitouch.c
  233. +++ b/drivers/hid/hid-multitouch.c
  234. @@ -76,6 +76,7 @@ MODULE_LICENSE("GPL");
  235. #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
  236. #define MT_QUIRK_DISABLE_WAKEUP BIT(21)
  237. #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(22)
  238. +#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(23)
  239. #define MT_INPUTMODE_TOUCHSCREEN 0x02
  240. #define MT_INPUTMODE_TOUCHPAD 0x03
  241. @@ -83,6 +84,8 @@ MODULE_LICENSE("GPL");
  242. #define MT_BUTTONTYPE_CLICKPAD 0
  243. #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086
  244. +#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072
  245. +#define MS_TYPE_COVER_APPLICATION 0xff050050
  246. enum latency_mode {
  247. HID_LATENCY_NORMAL = 0,
  248. @@ -408,6 +411,7 @@ static const struct mt_class mt_classes[] = {
  249. },
  250. { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER,
  251. .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT |
  252. + MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH |
  253. MT_QUIRK_ALWAYS_VALID |
  254. MT_QUIRK_IGNORE_DUPLICATES |
  255. MT_QUIRK_HOVERING |
  256. @@ -1368,6 +1372,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
  257. field->application != HID_CP_CONSUMER_CONTROL &&
  258. field->application != HID_GD_WIRELESS_RADIO_CTLS &&
  259. field->application != HID_GD_SYSTEM_MULTIAXIS &&
  260. + !(field->application == MS_TYPE_COVER_APPLICATION &&
  261. + application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
  262. + usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) &&
  263. !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
  264. application->quirks & MT_QUIRK_ASUS_CUSTOM_UP))
  265. return -1;
  266. @@ -1395,6 +1402,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
  267. return 1;
  268. }
  269. + /*
  270. + * The Microsoft Surface Pro Typecover has a non-standard HID
  271. + * tablet mode switch on a vendor specific usage page with vendor
  272. + * specific usage.
  273. + */
  274. + if (field->application == MS_TYPE_COVER_APPLICATION &&
  275. + application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
  276. + usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) {
  277. + usage->type = EV_SW;
  278. + usage->code = SW_TABLET_MODE;
  279. + *max = SW_MAX;
  280. + *bit = hi->input->swbit;
  281. + return 1;
  282. + }
  283. +
  284. if (rdata->is_mt_collection)
  285. return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
  286. application);
  287. @@ -1416,6 +1438,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
  288. {
  289. struct mt_device *td = hid_get_drvdata(hdev);
  290. struct mt_report_data *rdata;
  291. + struct input_dev *input;
  292. rdata = mt_find_report_data(td, field->report);
  293. if (rdata && rdata->is_mt_collection) {
  294. @@ -1423,6 +1446,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
  295. return -1;
  296. }
  297. + /*
  298. + * We own an input device which acts as a tablet mode switch for
  299. + * the Surface Pro Typecover.
  300. + */
  301. + if (field->application == MS_TYPE_COVER_APPLICATION &&
  302. + rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
  303. + usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) {
  304. + input = hi->input;
  305. + input_set_capability(input, EV_SW, SW_TABLET_MODE);
  306. + input_report_switch(input, SW_TABLET_MODE, 0);
  307. + return -1;
  308. + }
  309. +
  310. /* let hid-core decide for the others */
  311. return 0;
  312. }
  313. @@ -1432,11 +1468,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
  314. {
  315. struct mt_device *td = hid_get_drvdata(hid);
  316. struct mt_report_data *rdata;
  317. + struct input_dev *input;
  318. rdata = mt_find_report_data(td, field->report);
  319. if (rdata && rdata->is_mt_collection)
  320. return mt_touch_event(hid, field, usage, value);
  321. + if (field->application == MS_TYPE_COVER_APPLICATION &&
  322. + rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
  323. + usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) {
  324. + input = field->hidinput->input;
  325. + input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22);
  326. + input_sync(input);
  327. + return 1;
  328. + }
  329. +
  330. return 0;
  331. }
  332. @@ -1589,6 +1635,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app)
  333. app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
  334. }
  335. +static int get_type_cover_field(struct hid_report_enum *rep_enum,
  336. + struct hid_field **field, int usage)
  337. +{
  338. + struct hid_report *rep;
  339. + struct hid_field *cur_field;
  340. + int i, j;
  341. +
  342. + list_for_each_entry(rep, &rep_enum->report_list, list) {
  343. + for (i = 0; i < rep->maxfield; i++) {
  344. + cur_field = rep->field[i];
  345. + if (cur_field->application != MS_TYPE_COVER_APPLICATION)
  346. + continue;
  347. + for (j = 0; j < cur_field->maxusage; j++) {
  348. + if (cur_field->usage[j].hid == usage) {
  349. + *field = cur_field;
  350. + return true;
  351. + }
  352. + }
  353. + }
  354. + }
  355. + return false;
  356. +}
  357. +
  358. +static void request_type_cover_tablet_mode_switch(struct hid_device *hdev)
  359. +{
  360. + struct hid_field *field;
  361. +
  362. + if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT],
  363. + &field,
  364. + MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) {
  365. + hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT);
  366. + } else {
  367. + hid_err(hdev, "couldn't find tablet mode field\n");
  368. + }
  369. +}
  370. +
  371. static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
  372. {
  373. struct mt_device *td = hid_get_drvdata(hdev);
  374. @@ -1638,6 +1720,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
  375. /* force BTN_STYLUS to allow tablet matching in udev */
  376. __set_bit(BTN_STYLUS, hi->input->keybit);
  377. break;
  378. + case MS_TYPE_COVER_APPLICATION:
  379. + if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) {
  380. + suffix = "Tablet Mode Switch";
  381. + request_type_cover_tablet_mode_switch(hdev);
  382. + break;
  383. + }
  384. + fallthrough;
  385. default:
  386. suffix = "UNKNOWN";
  387. break;
  388. @@ -1726,30 +1815,6 @@ static void mt_expired_timeout(struct timer_list *t)
  389. clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
  390. }
  391. -static void get_type_cover_backlight_field(struct hid_device *hdev,
  392. - struct hid_field **field)
  393. -{
  394. - struct hid_report_enum *rep_enum;
  395. - struct hid_report *rep;
  396. - struct hid_field *cur_field;
  397. - int i, j;
  398. -
  399. - rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
  400. - list_for_each_entry(rep, &rep_enum->report_list, list) {
  401. - for (i = 0; i < rep->maxfield; i++) {
  402. - cur_field = rep->field[i];
  403. -
  404. - for (j = 0; j < cur_field->maxusage; j++) {
  405. - if (cur_field->usage[j].hid
  406. - == MS_TYPE_COVER_FEATURE_REPORT_USAGE) {
  407. - *field = cur_field;
  408. - return;
  409. - }
  410. - }
  411. - }
  412. - }
  413. -}
  414. -
  415. static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
  416. {
  417. struct usb_device *udev = hid_to_usb_dev(hdev);
  418. @@ -1758,8 +1823,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
  419. /* Wake up the device in case it's already suspended */
  420. pm_runtime_get_sync(&udev->dev);
  421. - get_type_cover_backlight_field(hdev, &field);
  422. - if (!field) {
  423. + if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT],
  424. + &field,
  425. + MS_TYPE_COVER_FEATURE_REPORT_USAGE)) {
  426. hid_err(hdev, "couldn't find backlight field\n");
  427. goto out;
  428. }
  429. @@ -1885,13 +1951,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state)
  430. static int mt_reset_resume(struct hid_device *hdev)
  431. {
  432. + struct mt_device *td = hid_get_drvdata(hdev);
  433. +
  434. mt_release_contacts(hdev);
  435. mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
  436. +
  437. + /* Request an update on the typecover folding state on resume
  438. + * after reset.
  439. + */
  440. + if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH)
  441. + request_type_cover_tablet_mode_switch(hdev);
  442. +
  443. return 0;
  444. }
  445. static int mt_resume(struct hid_device *hdev)
  446. {
  447. + struct mt_device *td = hid_get_drvdata(hdev);
  448. +
  449. /* Some Elan legacy devices require SET_IDLE to be set on resume.
  450. * It should be safe to send it to other devices too.
  451. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
  452. @@ -1900,6 +1977,10 @@ static int mt_resume(struct hid_device *hdev)
  453. mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
  454. + /* Request an update on the typecover folding state on resume. */
  455. + if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH)
  456. + request_type_cover_tablet_mode_switch(hdev);
  457. +
  458. return 0;
  459. }
  460. #endif
  461. @@ -1907,6 +1988,21 @@ static int mt_resume(struct hid_device *hdev)
  462. static void mt_remove(struct hid_device *hdev)
  463. {
  464. struct mt_device *td = hid_get_drvdata(hdev);
  465. + struct hid_field *field;
  466. + struct input_dev *input;
  467. +
  468. + /* Reset tablet mode switch on disconnect. */
  469. + if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) {
  470. + if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT],
  471. + &field,
  472. + MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) {
  473. + input = field->hidinput->input;
  474. + input_report_switch(input, SW_TABLET_MODE, 0);
  475. + input_sync(input);
  476. + } else {
  477. + hid_err(hdev, "couldn't find tablet mode field\n");
  478. + }
  479. + }
  480. unregister_pm_notifier(&td->pm_notifier);
  481. del_timer_sync(&td->release_timer);
  482. --
  483. 2.38.1