18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * HID driver for the apple ir device 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Original driver written by James McKenzie 68c2ecf20Sopenharmony_ci * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de> 78c2ecf20Sopenharmony_ci * Updated to support newer remotes by Bastien Nocera <hadess@hadess.net> 88c2ecf20Sopenharmony_ci * Ported to HID subsystem by Benjamin Tissoires <benjamin.tissoires@gmail.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright (C) 2006 James McKenzie 118c2ecf20Sopenharmony_ci * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com> 128c2ecf20Sopenharmony_ci * Copyright (C) 2008 Novell Inc. 138c2ecf20Sopenharmony_ci * Copyright (C) 2010, 2012 Bastien Nocera <hadess@hadess.net> 148c2ecf20Sopenharmony_ci * Copyright (C) 2013 Benjamin Tissoires <benjamin.tissoires@gmail.com> 158c2ecf20Sopenharmony_ci * Copyright (C) 2013 Red Hat Inc. All Rights Reserved 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/device.h> 198c2ecf20Sopenharmony_ci#include <linux/hid.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include "hid-ids.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciMODULE_AUTHOR("James McKenzie"); 248c2ecf20Sopenharmony_ciMODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>"); 258c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HID Apple IR remote controls"); 268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define KEY_MASK 0x0F 298c2ecf20Sopenharmony_ci#define TWO_PACKETS_MASK 0x40 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * James McKenzie has two devices both of which report the following 338c2ecf20Sopenharmony_ci * 25 87 ee 83 0a + 348c2ecf20Sopenharmony_ci * 25 87 ee 83 0c - 358c2ecf20Sopenharmony_ci * 25 87 ee 83 09 << 368c2ecf20Sopenharmony_ci * 25 87 ee 83 06 >> 378c2ecf20Sopenharmony_ci * 25 87 ee 83 05 >" 388c2ecf20Sopenharmony_ci * 25 87 ee 83 03 menu 398c2ecf20Sopenharmony_ci * 26 00 00 00 00 for key repeat 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * Thomas Glanzmann reports the following responses 448c2ecf20Sopenharmony_ci * 25 87 ee ca 0b + 458c2ecf20Sopenharmony_ci * 25 87 ee ca 0d - 468c2ecf20Sopenharmony_ci * 25 87 ee ca 08 << 478c2ecf20Sopenharmony_ci * 25 87 ee ca 07 >> 488c2ecf20Sopenharmony_ci * 25 87 ee ca 04 >" 498c2ecf20Sopenharmony_ci * 25 87 ee ca 02 menu 508c2ecf20Sopenharmony_ci * 26 00 00 00 00 for key repeat 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * He also observes the following event sometimes 538c2ecf20Sopenharmony_ci * sent after a key is release, which I interpret 548c2ecf20Sopenharmony_ci * as a flat battery message 558c2ecf20Sopenharmony_ci * 25 87 e0 ca 06 flat battery 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * Alexandre Karpenko reports the following responses for Device ID 0x8242 608c2ecf20Sopenharmony_ci * 25 87 ee 47 0b + 618c2ecf20Sopenharmony_ci * 25 87 ee 47 0d - 628c2ecf20Sopenharmony_ci * 25 87 ee 47 08 << 638c2ecf20Sopenharmony_ci * 25 87 ee 47 07 >> 648c2ecf20Sopenharmony_ci * 25 87 ee 47 04 >" 658c2ecf20Sopenharmony_ci * 25 87 ee 47 02 menu 668c2ecf20Sopenharmony_ci * 26 87 ee 47 ** for key repeat (** is the code of the key being held) 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* 708c2ecf20Sopenharmony_ci * Bastien Nocera's remote 718c2ecf20Sopenharmony_ci * 25 87 ee 91 5f followed by 728c2ecf20Sopenharmony_ci * 25 87 ee 91 05 gives you >" 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * 25 87 ee 91 5c followed by 758c2ecf20Sopenharmony_ci * 25 87 ee 91 05 gives you the middle button 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * Fabien Andre's remote 808c2ecf20Sopenharmony_ci * 25 87 ee a3 5e followed by 818c2ecf20Sopenharmony_ci * 25 87 ee a3 04 gives you >" 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * 25 87 ee a3 5d followed by 848c2ecf20Sopenharmony_ci * 25 87 ee a3 04 gives you the middle button 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic const unsigned short appleir_key_table[] = { 888c2ecf20Sopenharmony_ci KEY_RESERVED, 898c2ecf20Sopenharmony_ci KEY_MENU, 908c2ecf20Sopenharmony_ci KEY_PLAYPAUSE, 918c2ecf20Sopenharmony_ci KEY_FORWARD, 928c2ecf20Sopenharmony_ci KEY_BACK, 938c2ecf20Sopenharmony_ci KEY_VOLUMEUP, 948c2ecf20Sopenharmony_ci KEY_VOLUMEDOWN, 958c2ecf20Sopenharmony_ci KEY_RESERVED, 968c2ecf20Sopenharmony_ci KEY_RESERVED, 978c2ecf20Sopenharmony_ci KEY_RESERVED, 988c2ecf20Sopenharmony_ci KEY_RESERVED, 998c2ecf20Sopenharmony_ci KEY_RESERVED, 1008c2ecf20Sopenharmony_ci KEY_RESERVED, 1018c2ecf20Sopenharmony_ci KEY_RESERVED, 1028c2ecf20Sopenharmony_ci KEY_ENTER, 1038c2ecf20Sopenharmony_ci KEY_PLAYPAUSE, 1048c2ecf20Sopenharmony_ci KEY_RESERVED, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistruct appleir { 1088c2ecf20Sopenharmony_ci struct input_dev *input_dev; 1098c2ecf20Sopenharmony_ci struct hid_device *hid; 1108c2ecf20Sopenharmony_ci unsigned short keymap[ARRAY_SIZE(appleir_key_table)]; 1118c2ecf20Sopenharmony_ci struct timer_list key_up_timer; /* timer for key up */ 1128c2ecf20Sopenharmony_ci spinlock_t lock; /* protects .current_key */ 1138c2ecf20Sopenharmony_ci int current_key; /* the currently pressed key */ 1148c2ecf20Sopenharmony_ci int prev_key_idx; /* key index in a 2 packets message */ 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int get_key(int data) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci /* 1208c2ecf20Sopenharmony_ci * The key is coded accross bits 2..9: 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * 0x00 or 0x01 ( ) key: 0 -> KEY_RESERVED 1238c2ecf20Sopenharmony_ci * 0x02 or 0x03 ( menu ) key: 1 -> KEY_MENU 1248c2ecf20Sopenharmony_ci * 0x04 or 0x05 ( >" ) key: 2 -> KEY_PLAYPAUSE 1258c2ecf20Sopenharmony_ci * 0x06 or 0x07 ( >> ) key: 3 -> KEY_FORWARD 1268c2ecf20Sopenharmony_ci * 0x08 or 0x09 ( << ) key: 4 -> KEY_BACK 1278c2ecf20Sopenharmony_ci * 0x0a or 0x0b ( + ) key: 5 -> KEY_VOLUMEUP 1288c2ecf20Sopenharmony_ci * 0x0c or 0x0d ( - ) key: 6 -> KEY_VOLUMEDOWN 1298c2ecf20Sopenharmony_ci * 0x0e or 0x0f ( ) key: 7 -> KEY_RESERVED 1308c2ecf20Sopenharmony_ci * 0x50 or 0x51 ( ) key: 8 -> KEY_RESERVED 1318c2ecf20Sopenharmony_ci * 0x52 or 0x53 ( ) key: 9 -> KEY_RESERVED 1328c2ecf20Sopenharmony_ci * 0x54 or 0x55 ( ) key: 10 -> KEY_RESERVED 1338c2ecf20Sopenharmony_ci * 0x56 or 0x57 ( ) key: 11 -> KEY_RESERVED 1348c2ecf20Sopenharmony_ci * 0x58 or 0x59 ( ) key: 12 -> KEY_RESERVED 1358c2ecf20Sopenharmony_ci * 0x5a or 0x5b ( ) key: 13 -> KEY_RESERVED 1368c2ecf20Sopenharmony_ci * 0x5c or 0x5d ( middle ) key: 14 -> KEY_ENTER 1378c2ecf20Sopenharmony_ci * 0x5e or 0x5f ( >" ) key: 15 -> KEY_PLAYPAUSE 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci * Packets starting with 0x5 are part of a two-packets message, 1408c2ecf20Sopenharmony_ci * we notify the caller by sending a negative value. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci int key = (data >> 1) & KEY_MASK; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if ((data & TWO_PACKETS_MASK)) 1458c2ecf20Sopenharmony_ci /* Part of a 2 packets-command */ 1468c2ecf20Sopenharmony_ci key = -key; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return key; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic void key_up(struct hid_device *hid, struct appleir *appleir, int key) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci input_report_key(appleir->input_dev, key, 0); 1548c2ecf20Sopenharmony_ci input_sync(appleir->input_dev); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void key_down(struct hid_device *hid, struct appleir *appleir, int key) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci input_report_key(appleir->input_dev, key, 1); 1608c2ecf20Sopenharmony_ci input_sync(appleir->input_dev); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void battery_flat(struct appleir *appleir) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci dev_err(&appleir->input_dev->dev, "possible flat battery?\n"); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void key_up_tick(struct timer_list *t) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct appleir *appleir = from_timer(appleir, t, key_up_timer); 1718c2ecf20Sopenharmony_ci struct hid_device *hid = appleir->hid; 1728c2ecf20Sopenharmony_ci unsigned long flags; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci spin_lock_irqsave(&appleir->lock, flags); 1758c2ecf20Sopenharmony_ci if (appleir->current_key) { 1768c2ecf20Sopenharmony_ci key_up(hid, appleir, appleir->current_key); 1778c2ecf20Sopenharmony_ci appleir->current_key = 0; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&appleir->lock, flags); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic int appleir_raw_event(struct hid_device *hid, struct hid_report *report, 1838c2ecf20Sopenharmony_ci u8 *data, int len) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct appleir *appleir = hid_get_drvdata(hid); 1868c2ecf20Sopenharmony_ci static const u8 keydown[] = { 0x25, 0x87, 0xee }; 1878c2ecf20Sopenharmony_ci static const u8 keyrepeat[] = { 0x26, }; 1888c2ecf20Sopenharmony_ci static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 }; 1898c2ecf20Sopenharmony_ci unsigned long flags; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (len != 5) 1928c2ecf20Sopenharmony_ci goto out; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (!memcmp(data, keydown, sizeof(keydown))) { 1958c2ecf20Sopenharmony_ci int index; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci spin_lock_irqsave(&appleir->lock, flags); 1988c2ecf20Sopenharmony_ci /* 1998c2ecf20Sopenharmony_ci * If we already have a key down, take it up before marking 2008c2ecf20Sopenharmony_ci * this one down 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci if (appleir->current_key) 2038c2ecf20Sopenharmony_ci key_up(hid, appleir, appleir->current_key); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* Handle dual packet commands */ 2068c2ecf20Sopenharmony_ci if (appleir->prev_key_idx > 0) 2078c2ecf20Sopenharmony_ci index = appleir->prev_key_idx; 2088c2ecf20Sopenharmony_ci else 2098c2ecf20Sopenharmony_ci index = get_key(data[4]); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (index >= 0) { 2128c2ecf20Sopenharmony_ci appleir->current_key = appleir->keymap[index]; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci key_down(hid, appleir, appleir->current_key); 2158c2ecf20Sopenharmony_ci /* 2168c2ecf20Sopenharmony_ci * Remote doesn't do key up, either pull them up, in 2178c2ecf20Sopenharmony_ci * the test above, or here set a timer which pulls 2188c2ecf20Sopenharmony_ci * them up after 1/8 s 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci mod_timer(&appleir->key_up_timer, jiffies + HZ / 8); 2218c2ecf20Sopenharmony_ci appleir->prev_key_idx = 0; 2228c2ecf20Sopenharmony_ci } else 2238c2ecf20Sopenharmony_ci /* Remember key for next packet */ 2248c2ecf20Sopenharmony_ci appleir->prev_key_idx = -index; 2258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&appleir->lock, flags); 2268c2ecf20Sopenharmony_ci goto out; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci appleir->prev_key_idx = 0; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) { 2328c2ecf20Sopenharmony_ci key_down(hid, appleir, appleir->current_key); 2338c2ecf20Sopenharmony_ci /* 2348c2ecf20Sopenharmony_ci * Remote doesn't do key up, either pull them up, in the test 2358c2ecf20Sopenharmony_ci * above, or here set a timer which pulls them up after 1/8 s 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci mod_timer(&appleir->key_up_timer, jiffies + HZ / 8); 2388c2ecf20Sopenharmony_ci goto out; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (!memcmp(data, flatbattery, sizeof(flatbattery))) { 2428c2ecf20Sopenharmony_ci battery_flat(appleir); 2438c2ecf20Sopenharmony_ci /* Fall through */ 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciout: 2478c2ecf20Sopenharmony_ci /* let hidraw and hiddev handle the report */ 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int appleir_input_configured(struct hid_device *hid, 2528c2ecf20Sopenharmony_ci struct hid_input *hidinput) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct input_dev *input_dev = hidinput->input; 2558c2ecf20Sopenharmony_ci struct appleir *appleir = hid_get_drvdata(hid); 2568c2ecf20Sopenharmony_ci int i; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci appleir->input_dev = input_dev; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci input_dev->keycode = appleir->keymap; 2618c2ecf20Sopenharmony_ci input_dev->keycodesize = sizeof(unsigned short); 2628c2ecf20Sopenharmony_ci input_dev->keycodemax = ARRAY_SIZE(appleir->keymap); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap)); 2678c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++) 2688c2ecf20Sopenharmony_ci set_bit(appleir->keymap[i], input_dev->keybit); 2698c2ecf20Sopenharmony_ci clear_bit(KEY_RESERVED, input_dev->keybit); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic int appleir_input_mapping(struct hid_device *hid, 2758c2ecf20Sopenharmony_ci struct hid_input *hi, struct hid_field *field, 2768c2ecf20Sopenharmony_ci struct hid_usage *usage, unsigned long **bit, int *max) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci return -1; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int appleir_probe(struct hid_device *hid, const struct hid_device_id *id) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci int ret; 2848c2ecf20Sopenharmony_ci struct appleir *appleir; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci appleir = devm_kzalloc(&hid->dev, sizeof(struct appleir), GFP_KERNEL); 2878c2ecf20Sopenharmony_ci if (!appleir) 2888c2ecf20Sopenharmony_ci return -ENOMEM; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci appleir->hid = hid; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* force input as some remotes bypass the input registration */ 2938c2ecf20Sopenharmony_ci hid->quirks |= HID_QUIRK_HIDINPUT_FORCE; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci spin_lock_init(&appleir->lock); 2968c2ecf20Sopenharmony_ci timer_setup(&appleir->key_up_timer, key_up_tick, 0); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci hid_set_drvdata(hid, appleir); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ret = hid_parse(hid); 3018c2ecf20Sopenharmony_ci if (ret) { 3028c2ecf20Sopenharmony_ci hid_err(hid, "parse failed\n"); 3038c2ecf20Sopenharmony_ci goto fail; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci ret = hid_hw_start(hid, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE); 3078c2ecf20Sopenharmony_ci if (ret) { 3088c2ecf20Sopenharmony_ci hid_err(hid, "hw start failed\n"); 3098c2ecf20Sopenharmony_ci goto fail; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_cifail: 3148c2ecf20Sopenharmony_ci devm_kfree(&hid->dev, appleir); 3158c2ecf20Sopenharmony_ci return ret; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic void appleir_remove(struct hid_device *hid) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct appleir *appleir = hid_get_drvdata(hid); 3218c2ecf20Sopenharmony_ci hid_hw_stop(hid); 3228c2ecf20Sopenharmony_ci del_timer_sync(&appleir->key_up_timer); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic const struct hid_device_id appleir_devices[] = { 3268c2ecf20Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, 3278c2ecf20Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) }, 3288c2ecf20Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) }, 3298c2ecf20Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, 3308c2ecf20Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) }, 3318c2ecf20Sopenharmony_ci { } 3328c2ecf20Sopenharmony_ci}; 3338c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(hid, appleir_devices); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic struct hid_driver appleir_driver = { 3368c2ecf20Sopenharmony_ci .name = "appleir", 3378c2ecf20Sopenharmony_ci .id_table = appleir_devices, 3388c2ecf20Sopenharmony_ci .raw_event = appleir_raw_event, 3398c2ecf20Sopenharmony_ci .input_configured = appleir_input_configured, 3408c2ecf20Sopenharmony_ci .probe = appleir_probe, 3418c2ecf20Sopenharmony_ci .remove = appleir_remove, 3428c2ecf20Sopenharmony_ci .input_mapping = appleir_input_mapping, 3438c2ecf20Sopenharmony_ci}; 3448c2ecf20Sopenharmony_cimodule_hid_driver(appleir_driver); 345