LCOV - code coverage report
Current view: top level - drivers/hid - hid-a4tech.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 48 2.1 %
Date: 2023-04-06 08:38:28 Functions: 1 6 16.7 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  *  HID driver for some a4tech "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             : #include <linux/slab.h>
      20             : 
      21             : #include "hid-ids.h"
      22             : 
      23             : #define A4_2WHEEL_MOUSE_HACK_7  0x01
      24             : #define A4_2WHEEL_MOUSE_HACK_B8 0x02
      25             : 
      26             : #define A4_WHEEL_ORIENTATION    (HID_UP_GENDESK | 0x000000b8)
      27             : 
      28             : struct a4tech_sc {
      29             :         unsigned long quirks;
      30             :         unsigned int hw_wheel;
      31             :         __s32 delayed_value;
      32             : };
      33             : 
      34           0 : static int a4_input_mapping(struct hid_device *hdev, struct hid_input *hi,
      35             :                             struct hid_field *field, struct hid_usage *usage,
      36             :                             unsigned long **bit, int *max)
      37             : {
      38           0 :         struct a4tech_sc *a4 = hid_get_drvdata(hdev);
      39             : 
      40           0 :         if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8 &&
      41           0 :             usage->hid == A4_WHEEL_ORIENTATION) {
      42             :                 /*
      43             :                  * We do not want to have this usage mapped to anything as it's
      44             :                  * nonstandard and doesn't really behave like an HID report.
      45             :                  * It's only selecting the orientation (vertical/horizontal) of
      46             :                  * the previous mouse wheel report. The input_events will be
      47             :                  * generated once both reports are recorded in a4_event().
      48             :                  */
      49             :                 return -1;
      50             :         }
      51             : 
      52           0 :         return 0;
      53             : 
      54             : }
      55             : 
      56           0 : static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
      57             :                 struct hid_field *field, struct hid_usage *usage,
      58             :                 unsigned long **bit, int *max)
      59             : {
      60           0 :         struct a4tech_sc *a4 = hid_get_drvdata(hdev);
      61             : 
      62           0 :         if (usage->type == EV_REL && usage->code == REL_WHEEL_HI_RES) {
      63           0 :                 set_bit(REL_HWHEEL, *bit);
      64           0 :                 set_bit(REL_HWHEEL_HI_RES, *bit);
      65             :         }
      66             : 
      67           0 :         if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007)
      68             :                 return -1;
      69             : 
      70           0 :         return 0;
      71             : }
      72             : 
      73           0 : static int a4_event(struct hid_device *hdev, struct hid_field *field,
      74             :                 struct hid_usage *usage, __s32 value)
      75             : {
      76           0 :         struct a4tech_sc *a4 = hid_get_drvdata(hdev);
      77             :         struct input_dev *input;
      78             : 
      79           0 :         if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput)
      80             :                 return 0;
      81             : 
      82           0 :         input = field->hidinput->input;
      83             : 
      84           0 :         if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) {
      85           0 :                 if (usage->type == EV_REL && usage->code == REL_WHEEL_HI_RES) {
      86           0 :                         a4->delayed_value = value;
      87           0 :                         return 1;
      88             :                 }
      89             : 
      90           0 :                 if (usage->hid == A4_WHEEL_ORIENTATION) {
      91           0 :                         input_event(input, EV_REL, value ? REL_HWHEEL :
      92             :                                         REL_WHEEL, a4->delayed_value);
      93           0 :                         input_event(input, EV_REL, value ? REL_HWHEEL_HI_RES :
      94           0 :                                         REL_WHEEL_HI_RES, a4->delayed_value * 120);
      95           0 :                         return 1;
      96             :                 }
      97             :         }
      98             : 
      99           0 :         if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) {
     100           0 :                 a4->hw_wheel = !!value;
     101           0 :                 return 1;
     102             :         }
     103             : 
     104           0 :         if (usage->code == REL_WHEEL_HI_RES && a4->hw_wheel) {
     105           0 :                 input_event(input, usage->type, REL_HWHEEL, value);
     106           0 :                 input_event(input, usage->type, REL_HWHEEL_HI_RES, value * 120);
     107           0 :                 return 1;
     108             :         }
     109             : 
     110             :         return 0;
     111             : }
     112             : 
     113           0 : static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
     114             : {
     115             :         struct a4tech_sc *a4;
     116             :         int ret;
     117             : 
     118           0 :         a4 = devm_kzalloc(&hdev->dev, sizeof(*a4), GFP_KERNEL);
     119           0 :         if (a4 == NULL) {
     120           0 :                 hid_err(hdev, "can't alloc device descriptor\n");
     121           0 :                 return -ENOMEM;
     122             :         }
     123             : 
     124           0 :         a4->quirks = id->driver_data;
     125             : 
     126           0 :         hid_set_drvdata(hdev, a4);
     127             : 
     128           0 :         ret = hid_parse(hdev);
     129           0 :         if (ret) {
     130           0 :                 hid_err(hdev, "parse failed\n");
     131           0 :                 return ret;
     132             :         }
     133             : 
     134           0 :         ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
     135           0 :         if (ret) {
     136           0 :                 hid_err(hdev, "hw start failed\n");
     137           0 :                 return ret;
     138             :         }
     139             : 
     140             :         return 0;
     141             : }
     142             : 
     143             : static const struct hid_device_id a4_devices[] = {
     144             :         { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU),
     145             :                 .driver_data = A4_2WHEEL_MOUSE_HACK_7 },
     146             :         { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D),
     147             :                 .driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
     148             :         { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649),
     149             :                 .driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
     150             :         { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_NB_95),
     151             :                 .driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
     152             :         { }
     153             : };
     154             : MODULE_DEVICE_TABLE(hid, a4_devices);
     155             : 
     156             : static struct hid_driver a4_driver = {
     157             :         .name = "a4tech",
     158             :         .id_table = a4_devices,
     159             :         .input_mapping = a4_input_mapping,
     160             :         .input_mapped = a4_input_mapped,
     161             :         .event = a4_event,
     162             :         .probe = a4_probe,
     163             : };
     164           1 : module_hid_driver(a4_driver);
     165             : 
     166             : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14