LCOV - code coverage report
Current view: top level - drivers/hid - hid-microsoft.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 150 0.7 %
Date: 2023-08-24 13:40:31 Functions: 1 13 7.7 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  *  HID driver for some microsoft "special" devices
       4             :  *
       5             :  *  Copyright (c) 1999 Andreas Gal
       6             :  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
       7             :  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
       8             :  *  Copyright (c) 2006-2007 Jiri Kosina
       9             :  *  Copyright (c) 2008 Jiri Slaby
      10             :  */
      11             : 
      12             : /*
      13             :  */
      14             : 
      15             : #include <linux/device.h>
      16             : #include <linux/input.h>
      17             : #include <linux/hid.h>
      18             : #include <linux/module.h>
      19             : 
      20             : #include "hid-ids.h"
      21             : 
      22             : #define MS_HIDINPUT             BIT(0)
      23             : #define MS_ERGONOMY             BIT(1)
      24             : #define MS_PRESENTER            BIT(2)
      25             : #define MS_RDESC                BIT(3)
      26             : #define MS_NOGET                BIT(4)
      27             : #define MS_DUPLICATE_USAGES     BIT(5)
      28             : #define MS_SURFACE_DIAL         BIT(6)
      29             : #define MS_QUIRK_FF             BIT(7)
      30             : 
      31             : struct ms_data {
      32             :         unsigned long quirks;
      33             :         struct hid_device *hdev;
      34             :         struct work_struct ff_worker;
      35             :         __u8 strong;
      36             :         __u8 weak;
      37             :         void *output_report_dmabuf;
      38             : };
      39             : 
      40             : #define XB1S_FF_REPORT          3
      41             : #define ENABLE_WEAK             BIT(0)
      42             : #define ENABLE_STRONG           BIT(1)
      43             : 
      44             : enum {
      45             :         MAGNITUDE_STRONG = 2,
      46             :         MAGNITUDE_WEAK,
      47             :         MAGNITUDE_NUM
      48             : };
      49             : 
      50             : struct xb1s_ff_report {
      51             :         __u8    report_id;
      52             :         __u8    enable;
      53             :         __u8    magnitude[MAGNITUDE_NUM];
      54             :         __u8    duration_10ms;
      55             :         __u8    start_delay_10ms;
      56             :         __u8    loop_count;
      57             : } __packed;
      58             : 
      59           0 : static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
      60             :                 unsigned int *rsize)
      61             : {
      62           0 :         struct ms_data *ms = hid_get_drvdata(hdev);
      63           0 :         unsigned long quirks = ms->quirks;
      64             : 
      65             :         /*
      66             :          * Microsoft Wireless Desktop Receiver (Model 1028) has
      67             :          * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
      68             :          */
      69           0 :         if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 &&
      70           0 :                         rdesc[559] == 0x29) {
      71           0 :                 hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
      72           0 :                 rdesc[557] = 0x35;
      73           0 :                 rdesc[559] = 0x45;
      74             :         }
      75           0 :         return rdesc;
      76             : }
      77             : 
      78             : #define ms_map_key_clear(c)     hid_map_usage_clear(hi, usage, bit, max, \
      79             :                                         EV_KEY, (c))
      80           0 : static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
      81             :                 unsigned long **bit, int *max)
      82             : {
      83           0 :         struct input_dev *input = hi->input;
      84             : 
      85           0 :         if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
      86           0 :                 switch (usage->hid & HID_USAGE) {
      87             :                 /*
      88             :                  * Microsoft uses these 2 reserved usage ids for 2 keys on
      89             :                  * the MS office kb labelled "Office Home" and "Task Pane".
      90             :                  */
      91             :                 case 0x29d:
      92           0 :                         ms_map_key_clear(KEY_PROG1);
      93           0 :                         return 1;
      94             :                 case 0x29e:
      95           0 :                         ms_map_key_clear(KEY_PROG2);
      96           0 :                         return 1;
      97             :                 }
      98             :                 return 0;
      99             :         }
     100             : 
     101           0 :         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
     102             :                 return 0;
     103             : 
     104           0 :         switch (usage->hid & HID_USAGE) {
     105           0 :         case 0xfd06: ms_map_key_clear(KEY_CHAT);        break;
     106           0 :         case 0xfd07: ms_map_key_clear(KEY_PHONE);       break;
     107             :         case 0xff00:
     108             :                 /* Special keypad keys */
     109           0 :                 ms_map_key_clear(KEY_KPEQUAL);
     110           0 :                 set_bit(KEY_KPLEFTPAREN, input->keybit);
     111           0 :                 set_bit(KEY_KPRIGHTPAREN, input->keybit);
     112             :                 break;
     113             :         case 0xff01:
     114             :                 /* Scroll wheel */
     115           0 :                 hid_map_usage_clear(hi, usage, bit, max, EV_REL, REL_WHEEL);
     116           0 :                 break;
     117             :         case 0xff02:
     118             :                 /*
     119             :                  * This byte contains a copy of the modifier keys byte of a
     120             :                  * standard hid keyboard report, as send by interface 0
     121             :                  * (this usage is found on interface 1).
     122             :                  *
     123             :                  * This byte only gets send when another key in the same report
     124             :                  * changes state, and as such is useless, ignore it.
     125             :                  */
     126             :                 return -1;
     127             :         case 0xff05:
     128           0 :                 set_bit(EV_REP, input->evbit);
     129           0 :                 ms_map_key_clear(KEY_F13);
     130           0 :                 set_bit(KEY_F14, input->keybit);
     131           0 :                 set_bit(KEY_F15, input->keybit);
     132           0 :                 set_bit(KEY_F16, input->keybit);
     133           0 :                 set_bit(KEY_F17, input->keybit);
     134           0 :                 set_bit(KEY_F18, input->keybit);
     135             :                 break;
     136             :         default:
     137           0 :                 return 0;
     138             :         }
     139             :         return 1;
     140             : }
     141             : 
     142           0 : static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
     143             :                 unsigned long **bit, int *max)
     144             : {
     145           0 :         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
     146             :                 return 0;
     147             : 
     148           0 :         set_bit(EV_REP, hi->input->evbit);
     149           0 :         switch (usage->hid & HID_USAGE) {
     150           0 :         case 0xfd08: ms_map_key_clear(KEY_FORWARD);     break;
     151           0 :         case 0xfd09: ms_map_key_clear(KEY_BACK);        break;
     152           0 :         case 0xfd0b: ms_map_key_clear(KEY_PLAYPAUSE);   break;
     153           0 :         case 0xfd0e: ms_map_key_clear(KEY_CLOSE);       break;
     154           0 :         case 0xfd0f: ms_map_key_clear(KEY_PLAY);        break;
     155             :         default:
     156             :                 return 0;
     157             :         }
     158             :         return 1;
     159             : }
     160             : 
     161             : static int ms_surface_dial_quirk(struct hid_input *hi, struct hid_field *field,
     162             :                 struct hid_usage *usage, unsigned long **bit, int *max)
     163             : {
     164           0 :         switch (usage->hid & HID_USAGE_PAGE) {
     165             :         case 0xff070000:
     166             :         case HID_UP_DIGITIZER:
     167             :                 /* ignore those axis */
     168             :                 return -1;
     169             :         case HID_UP_GENDESK:
     170           0 :                 switch (usage->hid) {
     171             :                 case HID_GD_X:
     172             :                 case HID_GD_Y:
     173             :                 case HID_GD_RFKILL_BTN:
     174             :                         /* ignore those axis */
     175             :                         return -1;
     176             :                 }
     177             :         }
     178             : 
     179             :         return 0;
     180             : }
     181             : 
     182           0 : static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
     183             :                 struct hid_field *field, struct hid_usage *usage,
     184             :                 unsigned long **bit, int *max)
     185             : {
     186           0 :         struct ms_data *ms = hid_get_drvdata(hdev);
     187           0 :         unsigned long quirks = ms->quirks;
     188             : 
     189           0 :         if (quirks & MS_ERGONOMY) {
     190           0 :                 int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max);
     191           0 :                 if (ret)
     192             :                         return ret;
     193             :         }
     194             : 
     195           0 :         if ((quirks & MS_PRESENTER) &&
     196           0 :                         ms_presenter_8k_quirk(hi, usage, bit, max))
     197             :                 return 1;
     198             : 
     199           0 :         if (quirks & MS_SURFACE_DIAL) {
     200           0 :                 int ret = ms_surface_dial_quirk(hi, field, usage, bit, max);
     201             : 
     202           0 :                 if (ret)
     203             :                         return ret;
     204             :         }
     205             : 
     206             :         return 0;
     207             : }
     208             : 
     209           0 : static int ms_input_mapped(struct hid_device *hdev, struct hid_input *hi,
     210             :                 struct hid_field *field, struct hid_usage *usage,
     211             :                 unsigned long **bit, int *max)
     212             : {
     213           0 :         struct ms_data *ms = hid_get_drvdata(hdev);
     214           0 :         unsigned long quirks = ms->quirks;
     215             : 
     216           0 :         if (quirks & MS_DUPLICATE_USAGES)
     217           0 :                 clear_bit(usage->code, *bit);
     218             : 
     219           0 :         return 0;
     220             : }
     221             : 
     222           0 : static int ms_event(struct hid_device *hdev, struct hid_field *field,
     223             :                 struct hid_usage *usage, __s32 value)
     224             : {
     225           0 :         struct ms_data *ms = hid_get_drvdata(hdev);
     226           0 :         unsigned long quirks = ms->quirks;
     227             :         struct input_dev *input;
     228             : 
     229           0 :         if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
     230           0 :                         !usage->type)
     231             :                 return 0;
     232             : 
     233           0 :         input = field->hidinput->input;
     234             : 
     235             :         /* Handling MS keyboards special buttons */
     236           0 :         if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff00)) {
     237             :                 /* Special keypad keys */
     238           0 :                 input_report_key(input, KEY_KPEQUAL, value & 0x01);
     239           0 :                 input_report_key(input, KEY_KPLEFTPAREN, value & 0x02);
     240           0 :                 input_report_key(input, KEY_KPRIGHTPAREN, value & 0x04);
     241           0 :                 return 1;
     242             :         }
     243             : 
     244           0 :         if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff01)) {
     245             :                 /* Scroll wheel */
     246           0 :                 int step = ((value & 0x60) >> 5) + 1;
     247             : 
     248           0 :                 switch (value & 0x1f) {
     249             :                 case 0x01:
     250             :                         input_report_rel(input, REL_WHEEL, step);
     251             :                         break;
     252             :                 case 0x1f:
     253           0 :                         input_report_rel(input, REL_WHEEL, -step);
     254             :                         break;
     255             :                 }
     256             :                 return 1;
     257             :         }
     258             : 
     259           0 :         if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
     260             :                 static unsigned int last_key = 0;
     261           0 :                 unsigned int key = 0;
     262           0 :                 switch (value) {
     263             :                 case 0x01: key = KEY_F14; break;
     264             :                 case 0x02: key = KEY_F15; break;
     265             :                 case 0x04: key = KEY_F16; break;
     266             :                 case 0x08: key = KEY_F17; break;
     267             :                 case 0x10: key = KEY_F18; break;
     268             :                 }
     269           0 :                 if (key) {
     270           0 :                         input_event(input, usage->type, key, 1);
     271           0 :                         last_key = key;
     272             :                 } else
     273           0 :                         input_event(input, usage->type, last_key, 0);
     274             : 
     275             :                 return 1;
     276             :         }
     277             : 
     278             :         return 0;
     279             : }
     280             : 
     281           0 : static void ms_ff_worker(struct work_struct *work)
     282             : {
     283           0 :         struct ms_data *ms = container_of(work, struct ms_data, ff_worker);
     284           0 :         struct hid_device *hdev = ms->hdev;
     285           0 :         struct xb1s_ff_report *r = ms->output_report_dmabuf;
     286             :         int ret;
     287             : 
     288           0 :         memset(r, 0, sizeof(*r));
     289             : 
     290           0 :         r->report_id = XB1S_FF_REPORT;
     291           0 :         r->enable = ENABLE_WEAK | ENABLE_STRONG;
     292             :         /*
     293             :          * Specifying maximum duration and maximum loop count should
     294             :          * cover maximum duration of a single effect, which is 65536
     295             :          * ms
     296             :          */
     297           0 :         r->duration_10ms = U8_MAX;
     298           0 :         r->loop_count = U8_MAX;
     299           0 :         r->magnitude[MAGNITUDE_STRONG] = ms->strong; /* left actuator */
     300           0 :         r->magnitude[MAGNITUDE_WEAK] = ms->weak;     /* right actuator */
     301             : 
     302           0 :         ret = hid_hw_output_report(hdev, (__u8 *)r, sizeof(*r));
     303           0 :         if (ret < 0)
     304           0 :                 hid_warn(hdev, "failed to send FF report\n");
     305           0 : }
     306             : 
     307           0 : static int ms_play_effect(struct input_dev *dev, void *data,
     308             :                           struct ff_effect *effect)
     309             : {
     310           0 :         struct hid_device *hid = input_get_drvdata(dev);
     311           0 :         struct ms_data *ms = hid_get_drvdata(hid);
     312             : 
     313           0 :         if (effect->type != FF_RUMBLE)
     314             :                 return 0;
     315             : 
     316             :         /*
     317             :          * Magnitude is 0..100 so scale the 16-bit input here
     318             :          */
     319           0 :         ms->strong = ((u32) effect->u.rumble.strong_magnitude * 100) / U16_MAX;
     320           0 :         ms->weak = ((u32) effect->u.rumble.weak_magnitude * 100) / U16_MAX;
     321             : 
     322           0 :         schedule_work(&ms->ff_worker);
     323           0 :         return 0;
     324             : }
     325             : 
     326           0 : static int ms_init_ff(struct hid_device *hdev)
     327             : {
     328             :         struct hid_input *hidinput;
     329             :         struct input_dev *input_dev;
     330           0 :         struct ms_data *ms = hid_get_drvdata(hdev);
     331             : 
     332           0 :         if (list_empty(&hdev->inputs)) {
     333           0 :                 hid_err(hdev, "no inputs found\n");
     334           0 :                 return -ENODEV;
     335             :         }
     336           0 :         hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
     337           0 :         input_dev = hidinput->input;
     338             : 
     339           0 :         if (!(ms->quirks & MS_QUIRK_FF))
     340             :                 return 0;
     341             : 
     342           0 :         ms->hdev = hdev;
     343           0 :         INIT_WORK(&ms->ff_worker, ms_ff_worker);
     344             : 
     345           0 :         ms->output_report_dmabuf = devm_kzalloc(&hdev->dev,
     346             :                                                 sizeof(struct xb1s_ff_report),
     347             :                                                 GFP_KERNEL);
     348           0 :         if (ms->output_report_dmabuf == NULL)
     349             :                 return -ENOMEM;
     350             : 
     351           0 :         input_set_capability(input_dev, EV_FF, FF_RUMBLE);
     352           0 :         return input_ff_create_memless(input_dev, NULL, ms_play_effect);
     353             : }
     354             : 
     355             : static void ms_remove_ff(struct hid_device *hdev)
     356             : {
     357           0 :         struct ms_data *ms = hid_get_drvdata(hdev);
     358             : 
     359           0 :         if (!(ms->quirks & MS_QUIRK_FF))
     360             :                 return;
     361             : 
     362           0 :         cancel_work_sync(&ms->ff_worker);
     363             : }
     364             : 
     365           0 : static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
     366             : {
     367           0 :         unsigned long quirks = id->driver_data;
     368             :         struct ms_data *ms;
     369             :         int ret;
     370             : 
     371           0 :         ms = devm_kzalloc(&hdev->dev, sizeof(*ms), GFP_KERNEL);
     372           0 :         if (ms == NULL)
     373             :                 return -ENOMEM;
     374             : 
     375           0 :         ms->quirks = quirks;
     376             : 
     377           0 :         hid_set_drvdata(hdev, ms);
     378             : 
     379           0 :         if (quirks & MS_NOGET)
     380           0 :                 hdev->quirks |= HID_QUIRK_NOGET;
     381             : 
     382           0 :         if (quirks & MS_SURFACE_DIAL)
     383           0 :                 hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
     384             : 
     385           0 :         ret = hid_parse(hdev);
     386           0 :         if (ret) {
     387           0 :                 hid_err(hdev, "parse failed\n");
     388           0 :                 goto err_free;
     389             :         }
     390             : 
     391           0 :         ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ?
     392             :                                 HID_CONNECT_HIDINPUT_FORCE : 0));
     393           0 :         if (ret) {
     394           0 :                 hid_err(hdev, "hw start failed\n");
     395           0 :                 goto err_free;
     396             :         }
     397             : 
     398           0 :         ret = ms_init_ff(hdev);
     399           0 :         if (ret)
     400           0 :                 hid_err(hdev, "could not initialize ff, continuing anyway");
     401             : 
     402             :         return 0;
     403             : err_free:
     404             :         return ret;
     405             : }
     406             : 
     407           0 : static void ms_remove(struct hid_device *hdev)
     408             : {
     409           0 :         hid_hw_stop(hdev);
     410           0 :         ms_remove_ff(hdev);
     411           0 : }
     412             : 
     413             : static const struct hid_device_id ms_devices[] = {
     414             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV),
     415             :                 .driver_data = MS_HIDINPUT },
     416             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB),
     417             :                 .driver_data = MS_ERGONOMY },
     418             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K),
     419             :                 .driver_data = MS_ERGONOMY },
     420             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
     421             :                 .driver_data = MS_ERGONOMY },
     422             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K),
     423             :                 .driver_data = MS_ERGONOMY },
     424             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
     425             :                 .driver_data = MS_ERGONOMY | MS_RDESC },
     426             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
     427             :                 .driver_data = MS_PRESENTER },
     428             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K),
     429             :                 .driver_data = MS_ERGONOMY },
     430             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K),
     431             :                 .driver_data = MS_ERGONOMY },
     432             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600),
     433             :                 .driver_data = MS_ERGONOMY },
     434             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1),
     435             :                 .driver_data = MS_ERGONOMY },
     436             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0),
     437             :                 .driver_data = MS_NOGET },
     438             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
     439             :                 .driver_data = MS_DUPLICATE_USAGES },
     440             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER),
     441             :                 .driver_data = MS_HIDINPUT },
     442             :         { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD),
     443             :                 .driver_data = MS_ERGONOMY},
     444             : 
     445             :         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
     446             :                 .driver_data = MS_PRESENTER },
     447             :         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x091B),
     448             :                 .driver_data = MS_SURFACE_DIAL },
     449             : 
     450             :         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_CONTROLLER_MODEL_1708),
     451             :                 .driver_data = MS_QUIRK_FF },
     452             :         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_CONTROLLER_MODEL_1708_BLE),
     453             :                 .driver_data = MS_QUIRK_FF },
     454             :         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_CONTROLLER_MODEL_1914),
     455             :                 .driver_data = MS_QUIRK_FF },
     456             :         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_CONTROLLER_MODEL_1797),
     457             :                 .driver_data = MS_QUIRK_FF },
     458             :         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_CONTROLLER_MODEL_1797_BLE),
     459             :                 .driver_data = MS_QUIRK_FF },
     460             :         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS),
     461             :                 .driver_data = MS_QUIRK_FF },
     462             :         { }
     463             : };
     464             : MODULE_DEVICE_TABLE(hid, ms_devices);
     465             : 
     466             : static struct hid_driver ms_driver = {
     467             :         .name = "microsoft",
     468             :         .id_table = ms_devices,
     469             :         .report_fixup = ms_report_fixup,
     470             :         .input_mapping = ms_input_mapping,
     471             :         .input_mapped = ms_input_mapped,
     472             :         .event = ms_event,
     473             :         .probe = ms_probe,
     474             :         .remove = ms_remove,
     475             : };
     476           1 : module_hid_driver(ms_driver);
     477             : 
     478             : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14