1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * HID driver for primax and similar keyboards with in-band modifiers 4 * 5 * Copyright 2011 Google Inc. All Rights Reserved 6 * 7 * Author: 8 * Terry Lambert <tlambert@google.com> 9 */ 10 11 #include <linux/device.h> 12 #include <linux/hid.h> 13 #include <linux/module.h> 14 15 #include "hid-ids.h" 16 17 static int px_raw_event(struct hid_device *hid, struct hid_report *report, 18 u8 *data, int size) 19 { 20 int idx = size; 21 22 switch (report->id) { 23 case 0: /* keyboard input */ 24 /* 25 * Convert in-band modifier key values into out of band 26 * modifier bits and pull the key strokes from the report. 27 * Thus a report data set which looked like: 28 * 29 * [00][00][E0][30][00][00][00][00] 30 * (no modifier bits + "Left Shift" key + "1" key) 31 * 32 * Would be converted to: 33 * 34 * [01][00][00][30][00][00][00][00] 35 * (Left Shift modifier bit + "1" key) 36 * 37 * As long as it's in the size range, the upper level 38 * drivers don't particularly care if there are in-band 39 * 0-valued keys, so they don't stop parsing. 40 */ 41 while (--idx > 1) { 42 if (data[idx] < 0xE0 || data[idx] > 0xE7) 43 continue; 44 data[0] |= (1 << (data[idx] - 0xE0)); 45 data[idx] = 0; 46 } 47 hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, 0); 48 return 1; 49 50 default: /* unknown report */ 51 /* Unknown report type; pass upstream */ 52 hid_info(hid, "unknown report type %d\n", report->id); 53 break; 54 } 55 56 return 0; 57 } 58 59 static const struct hid_device_id px_devices[] = { 60 { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, 61 { } 62 }; 63 MODULE_DEVICE_TABLE(hid, px_devices); 64 65 static struct hid_driver px_driver = { 66 .name = "primax", 67 .id_table = px_devices, 68 .raw_event = px_raw_event, 69 }; 70 module_hid_driver(px_driver); 71 72 MODULE_AUTHOR("Terry Lambert <tlambert@google.com>"); 73 MODULE_DESCRIPTION("HID driver for primax and similar keyboards with in-band modifiers"); 74 MODULE_LICENSE("GPL"); 75