linux/drivers/hid/hid-gfrm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * HID driver for Google Fiber TV Box remote controls
   4 *
   5 * Copyright (c) 2014-2015 Google Inc.
   6 *
   7 * Author: Petri Gynther <pgynther@google.com>
   8 */
   9#include <linux/device.h>
  10#include <linux/hid.h>
  11#include <linux/input.h>
  12#include <linux/module.h>
  13
  14#include "hid-ids.h"
  15
  16#define GFRM100  1  /* Google Fiber GFRM100 (Bluetooth classic) */
  17#define GFRM200  2  /* Google Fiber GFRM200 (Bluetooth LE) */
  18
  19#define GFRM100_SEARCH_KEY_REPORT_ID   0xF7
  20#define GFRM100_SEARCH_KEY_DOWN        0x0
  21#define GFRM100_SEARCH_KEY_AUDIO_DATA  0x1
  22#define GFRM100_SEARCH_KEY_UP          0x2
  23
  24static u8 search_key_dn[3] = {0x40, 0x21, 0x02};
  25static u8 search_key_up[3] = {0x40, 0x00, 0x00};
  26
  27static int gfrm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
  28                struct hid_field *field, struct hid_usage *usage,
  29                unsigned long **bit, int *max)
  30{
  31        unsigned long hdev_type = (unsigned long) hid_get_drvdata(hdev);
  32
  33        if (hdev_type == GFRM100) {
  34                if (usage->hid == (HID_UP_CONSUMER | 0x4)) {
  35                        /* Consumer.0004 -> KEY_INFO */
  36                        hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_INFO);
  37                        return 1;
  38                }
  39
  40                if (usage->hid == (HID_UP_CONSUMER | 0x41)) {
  41                        /* Consumer.0041 -> KEY_OK */
  42                        hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_OK);
  43                        return 1;
  44                }
  45        }
  46
  47        return 0;
  48}
  49
  50static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report,
  51                u8 *data, int size)
  52{
  53        unsigned long hdev_type = (unsigned long) hid_get_drvdata(hdev);
  54        int ret = 0;
  55
  56        if (hdev_type != GFRM100)
  57                return 0;
  58
  59        if (size < 2 || data[0] != GFRM100_SEARCH_KEY_REPORT_ID)
  60                return 0;
  61
  62        /*
  63         * Convert GFRM100 Search key reports into Consumer.0221 (Key.Search)
  64         * reports. Ignore audio data.
  65         */
  66        switch (data[1]) {
  67        case GFRM100_SEARCH_KEY_DOWN:
  68                ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_dn,
  69                                           sizeof(search_key_dn), 1);
  70                break;
  71
  72        case GFRM100_SEARCH_KEY_AUDIO_DATA:
  73                break;
  74
  75        case GFRM100_SEARCH_KEY_UP:
  76                ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_up,
  77                                           sizeof(search_key_up), 1);
  78                break;
  79
  80        default:
  81                break;
  82        }
  83
  84        return (ret < 0) ? ret : -1;
  85}
  86
  87static int gfrm_input_configured(struct hid_device *hid, struct hid_input *hidinput)
  88{
  89        /*
  90         * Enable software autorepeat with:
  91         * - repeat delay: 400 msec
  92         * - repeat period: 100 msec
  93         */
  94        input_enable_softrepeat(hidinput->input, 400, 100);
  95        return 0;
  96}
  97
  98static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id)
  99{
 100        int ret;
 101
 102        hid_set_drvdata(hdev, (void *) id->driver_data);
 103
 104        ret = hid_parse(hdev);
 105        if (ret)
 106                goto done;
 107
 108        if (id->driver_data == GFRM100) {
 109                /*
 110                 * GFRM100 HID Report Descriptor does not describe the Search
 111                 * key reports. Thus, we need to add it manually here, so that
 112                 * those reports reach gfrm_raw_event() from hid_input_report().
 113                 */
 114                if (!hid_register_report(hdev, HID_INPUT_REPORT,
 115                                         GFRM100_SEARCH_KEY_REPORT_ID, 0)) {
 116                        ret = -ENOMEM;
 117                        goto done;
 118                }
 119        }
 120
 121        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 122done:
 123        return ret;
 124}
 125
 126static const struct hid_device_id gfrm_devices[] = {
 127        { HID_BLUETOOTH_DEVICE(0x58, 0x2000),
 128                .driver_data = GFRM100 },
 129        { HID_BLUETOOTH_DEVICE(0x471, 0x2210),
 130                .driver_data = GFRM200 },
 131        { }
 132};
 133MODULE_DEVICE_TABLE(hid, gfrm_devices);
 134
 135static struct hid_driver gfrm_driver = {
 136        .name = "gfrm",
 137        .id_table = gfrm_devices,
 138        .probe = gfrm_probe,
 139        .input_mapping = gfrm_input_mapping,
 140        .raw_event = gfrm_raw_event,
 141        .input_configured = gfrm_input_configured,
 142};
 143
 144module_hid_driver(gfrm_driver);
 145
 146MODULE_AUTHOR("Petri Gynther <pgynther@google.com>");
 147MODULE_DESCRIPTION("Google Fiber TV Box remote control driver");
 148MODULE_LICENSE("GPL");
 149