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