167 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * HID driver for Maltron L904 *5 * Copyright (c) 1999 Andreas Gal6 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>7 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc8 * Copyright (c) 2008 Jiri Slaby9 * Copyright (c) 2012 David Dillow <dave@thedillows.org>10 * Copyright (c) 2006-2013 Jiri Kosina11 * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com>12 * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com>13 * Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com>14 * Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com>15 * Copyright (c) 2018 William Whistler <wtbw@wtbw.co.uk>16 */17 18#include <linux/device.h>19#include <linux/hid.h>20#include <linux/module.h>21 22#include "hid-ids.h"23 24/* The original buggy USB descriptor */25static const u8 maltron_rdesc_o[] = {26 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */27 0x09, 0x80, /* Usage (Sys Control) */28 0xA1, 0x01, /* Collection (Application) */29 0x85, 0x02, /* Report ID (2) */30 0x75, 0x01, /* Report Size (1) */31 0x95, 0x01, /* Report Count (1) */32 0x15, 0x00, /* Logical Minimum (0) */33 0x25, 0x01, /* Logical Maximum (1) */34 0x09, 0x82, /* Usage (Sys Sleep) */35 0x81, 0x06, /* Input (Data,Var,Rel) */36 0x09, 0x82, /* Usage (Sys Sleep) */37 0x81, 0x06, /* Input (Data,Var,Rel) */38 0x09, 0x83, /* Usage (Sys Wake Up) */39 0x81, 0x06, /* Input (Data,Var,Rel) */40 0x75, 0x05, /* Report Size (5) */41 0x81, 0x01, /* Input (Const,Array,Abs) */42 0xC0, /* End Collection */43 0x05, 0x0C, /* Usage Page (Consumer) */44 0x09, 0x01, /* Usage (Consumer Control) */45 0xA1, 0x01, /* Collection (Application) */46 0x85, 0x03, /* Report ID (3) */47 0x95, 0x01, /* Report Count (1) */48 0x75, 0x10, /* Report Size (16) */49 0x19, 0x00, /* Usage Minimum (Unassigned) */50 0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */51 0x81, 0x00, /* Input (Data,Array,Abs) */52 0xC0, /* End Collection */53 0x06, 0x7F, 0xFF, /* Usage Page (Vendor Defined 0xFF7F) */54 0x09, 0x01, /* Usage (0x01) */55 0xA1, 0x01, /* Collection (Application) */56 0x85, 0x04, /* Report ID (4) */57 0x95, 0x01, /* Report Count (1) */58 0x75, 0x10, /* Report Size (16) */59 0x19, 0x00, /* Usage Minimum (0x00) */60 0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */61 0x81, 0x00, /* Input (Data,Array,Abs) */62 0x75, 0x02, /* Report Size (2) */63 0x25, 0x02, /* Logical Maximum (2) */64 0x09, 0x90, /* Usage (0x90) */65 0xB1, 0x02, /* Feature (Data,Var,Abs) */66 0x75, 0x06, /* Report Size (6) */67 0xB1, 0x01, /* Feature (Const,Array,Abs) */68 0x75, 0x01, /* Report Size (1) */69 0x25, 0x01, /* Logical Maximum (1) */70 0x05, 0x08, /* Usage Page (LEDs) */71 0x09, 0x2A, /* Usage (On-Line) */72 0x91, 0x02, /* Output (Data,Var,Abs) */73 0x09, 0x4B, /* Usage (Generic Indicator) */74 0x91, 0x02, /* Output (Data,Var,Abs) */75 0x75, 0x06, /* Report Size (6) */76 0x95, 0x01, /* Report Count (1) */77 0x91, 0x01, /* Output (Const,Array,Abs) */78 0xC0 /* End Collection */79};80 81/* The patched descriptor, allowing media key events to be accepted as valid */82static const u8 maltron_rdesc[] = {83 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */84 0x09, 0x80, /* Usage (Sys Control) */85 0xA1, 0x01, /* Collection (Application) */86 0x85, 0x02, /* Report ID (2) */87 0x75, 0x01, /* Report Size (1) */88 0x95, 0x01, /* Report Count (1) */89 0x15, 0x00, /* Logical Minimum (0) */90 0x25, 0x01, /* Logical Maximum (1) */91 0x09, 0x82, /* Usage (Sys Sleep) */92 0x81, 0x06, /* Input (Data,Var,Rel) */93 0x09, 0x82, /* Usage (Sys Sleep) */94 0x81, 0x06, /* Input (Data,Var,Rel) */95 0x09, 0x83, /* Usage (Sys Wake Up) */96 0x81, 0x06, /* Input (Data,Var,Rel) */97 0x75, 0x05, /* Report Size (5) */98 0x81, 0x01, /* Input (Const,Array,Abs) */99 0xC0, /* End Collection */100 0x05, 0x0C, /* Usage Page (Consumer) */101 0x09, 0x01, /* Usage (Consumer Control) */102 0xA1, 0x01, /* Collection (Application) */103 0x85, 0x03, /* Report ID (3) */104 0x15, 0x00, /* Logical Minimum (0) - changed */105 0x26, 0xFF, 0x7F, /* Logical Maximum (32767) - changed */106 0x95, 0x01, /* Report Count (1) */107 0x75, 0x10, /* Report Size (16) */108 0x19, 0x00, /* Usage Minimum (Unassigned) */109 0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */110 0x81, 0x00, /* Input (Data,Array,Abs) */111 0xC0, /* End Collection */112 0x06, 0x7F, 0xFF, /* Usage Page (Vendor Defined 0xFF7F) */113 0x09, 0x01, /* Usage (0x01) */114 0xA1, 0x01, /* Collection (Application) */115 0x85, 0x04, /* Report ID (4) */116 0x95, 0x01, /* Report Count (1) */117 0x75, 0x10, /* Report Size (16) */118 0x19, 0x00, /* Usage Minimum (0x00) */119 0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */120 0x81, 0x00, /* Input (Data,Array,Abs) */121 0x75, 0x02, /* Report Size (2) */122 0x25, 0x02, /* Logical Maximum (2) */123 0x09, 0x90, /* Usage (0x90) */124 0xB1, 0x02, /* Feature (Data,Var,Abs) */125 0x75, 0x06, /* Report Size (6) */126 0xB1, 0x01, /* Feature (Const,Array,Abs) */127 0x75, 0x01, /* Report Size (1) */128 0x25, 0x01, /* Logical Maximum (1) */129 0x05, 0x08, /* Usage Page (LEDs) */130 0x09, 0x2A, /* Usage (On-Line) */131 0x91, 0x02, /* Output (Data,Var,Abs) */132 0x09, 0x4B, /* Usage (Generic Indicator) */133 0x91, 0x02, /* Output (Data,Var,Abs) */134 0x75, 0x06, /* Report Size (6) */135 0x95, 0x01, /* Report Count (1) */136 0x91, 0x01, /* Output (Const,Array,Abs) */137 0xC0 /* End Collection */138};139 140static const __u8 *maltron_report_fixup(struct hid_device *hdev, __u8 *rdesc,141 unsigned int *rsize)142{143 if (*rsize == sizeof(maltron_rdesc_o) &&144 !memcmp(maltron_rdesc_o, rdesc, sizeof(maltron_rdesc_o))) {145 hid_info(hdev, "Replacing Maltron L90 keyboard report descriptor\n");146 *rsize = sizeof(maltron_rdesc);147 return maltron_rdesc;148 }149 return rdesc;150}151 152static const struct hid_device_id maltron_devices[] = {153 { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_MALTRON_KB)},154 { }155};156MODULE_DEVICE_TABLE(hid, maltron_devices);157 158static struct hid_driver maltron_driver = {159 .name = "maltron",160 .id_table = maltron_devices,161 .report_fixup = maltron_report_fixup162};163module_hid_driver(maltron_driver);164 165MODULE_DESCRIPTION("HID driver for Maltron L90");166MODULE_LICENSE("GPL");167