1 // SPDX-License-Identifier: GPL-2.0+
3 * HID driver for Google Hammer device.
5 * Copyright (c) 2017 Google Inc.
6 * Author: Wei-Ning Huang <wnhuang@google.com>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
16 #include <linux/hid.h>
17 #include <linux/leds.h>
18 #include <linux/module.h>
22 #define MAX_BRIGHTNESS 100
24 /* HID usage for keyboard backlight (Alphanumeric display brightness) */
25 #define HID_AD_BRIGHTNESS 0x00140046
27 struct hammer_kbd_leds
{
28 struct led_classdev cdev
;
29 struct hid_device
*hdev
;
30 u8 buf
[2] ____cacheline_aligned
;
33 static int hammer_kbd_brightness_set_blocking(struct led_classdev
*cdev
,
34 enum led_brightness br
)
36 struct hammer_kbd_leds
*led
= container_of(cdev
,
37 struct hammer_kbd_leds
,
45 * Request USB HID device to be in Full On mode, so that sending
46 * hardware output report and hardware raw request won't fail.
48 ret
= hid_hw_power(led
->hdev
, PM_HINT_FULLON
);
50 hid_err(led
->hdev
, "failed: device not resumed %d\n", ret
);
54 ret
= hid_hw_output_report(led
->hdev
, led
->buf
, sizeof(led
->buf
));
56 ret
= hid_hw_raw_request(led
->hdev
, 0, led
->buf
,
61 hid_err(led
->hdev
, "failed to set keyboard backlight: %d\n",
64 /* Request USB HID device back to Normal Mode. */
65 hid_hw_power(led
->hdev
, PM_HINT_NORMAL
);
70 static int hammer_register_leds(struct hid_device
*hdev
)
72 struct hammer_kbd_leds
*kbd_backlight
;
74 kbd_backlight
= devm_kzalloc(&hdev
->dev
,
75 sizeof(*kbd_backlight
),
80 kbd_backlight
->hdev
= hdev
;
81 kbd_backlight
->cdev
.name
= "hammer::kbd_backlight";
82 kbd_backlight
->cdev
.max_brightness
= MAX_BRIGHTNESS
;
83 kbd_backlight
->cdev
.brightness_set_blocking
=
84 hammer_kbd_brightness_set_blocking
;
85 kbd_backlight
->cdev
.flags
= LED_HW_PLUGGABLE
;
87 /* Set backlight to 0% initially. */
88 hammer_kbd_brightness_set_blocking(&kbd_backlight
->cdev
, 0);
90 return devm_led_classdev_register(&hdev
->dev
, &kbd_backlight
->cdev
);
93 static int hammer_input_configured(struct hid_device
*hdev
,
96 struct list_head
*report_list
=
97 &hdev
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
98 struct hid_report
*report
;
100 if (list_empty(report_list
))
103 report
= list_first_entry(report_list
, struct hid_report
, list
);
105 if (report
->maxfield
== 1 &&
106 report
->field
[0]->application
== HID_GD_KEYBOARD
&&
107 report
->field
[0]->maxusage
== 1 &&
108 report
->field
[0]->usage
[0].hid
== HID_AD_BRIGHTNESS
) {
109 int err
= hammer_register_leds(hdev
);
113 "Failed to register keyboard backlight: %d\n",
120 static const struct hid_device_id hammer_devices
[] = {
121 { HID_DEVICE(BUS_USB
, HID_GROUP_GENERIC
,
122 USB_VENDOR_ID_GOOGLE
, USB_DEVICE_ID_GOOGLE_HAMMER
) },
123 { HID_DEVICE(BUS_USB
, HID_GROUP_GENERIC
,
124 USB_VENDOR_ID_GOOGLE
, USB_DEVICE_ID_GOOGLE_STAFF
) },
125 { HID_DEVICE(BUS_USB
, HID_GROUP_GENERIC
,
126 USB_VENDOR_ID_GOOGLE
, USB_DEVICE_ID_GOOGLE_WAND
) },
127 { HID_DEVICE(BUS_USB
, HID_GROUP_GENERIC
,
128 USB_VENDOR_ID_GOOGLE
, USB_DEVICE_ID_GOOGLE_WHISKERS
) },
131 MODULE_DEVICE_TABLE(hid
, hammer_devices
);
133 static struct hid_driver hammer_driver
= {
135 .id_table
= hammer_devices
,
136 .input_configured
= hammer_input_configured
,
138 module_hid_driver(hammer_driver
);
140 MODULE_LICENSE("GPL");