LCOV - code coverage report
Current view: top level - drivers/hid - hid-cypress.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 57 1.8 %
Date: 2023-08-24 13:40:31 Functions: 1 8 12.5 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  *  HID driver for some cypress "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/hid.h>
      17             : #include <linux/input.h>
      18             : #include <linux/module.h>
      19             : 
      20             : #include "hid-ids.h"
      21             : 
      22             : #define CP_RDESC_SWAPPED_MIN_MAX        0x01
      23             : #define CP_2WHEEL_MOUSE_HACK            0x02
      24             : #define CP_2WHEEL_MOUSE_HACK_ON         0x04
      25             : 
      26             : #define VA_INVAL_LOGICAL_BOUNDARY       0x08
      27             : 
      28             : /*
      29             :  * Some USB barcode readers from cypress have usage min and usage max in
      30             :  * the wrong order
      31             :  */
      32           0 : static __u8 *cp_rdesc_fixup(struct hid_device *hdev, __u8 *rdesc,
      33             :                 unsigned int *rsize)
      34             : {
      35             :         unsigned int i;
      36             : 
      37           0 :         if (*rsize < 4)
      38             :                 return rdesc;
      39             : 
      40           0 :         for (i = 0; i < *rsize - 4; i++)
      41           0 :                 if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) {
      42           0 :                         rdesc[i] = 0x19;
      43           0 :                         rdesc[i + 2] = 0x29;
      44           0 :                         swap(rdesc[i + 3], rdesc[i + 1]);
      45             :                 }
      46             :         return rdesc;
      47             : }
      48             : 
      49           0 : static __u8 *va_logical_boundary_fixup(struct hid_device *hdev, __u8 *rdesc,
      50             :                 unsigned int *rsize)
      51             : {
      52             :         /*
      53             :          * Varmilo VA104M (with VID Cypress and device ID 07B1) incorrectly
      54             :          * reports Logical Minimum of its Consumer Control device as 572
      55             :          * (0x02 0x3c). Fix this by setting its Logical Minimum to zero.
      56             :          */
      57           0 :         if (*rsize == 25 &&
      58           0 :                         rdesc[0] == 0x05 && rdesc[1] == 0x0c &&
      59           0 :                         rdesc[2] == 0x09 && rdesc[3] == 0x01 &&
      60           0 :                         rdesc[6] == 0x19 && rdesc[7] == 0x00 &&
      61           0 :                         rdesc[11] == 0x16 && rdesc[12] == 0x3c && rdesc[13] == 0x02) {
      62           0 :                 hid_info(hdev,
      63             :                          "fixing up varmilo VA104M consumer control report descriptor\n");
      64           0 :                 rdesc[12] = 0x00;
      65           0 :                 rdesc[13] = 0x00;
      66             :         }
      67           0 :         return rdesc;
      68             : }
      69             : 
      70           0 : static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
      71             :                 unsigned int *rsize)
      72             : {
      73           0 :         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
      74             : 
      75           0 :         if (quirks & CP_RDESC_SWAPPED_MIN_MAX)
      76           0 :                 rdesc = cp_rdesc_fixup(hdev, rdesc, rsize);
      77           0 :         if (quirks & VA_INVAL_LOGICAL_BOUNDARY)
      78           0 :                 rdesc = va_logical_boundary_fixup(hdev, rdesc, rsize);
      79             : 
      80           0 :         return rdesc;
      81             : }
      82             : 
      83           0 : static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
      84             :                 struct hid_field *field, struct hid_usage *usage,
      85             :                 unsigned long **bit, int *max)
      86             : {
      87           0 :         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
      88             : 
      89           0 :         if (!(quirks & CP_2WHEEL_MOUSE_HACK))
      90             :                 return 0;
      91             : 
      92           0 :         if (usage->type == EV_REL && usage->code == REL_WHEEL)
      93           0 :                 set_bit(REL_HWHEEL, *bit);
      94           0 :         if (usage->hid == 0x00090005)
      95             :                 return -1;
      96             : 
      97           0 :         return 0;
      98             : }
      99             : 
     100           0 : static int cp_event(struct hid_device *hdev, struct hid_field *field,
     101             :                 struct hid_usage *usage, __s32 value)
     102             : {
     103           0 :         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
     104             : 
     105           0 :         if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
     106           0 :                         !usage->type || !(quirks & CP_2WHEEL_MOUSE_HACK))
     107             :                 return 0;
     108             : 
     109           0 :         if (usage->hid == 0x00090005) {
     110           0 :                 if (value)
     111           0 :                         quirks |=  CP_2WHEEL_MOUSE_HACK_ON;
     112             :                 else
     113           0 :                         quirks &= ~CP_2WHEEL_MOUSE_HACK_ON;
     114           0 :                 hid_set_drvdata(hdev, (void *)quirks);
     115           0 :                 return 1;
     116             :         }
     117             : 
     118           0 :         if (usage->code == REL_WHEEL && (quirks & CP_2WHEEL_MOUSE_HACK_ON)) {
     119           0 :                 struct input_dev *input = field->hidinput->input;
     120             : 
     121           0 :                 input_event(input, usage->type, REL_HWHEEL, value);
     122           0 :                 return 1;
     123             :         }
     124             : 
     125             :         return 0;
     126             : }
     127             : 
     128           0 : static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id)
     129             : {
     130           0 :         unsigned long quirks = id->driver_data;
     131             :         int ret;
     132             : 
     133           0 :         hid_set_drvdata(hdev, (void *)quirks);
     134             : 
     135           0 :         ret = hid_parse(hdev);
     136           0 :         if (ret) {
     137           0 :                 hid_err(hdev, "parse failed\n");
     138           0 :                 goto err_free;
     139             :         }
     140             : 
     141           0 :         ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
     142           0 :         if (ret) {
     143           0 :                 hid_err(hdev, "hw start failed\n");
     144           0 :                 goto err_free;
     145             :         }
     146             : 
     147             :         return 0;
     148             : err_free:
     149             :         return ret;
     150             : }
     151             : 
     152             : static const struct hid_device_id cp_devices[] = {
     153             :         { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1),
     154             :                 .driver_data = CP_RDESC_SWAPPED_MIN_MAX },
     155             :         { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2),
     156             :                 .driver_data = CP_RDESC_SWAPPED_MIN_MAX },
     157             :         { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3),
     158             :                 .driver_data = CP_RDESC_SWAPPED_MIN_MAX },
     159             :         { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4),
     160             :                 .driver_data = CP_RDESC_SWAPPED_MIN_MAX },
     161             :         { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
     162             :                 .driver_data = CP_2WHEEL_MOUSE_HACK },
     163             :         { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1),
     164             :                 .driver_data = VA_INVAL_LOGICAL_BOUNDARY },
     165             :         { }
     166             : };
     167             : MODULE_DEVICE_TABLE(hid, cp_devices);
     168             : 
     169             : static struct hid_driver cp_driver = {
     170             :         .name = "cypress",
     171             :         .id_table = cp_devices,
     172             :         .report_fixup = cp_report_fixup,
     173             :         .input_mapped = cp_input_mapped,
     174             :         .event = cp_event,
     175             :         .probe = cp_probe,
     176             : };
     177           1 : module_hid_driver(cp_driver);
     178             : 
     179             : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14