Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'hid-for-linus-2024010801' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID updates from Jiri Kosina:

- assorted functional fixes for hid-steam ported from SteamOS betas
(Vicki Pfau)

- fix for custom sensor-hub sensors (hinge angle sensor and LISS
sensors) not working (Yauhen Kharuzhy)

- functional fix for handling Confidence in Wacom driver (Jason
Gerecke)

- support for Ilitek ili2901 touchscreen (Zhengqiao Xia)

- power management fix for Wacom userspace battery exporting
(Tatsunosuke Tobita)

- rework of wait-for-reset in order to reduce the need for
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET qurk; the success rate is now 50%
better, but there are still further improvements to be made (Hans de
Goede)

- greatly improved coverage of Tablets in hid-selftests (Benjamin
Tissoires)

- support for Nintendo NSO controllers -- SNES, Genesis and N64 (Ryan
McClelland)

- support for controlling mcp2200 GPIOs (Johannes Roith)

- power management improvement for EHL OOB wakeup in intel-ish
(Kai-Heng Feng)

- other assorted device-specific fixes and code cleanups

* tag 'hid-for-linus-2024010801' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (53 commits)
HID: amd_sfh: Add a new interface for exporting ALS data
HID: amd_sfh: Add a new interface for exporting HPD data
HID: amd_sfh: rename float_to_int() to amd_sfh_float_to_int()
HID: i2c-hid: elan: Add ili2901 timing
dt-bindings: HID: i2c-hid: elan: Introduce Ilitek ili2901
HID: bpf: make bus_type const in struct hid_bpf_ops
HID: make ishtp_cl_bus_type const
HID: make hid_bus_type const
HID: hid-steam: Add gamepad-only mode switched to by holding options
HID: hid-steam: Better handling of serial number length
HID: hid-steam: Update list of identifiers from SDL
HID: hid-steam: Make client_opened a counter
HID: hid-steam: Clean up locking
HID: hid-steam: Disable watchdog instead of using a heartbeat
HID: hid-steam: Avoid overwriting smoothing parameter
HID: magicmouse: fix kerneldoc for struct magicmouse_sc
HID: sensor-hub: Enable hid core report processing for all devices
HID: wacom: Add additional tests of confidence behavior
HID: wacom: Correct behavior when processing some confidence == false touches
HID: nintendo: add support for nso controllers
...

+2834 -1050
+3 -2
Documentation/devicetree/bindings/input/elan,ekth6915.yaml
··· 18 18 19 19 properties: 20 20 compatible: 21 - items: 22 - - const: elan,ekth6915 21 + enum: 22 + - elan,ekth6915 23 + - ilitek,ili2901 23 24 24 25 reg: 25 26 const: 0x10
+16 -6
drivers/hid/Kconfig
··· 761 761 module will be called hid-multitouch. 762 762 763 763 config HID_NINTENDO 764 - tristate "Nintendo Joy-Con and Pro Controller support" 764 + tristate "Nintendo Joy-Con, NSO, and Pro Controller support" 765 765 depends on NEW_LEDS 766 766 depends on LEDS_CLASS 767 767 select POWER_SUPPLY 768 768 help 769 - Adds support for the Nintendo Switch Joy-Cons and Pro Controller. 769 + Adds support for the Nintendo Switch Joy-Cons, NSO, Pro Controller. 770 770 All controllers support bluetooth, and the Pro Controller also supports 771 - its USB mode. 771 + its USB mode. This also includes support for the Nintendo Switch Online 772 + Controllers which include the Genesis, SNES, and N64 controllers. 772 773 773 774 To compile this driver as a module, choose M here: the 774 775 module will be called hid-nintendo. ··· 780 779 select INPUT_FF_MEMLESS 781 780 help 782 781 Say Y here if you have a Nintendo Switch controller and want to enable 783 - force feedback support for it. This works for both joy-cons and the pro 784 - controller. For the pro controller, both rumble motors can be controlled 785 - individually. 782 + force feedback support for it. This works for both joy-cons, the pro 783 + controller, and the NSO N64 controller. For the pro controller, both 784 + rumble motors can be controlled individually. 786 785 787 786 config HID_NTI 788 787 tristate "NTI keyboard adapters" ··· 1296 1295 Support for Alps I2C HID touchpads and StickPointer. 1297 1296 Say Y here if you have a Alps touchpads over i2c-hid or usbhid 1298 1297 and want support for its special functionalities. 1298 + 1299 + config HID_MCP2200 1300 + tristate "Microchip MCP2200 HID USB-to-GPIO bridge" 1301 + depends on USB_HID && GPIOLIB 1302 + help 1303 + Provides GPIO functionality over USB-HID through MCP2200 device. 1304 + 1305 + To compile this driver as a module, choose M here: the module 1306 + will be called hid-mcp2200.ko. 1299 1307 1300 1308 config HID_MCP2221 1301 1309 tristate "Microchip MCP2221 HID USB-to-I2C/SMbus host support"
+1
drivers/hid/Makefile
··· 79 79 obj-$(CONFIG_HID_MACALLY) += hid-macally.o 80 80 obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o 81 81 obj-$(CONFIG_HID_MALTRON) += hid-maltron.o 82 + obj-$(CONFIG_HID_MCP2200) += hid-mcp2200.o 82 83 obj-$(CONFIG_HID_MCP2221) += hid-mcp2221.o 83 84 obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o 84 85 obj-$(CONFIG_HID_MEGAWORLD_FF) += hid-megaworld.o
+6
drivers/hid/amd-sfh-hid/amd_sfh_common.h
··· 37 37 dma_addr_t dma_address; 38 38 }; 39 39 40 + struct sfh_dev_status { 41 + bool is_hpd_present; 42 + bool is_als_present; 43 + }; 44 + 40 45 struct amd_mp2_dev { 41 46 struct pci_dev *pdev; 42 47 struct amdtp_cl_data *cl_data; ··· 52 47 struct amd_input_data in_data; 53 48 /* mp2 active control status */ 54 49 u32 mp2_acs; 50 + struct sfh_dev_status dev_en; 55 51 }; 56 52 57 53 struct amd_mp2_ops {
+15 -13
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
··· 132 132 common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM; 133 133 } 134 134 135 - static int float_to_int(u32 flt32_val) 135 + int amd_sfh_float_to_int(u32 flt32_val) 136 136 { 137 137 int fraction, shift, mantissa, sign, exp, zeropre; 138 138 ··· 201 201 OFFSET_SENSOR_DATA_DEFAULT; 202 202 memcpy_fromio(&accel_data, sensoraddr, sizeof(struct sfh_accel_data)); 203 203 get_common_inputs(&acc_input.common_property, report_id); 204 - acc_input.in_accel_x_value = float_to_int(accel_data.acceldata.x) / 100; 205 - acc_input.in_accel_y_value = float_to_int(accel_data.acceldata.y) / 100; 206 - acc_input.in_accel_z_value = float_to_int(accel_data.acceldata.z) / 100; 204 + acc_input.in_accel_x_value = amd_sfh_float_to_int(accel_data.acceldata.x) / 100; 205 + acc_input.in_accel_y_value = amd_sfh_float_to_int(accel_data.acceldata.y) / 100; 206 + acc_input.in_accel_z_value = amd_sfh_float_to_int(accel_data.acceldata.z) / 100; 207 207 memcpy(input_report, &acc_input, sizeof(acc_input)); 208 208 report_size = sizeof(acc_input); 209 209 break; ··· 212 212 OFFSET_SENSOR_DATA_DEFAULT; 213 213 memcpy_fromio(&gyro_data, sensoraddr, sizeof(struct sfh_gyro_data)); 214 214 get_common_inputs(&gyro_input.common_property, report_id); 215 - gyro_input.in_angel_x_value = float_to_int(gyro_data.gyrodata.x) / 1000; 216 - gyro_input.in_angel_y_value = float_to_int(gyro_data.gyrodata.y) / 1000; 217 - gyro_input.in_angel_z_value = float_to_int(gyro_data.gyrodata.z) / 1000; 215 + gyro_input.in_angel_x_value = amd_sfh_float_to_int(gyro_data.gyrodata.x) / 1000; 216 + gyro_input.in_angel_y_value = amd_sfh_float_to_int(gyro_data.gyrodata.y) / 1000; 217 + gyro_input.in_angel_z_value = amd_sfh_float_to_int(gyro_data.gyrodata.z) / 1000; 218 218 memcpy(input_report, &gyro_input, sizeof(gyro_input)); 219 219 report_size = sizeof(gyro_input); 220 220 break; ··· 223 223 OFFSET_SENSOR_DATA_DEFAULT; 224 224 memcpy_fromio(&mag_data, sensoraddr, sizeof(struct sfh_mag_data)); 225 225 get_common_inputs(&magno_input.common_property, report_id); 226 - magno_input.in_magno_x = float_to_int(mag_data.magdata.x) / 100; 227 - magno_input.in_magno_y = float_to_int(mag_data.magdata.y) / 100; 228 - magno_input.in_magno_z = float_to_int(mag_data.magdata.z) / 100; 226 + magno_input.in_magno_x = amd_sfh_float_to_int(mag_data.magdata.x) / 100; 227 + magno_input.in_magno_y = amd_sfh_float_to_int(mag_data.magdata.y) / 100; 228 + magno_input.in_magno_z = amd_sfh_float_to_int(mag_data.magdata.z) / 100; 229 229 magno_input.in_magno_accuracy = mag_data.accuracy / 100; 230 230 memcpy(input_report, &magno_input, sizeof(magno_input)); 231 231 report_size = sizeof(magno_input); ··· 235 235 OFFSET_SENSOR_DATA_DEFAULT; 236 236 memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data)); 237 237 get_common_inputs(&als_input.common_property, report_id); 238 - als_input.illuminance_value = float_to_int(als_data.lux); 238 + als_input.illuminance_value = amd_sfh_float_to_int(als_data.lux); 239 239 240 240 memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info)); 241 241 if (binfo.sbase.s_prop[ALS_IDX].sf.feat & 0x2) { 242 242 als_input.light_color_temp = als_data.light_color_temp; 243 - als_input.chromaticity_x_value = float_to_int(als_data.chromaticity_x); 244 - als_input.chromaticity_y_value = float_to_int(als_data.chromaticity_y); 243 + als_input.chromaticity_x_value = 244 + amd_sfh_float_to_int(als_data.chromaticity_x); 245 + als_input.chromaticity_y_value = 246 + amd_sfh_float_to_int(als_data.chromaticity_y); 245 247 } 246 248 247 249 report_size = sizeof(als_input);
+20
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c
··· 73 73 int i, status; 74 74 75 75 for (i = 0; i < cl_data->num_hid_devices; i++) { 76 + switch (cl_data->sensor_idx[i]) { 77 + case HPD_IDX: 78 + privdata->dev_en.is_hpd_present = false; 79 + break; 80 + case ALS_IDX: 81 + privdata->dev_en.is_als_present = false; 82 + break; 83 + } 84 + 76 85 if (cl_data->sensor_sts[i] == SENSOR_ENABLED) { 77 86 privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]); 78 87 status = amd_sfh_wait_for_response ··· 187 178 rc = amdtp_hid_probe(i, cl_data); 188 179 if (rc) 189 180 goto cleanup; 181 + switch (cl_data->sensor_idx[i]) { 182 + case HPD_IDX: 183 + privdata->dev_en.is_hpd_present = true; 184 + break; 185 + case ALS_IDX: 186 + privdata->dev_en.is_als_present = true; 187 + break; 188 + } 190 189 } 191 190 dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n", 192 191 cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), ··· 276 259 { 277 260 struct amd_mp2_dev *mp2 = privdata; 278 261 262 + sfh_deinit_emp2(); 279 263 amd_sfh_hid_client_deinit(privdata); 280 264 mp2->mp2_ops->stop_all(mp2); 281 265 pci_intx(mp2->pdev, false); ··· 329 311 330 312 rc = amd_sfh_irq_init(mp2); 331 313 if (rc) { 314 + sfh_deinit_emp2(); 332 315 dev_err(dev, "amd_sfh_irq_init failed\n"); 333 316 return rc; 334 317 } 335 318 336 319 rc = amd_sfh1_1_hid_client_init(mp2); 337 320 if (rc) { 321 + sfh_deinit_emp2(); 338 322 dev_err(dev, "amd_sfh1_1_hid_client_init failed\n"); 339 323 return rc; 340 324 }
+59
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
··· 7 7 * 8 8 * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> 9 9 */ 10 + #include <linux/amd-pmf-io.h> 10 11 #include <linux/io-64-nonatomic-lo-hi.h> 11 12 #include <linux/iopoll.h> 12 13 13 14 #include "amd_sfh_interface.h" 15 + 16 + static struct amd_mp2_dev *emp2; 14 17 15 18 static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id) 16 19 { ··· 76 73 .response = amd_sfh_wait_response, 77 74 }; 78 75 76 + void sfh_deinit_emp2(void) 77 + { 78 + emp2 = NULL; 79 + } 80 + 79 81 void sfh_interface_init(struct amd_mp2_dev *mp2) 80 82 { 81 83 mp2->mp2_ops = &amd_sfh_ops; 84 + emp2 = mp2; 82 85 } 86 + 87 + static int amd_sfh_hpd_info(u8 *user_present) 88 + { 89 + struct hpd_status hpdstatus; 90 + 91 + if (!user_present) 92 + return -EINVAL; 93 + 94 + if (!emp2 || !emp2->dev_en.is_hpd_present) 95 + return -ENODEV; 96 + 97 + hpdstatus.val = readl(emp2->mmio + AMD_C2P_MSG(4)); 98 + *user_present = hpdstatus.shpd.presence; 99 + 100 + return 0; 101 + } 102 + 103 + static int amd_sfh_als_info(u32 *ambient_light) 104 + { 105 + struct sfh_als_data als_data; 106 + void __iomem *sensoraddr; 107 + 108 + if (!ambient_light) 109 + return -EINVAL; 110 + 111 + if (!emp2 || !emp2->dev_en.is_als_present) 112 + return -ENODEV; 113 + 114 + sensoraddr = emp2->vsbase + 115 + (ALS_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) + 116 + OFFSET_SENSOR_DATA_DEFAULT; 117 + memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data)); 118 + *ambient_light = amd_sfh_float_to_int(als_data.lux); 119 + 120 + return 0; 121 + } 122 + 123 + int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op) 124 + { 125 + if (sfh_info) { 126 + switch (op) { 127 + case MT_HPD: 128 + return amd_sfh_hpd_info(&sfh_info->user_present); 129 + case MT_ALS: 130 + return amd_sfh_als_info(&sfh_info->ambient_light); 131 + } 132 + } 133 + return -EINVAL; 134 + } 135 + EXPORT_SYMBOL_GPL(amd_get_sfh_info);
+2
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
··· 165 165 }; 166 166 167 167 void sfh_interface_init(struct amd_mp2_dev *mp2); 168 + void sfh_deinit_emp2(void); 168 169 void amd_sfh1_1_set_desc_ops(struct amd_mp2_ops *mp2_ops); 170 + int amd_sfh_float_to_int(u32 flt32_val); 169 171 #endif
+1 -1
drivers/hid/hid-core.c
··· 2749 2749 return 0; 2750 2750 } 2751 2751 2752 - struct bus_type hid_bus_type = { 2752 + const struct bus_type hid_bus_type = { 2753 2753 .name = "hid", 2754 2754 .dev_groups = hid_dev_groups, 2755 2755 .drv_groups = hid_drv_groups,
+5 -1
drivers/hid/hid-ids.h
··· 916 916 #define USB_DEVICE_ID_PICK16F1454 0x0042 917 917 #define USB_DEVICE_ID_PICK16F1454_V2 0xf2f7 918 918 #define USB_DEVICE_ID_LUXAFOR 0xf372 919 + #define USB_DEVICE_ID_MCP2200 0x00df 919 920 #define USB_DEVICE_ID_MCP2221 0x00dd 920 921 921 922 #define USB_VENDOR_ID_MICROSOFT 0x045e ··· 988 987 #define USB_DEVICE_ID_NINTENDO_JOYCONL 0x2006 989 988 #define USB_DEVICE_ID_NINTENDO_JOYCONR 0x2007 990 989 #define USB_DEVICE_ID_NINTENDO_PROCON 0x2009 991 - #define USB_DEVICE_ID_NINTENDO_CHRGGRIP 0x200E 990 + #define USB_DEVICE_ID_NINTENDO_CHRGGRIP 0x200e 991 + #define USB_DEVICE_ID_NINTENDO_SNESCON 0x2017 992 + #define USB_DEVICE_ID_NINTENDO_GENCON 0x201e 993 + #define USB_DEVICE_ID_NINTENDO_N64CON 0x2019 992 994 993 995 #define USB_VENDOR_ID_NOVATEK 0x0603 994 996 #define USB_DEVICE_ID_NOVATEK_PCT 0x0600
+3
drivers/hid/hid-magicmouse.c
··· 120 120 * @scroll_jiffies: Time of last scroll motion. 121 121 * @touches: Most recent data for a touch, indexed by tracking ID. 122 122 * @tracking_ids: Mapping of current touch input data to @touches. 123 + * @hdev: Pointer to the underlying HID device. 124 + * @work: Workqueue to handle initialization retry for quirky devices. 125 + * @battery_timer: Timer for obtaining battery level information. 123 126 */ 124 127 struct magicmouse_sc { 125 128 struct input_dev *input;
+392
drivers/hid/hid-mcp2200.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * MCP2200 - Microchip USB to GPIO bridge 4 + * 5 + * Copyright (c) 2023, Johannes Roith <johannes@gnu-linux.rocks> 6 + * 7 + * Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/22228A.pdf 8 + * App Note for HID: https://ww1.microchip.com/downloads/en/DeviceDoc/93066A.pdf 9 + */ 10 + #include <linux/completion.h> 11 + #include <linux/delay.h> 12 + #include <linux/err.h> 13 + #include <linux/gpio/driver.h> 14 + #include <linux/hid.h> 15 + #include <linux/hidraw.h> 16 + #include <linux/module.h> 17 + #include <linux/mutex.h> 18 + #include "hid-ids.h" 19 + 20 + /* Commands codes in a raw output report */ 21 + #define SET_CLEAR_OUTPUTS 0x08 22 + #define CONFIGURE 0x10 23 + #define READ_EE 0x20 24 + #define WRITE_EE 0x40 25 + #define READ_ALL 0x80 26 + 27 + /* MCP GPIO direction encoding */ 28 + enum MCP_IO_DIR { 29 + MCP2200_DIR_OUT = 0x00, 30 + MCP2200_DIR_IN = 0x01, 31 + }; 32 + 33 + /* Altternative pin assignments */ 34 + #define TXLED 2 35 + #define RXLED 3 36 + #define USBCFG 6 37 + #define SSPND 7 38 + #define MCP_NGPIO 8 39 + 40 + /* CMD to set or clear a GPIO output */ 41 + struct mcp_set_clear_outputs { 42 + u8 cmd; 43 + u8 dummys1[10]; 44 + u8 set_bmap; 45 + u8 clear_bmap; 46 + u8 dummys2[3]; 47 + } __packed; 48 + 49 + /* CMD to configure the IOs */ 50 + struct mcp_configure { 51 + u8 cmd; 52 + u8 dummys1[3]; 53 + u8 io_bmap; 54 + u8 config_alt_pins; 55 + u8 io_default_val_bmap; 56 + u8 config_alt_options; 57 + u8 baud_h; 58 + u8 baud_l; 59 + u8 dummys2[6]; 60 + } __packed; 61 + 62 + /* CMD to read all parameters */ 63 + struct mcp_read_all { 64 + u8 cmd; 65 + u8 dummys[15]; 66 + } __packed; 67 + 68 + /* Response to the read all cmd */ 69 + struct mcp_read_all_resp { 70 + u8 cmd; 71 + u8 eep_addr; 72 + u8 dummy; 73 + u8 eep_val; 74 + u8 io_bmap; 75 + u8 config_alt_pins; 76 + u8 io_default_val_bmap; 77 + u8 config_alt_options; 78 + u8 baud_h; 79 + u8 baud_l; 80 + u8 io_port_val_bmap; 81 + u8 dummys[5]; 82 + } __packed; 83 + 84 + struct mcp2200 { 85 + struct hid_device *hdev; 86 + struct mutex lock; 87 + struct completion wait_in_report; 88 + u8 gpio_dir; 89 + u8 gpio_val; 90 + u8 gpio_inval; 91 + u8 baud_h; 92 + u8 baud_l; 93 + u8 config_alt_pins; 94 + u8 gpio_reset_val; 95 + u8 config_alt_options; 96 + int status; 97 + struct gpio_chip gc; 98 + u8 hid_report[16]; 99 + }; 100 + 101 + /* this executes the READ_ALL cmd */ 102 + static int mcp_cmd_read_all(struct mcp2200 *mcp) 103 + { 104 + struct mcp_read_all *read_all; 105 + int len, t; 106 + 107 + reinit_completion(&mcp->wait_in_report); 108 + 109 + mutex_lock(&mcp->lock); 110 + 111 + read_all = (struct mcp_read_all *) mcp->hid_report; 112 + read_all->cmd = READ_ALL; 113 + len = hid_hw_output_report(mcp->hdev, (u8 *) read_all, 114 + sizeof(struct mcp_read_all)); 115 + 116 + mutex_unlock(&mcp->lock); 117 + 118 + if (len != sizeof(struct mcp_read_all)) 119 + return -EINVAL; 120 + 121 + t = wait_for_completion_timeout(&mcp->wait_in_report, 122 + msecs_to_jiffies(4000)); 123 + if (!t) 124 + return -ETIMEDOUT; 125 + 126 + /* return status, negative value if wrong response was received */ 127 + return mcp->status; 128 + } 129 + 130 + static void mcp_set_multiple(struct gpio_chip *gc, unsigned long *mask, 131 + unsigned long *bits) 132 + { 133 + struct mcp2200 *mcp = gpiochip_get_data(gc); 134 + u8 value; 135 + int status; 136 + struct mcp_set_clear_outputs *cmd; 137 + 138 + mutex_lock(&mcp->lock); 139 + cmd = (struct mcp_set_clear_outputs *) mcp->hid_report; 140 + 141 + value = mcp->gpio_val & ~*mask; 142 + value |= (*mask & *bits); 143 + 144 + cmd->cmd = SET_CLEAR_OUTPUTS; 145 + cmd->set_bmap = value; 146 + cmd->clear_bmap = ~(value); 147 + 148 + status = hid_hw_output_report(mcp->hdev, (u8 *) cmd, 149 + sizeof(struct mcp_set_clear_outputs)); 150 + 151 + if (status == sizeof(struct mcp_set_clear_outputs)) 152 + mcp->gpio_val = value; 153 + 154 + mutex_unlock(&mcp->lock); 155 + } 156 + 157 + static void mcp_set(struct gpio_chip *gc, unsigned int gpio_nr, int value) 158 + { 159 + unsigned long mask = 1 << gpio_nr; 160 + unsigned long bmap_value = value << gpio_nr; 161 + 162 + mcp_set_multiple(gc, &mask, &bmap_value); 163 + } 164 + 165 + static int mcp_get_multiple(struct gpio_chip *gc, unsigned long *mask, 166 + unsigned long *bits) 167 + { 168 + u32 val; 169 + struct mcp2200 *mcp = gpiochip_get_data(gc); 170 + int status; 171 + 172 + status = mcp_cmd_read_all(mcp); 173 + if (status) 174 + return status; 175 + 176 + val = mcp->gpio_inval; 177 + *bits = (val & *mask); 178 + return 0; 179 + } 180 + 181 + static int mcp_get(struct gpio_chip *gc, unsigned int gpio_nr) 182 + { 183 + unsigned long mask = 0, bits = 0; 184 + 185 + mask = (1 << gpio_nr); 186 + mcp_get_multiple(gc, &mask, &bits); 187 + return bits > 0; 188 + } 189 + 190 + static int mcp_get_direction(struct gpio_chip *gc, unsigned int gpio_nr) 191 + { 192 + struct mcp2200 *mcp = gpiochip_get_data(gc); 193 + 194 + return (mcp->gpio_dir & (MCP2200_DIR_IN << gpio_nr)) 195 + ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; 196 + } 197 + 198 + static int mcp_set_direction(struct gpio_chip *gc, unsigned int gpio_nr, 199 + enum MCP_IO_DIR io_direction) 200 + { 201 + struct mcp2200 *mcp = gpiochip_get_data(gc); 202 + struct mcp_configure *conf; 203 + int status; 204 + /* after the configure cmd we will need to set the outputs again */ 205 + unsigned long mask = ~(mcp->gpio_dir); /* only set outputs */ 206 + unsigned long bits = mcp->gpio_val; 207 + /* Offsets of alternative pins in config_alt_pins, 0 is not used */ 208 + u8 alt_pin_conf[8] = {SSPND, USBCFG, 0, 0, 0, 0, RXLED, TXLED}; 209 + u8 config_alt_pins = mcp->config_alt_pins; 210 + 211 + /* Read in the reset baudrate first, we need it later */ 212 + status = mcp_cmd_read_all(mcp); 213 + if (status != 0) 214 + return status; 215 + 216 + mutex_lock(&mcp->lock); 217 + conf = (struct mcp_configure *) mcp->hid_report; 218 + 219 + /* configure will reset the chip! */ 220 + conf->cmd = CONFIGURE; 221 + conf->io_bmap = (mcp->gpio_dir & ~(1 << gpio_nr)) 222 + | (io_direction << gpio_nr); 223 + /* Don't overwrite the reset parameters */ 224 + conf->baud_h = mcp->baud_h; 225 + conf->baud_l = mcp->baud_l; 226 + conf->config_alt_options = mcp->config_alt_options; 227 + conf->io_default_val_bmap = mcp->gpio_reset_val; 228 + /* Adjust alt. func if necessary */ 229 + if (alt_pin_conf[gpio_nr]) 230 + config_alt_pins &= ~(1 << alt_pin_conf[gpio_nr]); 231 + conf->config_alt_pins = config_alt_pins; 232 + 233 + status = hid_hw_output_report(mcp->hdev, (u8 *) conf, 234 + sizeof(struct mcp_set_clear_outputs)); 235 + 236 + if (status == sizeof(struct mcp_set_clear_outputs)) { 237 + mcp->gpio_dir = conf->io_bmap; 238 + mcp->config_alt_pins = config_alt_pins; 239 + } else { 240 + mutex_unlock(&mcp->lock); 241 + return -EIO; 242 + } 243 + 244 + mutex_unlock(&mcp->lock); 245 + 246 + /* Configure CMD will clear all IOs -> rewrite them */ 247 + mcp_set_multiple(gc, &mask, &bits); 248 + return 0; 249 + } 250 + 251 + static int mcp_direction_input(struct gpio_chip *gc, unsigned int gpio_nr) 252 + { 253 + return mcp_set_direction(gc, gpio_nr, MCP2200_DIR_IN); 254 + } 255 + 256 + static int mcp_direction_output(struct gpio_chip *gc, unsigned int gpio_nr, 257 + int value) 258 + { 259 + int ret; 260 + unsigned long mask, bmap_value; 261 + 262 + mask = 1 << gpio_nr; 263 + bmap_value = value << gpio_nr; 264 + 265 + ret = mcp_set_direction(gc, gpio_nr, MCP2200_DIR_OUT); 266 + if (!ret) 267 + mcp_set_multiple(gc, &mask, &bmap_value); 268 + return ret; 269 + } 270 + 271 + static const struct gpio_chip template_chip = { 272 + .label = "mcp2200", 273 + .owner = THIS_MODULE, 274 + .get_direction = mcp_get_direction, 275 + .direction_input = mcp_direction_input, 276 + .direction_output = mcp_direction_output, 277 + .set = mcp_set, 278 + .set_multiple = mcp_set_multiple, 279 + .get = mcp_get, 280 + .get_multiple = mcp_get_multiple, 281 + .base = -1, 282 + .ngpio = MCP_NGPIO, 283 + .can_sleep = true, 284 + }; 285 + 286 + /* 287 + * MCP2200 uses interrupt endpoint for input reports. This function 288 + * is called by HID layer when it receives i/p report from mcp2200, 289 + * which is actually a response to the previously sent command. 290 + */ 291 + static int mcp2200_raw_event(struct hid_device *hdev, struct hid_report *report, 292 + u8 *data, int size) 293 + { 294 + struct mcp2200 *mcp = hid_get_drvdata(hdev); 295 + struct mcp_read_all_resp *all_resp; 296 + 297 + switch (data[0]) { 298 + case READ_ALL: 299 + all_resp = (struct mcp_read_all_resp *) data; 300 + mcp->status = 0; 301 + mcp->gpio_inval = all_resp->io_port_val_bmap; 302 + mcp->baud_h = all_resp->baud_h; 303 + mcp->baud_l = all_resp->baud_l; 304 + mcp->gpio_reset_val = all_resp->io_default_val_bmap; 305 + mcp->config_alt_pins = all_resp->config_alt_pins; 306 + mcp->config_alt_options = all_resp->config_alt_options; 307 + break; 308 + default: 309 + mcp->status = -EIO; 310 + break; 311 + } 312 + 313 + complete(&mcp->wait_in_report); 314 + return 0; 315 + } 316 + 317 + static int mcp2200_probe(struct hid_device *hdev, const struct hid_device_id *id) 318 + { 319 + int ret; 320 + struct mcp2200 *mcp; 321 + 322 + mcp = devm_kzalloc(&hdev->dev, sizeof(*mcp), GFP_KERNEL); 323 + if (!mcp) 324 + return -ENOMEM; 325 + 326 + ret = hid_parse(hdev); 327 + if (ret) { 328 + hid_err(hdev, "can't parse reports\n"); 329 + return ret; 330 + } 331 + 332 + ret = hid_hw_start(hdev, 0); 333 + if (ret) { 334 + hid_err(hdev, "can't start hardware\n"); 335 + return ret; 336 + } 337 + 338 + hid_info(hdev, "USB HID v%x.%02x Device [%s] on %s\n", hdev->version >> 8, 339 + hdev->version & 0xff, hdev->name, hdev->phys); 340 + 341 + ret = hid_hw_open(hdev); 342 + if (ret) { 343 + hid_err(hdev, "can't open device\n"); 344 + hid_hw_stop(hdev); 345 + return ret; 346 + } 347 + 348 + mutex_init(&mcp->lock); 349 + init_completion(&mcp->wait_in_report); 350 + hid_set_drvdata(hdev, mcp); 351 + mcp->hdev = hdev; 352 + 353 + mcp->gc = template_chip; 354 + mcp->gc.parent = &hdev->dev; 355 + 356 + ret = devm_gpiochip_add_data(&hdev->dev, &mcp->gc, mcp); 357 + if (ret < 0) { 358 + hid_err(hdev, "Unable to register gpiochip\n"); 359 + hid_hw_close(hdev); 360 + hid_hw_stop(hdev); 361 + return ret; 362 + } 363 + 364 + return 0; 365 + } 366 + 367 + static void mcp2200_remove(struct hid_device *hdev) 368 + { 369 + hid_hw_close(hdev); 370 + hid_hw_stop(hdev); 371 + } 372 + 373 + static const struct hid_device_id mcp2200_devices[] = { 374 + { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_MCP2200) }, 375 + { } 376 + }; 377 + MODULE_DEVICE_TABLE(hid, mcp2200_devices); 378 + 379 + static struct hid_driver mcp2200_driver = { 380 + .name = "mcp2200", 381 + .id_table = mcp2200_devices, 382 + .probe = mcp2200_probe, 383 + .remove = mcp2200_remove, 384 + .raw_event = mcp2200_raw_event, 385 + }; 386 + 387 + /* Register with HID core */ 388 + module_hid_driver(mcp2200_driver); 389 + 390 + MODULE_AUTHOR("Johannes Roith <johannes@gnu-linux.rocks>"); 391 + MODULE_DESCRIPTION("MCP2200 Microchip HID USB to GPIO bridge"); 392 + MODULE_LICENSE("GPL");
+50 -22
drivers/hid/hid-mcp2221.c
··· 49 49 MCP2221_I2C_MASK_ADDR_NACK = 0x40, 50 50 MCP2221_I2C_WRADDRL_SEND = 0x21, 51 51 MCP2221_I2C_ADDR_NACK = 0x25, 52 + MCP2221_I2C_READ_PARTIAL = 0x54, 52 53 MCP2221_I2C_READ_COMPL = 0x55, 53 54 MCP2221_ALT_F_NOT_GPIOV = 0xEE, 54 55 MCP2221_ALT_F_NOT_GPIOD = 0xEF, ··· 188 187 return mcp_send_data_req_status(mcp, mcp->txbuf, 8); 189 188 } 190 189 190 + /* Check if the last command succeeded or failed and return the result. 191 + * If the command did fail, cancel that command which will free the i2c bus. 192 + */ 193 + static int mcp_chk_last_cmd_status_free_bus(struct mcp2221 *mcp) 194 + { 195 + int ret; 196 + 197 + ret = mcp_chk_last_cmd_status(mcp); 198 + if (ret) { 199 + /* The last command was a failure. 200 + * Send a cancel which will also free the bus. 201 + */ 202 + usleep_range(980, 1000); 203 + mcp_cancel_last_cmd(mcp); 204 + } 205 + 206 + return ret; 207 + } 208 + 191 209 static int mcp_set_i2c_speed(struct mcp2221 *mcp) 192 210 { 193 211 int ret; ··· 261 241 usleep_range(980, 1000); 262 242 263 243 if (last_status) { 264 - ret = mcp_chk_last_cmd_status(mcp); 244 + ret = mcp_chk_last_cmd_status_free_bus(mcp); 265 245 if (ret) 266 246 return ret; 267 247 } ··· 298 278 { 299 279 int ret; 300 280 u16 total_len; 281 + int retries = 0; 301 282 302 283 mcp->txbuf[0] = type; 303 284 if (msg) { ··· 322 301 mcp->rxbuf_idx = 0; 323 302 324 303 do { 304 + /* Wait for the data to be read by the device */ 305 + usleep_range(980, 1000); 306 + 325 307 memset(mcp->txbuf, 0, 4); 326 308 mcp->txbuf[0] = MCP2221_I2C_GET_DATA; 327 309 328 310 ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); 329 - if (ret) 330 - return ret; 331 - 332 - ret = mcp_chk_last_cmd_status(mcp); 333 - if (ret) 334 - return ret; 335 - 336 - usleep_range(980, 1000); 311 + if (ret) { 312 + if (retries < 5) { 313 + /* The data wasn't ready to read. 314 + * Wait a bit longer and try again. 315 + */ 316 + usleep_range(90, 100); 317 + retries++; 318 + } else { 319 + return ret; 320 + } 321 + } else { 322 + retries = 0; 323 + } 337 324 } while (mcp->rxbuf_idx < total_len); 325 + 326 + usleep_range(980, 1000); 327 + ret = mcp_chk_last_cmd_status_free_bus(mcp); 338 328 339 329 return ret; 340 330 } ··· 359 327 hid_hw_power(mcp->hdev, PM_HINT_FULLON); 360 328 361 329 mutex_lock(&mcp->lock); 362 - 363 - /* Setting speed before every transaction is required for mcp2221 */ 364 - ret = mcp_set_i2c_speed(mcp); 365 - if (ret) 366 - goto exit; 367 330 368 331 if (num == 1) { 369 332 if (msgs->flags & I2C_M_RD) { ··· 444 417 if (last_status) { 445 418 usleep_range(980, 1000); 446 419 447 - ret = mcp_chk_last_cmd_status(mcp); 448 - if (ret) 449 - return ret; 420 + ret = mcp_chk_last_cmd_status_free_bus(mcp); 450 421 } 451 422 452 423 return ret; ··· 461 436 hid_hw_power(mcp->hdev, PM_HINT_FULLON); 462 437 463 438 mutex_lock(&mcp->lock); 464 - 465 - ret = mcp_set_i2c_speed(mcp); 466 - if (ret) 467 - goto exit; 468 439 469 440 switch (size) { 470 441 ··· 812 791 mcp->status = -EIO; 813 792 break; 814 793 } 815 - if (data[2] == MCP2221_I2C_READ_COMPL) { 794 + if (data[2] == MCP2221_I2C_READ_COMPL || 795 + data[2] == MCP2221_I2C_READ_PARTIAL) { 816 796 buf = mcp->rxbuf; 817 797 memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]); 818 798 mcp->rxbuf_idx = mcp->rxbuf_idx + data[3]; ··· 1172 1150 if (i2c_clk_freq < 50) 1173 1151 i2c_clk_freq = 50; 1174 1152 mcp->cur_i2c_clk_div = (12000000 / (i2c_clk_freq * 1000)) - 3; 1153 + ret = mcp_set_i2c_speed(mcp); 1154 + if (ret) { 1155 + hid_err(hdev, "can't set i2c speed: %d\n", ret); 1156 + return ret; 1157 + } 1175 1158 1176 1159 mcp->adapter.owner = THIS_MODULE; 1177 1160 mcp->adapter.class = I2C_CLASS_HWMON; 1178 1161 mcp->adapter.algo = &mcp_i2c_algo; 1179 1162 mcp->adapter.retries = 1; 1180 1163 mcp->adapter.dev.parent = &hdev->dev; 1164 + ACPI_COMPANION_SET(&mcp->adapter.dev, ACPI_COMPANION(hdev->dev.parent)); 1181 1165 snprintf(mcp->adapter.name, sizeof(mcp->adapter.name), 1182 1166 "MCP2221 usb-i2c bridge"); 1183 1167
+631 -252
drivers/hid/hid-nintendo.c
··· 3 3 * HID driver for Nintendo Switch Joy-Cons and Pro Controllers 4 4 * 5 5 * Copyright (c) 2019-2021 Daniel J. Ogorchock <djogorchock@gmail.com> 6 + * Portions Copyright (c) 2020 Nadia Holmquist Pedersen <nadia@nhp.sh> 7 + * Copyright (c) 2022 Emily Strickland <linux@emily.st> 8 + * Copyright (c) 2023 Ryan McClelland <rymcclel@gmail.com> 6 9 * 7 10 * The following resources/projects were referenced for this driver: 8 11 * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering ··· 19 16 * 20 17 * This driver supports the Nintendo Switch Joy-Cons and Pro Controllers. The 21 18 * Pro Controllers can either be used over USB or Bluetooth. 19 + * 20 + * This driver also incorporates support for Nintendo Switch Online controllers 21 + * for the NES, SNES, Sega Genesis, and N64. 22 22 * 23 23 * The driver will retrieve the factory calibration info from the controllers, 24 24 * so little to no user calibration should be required. ··· 311 305 312 306 /* Controller type received as part of device info */ 313 307 enum joycon_ctlr_type { 314 - JOYCON_CTLR_TYPE_JCL = 0x01, 315 - JOYCON_CTLR_TYPE_JCR = 0x02, 316 - JOYCON_CTLR_TYPE_PRO = 0x03, 308 + JOYCON_CTLR_TYPE_JCL = 0x01, 309 + JOYCON_CTLR_TYPE_JCR = 0x02, 310 + JOYCON_CTLR_TYPE_PRO = 0x03, 311 + JOYCON_CTLR_TYPE_NESL = 0x09, 312 + JOYCON_CTLR_TYPE_NESR = 0x0A, 313 + JOYCON_CTLR_TYPE_SNES = 0x0B, 314 + JOYCON_CTLR_TYPE_GEN = 0x0D, 315 + JOYCON_CTLR_TYPE_N64 = 0x0C, 317 316 }; 318 317 319 318 struct joycon_stick_cal { ··· 358 347 #define JC_BTN_SL_L BIT(21) 359 348 #define JC_BTN_L BIT(22) 360 349 #define JC_BTN_ZL BIT(23) 350 + 351 + struct joycon_ctlr_button_mapping { 352 + u32 code; 353 + u32 bit; 354 + }; 355 + 356 + /* 357 + * D-pad is configured as buttons for the left Joy-Con only! 358 + */ 359 + static const struct joycon_ctlr_button_mapping left_joycon_button_mappings[] = { 360 + { BTN_TL, JC_BTN_L, }, 361 + { BTN_TL2, JC_BTN_ZL, }, 362 + { BTN_SELECT, JC_BTN_MINUS, }, 363 + { BTN_THUMBL, JC_BTN_LSTICK, }, 364 + { BTN_DPAD_UP, JC_BTN_UP, }, 365 + { BTN_DPAD_DOWN, JC_BTN_DOWN, }, 366 + { BTN_DPAD_LEFT, JC_BTN_LEFT, }, 367 + { BTN_DPAD_RIGHT, JC_BTN_RIGHT, }, 368 + { BTN_Z, JC_BTN_CAP, }, 369 + { /* sentinel */ }, 370 + }; 371 + 372 + /* 373 + * The unused *right*-side triggers become the SL/SR triggers for the *left* 374 + * Joy-Con, if and only if we're not using a charging grip. 375 + */ 376 + static const struct joycon_ctlr_button_mapping left_joycon_s_button_mappings[] = { 377 + { BTN_TR, JC_BTN_SL_L, }, 378 + { BTN_TR2, JC_BTN_SR_L, }, 379 + { /* sentinel */ }, 380 + }; 381 + 382 + static const struct joycon_ctlr_button_mapping right_joycon_button_mappings[] = { 383 + { BTN_EAST, JC_BTN_A, }, 384 + { BTN_SOUTH, JC_BTN_B, }, 385 + { BTN_NORTH, JC_BTN_X, }, 386 + { BTN_WEST, JC_BTN_Y, }, 387 + { BTN_TR, JC_BTN_R, }, 388 + { BTN_TR2, JC_BTN_ZR, }, 389 + { BTN_START, JC_BTN_PLUS, }, 390 + { BTN_THUMBR, JC_BTN_RSTICK, }, 391 + { BTN_MODE, JC_BTN_HOME, }, 392 + { /* sentinel */ }, 393 + }; 394 + 395 + /* 396 + * The unused *left*-side triggers become the SL/SR triggers for the *right* 397 + * Joy-Con, if and only if we're not using a charging grip. 398 + */ 399 + static const struct joycon_ctlr_button_mapping right_joycon_s_button_mappings[] = { 400 + { BTN_TL, JC_BTN_SL_R, }, 401 + { BTN_TL2, JC_BTN_SR_R, }, 402 + { /* sentinel */ }, 403 + }; 404 + 405 + static const struct joycon_ctlr_button_mapping procon_button_mappings[] = { 406 + { BTN_EAST, JC_BTN_A, }, 407 + { BTN_SOUTH, JC_BTN_B, }, 408 + { BTN_NORTH, JC_BTN_X, }, 409 + { BTN_WEST, JC_BTN_Y, }, 410 + { BTN_TL, JC_BTN_L, }, 411 + { BTN_TR, JC_BTN_R, }, 412 + { BTN_TL2, JC_BTN_ZL, }, 413 + { BTN_TR2, JC_BTN_ZR, }, 414 + { BTN_SELECT, JC_BTN_MINUS, }, 415 + { BTN_START, JC_BTN_PLUS, }, 416 + { BTN_THUMBL, JC_BTN_LSTICK, }, 417 + { BTN_THUMBR, JC_BTN_RSTICK, }, 418 + { BTN_MODE, JC_BTN_HOME, }, 419 + { BTN_Z, JC_BTN_CAP, }, 420 + { /* sentinel */ }, 421 + }; 422 + 423 + static const struct joycon_ctlr_button_mapping nescon_button_mappings[] = { 424 + { BTN_SOUTH, JC_BTN_A, }, 425 + { BTN_EAST, JC_BTN_B, }, 426 + { BTN_TL, JC_BTN_L, }, 427 + { BTN_TR, JC_BTN_R, }, 428 + { BTN_SELECT, JC_BTN_MINUS, }, 429 + { BTN_START, JC_BTN_PLUS, }, 430 + { /* sentinel */ }, 431 + }; 432 + 433 + static const struct joycon_ctlr_button_mapping snescon_button_mappings[] = { 434 + { BTN_EAST, JC_BTN_A, }, 435 + { BTN_SOUTH, JC_BTN_B, }, 436 + { BTN_NORTH, JC_BTN_X, }, 437 + { BTN_WEST, JC_BTN_Y, }, 438 + { BTN_TL, JC_BTN_L, }, 439 + { BTN_TR, JC_BTN_R, }, 440 + { BTN_TL2, JC_BTN_ZL, }, 441 + { BTN_TR2, JC_BTN_ZR, }, 442 + { BTN_SELECT, JC_BTN_MINUS, }, 443 + { BTN_START, JC_BTN_PLUS, }, 444 + { /* sentinel */ }, 445 + }; 446 + 447 + /* 448 + * "A", "B", and "C" are mapped positionally, rather than by label (e.g., "A" 449 + * gets assigned to BTN_EAST instead of BTN_A). 450 + */ 451 + static const struct joycon_ctlr_button_mapping gencon_button_mappings[] = { 452 + { BTN_SOUTH, JC_BTN_A, }, 453 + { BTN_EAST, JC_BTN_B, }, 454 + { BTN_WEST, JC_BTN_R, }, 455 + { BTN_SELECT, JC_BTN_ZR, }, 456 + { BTN_START, JC_BTN_PLUS, }, 457 + { BTN_MODE, JC_BTN_HOME, }, 458 + { BTN_Z, JC_BTN_CAP, }, 459 + { /* sentinel */ }, 460 + }; 461 + 462 + /* 463 + * N64's C buttons get assigned to d-pad directions and registered as buttons. 464 + */ 465 + static const struct joycon_ctlr_button_mapping n64con_button_mappings[] = { 466 + { BTN_A, JC_BTN_A, }, 467 + { BTN_B, JC_BTN_B, }, 468 + { BTN_TL2, JC_BTN_ZL, }, /* Z */ 469 + { BTN_TL, JC_BTN_L, }, 470 + { BTN_TR, JC_BTN_R, }, 471 + { BTN_TR2, JC_BTN_LSTICK, }, /* ZR */ 472 + { BTN_START, JC_BTN_PLUS, }, 473 + { BTN_FORWARD, JC_BTN_Y, }, /* C UP */ 474 + { BTN_BACK, JC_BTN_ZR, }, /* C DOWN */ 475 + { BTN_LEFT, JC_BTN_X, }, /* C LEFT */ 476 + { BTN_RIGHT, JC_BTN_MINUS, }, /* C RIGHT */ 477 + { BTN_MODE, JC_BTN_HOME, }, 478 + { BTN_Z, JC_BTN_CAP, }, 479 + { /* sentinel */ }, 480 + }; 361 481 362 482 enum joycon_msg_type { 363 483 JOYCON_MSG_TYPE_NONE, ··· 648 506 /* Does this controller have inputs associated with left joycon? */ 649 507 #define jc_type_has_left(ctlr) \ 650 508 (ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCL || \ 651 - ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO) 509 + ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO || \ 510 + ctlr->ctlr_type == JOYCON_CTLR_TYPE_N64) 652 511 653 512 /* Does this controller have inputs associated with right joycon? */ 654 513 #define jc_type_has_right(ctlr) \ 655 514 (ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR || \ 656 515 ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO) 516 + 517 + 518 + /* 519 + * Controller device helpers 520 + * 521 + * These look at the device ID known to the HID subsystem to identify a device, 522 + * but take caution: some NSO devices lie about themselves (NES Joy-Cons and 523 + * Sega Genesis controller). See type helpers below. 524 + * 525 + * These helpers are most useful early during the HID probe or in conjunction 526 + * with the capability helpers below. 527 + */ 528 + static inline bool joycon_device_is_left_joycon(struct joycon_ctlr *ctlr) 529 + { 530 + return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL; 531 + } 532 + 533 + static inline bool joycon_device_is_right_joycon(struct joycon_ctlr *ctlr) 534 + { 535 + return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONR; 536 + } 537 + 538 + static inline bool joycon_device_is_procon(struct joycon_ctlr *ctlr) 539 + { 540 + return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_PROCON; 541 + } 542 + 543 + static inline bool joycon_device_is_chrggrip(struct joycon_ctlr *ctlr) 544 + { 545 + return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_CHRGGRIP; 546 + } 547 + 548 + static inline bool joycon_device_is_snescon(struct joycon_ctlr *ctlr) 549 + { 550 + return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_SNESCON; 551 + } 552 + 553 + static inline bool joycon_device_is_gencon(struct joycon_ctlr *ctlr) 554 + { 555 + return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_GENCON; 556 + } 557 + 558 + static inline bool joycon_device_is_n64con(struct joycon_ctlr *ctlr) 559 + { 560 + return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_N64CON; 561 + } 562 + 563 + static inline bool joycon_device_has_usb(struct joycon_ctlr *ctlr) 564 + { 565 + return joycon_device_is_procon(ctlr) || 566 + joycon_device_is_chrggrip(ctlr) || 567 + joycon_device_is_snescon(ctlr) || 568 + joycon_device_is_gencon(ctlr) || 569 + joycon_device_is_n64con(ctlr); 570 + } 571 + 572 + /* 573 + * Controller type helpers 574 + * 575 + * These are slightly different than the device-ID-based helpers above. They are 576 + * generally more reliable, since they can distinguish between, e.g., Genesis 577 + * versus SNES, or NES Joy-Cons versus regular Switch Joy-Cons. They're most 578 + * useful for reporting available inputs. For other kinds of distinctions, see 579 + * the capability helpers below. 580 + * 581 + * They have two major drawbacks: (1) they're not available until after we set 582 + * the reporting method and then request the device info; (2) they can't 583 + * distinguish all controllers (like the Charging Grip from the Pro controller.) 584 + */ 585 + static inline bool joycon_type_is_left_joycon(struct joycon_ctlr *ctlr) 586 + { 587 + return ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCL; 588 + } 589 + 590 + static inline bool joycon_type_is_right_joycon(struct joycon_ctlr *ctlr) 591 + { 592 + return ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR; 593 + } 594 + 595 + static inline bool joycon_type_is_procon(struct joycon_ctlr *ctlr) 596 + { 597 + return ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO; 598 + } 599 + 600 + static inline bool joycon_type_is_snescon(struct joycon_ctlr *ctlr) 601 + { 602 + return ctlr->ctlr_type == JOYCON_CTLR_TYPE_SNES; 603 + } 604 + 605 + static inline bool joycon_type_is_gencon(struct joycon_ctlr *ctlr) 606 + { 607 + return ctlr->ctlr_type == JOYCON_CTLR_TYPE_GEN; 608 + } 609 + 610 + static inline bool joycon_type_is_n64con(struct joycon_ctlr *ctlr) 611 + { 612 + return ctlr->ctlr_type == JOYCON_CTLR_TYPE_N64; 613 + } 614 + 615 + static inline bool joycon_type_is_left_nescon(struct joycon_ctlr *ctlr) 616 + { 617 + return ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESL; 618 + } 619 + 620 + static inline bool joycon_type_is_right_nescon(struct joycon_ctlr *ctlr) 621 + { 622 + return ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESR; 623 + } 624 + 625 + static inline bool joycon_type_has_left_controls(struct joycon_ctlr *ctlr) 626 + { 627 + return joycon_type_is_left_joycon(ctlr) || 628 + joycon_type_is_procon(ctlr); 629 + } 630 + 631 + static inline bool joycon_type_has_right_controls(struct joycon_ctlr *ctlr) 632 + { 633 + return joycon_type_is_right_joycon(ctlr) || 634 + joycon_type_is_procon(ctlr); 635 + } 636 + 637 + static inline bool joycon_type_is_any_joycon(struct joycon_ctlr *ctlr) 638 + { 639 + return joycon_type_is_left_joycon(ctlr) || 640 + joycon_type_is_right_joycon(ctlr) || 641 + joycon_device_is_chrggrip(ctlr); 642 + } 643 + 644 + static inline bool joycon_type_is_any_nescon(struct joycon_ctlr *ctlr) 645 + { 646 + return joycon_type_is_left_nescon(ctlr) || 647 + joycon_type_is_right_nescon(ctlr); 648 + } 649 + 650 + /* 651 + * Controller capability helpers 652 + * 653 + * These helpers combine the use of the helpers above to detect certain 654 + * capabilities during initialization. They are always accurate but (since they 655 + * use type helpers) cannot be used early in the HID probe. 656 + */ 657 + static inline bool joycon_has_imu(struct joycon_ctlr *ctlr) 658 + { 659 + return joycon_device_is_chrggrip(ctlr) || 660 + joycon_type_is_any_joycon(ctlr) || 661 + joycon_type_is_procon(ctlr); 662 + } 663 + 664 + static inline bool joycon_has_joysticks(struct joycon_ctlr *ctlr) 665 + { 666 + return joycon_device_is_chrggrip(ctlr) || 667 + joycon_type_is_any_joycon(ctlr) || 668 + joycon_type_is_procon(ctlr) || 669 + joycon_type_is_n64con(ctlr); 670 + } 671 + 672 + static inline bool joycon_has_rumble(struct joycon_ctlr *ctlr) 673 + { 674 + return joycon_device_is_chrggrip(ctlr) || 675 + joycon_type_is_any_joycon(ctlr) || 676 + joycon_type_is_procon(ctlr) || 677 + joycon_type_is_n64con(ctlr); 678 + } 679 + 680 + static inline bool joycon_using_usb(struct joycon_ctlr *ctlr) 681 + { 682 + return ctlr->hdev->bus == BUS_USB; 683 + } 657 684 658 685 static int __joycon_hid_send(struct hid_device *hdev, u8 *data, size_t len) 659 686 { ··· 1607 1296 } 1608 1297 } 1609 1298 1610 - static void joycon_parse_report(struct joycon_ctlr *ctlr, 1611 - struct joycon_input_report *rep) 1299 + static void joycon_handle_rumble_report(struct joycon_ctlr *ctlr, struct joycon_input_report *rep) 1612 1300 { 1613 - struct input_dev *dev = ctlr->input; 1614 1301 unsigned long flags; 1615 - u8 tmp; 1616 - u32 btns; 1617 1302 unsigned long msecs = jiffies_to_msecs(jiffies); 1618 - unsigned long report_delta_ms = msecs - ctlr->last_input_report_msecs; 1619 1303 1620 1304 spin_lock_irqsave(&ctlr->lock, flags); 1621 1305 if (IS_ENABLED(CONFIG_NINTENDO_FF) && rep->vibrator_report && ··· 1629 1323 queue_work(ctlr->rumble_queue, &ctlr->rumble_worker); 1630 1324 } 1631 1325 1632 - /* Parse the battery status */ 1326 + spin_unlock_irqrestore(&ctlr->lock, flags); 1327 + } 1328 + 1329 + static void joycon_parse_battery_status(struct joycon_ctlr *ctlr, struct joycon_input_report *rep) 1330 + { 1331 + u8 tmp; 1332 + unsigned long flags; 1333 + 1334 + spin_lock_irqsave(&ctlr->lock, flags); 1335 + 1633 1336 tmp = rep->bat_con; 1634 1337 ctlr->host_powered = tmp & BIT(0); 1635 1338 ctlr->battery_charging = tmp & BIT(4); 1636 1339 tmp = tmp >> 5; 1340 + 1637 1341 switch (tmp) { 1638 1342 case 0: /* empty */ 1639 1343 ctlr->battery_capacity = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; ··· 1665 1349 hid_warn(ctlr->hdev, "Invalid battery status\n"); 1666 1350 break; 1667 1351 } 1352 + 1668 1353 spin_unlock_irqrestore(&ctlr->lock, flags); 1354 + } 1669 1355 1670 - /* Parse the buttons and sticks */ 1671 - btns = hid_field_extract(ctlr->hdev, rep->button_status, 0, 24); 1356 + static void joycon_report_left_stick(struct joycon_ctlr *ctlr, 1357 + struct joycon_input_report *rep) 1358 + { 1359 + u16 raw_x; 1360 + u16 raw_y; 1361 + s32 x; 1362 + s32 y; 1672 1363 1673 - if (jc_type_has_left(ctlr)) { 1674 - u16 raw_x; 1675 - u16 raw_y; 1676 - s32 x; 1677 - s32 y; 1364 + raw_x = hid_field_extract(ctlr->hdev, rep->left_stick, 0, 12); 1365 + raw_y = hid_field_extract(ctlr->hdev, rep->left_stick + 1, 4, 12); 1678 1366 1679 - /* get raw stick values */ 1680 - raw_x = hid_field_extract(ctlr->hdev, rep->left_stick, 0, 12); 1681 - raw_y = hid_field_extract(ctlr->hdev, 1682 - rep->left_stick + 1, 4, 12); 1683 - /* map the stick values */ 1684 - x = joycon_map_stick_val(&ctlr->left_stick_cal_x, raw_x); 1685 - y = -joycon_map_stick_val(&ctlr->left_stick_cal_y, raw_y); 1686 - /* report sticks */ 1687 - input_report_abs(dev, ABS_X, x); 1688 - input_report_abs(dev, ABS_Y, y); 1367 + x = joycon_map_stick_val(&ctlr->left_stick_cal_x, raw_x); 1368 + y = -joycon_map_stick_val(&ctlr->left_stick_cal_y, raw_y); 1689 1369 1690 - /* report buttons */ 1691 - input_report_key(dev, BTN_TL, btns & JC_BTN_L); 1692 - input_report_key(dev, BTN_TL2, btns & JC_BTN_ZL); 1693 - input_report_key(dev, BTN_SELECT, btns & JC_BTN_MINUS); 1694 - input_report_key(dev, BTN_THUMBL, btns & JC_BTN_LSTICK); 1695 - input_report_key(dev, BTN_Z, btns & JC_BTN_CAP); 1370 + input_report_abs(ctlr->input, ABS_X, x); 1371 + input_report_abs(ctlr->input, ABS_Y, y); 1372 + } 1696 1373 1697 - if (jc_type_is_joycon(ctlr)) { 1698 - /* Report the S buttons as the non-existent triggers */ 1699 - input_report_key(dev, BTN_TR, btns & JC_BTN_SL_L); 1700 - input_report_key(dev, BTN_TR2, btns & JC_BTN_SR_L); 1374 + static void joycon_report_right_stick(struct joycon_ctlr *ctlr, 1375 + struct joycon_input_report *rep) 1376 + { 1377 + u16 raw_x; 1378 + u16 raw_y; 1379 + s32 x; 1380 + s32 y; 1701 1381 1702 - /* Report d-pad as digital buttons for the joy-cons */ 1703 - input_report_key(dev, BTN_DPAD_DOWN, 1704 - btns & JC_BTN_DOWN); 1705 - input_report_key(dev, BTN_DPAD_UP, btns & JC_BTN_UP); 1706 - input_report_key(dev, BTN_DPAD_RIGHT, 1707 - btns & JC_BTN_RIGHT); 1708 - input_report_key(dev, BTN_DPAD_LEFT, 1709 - btns & JC_BTN_LEFT); 1710 - } else { 1711 - int hatx = 0; 1712 - int haty = 0; 1382 + raw_x = hid_field_extract(ctlr->hdev, rep->right_stick, 0, 12); 1383 + raw_y = hid_field_extract(ctlr->hdev, rep->right_stick + 1, 4, 12); 1713 1384 1714 - /* d-pad x */ 1715 - if (btns & JC_BTN_LEFT) 1716 - hatx = -1; 1717 - else if (btns & JC_BTN_RIGHT) 1718 - hatx = 1; 1719 - input_report_abs(dev, ABS_HAT0X, hatx); 1385 + x = joycon_map_stick_val(&ctlr->right_stick_cal_x, raw_x); 1386 + y = -joycon_map_stick_val(&ctlr->right_stick_cal_y, raw_y); 1720 1387 1721 - /* d-pad y */ 1722 - if (btns & JC_BTN_UP) 1723 - haty = -1; 1724 - else if (btns & JC_BTN_DOWN) 1725 - haty = 1; 1726 - input_report_abs(dev, ABS_HAT0Y, haty); 1727 - } 1388 + input_report_abs(ctlr->input, ABS_RX, x); 1389 + input_report_abs(ctlr->input, ABS_RY, y); 1390 + } 1391 + 1392 + static void joycon_report_dpad(struct joycon_ctlr *ctlr, 1393 + struct joycon_input_report *rep) 1394 + { 1395 + int hatx = 0; 1396 + int haty = 0; 1397 + u32 btns = hid_field_extract(ctlr->hdev, rep->button_status, 0, 24); 1398 + 1399 + if (btns & JC_BTN_LEFT) 1400 + hatx = -1; 1401 + else if (btns & JC_BTN_RIGHT) 1402 + hatx = 1; 1403 + 1404 + if (btns & JC_BTN_UP) 1405 + haty = -1; 1406 + else if (btns & JC_BTN_DOWN) 1407 + haty = 1; 1408 + 1409 + input_report_abs(ctlr->input, ABS_HAT0X, hatx); 1410 + input_report_abs(ctlr->input, ABS_HAT0Y, haty); 1411 + } 1412 + 1413 + static void joycon_report_buttons(struct joycon_ctlr *ctlr, 1414 + struct joycon_input_report *rep, 1415 + const struct joycon_ctlr_button_mapping button_mappings[]) 1416 + { 1417 + const struct joycon_ctlr_button_mapping *button; 1418 + u32 status = hid_field_extract(ctlr->hdev, rep->button_status, 0, 24); 1419 + 1420 + for (button = button_mappings; button->code; button++) 1421 + input_report_key(ctlr->input, button->code, status & button->bit); 1422 + } 1423 + 1424 + static void joycon_parse_report(struct joycon_ctlr *ctlr, 1425 + struct joycon_input_report *rep) 1426 + { 1427 + unsigned long flags; 1428 + unsigned long msecs = jiffies_to_msecs(jiffies); 1429 + unsigned long report_delta_ms = msecs - ctlr->last_input_report_msecs; 1430 + 1431 + if (joycon_has_rumble(ctlr)) 1432 + joycon_handle_rumble_report(ctlr, rep); 1433 + 1434 + joycon_parse_battery_status(ctlr, rep); 1435 + 1436 + if (joycon_type_is_left_joycon(ctlr)) { 1437 + joycon_report_left_stick(ctlr, rep); 1438 + joycon_report_buttons(ctlr, rep, left_joycon_button_mappings); 1439 + if (!joycon_device_is_chrggrip(ctlr)) 1440 + joycon_report_buttons(ctlr, rep, left_joycon_s_button_mappings); 1441 + } else if (joycon_type_is_right_joycon(ctlr)) { 1442 + joycon_report_right_stick(ctlr, rep); 1443 + joycon_report_buttons(ctlr, rep, right_joycon_button_mappings); 1444 + if (!joycon_device_is_chrggrip(ctlr)) 1445 + joycon_report_buttons(ctlr, rep, right_joycon_s_button_mappings); 1446 + } else if (joycon_type_is_procon(ctlr)) { 1447 + joycon_report_left_stick(ctlr, rep); 1448 + joycon_report_right_stick(ctlr, rep); 1449 + joycon_report_dpad(ctlr, rep); 1450 + joycon_report_buttons(ctlr, rep, procon_button_mappings); 1451 + } else if (joycon_type_is_any_nescon(ctlr)) { 1452 + joycon_report_dpad(ctlr, rep); 1453 + joycon_report_buttons(ctlr, rep, nescon_button_mappings); 1454 + } else if (joycon_type_is_snescon(ctlr)) { 1455 + joycon_report_dpad(ctlr, rep); 1456 + joycon_report_buttons(ctlr, rep, snescon_button_mappings); 1457 + } else if (joycon_type_is_gencon(ctlr)) { 1458 + joycon_report_dpad(ctlr, rep); 1459 + joycon_report_buttons(ctlr, rep, gencon_button_mappings); 1460 + } else if (joycon_type_is_n64con(ctlr)) { 1461 + joycon_report_left_stick(ctlr, rep); 1462 + joycon_report_dpad(ctlr, rep); 1463 + joycon_report_buttons(ctlr, rep, n64con_button_mappings); 1728 1464 } 1729 - if (jc_type_has_right(ctlr)) { 1730 - u16 raw_x; 1731 - u16 raw_y; 1732 - s32 x; 1733 - s32 y; 1734 1465 1735 - /* get raw stick values */ 1736 - raw_x = hid_field_extract(ctlr->hdev, rep->right_stick, 0, 12); 1737 - raw_y = hid_field_extract(ctlr->hdev, 1738 - rep->right_stick + 1, 4, 12); 1739 - /* map stick values */ 1740 - x = joycon_map_stick_val(&ctlr->right_stick_cal_x, raw_x); 1741 - y = -joycon_map_stick_val(&ctlr->right_stick_cal_y, raw_y); 1742 - /* report sticks */ 1743 - input_report_abs(dev, ABS_RX, x); 1744 - input_report_abs(dev, ABS_RY, y); 1745 - 1746 - /* report buttons */ 1747 - input_report_key(dev, BTN_TR, btns & JC_BTN_R); 1748 - input_report_key(dev, BTN_TR2, btns & JC_BTN_ZR); 1749 - if (jc_type_is_joycon(ctlr)) { 1750 - /* Report the S buttons as the non-existent triggers */ 1751 - input_report_key(dev, BTN_TL, btns & JC_BTN_SL_R); 1752 - input_report_key(dev, BTN_TL2, btns & JC_BTN_SR_R); 1753 - } 1754 - input_report_key(dev, BTN_START, btns & JC_BTN_PLUS); 1755 - input_report_key(dev, BTN_THUMBR, btns & JC_BTN_RSTICK); 1756 - input_report_key(dev, BTN_MODE, btns & JC_BTN_HOME); 1757 - input_report_key(dev, BTN_WEST, btns & JC_BTN_Y); 1758 - input_report_key(dev, BTN_NORTH, btns & JC_BTN_X); 1759 - input_report_key(dev, BTN_EAST, btns & JC_BTN_A); 1760 - input_report_key(dev, BTN_SOUTH, btns & JC_BTN_B); 1761 - } 1762 - 1763 - input_sync(dev); 1466 + input_sync(ctlr->input); 1764 1467 1765 1468 spin_lock_irqsave(&ctlr->lock, flags); 1766 1469 ctlr->last_input_report_msecs = msecs; ··· 1819 1484 } 1820 1485 1821 1486 /* parse IMU data if present */ 1822 - if (rep->id == JC_INPUT_IMU_DATA) 1487 + if ((rep->id == JC_INPUT_IMU_DATA) && joycon_has_imu(ctlr)) 1823 1488 joycon_parse_imu_report(ctlr, rep); 1824 1489 } 1825 1490 ··· 2032 1697 } 2033 1698 #endif /* IS_ENABLED(CONFIG_NINTENDO_FF) */ 2034 1699 2035 - static const unsigned int joycon_button_inputs_l[] = { 2036 - BTN_SELECT, BTN_Z, BTN_THUMBL, 2037 - BTN_TL, BTN_TL2, 2038 - 0 /* 0 signals end of array */ 2039 - }; 2040 - 2041 - static const unsigned int joycon_button_inputs_r[] = { 2042 - BTN_START, BTN_MODE, BTN_THUMBR, 2043 - BTN_SOUTH, BTN_EAST, BTN_NORTH, BTN_WEST, 2044 - BTN_TR, BTN_TR2, 2045 - 0 /* 0 signals end of array */ 2046 - }; 2047 - 2048 - /* We report joy-con d-pad inputs as buttons and pro controller as a hat. */ 2049 - static const unsigned int joycon_dpad_inputs_jc[] = { 2050 - BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT, 2051 - 0 /* 0 signals end of array */ 2052 - }; 2053 - 2054 - static int joycon_input_create(struct joycon_ctlr *ctlr) 1700 + static void joycon_config_left_stick(struct input_dev *idev) 2055 1701 { 2056 - struct hid_device *hdev; 2057 - const char *name; 2058 - const char *imu_name; 2059 - int ret; 2060 - int i; 1702 + input_set_abs_params(idev, 1703 + ABS_X, 1704 + -JC_MAX_STICK_MAG, 1705 + JC_MAX_STICK_MAG, 1706 + JC_STICK_FUZZ, 1707 + JC_STICK_FLAT); 1708 + input_set_abs_params(idev, 1709 + ABS_Y, 1710 + -JC_MAX_STICK_MAG, 1711 + JC_MAX_STICK_MAG, 1712 + JC_STICK_FUZZ, 1713 + JC_STICK_FLAT); 1714 + } 2061 1715 2062 - hdev = ctlr->hdev; 1716 + static void joycon_config_right_stick(struct input_dev *idev) 1717 + { 1718 + input_set_abs_params(idev, 1719 + ABS_RX, 1720 + -JC_MAX_STICK_MAG, 1721 + JC_MAX_STICK_MAG, 1722 + JC_STICK_FUZZ, 1723 + JC_STICK_FLAT); 1724 + input_set_abs_params(idev, 1725 + ABS_RY, 1726 + -JC_MAX_STICK_MAG, 1727 + JC_MAX_STICK_MAG, 1728 + JC_STICK_FUZZ, 1729 + JC_STICK_FLAT); 1730 + } 2063 1731 2064 - switch (hdev->product) { 2065 - case USB_DEVICE_ID_NINTENDO_PROCON: 2066 - name = "Nintendo Switch Pro Controller"; 2067 - imu_name = "Nintendo Switch Pro Controller IMU"; 2068 - break; 2069 - case USB_DEVICE_ID_NINTENDO_CHRGGRIP: 2070 - if (jc_type_has_left(ctlr)) { 2071 - name = "Nintendo Switch Left Joy-Con (Grip)"; 2072 - imu_name = "Nintendo Switch Left Joy-Con IMU (Grip)"; 2073 - } else { 2074 - name = "Nintendo Switch Right Joy-Con (Grip)"; 2075 - imu_name = "Nintendo Switch Right Joy-Con IMU (Grip)"; 2076 - } 2077 - break; 2078 - case USB_DEVICE_ID_NINTENDO_JOYCONL: 2079 - name = "Nintendo Switch Left Joy-Con"; 2080 - imu_name = "Nintendo Switch Left Joy-Con IMU"; 2081 - break; 2082 - case USB_DEVICE_ID_NINTENDO_JOYCONR: 2083 - name = "Nintendo Switch Right Joy-Con"; 2084 - imu_name = "Nintendo Switch Right Joy-Con IMU"; 2085 - break; 2086 - default: /* Should be impossible */ 2087 - hid_err(hdev, "Invalid hid product\n"); 2088 - return -EINVAL; 2089 - } 1732 + static void joycon_config_dpad(struct input_dev *idev) 1733 + { 1734 + input_set_abs_params(idev, 1735 + ABS_HAT0X, 1736 + -JC_MAX_DPAD_MAG, 1737 + JC_MAX_DPAD_MAG, 1738 + JC_DPAD_FUZZ, 1739 + JC_DPAD_FLAT); 1740 + input_set_abs_params(idev, 1741 + ABS_HAT0Y, 1742 + -JC_MAX_DPAD_MAG, 1743 + JC_MAX_DPAD_MAG, 1744 + JC_DPAD_FUZZ, 1745 + JC_DPAD_FLAT); 1746 + } 2090 1747 2091 - ctlr->input = devm_input_allocate_device(&hdev->dev); 2092 - if (!ctlr->input) 2093 - return -ENOMEM; 2094 - ctlr->input->id.bustype = hdev->bus; 2095 - ctlr->input->id.vendor = hdev->vendor; 2096 - ctlr->input->id.product = hdev->product; 2097 - ctlr->input->id.version = hdev->version; 2098 - ctlr->input->uniq = ctlr->mac_addr_str; 2099 - ctlr->input->name = name; 2100 - ctlr->input->phys = hdev->phys; 2101 - input_set_drvdata(ctlr->input, ctlr); 1748 + static void joycon_config_buttons(struct input_dev *idev, 1749 + const struct joycon_ctlr_button_mapping button_mappings[]) 1750 + { 1751 + const struct joycon_ctlr_button_mapping *button; 2102 1752 2103 - /* set up sticks and buttons */ 2104 - if (jc_type_has_left(ctlr)) { 2105 - input_set_abs_params(ctlr->input, ABS_X, 2106 - -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, 2107 - JC_STICK_FUZZ, JC_STICK_FLAT); 2108 - input_set_abs_params(ctlr->input, ABS_Y, 2109 - -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, 2110 - JC_STICK_FUZZ, JC_STICK_FLAT); 1753 + for (button = button_mappings; button->code; button++) 1754 + input_set_capability(idev, EV_KEY, button->code); 1755 + } 2111 1756 2112 - for (i = 0; joycon_button_inputs_l[i] > 0; i++) 2113 - input_set_capability(ctlr->input, EV_KEY, 2114 - joycon_button_inputs_l[i]); 2115 - 2116 - /* configure d-pad differently for joy-con vs pro controller */ 2117 - if (hdev->product != USB_DEVICE_ID_NINTENDO_PROCON) { 2118 - for (i = 0; joycon_dpad_inputs_jc[i] > 0; i++) 2119 - input_set_capability(ctlr->input, EV_KEY, 2120 - joycon_dpad_inputs_jc[i]); 2121 - } else { 2122 - input_set_abs_params(ctlr->input, ABS_HAT0X, 2123 - -JC_MAX_DPAD_MAG, JC_MAX_DPAD_MAG, 2124 - JC_DPAD_FUZZ, JC_DPAD_FLAT); 2125 - input_set_abs_params(ctlr->input, ABS_HAT0Y, 2126 - -JC_MAX_DPAD_MAG, JC_MAX_DPAD_MAG, 2127 - JC_DPAD_FUZZ, JC_DPAD_FLAT); 2128 - } 2129 - } 2130 - if (jc_type_has_right(ctlr)) { 2131 - input_set_abs_params(ctlr->input, ABS_RX, 2132 - -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, 2133 - JC_STICK_FUZZ, JC_STICK_FLAT); 2134 - input_set_abs_params(ctlr->input, ABS_RY, 2135 - -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, 2136 - JC_STICK_FUZZ, JC_STICK_FLAT); 2137 - 2138 - for (i = 0; joycon_button_inputs_r[i] > 0; i++) 2139 - input_set_capability(ctlr->input, EV_KEY, 2140 - joycon_button_inputs_r[i]); 2141 - } 2142 - 2143 - /* Let's report joy-con S triggers separately */ 2144 - if (hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL) { 2145 - input_set_capability(ctlr->input, EV_KEY, BTN_TR); 2146 - input_set_capability(ctlr->input, EV_KEY, BTN_TR2); 2147 - } else if (hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONR) { 2148 - input_set_capability(ctlr->input, EV_KEY, BTN_TL); 2149 - input_set_capability(ctlr->input, EV_KEY, BTN_TL2); 2150 - } 2151 - 1757 + static void joycon_config_rumble(struct joycon_ctlr *ctlr) 1758 + { 2152 1759 #if IS_ENABLED(CONFIG_NINTENDO_FF) 2153 1760 /* set up rumble */ 2154 1761 input_set_capability(ctlr->input, EV_FF, FF_RUMBLE); ··· 2103 1826 joycon_set_rumble(ctlr, 0, 0, false); 2104 1827 ctlr->rumble_msecs = jiffies_to_msecs(jiffies); 2105 1828 #endif 1829 + } 2106 1830 2107 - ret = input_register_device(ctlr->input); 2108 - if (ret) 2109 - return ret; 1831 + static int joycon_imu_input_create(struct joycon_ctlr *ctlr) 1832 + { 1833 + struct hid_device *hdev; 1834 + const char *imu_name; 1835 + int ret; 1836 + 1837 + hdev = ctlr->hdev; 2110 1838 2111 1839 /* configure the imu input device */ 2112 1840 ctlr->imu_input = devm_input_allocate_device(&hdev->dev); ··· 2123 1841 ctlr->imu_input->id.product = hdev->product; 2124 1842 ctlr->imu_input->id.version = hdev->version; 2125 1843 ctlr->imu_input->uniq = ctlr->mac_addr_str; 2126 - ctlr->imu_input->name = imu_name; 2127 1844 ctlr->imu_input->phys = hdev->phys; 1845 + 1846 + imu_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s (IMU)", ctlr->input->name); 1847 + if (!imu_name) 1848 + return -ENOMEM; 1849 + 1850 + ctlr->imu_input->name = imu_name; 1851 + 2128 1852 input_set_drvdata(ctlr->imu_input, ctlr); 2129 1853 2130 1854 /* configure imu axes */ ··· 2168 1880 ret = input_register_device(ctlr->imu_input); 2169 1881 if (ret) 2170 1882 return ret; 1883 + 1884 + return 0; 1885 + } 1886 + 1887 + static int joycon_input_create(struct joycon_ctlr *ctlr) 1888 + { 1889 + struct hid_device *hdev; 1890 + int ret; 1891 + 1892 + hdev = ctlr->hdev; 1893 + 1894 + ctlr->input = devm_input_allocate_device(&hdev->dev); 1895 + if (!ctlr->input) 1896 + return -ENOMEM; 1897 + ctlr->input->id.bustype = hdev->bus; 1898 + ctlr->input->id.vendor = hdev->vendor; 1899 + ctlr->input->id.product = hdev->product; 1900 + ctlr->input->id.version = hdev->version; 1901 + ctlr->input->uniq = ctlr->mac_addr_str; 1902 + ctlr->input->name = hdev->name; 1903 + ctlr->input->phys = hdev->phys; 1904 + input_set_drvdata(ctlr->input, ctlr); 1905 + 1906 + ret = input_register_device(ctlr->input); 1907 + if (ret) 1908 + return ret; 1909 + 1910 + if (joycon_type_is_right_joycon(ctlr)) { 1911 + joycon_config_right_stick(ctlr->input); 1912 + joycon_config_buttons(ctlr->input, right_joycon_button_mappings); 1913 + if (!joycon_device_is_chrggrip(ctlr)) 1914 + joycon_config_buttons(ctlr->input, right_joycon_s_button_mappings); 1915 + } else if (joycon_type_is_left_joycon(ctlr)) { 1916 + joycon_config_left_stick(ctlr->input); 1917 + joycon_config_buttons(ctlr->input, left_joycon_button_mappings); 1918 + if (!joycon_device_is_chrggrip(ctlr)) 1919 + joycon_config_buttons(ctlr->input, left_joycon_s_button_mappings); 1920 + } else if (joycon_type_is_procon(ctlr)) { 1921 + joycon_config_left_stick(ctlr->input); 1922 + joycon_config_right_stick(ctlr->input); 1923 + joycon_config_dpad(ctlr->input); 1924 + joycon_config_buttons(ctlr->input, procon_button_mappings); 1925 + } else if (joycon_type_is_any_nescon(ctlr)) { 1926 + joycon_config_dpad(ctlr->input); 1927 + joycon_config_buttons(ctlr->input, nescon_button_mappings); 1928 + } else if (joycon_type_is_snescon(ctlr)) { 1929 + joycon_config_dpad(ctlr->input); 1930 + joycon_config_buttons(ctlr->input, snescon_button_mappings); 1931 + } else if (joycon_type_is_gencon(ctlr)) { 1932 + joycon_config_dpad(ctlr->input); 1933 + joycon_config_buttons(ctlr->input, gencon_button_mappings); 1934 + } else if (joycon_type_is_n64con(ctlr)) { 1935 + joycon_config_dpad(ctlr->input); 1936 + joycon_config_left_stick(ctlr->input); 1937 + joycon_config_buttons(ctlr->input, n64con_button_mappings); 1938 + } 1939 + 1940 + if (joycon_has_imu(ctlr)) { 1941 + ret = joycon_imu_input_create(ctlr); 1942 + if (ret) 1943 + return ret; 1944 + } 1945 + 1946 + if (joycon_has_rumble(ctlr)) 1947 + joycon_config_rumble(ctlr); 2171 1948 2172 1949 return 0; 2173 1950 } ··· 2473 2120 struct joycon_input_report *report; 2474 2121 2475 2122 req.subcmd_id = JC_SUBCMD_REQ_DEV_INFO; 2476 - mutex_lock(&ctlr->output_mutex); 2477 2123 ret = joycon_send_subcmd(ctlr, &req, 0, HZ); 2478 - mutex_unlock(&ctlr->output_mutex); 2479 2124 if (ret) { 2480 2125 hid_err(ctlr->hdev, "Failed to get joycon info; ret=%d\n", ret); 2481 2126 return ret; ··· 2496 2145 return -ENOMEM; 2497 2146 hid_info(ctlr->hdev, "controller MAC = %s\n", ctlr->mac_addr_str); 2498 2147 2499 - /* Retrieve the type so we can distinguish for charging grip */ 2148 + /* 2149 + * Retrieve the type so we can distinguish the controller type 2150 + * Unfortantly the hdev->product can't always be used due to a ?bug? 2151 + * with the NSO Genesis controller. Over USB, it will report the 2152 + * PID as 0x201E, but over bluetooth it will report the PID as 0x2017 2153 + * which is the same as the NSO SNES controller. This is different from 2154 + * the rest of the controllers which will report the same PID over USB 2155 + * and bluetooth. 2156 + */ 2500 2157 ctlr->ctlr_type = report->subcmd_reply.data[2]; 2158 + hid_dbg(ctlr->hdev, "controller type = 0x%02X\n", ctlr->ctlr_type); 2501 2159 2502 2160 return 0; 2503 2161 } ··· 2518 2158 2519 2159 mutex_lock(&ctlr->output_mutex); 2520 2160 /* if handshake command fails, assume ble pro controller */ 2521 - if ((jc_type_is_procon(ctlr) || jc_type_is_chrggrip(ctlr)) && 2522 - !joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) { 2161 + if (joycon_using_usb(ctlr) && !joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) { 2523 2162 hid_dbg(hdev, "detected USB controller\n"); 2524 2163 /* set baudrate for improved latency */ 2525 2164 ret = joycon_send_usb(ctlr, JC_USB_CMD_BAUDRATE_3M, HZ); ··· 2543 2184 goto out_unlock; 2544 2185 } 2545 2186 2546 - /* get controller calibration data, and parse it */ 2547 - ret = joycon_request_calibration(ctlr); 2187 + /* needed to retrieve the controller type */ 2188 + ret = joycon_read_info(ctlr); 2548 2189 if (ret) { 2549 - /* 2550 - * We can function with default calibration, but it may be 2551 - * inaccurate. Provide a warning, and continue on. 2552 - */ 2553 - hid_warn(hdev, "Analog stick positions may be inaccurate\n"); 2190 + hid_err(hdev, "Failed to retrieve controller info; ret=%d\n", 2191 + ret); 2192 + goto out_unlock; 2554 2193 } 2555 2194 2556 - /* get IMU calibration data, and parse it */ 2557 - ret = joycon_request_imu_calibration(ctlr); 2558 - if (ret) { 2559 - /* 2560 - * We can function with default calibration, but it may be 2561 - * inaccurate. Provide a warning, and continue on. 2562 - */ 2563 - hid_warn(hdev, "Unable to read IMU calibration data\n"); 2195 + if (joycon_has_joysticks(ctlr)) { 2196 + /* get controller calibration data, and parse it */ 2197 + ret = joycon_request_calibration(ctlr); 2198 + if (ret) { 2199 + /* 2200 + * We can function with default calibration, but it may be 2201 + * inaccurate. Provide a warning, and continue on. 2202 + */ 2203 + hid_warn(hdev, "Analog stick positions may be inaccurate\n"); 2204 + } 2205 + } 2206 + 2207 + if (joycon_has_imu(ctlr)) { 2208 + /* get IMU calibration data, and parse it */ 2209 + ret = joycon_request_imu_calibration(ctlr); 2210 + if (ret) { 2211 + /* 2212 + * We can function with default calibration, but it may be 2213 + * inaccurate. Provide a warning, and continue on. 2214 + */ 2215 + hid_warn(hdev, "Unable to read IMU calibration data\n"); 2216 + } 2217 + 2218 + /* Enable the IMU */ 2219 + ret = joycon_enable_imu(ctlr); 2220 + if (ret) { 2221 + hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret); 2222 + goto out_unlock; 2223 + } 2564 2224 } 2565 2225 2566 2226 /* Set the reporting mode to 0x30, which is the full report mode */ ··· 2589 2211 goto out_unlock; 2590 2212 } 2591 2213 2592 - /* Enable rumble */ 2593 - ret = joycon_enable_rumble(ctlr); 2594 - if (ret) { 2595 - hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret); 2596 - goto out_unlock; 2597 - } 2598 - 2599 - /* Enable the IMU */ 2600 - ret = joycon_enable_imu(ctlr); 2601 - if (ret) { 2602 - hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret); 2603 - goto out_unlock; 2214 + if (joycon_has_rumble(ctlr)) { 2215 + /* Enable rumble */ 2216 + ret = joycon_enable_rumble(ctlr); 2217 + if (ret) { 2218 + hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret); 2219 + goto out_unlock; 2220 + } 2604 2221 } 2605 2222 2606 2223 out_unlock: ··· 2740 2367 goto err_close; 2741 2368 } 2742 2369 2743 - ret = joycon_read_info(ctlr); 2744 - if (ret) { 2745 - hid_err(hdev, "Failed to retrieve controller info; ret=%d\n", 2746 - ret); 2747 - goto err_close; 2748 - } 2749 - 2750 2370 /* Initialize the leds */ 2751 2371 ret = joycon_leds_create(ctlr); 2752 2372 if (ret) { ··· 2811 2445 static const struct hid_device_id nintendo_hid_devices[] = { 2812 2446 { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO, 2813 2447 USB_DEVICE_ID_NINTENDO_PROCON) }, 2448 + { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO, 2449 + USB_DEVICE_ID_NINTENDO_SNESCON) }, 2450 + { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO, 2451 + USB_DEVICE_ID_NINTENDO_GENCON) }, 2452 + { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO, 2453 + USB_DEVICE_ID_NINTENDO_N64CON) }, 2814 2454 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, 2815 2455 USB_DEVICE_ID_NINTENDO_PROCON) }, 2816 2456 { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO, ··· 2825 2453 USB_DEVICE_ID_NINTENDO_JOYCONL) }, 2826 2454 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, 2827 2455 USB_DEVICE_ID_NINTENDO_JOYCONR) }, 2456 + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, 2457 + USB_DEVICE_ID_NINTENDO_SNESCON) }, 2458 + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, 2459 + USB_DEVICE_ID_NINTENDO_GENCON) }, 2460 + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, 2461 + USB_DEVICE_ID_NINTENDO_N64CON) }, 2828 2462 { } 2829 2463 }; 2830 2464 MODULE_DEVICE_TABLE(hid, nintendo_hid_devices); ··· 2849 2471 module_hid_driver(nintendo_hid_driver); 2850 2472 2851 2473 MODULE_LICENSE("GPL"); 2474 + MODULE_AUTHOR("Ryan McClelland <rymcclel@gmail.com>"); 2475 + MODULE_AUTHOR("Emily Strickland <linux@emily.st>"); 2852 2476 MODULE_AUTHOR("Daniel J. Ogorchock <djogorchock@gmail.com>"); 2853 2477 MODULE_DESCRIPTION("Driver for Nintendo Switch Controllers"); 2854 -
+1 -1
drivers/hid/hid-sensor-hub.c
··· 632 632 } 633 633 INIT_LIST_HEAD(&hdev->inputs); 634 634 635 - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 635 + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | HID_CONNECT_DRIVER); 636 636 if (ret) { 637 637 hid_err(hdev, "hw start failed\n"); 638 638 return ret;
+391 -156
drivers/hid/hid-steam.c
··· 71 71 72 72 /* 73 73 * Commands that can be sent in a feature report. 74 - * Thanks to Valve for some valuable hints. 74 + * Thanks to Valve and SDL for the names. 75 75 */ 76 - #define STEAM_CMD_SET_MAPPINGS 0x80 77 - #define STEAM_CMD_CLEAR_MAPPINGS 0x81 78 - #define STEAM_CMD_GET_MAPPINGS 0x82 79 - #define STEAM_CMD_GET_ATTRIB 0x83 80 - #define STEAM_CMD_GET_ATTRIB_LABEL 0x84 81 - #define STEAM_CMD_DEFAULT_MAPPINGS 0x85 82 - #define STEAM_CMD_FACTORY_RESET 0x86 83 - #define STEAM_CMD_WRITE_REGISTER 0x87 84 - #define STEAM_CMD_CLEAR_REGISTER 0x88 85 - #define STEAM_CMD_READ_REGISTER 0x89 86 - #define STEAM_CMD_GET_REGISTER_LABEL 0x8a 87 - #define STEAM_CMD_GET_REGISTER_MAX 0x8b 88 - #define STEAM_CMD_GET_REGISTER_DEFAULT 0x8c 89 - #define STEAM_CMD_SET_MODE 0x8d 90 - #define STEAM_CMD_DEFAULT_MOUSE 0x8e 91 - #define STEAM_CMD_FORCEFEEDBAK 0x8f 92 - #define STEAM_CMD_REQUEST_COMM_STATUS 0xb4 93 - #define STEAM_CMD_GET_SERIAL 0xae 94 - #define STEAM_CMD_HAPTIC_RUMBLE 0xeb 76 + enum { 77 + ID_SET_DIGITAL_MAPPINGS = 0x80, 78 + ID_CLEAR_DIGITAL_MAPPINGS = 0x81, 79 + ID_GET_DIGITAL_MAPPINGS = 0x82, 80 + ID_GET_ATTRIBUTES_VALUES = 0x83, 81 + ID_GET_ATTRIBUTE_LABEL = 0x84, 82 + ID_SET_DEFAULT_DIGITAL_MAPPINGS = 0x85, 83 + ID_FACTORY_RESET = 0x86, 84 + ID_SET_SETTINGS_VALUES = 0x87, 85 + ID_CLEAR_SETTINGS_VALUES = 0x88, 86 + ID_GET_SETTINGS_VALUES = 0x89, 87 + ID_GET_SETTING_LABEL = 0x8A, 88 + ID_GET_SETTINGS_MAXS = 0x8B, 89 + ID_GET_SETTINGS_DEFAULTS = 0x8C, 90 + ID_SET_CONTROLLER_MODE = 0x8D, 91 + ID_LOAD_DEFAULT_SETTINGS = 0x8E, 92 + ID_TRIGGER_HAPTIC_PULSE = 0x8F, 93 + ID_TURN_OFF_CONTROLLER = 0x9F, 95 94 96 - /* Some useful register ids */ 97 - #define STEAM_REG_LPAD_MODE 0x07 98 - #define STEAM_REG_RPAD_MODE 0x08 99 - #define STEAM_REG_RPAD_MARGIN 0x18 100 - #define STEAM_REG_LED 0x2d 101 - #define STEAM_REG_GYRO_MODE 0x30 102 - #define STEAM_REG_LPAD_CLICK_PRESSURE 0x34 103 - #define STEAM_REG_RPAD_CLICK_PRESSURE 0x35 95 + ID_GET_DEVICE_INFO = 0xA1, 104 96 105 - /* Raw event identifiers */ 106 - #define STEAM_EV_INPUT_DATA 0x01 107 - #define STEAM_EV_CONNECT 0x03 108 - #define STEAM_EV_BATTERY 0x04 109 - #define STEAM_EV_DECK_INPUT_DATA 0x09 97 + ID_CALIBRATE_TRACKPADS = 0xA7, 98 + ID_RESERVED_0 = 0xA8, 99 + ID_SET_SERIAL_NUMBER = 0xA9, 100 + ID_GET_TRACKPAD_CALIBRATION = 0xAA, 101 + ID_GET_TRACKPAD_FACTORY_CALIBRATION = 0xAB, 102 + ID_GET_TRACKPAD_RAW_DATA = 0xAC, 103 + ID_ENABLE_PAIRING = 0xAD, 104 + ID_GET_STRING_ATTRIBUTE = 0xAE, 105 + ID_RADIO_ERASE_RECORDS = 0xAF, 106 + ID_RADIO_WRITE_RECORD = 0xB0, 107 + ID_SET_DONGLE_SETTING = 0xB1, 108 + ID_DONGLE_DISCONNECT_DEVICE = 0xB2, 109 + ID_DONGLE_COMMIT_DEVICE = 0xB3, 110 + ID_DONGLE_GET_WIRELESS_STATE = 0xB4, 111 + ID_CALIBRATE_GYRO = 0xB5, 112 + ID_PLAY_AUDIO = 0xB6, 113 + ID_AUDIO_UPDATE_START = 0xB7, 114 + ID_AUDIO_UPDATE_DATA = 0xB8, 115 + ID_AUDIO_UPDATE_COMPLETE = 0xB9, 116 + ID_GET_CHIPID = 0xBA, 117 + 118 + ID_CALIBRATE_JOYSTICK = 0xBF, 119 + ID_CALIBRATE_ANALOG_TRIGGERS = 0xC0, 120 + ID_SET_AUDIO_MAPPING = 0xC1, 121 + ID_CHECK_GYRO_FW_LOAD = 0xC2, 122 + ID_CALIBRATE_ANALOG = 0xC3, 123 + ID_DONGLE_GET_CONNECTED_SLOTS = 0xC4, 124 + 125 + ID_RESET_IMU = 0xCE, 126 + 127 + ID_TRIGGER_HAPTIC_CMD = 0xEA, 128 + ID_TRIGGER_RUMBLE_CMD = 0xEB, 129 + }; 130 + 131 + /* Settings IDs */ 132 + enum { 133 + /* 0 */ 134 + SETTING_MOUSE_SENSITIVITY, 135 + SETTING_MOUSE_ACCELERATION, 136 + SETTING_TRACKBALL_ROTATION_ANGLE, 137 + SETTING_HAPTIC_INTENSITY_UNUSED, 138 + SETTING_LEFT_GAMEPAD_STICK_ENABLED, 139 + SETTING_RIGHT_GAMEPAD_STICK_ENABLED, 140 + SETTING_USB_DEBUG_MODE, 141 + SETTING_LEFT_TRACKPAD_MODE, 142 + SETTING_RIGHT_TRACKPAD_MODE, 143 + SETTING_MOUSE_POINTER_ENABLED, 144 + 145 + /* 10 */ 146 + SETTING_DPAD_DEADZONE, 147 + SETTING_MINIMUM_MOMENTUM_VEL, 148 + SETTING_MOMENTUM_DECAY_AMMOUNT, 149 + SETTING_TRACKPAD_RELATIVE_MODE_TICKS_PER_PIXEL, 150 + SETTING_HAPTIC_INCREMENT, 151 + SETTING_DPAD_ANGLE_SIN, 152 + SETTING_DPAD_ANGLE_COS, 153 + SETTING_MOMENTUM_VERTICAL_DIVISOR, 154 + SETTING_MOMENTUM_MAXIMUM_VELOCITY, 155 + SETTING_TRACKPAD_Z_ON, 156 + 157 + /* 20 */ 158 + SETTING_TRACKPAD_Z_OFF, 159 + SETTING_SENSITIVY_SCALE_AMMOUNT, 160 + SETTING_LEFT_TRACKPAD_SECONDARY_MODE, 161 + SETTING_RIGHT_TRACKPAD_SECONDARY_MODE, 162 + SETTING_SMOOTH_ABSOLUTE_MOUSE, 163 + SETTING_STEAMBUTTON_POWEROFF_TIME, 164 + SETTING_UNUSED_1, 165 + SETTING_TRACKPAD_OUTER_RADIUS, 166 + SETTING_TRACKPAD_Z_ON_LEFT, 167 + SETTING_TRACKPAD_Z_OFF_LEFT, 168 + 169 + /* 30 */ 170 + SETTING_TRACKPAD_OUTER_SPIN_VEL, 171 + SETTING_TRACKPAD_OUTER_SPIN_RADIUS, 172 + SETTING_TRACKPAD_OUTER_SPIN_HORIZONTAL_ONLY, 173 + SETTING_TRACKPAD_RELATIVE_MODE_DEADZONE, 174 + SETTING_TRACKPAD_RELATIVE_MODE_MAX_VEL, 175 + SETTING_TRACKPAD_RELATIVE_MODE_INVERT_Y, 176 + SETTING_TRACKPAD_DOUBLE_TAP_BEEP_ENABLED, 177 + SETTING_TRACKPAD_DOUBLE_TAP_BEEP_PERIOD, 178 + SETTING_TRACKPAD_DOUBLE_TAP_BEEP_COUNT, 179 + SETTING_TRACKPAD_OUTER_RADIUS_RELEASE_ON_TRANSITION, 180 + 181 + /* 40 */ 182 + SETTING_RADIAL_MODE_ANGLE, 183 + SETTING_HAPTIC_INTENSITY_MOUSE_MODE, 184 + SETTING_LEFT_DPAD_REQUIRES_CLICK, 185 + SETTING_RIGHT_DPAD_REQUIRES_CLICK, 186 + SETTING_LED_BASELINE_BRIGHTNESS, 187 + SETTING_LED_USER_BRIGHTNESS, 188 + SETTING_ENABLE_RAW_JOYSTICK, 189 + SETTING_ENABLE_FAST_SCAN, 190 + SETTING_IMU_MODE, 191 + SETTING_WIRELESS_PACKET_VERSION, 192 + 193 + /* 50 */ 194 + SETTING_SLEEP_INACTIVITY_TIMEOUT, 195 + SETTING_TRACKPAD_NOISE_THRESHOLD, 196 + SETTING_LEFT_TRACKPAD_CLICK_PRESSURE, 197 + SETTING_RIGHT_TRACKPAD_CLICK_PRESSURE, 198 + SETTING_LEFT_BUMPER_CLICK_PRESSURE, 199 + SETTING_RIGHT_BUMPER_CLICK_PRESSURE, 200 + SETTING_LEFT_GRIP_CLICK_PRESSURE, 201 + SETTING_RIGHT_GRIP_CLICK_PRESSURE, 202 + SETTING_LEFT_GRIP2_CLICK_PRESSURE, 203 + SETTING_RIGHT_GRIP2_CLICK_PRESSURE, 204 + 205 + /* 60 */ 206 + SETTING_PRESSURE_MODE, 207 + SETTING_CONTROLLER_TEST_MODE, 208 + SETTING_TRIGGER_MODE, 209 + SETTING_TRACKPAD_Z_THRESHOLD, 210 + SETTING_FRAME_RATE, 211 + SETTING_TRACKPAD_FILT_CTRL, 212 + SETTING_TRACKPAD_CLIP, 213 + SETTING_DEBUG_OUTPUT_SELECT, 214 + SETTING_TRIGGER_THRESHOLD_PERCENT, 215 + SETTING_TRACKPAD_FREQUENCY_HOPPING, 216 + 217 + /* 70 */ 218 + SETTING_HAPTICS_ENABLED, 219 + SETTING_STEAM_WATCHDOG_ENABLE, 220 + SETTING_TIMP_TOUCH_THRESHOLD_ON, 221 + SETTING_TIMP_TOUCH_THRESHOLD_OFF, 222 + SETTING_FREQ_HOPPING, 223 + SETTING_TEST_CONTROL, 224 + SETTING_HAPTIC_MASTER_GAIN_DB, 225 + SETTING_THUMB_TOUCH_THRESH, 226 + SETTING_DEVICE_POWER_STATUS, 227 + SETTING_HAPTIC_INTENSITY, 228 + 229 + /* 80 */ 230 + SETTING_STABILIZER_ENABLED, 231 + SETTING_TIMP_MODE_MTE, 232 + }; 233 + 234 + /* Input report identifiers */ 235 + enum 236 + { 237 + ID_CONTROLLER_STATE = 1, 238 + ID_CONTROLLER_DEBUG = 2, 239 + ID_CONTROLLER_WIRELESS = 3, 240 + ID_CONTROLLER_STATUS = 4, 241 + ID_CONTROLLER_DEBUG2 = 5, 242 + ID_CONTROLLER_SECONDARY_STATE = 6, 243 + ID_CONTROLLER_BLE_STATE = 7, 244 + ID_CONTROLLER_DECK_STATE = 9 245 + }; 246 + 247 + /* String attribute idenitifiers */ 248 + enum { 249 + ATTRIB_STR_BOARD_SERIAL, 250 + ATTRIB_STR_UNIT_SERIAL, 251 + }; 110 252 111 253 /* Values for GYRO_MODE (bitmask) */ 112 - #define STEAM_GYRO_MODE_OFF 0x0000 113 - #define STEAM_GYRO_MODE_STEERING 0x0001 114 - #define STEAM_GYRO_MODE_TILT 0x0002 115 - #define STEAM_GYRO_MODE_SEND_ORIENTATION 0x0004 116 - #define STEAM_GYRO_MODE_SEND_RAW_ACCEL 0x0008 117 - #define STEAM_GYRO_MODE_SEND_RAW_GYRO 0x0010 254 + enum { 255 + SETTING_GYRO_MODE_OFF = 0, 256 + SETTING_GYRO_MODE_STEERING = BIT(0), 257 + SETTING_GYRO_MODE_TILT = BIT(1), 258 + SETTING_GYRO_MODE_SEND_ORIENTATION = BIT(2), 259 + SETTING_GYRO_MODE_SEND_RAW_ACCEL = BIT(3), 260 + SETTING_GYRO_MODE_SEND_RAW_GYRO = BIT(4), 261 + }; 262 + 263 + /* Trackpad modes */ 264 + enum { 265 + TRACKPAD_ABSOLUTE_MOUSE, 266 + TRACKPAD_RELATIVE_MOUSE, 267 + TRACKPAD_DPAD_FOUR_WAY_DISCRETE, 268 + TRACKPAD_DPAD_FOUR_WAY_OVERLAP, 269 + TRACKPAD_DPAD_EIGHT_WAY, 270 + TRACKPAD_RADIAL_MODE, 271 + TRACKPAD_ABSOLUTE_DPAD, 272 + TRACKPAD_NONE, 273 + TRACKPAD_GESTURE_KEYBOARD, 274 + }; 275 + 276 + /* Pad identifiers for the deck */ 277 + #define STEAM_PAD_LEFT 0 278 + #define STEAM_PAD_RIGHT 1 279 + #define STEAM_PAD_BOTH 2 118 280 119 281 /* Other random constants */ 120 - #define STEAM_SERIAL_LEN 10 282 + #define STEAM_SERIAL_LEN 0x15 121 283 122 284 struct steam_device { 123 285 struct list_head list; 124 286 spinlock_t lock; 125 287 struct hid_device *hdev, *client_hdev; 126 - struct mutex mutex; 127 - bool client_opened; 288 + struct mutex report_mutex; 289 + unsigned long client_opened; 128 290 struct input_dev __rcu *input; 129 291 unsigned long quirks; 130 292 struct work_struct work_connect; ··· 296 134 struct power_supply __rcu *battery; 297 135 u8 battery_charge; 298 136 u16 voltage; 299 - struct delayed_work heartbeat; 137 + struct delayed_work mode_switch; 138 + bool did_mode_switch; 139 + bool gamepad_mode; 300 140 struct work_struct rumble_work; 301 141 u16 rumble_left; 302 142 u16 rumble_right; ··· 390 226 return steam_send_report(steam, &cmd, 1); 391 227 } 392 228 393 - static int steam_write_registers(struct steam_device *steam, 229 + static int steam_write_settings(struct steam_device *steam, 394 230 /* u8 reg, u16 val */...) 395 231 { 396 232 /* Send: 0x87 len (reg valLo valHi)* */ 397 233 u8 reg; 398 234 u16 val; 399 - u8 cmd[64] = {STEAM_CMD_WRITE_REGISTER, 0x00}; 235 + u8 cmd[64] = {ID_SET_SETTINGS_VALUES, 0x00}; 400 236 int ret; 401 237 va_list args; 402 238 ··· 429 265 { 430 266 /* 431 267 * Send: 0xae 0x15 0x01 432 - * Recv: 0xae 0x15 0x01 serialnumber (10 chars) 268 + * Recv: 0xae 0x15 0x01 serialnumber 433 269 */ 434 - int ret; 435 - u8 cmd[] = {STEAM_CMD_GET_SERIAL, 0x15, 0x01}; 270 + int ret = 0; 271 + u8 cmd[] = {ID_GET_STRING_ATTRIBUTE, sizeof(steam->serial_no), ATTRIB_STR_UNIT_SERIAL}; 436 272 u8 reply[3 + STEAM_SERIAL_LEN + 1]; 437 273 274 + mutex_lock(&steam->report_mutex); 438 275 ret = steam_send_report(steam, cmd, sizeof(cmd)); 439 276 if (ret < 0) 440 - return ret; 277 + goto out; 441 278 ret = steam_recv_report(steam, reply, sizeof(reply)); 442 279 if (ret < 0) 443 - return ret; 444 - if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != 0x01) 445 - return -EIO; 280 + goto out; 281 + if (reply[0] != ID_GET_STRING_ATTRIBUTE || reply[1] < 1 || 282 + reply[1] > sizeof(steam->serial_no) || reply[2] != ATTRIB_STR_UNIT_SERIAL) { 283 + ret = -EIO; 284 + goto out; 285 + } 446 286 reply[3 + STEAM_SERIAL_LEN] = 0; 447 - strscpy(steam->serial_no, reply + 3, sizeof(steam->serial_no)); 448 - return 0; 287 + strscpy(steam->serial_no, reply + 3, reply[1]); 288 + out: 289 + mutex_unlock(&steam->report_mutex); 290 + return ret; 449 291 } 450 292 451 293 /* ··· 461 291 */ 462 292 static inline int steam_request_conn_status(struct steam_device *steam) 463 293 { 464 - return steam_send_report_byte(steam, STEAM_CMD_REQUEST_COMM_STATUS); 294 + int ret; 295 + mutex_lock(&steam->report_mutex); 296 + ret = steam_send_report_byte(steam, ID_DONGLE_GET_WIRELESS_STATE); 297 + mutex_unlock(&steam->report_mutex); 298 + return ret; 299 + } 300 + 301 + /* 302 + * Send a haptic pulse to the trackpads 303 + * Duration and interval are measured in microseconds, count is the number 304 + * of pulses to send for duration time with interval microseconds between them 305 + * and gain is measured in decibels, ranging from -24 to +6 306 + */ 307 + static inline int steam_haptic_pulse(struct steam_device *steam, u8 pad, 308 + u16 duration, u16 interval, u16 count, u8 gain) 309 + { 310 + int ret; 311 + u8 report[10] = {ID_TRIGGER_HAPTIC_PULSE, 8}; 312 + 313 + /* Left and right are swapped on this report for legacy reasons */ 314 + if (pad < STEAM_PAD_BOTH) 315 + pad ^= 1; 316 + 317 + report[2] = pad; 318 + report[3] = duration & 0xFF; 319 + report[4] = duration >> 8; 320 + report[5] = interval & 0xFF; 321 + report[6] = interval >> 8; 322 + report[7] = count & 0xFF; 323 + report[8] = count >> 8; 324 + report[9] = gain; 325 + 326 + mutex_lock(&steam->report_mutex); 327 + ret = steam_send_report(steam, report, sizeof(report)); 328 + mutex_unlock(&steam->report_mutex); 329 + return ret; 465 330 } 466 331 467 332 static inline int steam_haptic_rumble(struct steam_device *steam, 468 333 u16 intensity, u16 left_speed, u16 right_speed, 469 334 u8 left_gain, u8 right_gain) 470 335 { 471 - u8 report[11] = {STEAM_CMD_HAPTIC_RUMBLE, 9}; 336 + int ret; 337 + u8 report[11] = {ID_TRIGGER_RUMBLE_CMD, 9}; 472 338 473 339 report[3] = intensity & 0xFF; 474 340 report[4] = intensity >> 8; ··· 515 309 report[9] = left_gain; 516 310 report[10] = right_gain; 517 311 518 - return steam_send_report(steam, report, sizeof(report)); 312 + mutex_lock(&steam->report_mutex); 313 + ret = steam_send_report(steam, report, sizeof(report)); 314 + mutex_unlock(&steam->report_mutex); 315 + return ret; 519 316 } 520 317 521 318 static void steam_haptic_rumble_cb(struct work_struct *work) ··· 544 335 545 336 static void steam_set_lizard_mode(struct steam_device *steam, bool enable) 546 337 { 547 - if (enable) { 548 - /* enable esc, enter, cursors */ 549 - steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MAPPINGS); 550 - /* enable mouse */ 551 - steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MOUSE); 552 - steam_write_registers(steam, 553 - STEAM_REG_RPAD_MARGIN, 0x01, /* enable margin */ 554 - 0); 338 + if (steam->gamepad_mode) 339 + enable = false; 555 340 556 - cancel_delayed_work_sync(&steam->heartbeat); 341 + if (enable) { 342 + mutex_lock(&steam->report_mutex); 343 + /* enable esc, enter, cursors */ 344 + steam_send_report_byte(steam, ID_SET_DEFAULT_DIGITAL_MAPPINGS); 345 + /* reset settings */ 346 + steam_send_report_byte(steam, ID_LOAD_DEFAULT_SETTINGS); 347 + mutex_unlock(&steam->report_mutex); 557 348 } else { 349 + mutex_lock(&steam->report_mutex); 558 350 /* disable esc, enter, cursor */ 559 - steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS); 351 + steam_send_report_byte(steam, ID_CLEAR_DIGITAL_MAPPINGS); 560 352 561 353 if (steam->quirks & STEAM_QUIRK_DECK) { 562 - steam_write_registers(steam, 563 - STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */ 564 - STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */ 565 - STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ 566 - STEAM_REG_LPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */ 567 - STEAM_REG_RPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */ 354 + steam_write_settings(steam, 355 + SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */ 356 + SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */ 357 + SETTING_LEFT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable haptic click */ 358 + SETTING_RIGHT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable haptic click */ 359 + SETTING_STEAM_WATCHDOG_ENABLE, 0, /* disable watchdog that tests if Steam is active */ 568 360 0); 569 - /* 570 - * The Steam Deck has a watchdog that automatically enables 571 - * lizard mode if it doesn't see any traffic for too long 572 - */ 573 - if (!work_busy(&steam->heartbeat.work)) 574 - schedule_delayed_work(&steam->heartbeat, 5 * HZ); 361 + mutex_unlock(&steam->report_mutex); 575 362 } else { 576 - steam_write_registers(steam, 577 - STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */ 578 - STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */ 579 - STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ 363 + steam_write_settings(steam, 364 + SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */ 365 + SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */ 580 366 0); 367 + mutex_unlock(&steam->report_mutex); 581 368 } 582 369 } 583 370 } ··· 581 376 static int steam_input_open(struct input_dev *dev) 582 377 { 583 378 struct steam_device *steam = input_get_drvdata(dev); 379 + unsigned long flags; 380 + bool set_lizard_mode; 584 381 585 - mutex_lock(&steam->mutex); 586 - if (!steam->client_opened && lizard_mode) 587 - steam_set_lizard_mode(steam, false); 588 - mutex_unlock(&steam->mutex); 382 + /* 383 + * Disabling lizard mode automatically is only done on the Steam 384 + * Controller. On the Steam Deck, this is toggled manually by holding 385 + * the options button instead, handled by steam_mode_switch_cb. 386 + */ 387 + if (!(steam->quirks & STEAM_QUIRK_DECK)) { 388 + spin_lock_irqsave(&steam->lock, flags); 389 + set_lizard_mode = !steam->client_opened && lizard_mode; 390 + spin_unlock_irqrestore(&steam->lock, flags); 391 + if (set_lizard_mode) 392 + steam_set_lizard_mode(steam, false); 393 + } 394 + 589 395 return 0; 590 396 } 591 397 592 398 static void steam_input_close(struct input_dev *dev) 593 399 { 594 400 struct steam_device *steam = input_get_drvdata(dev); 401 + unsigned long flags; 402 + bool set_lizard_mode; 595 403 596 - mutex_lock(&steam->mutex); 597 - if (!steam->client_opened && lizard_mode) 598 - steam_set_lizard_mode(steam, true); 599 - mutex_unlock(&steam->mutex); 404 + if (!(steam->quirks & STEAM_QUIRK_DECK)) { 405 + spin_lock_irqsave(&steam->lock, flags); 406 + set_lizard_mode = !steam->client_opened && lizard_mode; 407 + spin_unlock_irqrestore(&steam->lock, flags); 408 + if (set_lizard_mode) 409 + steam_set_lizard_mode(steam, true); 410 + } 600 411 } 601 412 602 413 static enum power_supply_property steam_battery_props[] = { ··· 856 635 static int steam_register(struct steam_device *steam) 857 636 { 858 637 int ret; 859 - bool client_opened; 638 + unsigned long client_opened; 639 + unsigned long flags; 860 640 861 641 /* 862 642 * This function can be called several times in a row with the ··· 870 648 * Unlikely, but getting the serial could fail, and it is not so 871 649 * important, so make up a serial number and go on. 872 650 */ 873 - mutex_lock(&steam->mutex); 874 651 if (steam_get_serial(steam) < 0) 875 652 strscpy(steam->serial_no, "XXXXXXXXXX", 876 653 sizeof(steam->serial_no)); 877 - mutex_unlock(&steam->mutex); 878 654 879 655 hid_info(steam->hdev, "Steam Controller '%s' connected", 880 656 steam->serial_no); ··· 887 667 mutex_unlock(&steam_devices_lock); 888 668 } 889 669 890 - mutex_lock(&steam->mutex); 670 + spin_lock_irqsave(&steam->lock, flags); 891 671 client_opened = steam->client_opened; 892 - if (!client_opened) 672 + spin_unlock_irqrestore(&steam->lock, flags); 673 + if (!client_opened) { 893 674 steam_set_lizard_mode(steam, lizard_mode); 894 - mutex_unlock(&steam->mutex); 895 - 896 - if (!client_opened) 897 675 ret = steam_input_register(steam); 898 - else 676 + } else 899 677 ret = 0; 900 678 901 679 return ret; ··· 937 719 } 938 720 } 939 721 722 + static void steam_mode_switch_cb(struct work_struct *work) 723 + { 724 + struct steam_device *steam = container_of(to_delayed_work(work), 725 + struct steam_device, mode_switch); 726 + unsigned long flags; 727 + bool client_opened; 728 + steam->gamepad_mode = !steam->gamepad_mode; 729 + if (!lizard_mode) 730 + return; 731 + 732 + if (steam->gamepad_mode) 733 + steam_set_lizard_mode(steam, false); 734 + else { 735 + spin_lock_irqsave(&steam->lock, flags); 736 + client_opened = steam->client_opened; 737 + spin_unlock_irqrestore(&steam->lock, flags); 738 + if (!client_opened) 739 + steam_set_lizard_mode(steam, lizard_mode); 740 + } 741 + 742 + steam_haptic_pulse(steam, STEAM_PAD_RIGHT, 0x190, 0, 1, 0); 743 + if (steam->gamepad_mode) { 744 + steam_haptic_pulse(steam, STEAM_PAD_LEFT, 0x14D, 0x14D, 0x2D, 0); 745 + } else { 746 + steam_haptic_pulse(steam, STEAM_PAD_LEFT, 0x1F4, 0x1F4, 0x1E, 0); 747 + } 748 + } 749 + 940 750 static bool steam_is_valve_interface(struct hid_device *hdev) 941 751 { 942 752 struct hid_report_enum *rep_enum; ··· 982 736 */ 983 737 rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; 984 738 return !list_empty(&rep_enum->report_list); 985 - } 986 - 987 - static void steam_lizard_mode_heartbeat(struct work_struct *work) 988 - { 989 - struct steam_device *steam = container_of(work, struct steam_device, 990 - heartbeat.work); 991 - 992 - mutex_lock(&steam->mutex); 993 - if (!steam->client_opened && steam->client_hdev) { 994 - steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS); 995 - steam_write_registers(steam, 996 - STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ 997 - 0); 998 - schedule_delayed_work(&steam->heartbeat, 5 * HZ); 999 - } 1000 - mutex_unlock(&steam->mutex); 1001 739 } 1002 740 1003 741 static int steam_client_ll_parse(struct hid_device *hdev) ··· 1004 774 static int steam_client_ll_open(struct hid_device *hdev) 1005 775 { 1006 776 struct steam_device *steam = hdev->driver_data; 777 + unsigned long flags; 1007 778 1008 - mutex_lock(&steam->mutex); 1009 - steam->client_opened = true; 1010 - mutex_unlock(&steam->mutex); 779 + spin_lock_irqsave(&steam->lock, flags); 780 + steam->client_opened++; 781 + spin_unlock_irqrestore(&steam->lock, flags); 1011 782 1012 783 steam_input_unregister(steam); 1013 784 ··· 1023 792 bool connected; 1024 793 1025 794 spin_lock_irqsave(&steam->lock, flags); 1026 - connected = steam->connected; 795 + steam->client_opened--; 796 + connected = steam->connected && !steam->client_opened; 1027 797 spin_unlock_irqrestore(&steam->lock, flags); 1028 798 1029 - mutex_lock(&steam->mutex); 1030 - steam->client_opened = false; 1031 - if (connected) 799 + if (connected) { 1032 800 steam_set_lizard_mode(steam, lizard_mode); 1033 - mutex_unlock(&steam->mutex); 1034 - 1035 - if (connected) 1036 801 steam_input_register(steam); 802 + } 1037 803 } 1038 804 1039 805 static int steam_client_ll_raw_request(struct hid_device *hdev, ··· 1116 888 steam->hdev = hdev; 1117 889 hid_set_drvdata(hdev, steam); 1118 890 spin_lock_init(&steam->lock); 1119 - mutex_init(&steam->mutex); 891 + mutex_init(&steam->report_mutex); 1120 892 steam->quirks = id->driver_data; 1121 893 INIT_WORK(&steam->work_connect, steam_work_connect_cb); 894 + INIT_DELAYED_WORK(&steam->mode_switch, steam_mode_switch_cb); 1122 895 INIT_LIST_HEAD(&steam->list); 1123 - INIT_DEFERRABLE_WORK(&steam->heartbeat, steam_lizard_mode_heartbeat); 1124 896 INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb); 1125 - 1126 - steam->client_hdev = steam_create_client_hid(hdev); 1127 - if (IS_ERR(steam->client_hdev)) { 1128 - ret = PTR_ERR(steam->client_hdev); 1129 - goto client_hdev_fail; 1130 - } 1131 - steam->client_hdev->driver_data = steam; 1132 897 1133 898 /* 1134 899 * With the real steam controller interface, do not connect hidraw. ··· 1130 909 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDRAW); 1131 910 if (ret) 1132 911 goto hid_hw_start_fail; 1133 - 1134 - ret = hid_add_device(steam->client_hdev); 1135 - if (ret) 1136 - goto client_hdev_add_fail; 1137 912 1138 913 ret = hid_hw_open(hdev); 1139 914 if (ret) { ··· 1156 939 } 1157 940 } 1158 941 942 + steam->client_hdev = steam_create_client_hid(hdev); 943 + if (IS_ERR(steam->client_hdev)) { 944 + ret = PTR_ERR(steam->client_hdev); 945 + goto client_hdev_fail; 946 + } 947 + steam->client_hdev->driver_data = steam; 948 + 949 + ret = hid_add_device(steam->client_hdev); 950 + if (ret) 951 + goto client_hdev_add_fail; 952 + 1159 953 return 0; 1160 954 1161 - input_register_fail: 1162 - hid_hw_open_fail: 1163 955 client_hdev_add_fail: 1164 956 hid_hw_stop(hdev); 1165 - hid_hw_start_fail: 1166 - hid_destroy_device(steam->client_hdev); 1167 957 client_hdev_fail: 958 + hid_destroy_device(steam->client_hdev); 959 + input_register_fail: 960 + hid_hw_open_fail: 961 + hid_hw_start_fail: 1168 962 cancel_work_sync(&steam->work_connect); 1169 - cancel_delayed_work_sync(&steam->heartbeat); 963 + cancel_delayed_work_sync(&steam->mode_switch); 1170 964 cancel_work_sync(&steam->rumble_work); 1171 965 steam_alloc_fail: 1172 966 hid_err(hdev, "%s: failed with error %d\n", ··· 1194 966 return; 1195 967 } 1196 968 1197 - hid_destroy_device(steam->client_hdev); 1198 - mutex_lock(&steam->mutex); 1199 - steam->client_hdev = NULL; 1200 - steam->client_opened = false; 1201 - cancel_delayed_work_sync(&steam->heartbeat); 1202 - mutex_unlock(&steam->mutex); 969 + cancel_delayed_work_sync(&steam->mode_switch); 1203 970 cancel_work_sync(&steam->work_connect); 971 + hid_destroy_device(steam->client_hdev); 972 + steam->client_hdev = NULL; 973 + steam->client_opened = 0; 1204 974 if (steam->quirks & STEAM_QUIRK_WIRELESS) { 1205 975 hid_info(hdev, "Steam wireless receiver disconnected"); 1206 976 } ··· 1480 1254 b13 = data[13]; 1481 1255 b14 = data[14]; 1482 1256 1257 + if (!(b9 & BIT(6)) && steam->did_mode_switch) { 1258 + steam->did_mode_switch = false; 1259 + cancel_delayed_work_sync(&steam->mode_switch); 1260 + } else if (!steam->client_opened && (b9 & BIT(6)) && !steam->did_mode_switch) { 1261 + steam->did_mode_switch = true; 1262 + schedule_delayed_work(&steam->mode_switch, 45 * HZ / 100); 1263 + } 1264 + 1265 + if (!steam->gamepad_mode) 1266 + return; 1267 + 1483 1268 lpad_touched = b10 & BIT(3); 1484 1269 rpad_touched = b10 & BIT(4); 1485 1270 ··· 1612 1375 return 0; 1613 1376 1614 1377 switch (data[2]) { 1615 - case STEAM_EV_INPUT_DATA: 1378 + case ID_CONTROLLER_STATE: 1616 1379 if (steam->client_opened) 1617 1380 return 0; 1618 1381 rcu_read_lock(); ··· 1621 1384 steam_do_input_event(steam, input, data); 1622 1385 rcu_read_unlock(); 1623 1386 break; 1624 - case STEAM_EV_DECK_INPUT_DATA: 1387 + case ID_CONTROLLER_DECK_STATE: 1625 1388 if (steam->client_opened) 1626 1389 return 0; 1627 1390 rcu_read_lock(); ··· 1630 1393 steam_do_deck_input_event(steam, input, data); 1631 1394 rcu_read_unlock(); 1632 1395 break; 1633 - case STEAM_EV_CONNECT: 1396 + case ID_CONTROLLER_WIRELESS: 1634 1397 /* 1635 1398 * The payload of this event is a single byte: 1636 1399 * 0x01: disconnected. ··· 1645 1408 break; 1646 1409 } 1647 1410 break; 1648 - case STEAM_EV_BATTERY: 1411 + case ID_CONTROLLER_STATUS: 1649 1412 if (steam->quirks & STEAM_QUIRK_WIRELESS) { 1650 1413 rcu_read_lock(); 1651 1414 battery = rcu_dereference(steam->battery); ··· 1676 1439 1677 1440 mutex_lock(&steam_devices_lock); 1678 1441 list_for_each_entry(steam, &steam_devices, list) { 1679 - mutex_lock(&steam->mutex); 1680 1442 if (!steam->client_opened) 1681 1443 steam_set_lizard_mode(steam, lizard_mode); 1682 - mutex_unlock(&steam->mutex); 1683 1444 } 1684 1445 mutex_unlock(&steam_devices_lock); 1685 1446 return 0;
+70 -67
drivers/hid/i2c-hid/i2c-hid-core.c
··· 44 44 #include "i2c-hid.h" 45 45 46 46 /* quirks to control the device */ 47 - #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) 48 - #define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1) 49 - #define I2C_HID_QUIRK_BOGUS_IRQ BIT(4) 50 - #define I2C_HID_QUIRK_RESET_ON_RESUME BIT(5) 51 - #define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(6) 52 - #define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(7) 47 + #define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(0) 48 + #define I2C_HID_QUIRK_BOGUS_IRQ BIT(1) 49 + #define I2C_HID_QUIRK_RESET_ON_RESUME BIT(2) 50 + #define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(3) 51 + #define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(4) 53 52 54 53 /* Command opcodes */ 55 54 #define I2C_HID_OPCODE_RESET 0x01 ··· 119 120 __u16 idProduct; 120 121 __u32 quirks; 121 122 } i2c_hid_quirks[] = { 122 - { USB_VENDOR_ID_WEIDA, HID_ANY_ID, 123 - I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, 124 123 { I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288, 125 124 I2C_HID_QUIRK_NO_IRQ_AFTER_RESET }, 126 125 { I2C_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_VOYO_WINPAD_A15, ··· 392 395 * The call will get a return value (EREMOTEIO) but device will be 393 396 * triggered and activated. After that, it goes like a normal device. 394 397 */ 395 - if (power_state == I2C_HID_PWR_ON && 396 - ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) { 398 + if (power_state == I2C_HID_PWR_ON) { 397 399 ret = i2c_hid_set_power_command(ihid, I2C_HID_PWR_ON); 398 400 399 401 /* Device was already activated */ ··· 422 426 return ret; 423 427 } 424 428 425 - static int i2c_hid_execute_reset(struct i2c_hid *ihid) 429 + static int i2c_hid_start_hwreset(struct i2c_hid *ihid) 426 430 { 427 431 size_t length = 0; 428 432 int ret; 429 433 430 - i2c_hid_dbg(ihid, "resetting...\n"); 434 + i2c_hid_dbg(ihid, "%s\n", __func__); 435 + 436 + /* 437 + * This prevents sending feature reports while the device is 438 + * being reset. Otherwise we may lose the reset complete 439 + * interrupt. 440 + */ 441 + lockdep_assert_held(&ihid->reset_lock); 442 + 443 + ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); 444 + if (ret) 445 + return ret; 431 446 432 447 /* Prepare reset command. Command register goes first. */ 433 448 *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister; ··· 451 444 452 445 ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0); 453 446 if (ret) { 454 - dev_err(&ihid->client->dev, "failed to reset device.\n"); 455 - goto out; 447 + dev_err(&ihid->client->dev, 448 + "failed to reset device: %d\n", ret); 449 + goto err_clear_reset; 456 450 } 457 451 458 - if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) { 459 - msleep(100); 460 - goto out; 461 - } 452 + return 0; 462 453 463 - i2c_hid_dbg(ihid, "%s: waiting...\n", __func__); 464 - if (!wait_event_timeout(ihid->wait, 465 - !test_bit(I2C_HID_RESET_PENDING, &ihid->flags), 466 - msecs_to_jiffies(5000))) { 467 - ret = -ENODATA; 468 - goto out; 469 - } 470 - i2c_hid_dbg(ihid, "%s: finished.\n", __func__); 471 - 472 - out: 454 + err_clear_reset: 473 455 clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); 456 + i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); 474 457 return ret; 475 458 } 476 459 477 - static int i2c_hid_hwreset(struct i2c_hid *ihid) 460 + static int i2c_hid_finish_hwreset(struct i2c_hid *ihid) 478 461 { 479 - int ret; 462 + int ret = 0; 480 463 481 - i2c_hid_dbg(ihid, "%s\n", __func__); 464 + i2c_hid_dbg(ihid, "%s: waiting...\n", __func__); 482 465 483 - /* 484 - * This prevents sending feature reports while the device is 485 - * being reset. Otherwise we may lose the reset complete 486 - * interrupt. 487 - */ 488 - mutex_lock(&ihid->reset_lock); 489 - 490 - ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); 491 - if (ret) 492 - goto out_unlock; 493 - 494 - ret = i2c_hid_execute_reset(ihid); 495 - if (ret) { 496 - dev_err(&ihid->client->dev, 497 - "failed to reset device: %d\n", ret); 498 - i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); 499 - goto out_unlock; 466 + if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) { 467 + msleep(100); 468 + clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); 469 + } else if (!wait_event_timeout(ihid->wait, 470 + !test_bit(I2C_HID_RESET_PENDING, &ihid->flags), 471 + msecs_to_jiffies(1000))) { 472 + dev_warn(&ihid->client->dev, "device did not ack reset within 1000 ms\n"); 473 + clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); 500 474 } 475 + i2c_hid_dbg(ihid, "%s: finished.\n", __func__); 501 476 502 477 /* At least some SIS devices need this after reset */ 503 478 if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET)) 504 479 ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); 505 480 506 - out_unlock: 507 - mutex_unlock(&ihid->reset_lock); 508 481 return ret; 509 482 } 510 483 ··· 716 729 struct i2c_client *client = hid->driver_data; 717 730 struct i2c_hid *ihid = i2c_get_clientdata(client); 718 731 struct i2c_hid_desc *hdesc = &ihid->hdesc; 732 + char *rdesc = NULL, *use_override = NULL; 719 733 unsigned int rsize; 720 - char *rdesc; 721 734 int ret; 722 735 int tries = 3; 723 - char *use_override; 724 736 725 737 i2c_hid_dbg(ihid, "entering %s\n", __func__); 726 738 ··· 729 743 return -EINVAL; 730 744 } 731 745 746 + mutex_lock(&ihid->reset_lock); 732 747 do { 733 - ret = i2c_hid_hwreset(ihid); 748 + ret = i2c_hid_start_hwreset(ihid); 734 749 if (ret) 735 750 msleep(1000); 736 751 } while (tries-- > 0 && ret); 737 752 738 753 if (ret) 739 - return ret; 754 + goto abort_reset; 740 755 741 756 use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name, 742 757 &rsize); ··· 749 762 rdesc = kzalloc(rsize, GFP_KERNEL); 750 763 751 764 if (!rdesc) { 752 - dbg_hid("couldn't allocate rdesc memory\n"); 753 - return -ENOMEM; 765 + ret = -ENOMEM; 766 + goto abort_reset; 754 767 } 755 768 756 769 i2c_hid_dbg(ihid, "asking HID report descriptor\n"); ··· 760 773 rdesc, rsize); 761 774 if (ret) { 762 775 hid_err(hid, "reading report descriptor failed\n"); 763 - kfree(rdesc); 764 - return -EIO; 776 + goto abort_reset; 765 777 } 766 778 } 779 + 780 + /* 781 + * Windows directly reads the report-descriptor after sending reset 782 + * and then waits for resets completion afterwards. Some touchpads 783 + * actually wait for the report-descriptor to be read before signalling 784 + * reset completion. 785 + */ 786 + ret = i2c_hid_finish_hwreset(ihid); 787 + abort_reset: 788 + clear_bit(I2C_HID_RESET_PENDING, &ihid->flags); 789 + mutex_unlock(&ihid->reset_lock); 790 + if (ret) 791 + goto out; 767 792 768 793 i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc); 769 794 770 795 ret = hid_parse_report(hid, rdesc, rsize); 796 + if (ret) 797 + dbg_hid("parsing report descriptor failed\n"); 798 + 799 + out: 771 800 if (!use_override) 772 801 kfree(rdesc); 773 802 774 - if (ret) { 775 - dbg_hid("parsing report descriptor failed\n"); 776 - return ret; 777 - } 778 - 779 - return 0; 803 + return ret; 780 804 } 781 805 782 806 static int i2c_hid_start(struct hid_device *hid) ··· 985 987 * However some ALPS touchpads generate IRQ storm without reset, so 986 988 * let's still reset them here. 987 989 */ 988 - if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME) 989 - ret = i2c_hid_hwreset(ihid); 990 - else 990 + if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME) { 991 + mutex_lock(&ihid->reset_lock); 992 + ret = i2c_hid_start_hwreset(ihid); 993 + if (ret == 0) 994 + ret = i2c_hid_finish_hwreset(ihid); 995 + mutex_unlock(&ihid->reset_lock); 996 + } else { 991 997 ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); 998 + } 992 999 993 1000 if (ret) 994 1001 return ret;
+8
drivers/hid/i2c-hid/i2c-hid-of-elan.c
··· 130 130 .main_supply_name = NULL, 131 131 }; 132 132 133 + static const struct elan_i2c_hid_chip_data ilitek_ili2901_chip_data = { 134 + .post_power_delay_ms = 10, 135 + .post_gpio_reset_on_delay_ms = 100, 136 + .hid_descriptor_address = 0x0001, 137 + .main_supply_name = "vcc33", 138 + }; 139 + 133 140 static const struct of_device_id elan_i2c_hid_of_match[] = { 134 141 { .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data }, 135 142 { .compatible = "ilitek,ili9882t", .data = &ilitek_ili9882t_chip_data }, 143 + { .compatible = "ilitek,ili2901", .data = &ilitek_ili2901_chip_data }, 136 144 { } 137 145 }; 138 146 MODULE_DEVICE_TABLE(of, elan_i2c_hid_of_match);
+15 -52
drivers/hid/intel-ish-hid/ipc/pci-ish.c
··· 119 119 return !pm_resume_via_firmware() || pdev->device == CHV_DEVICE_ID; 120 120 } 121 121 122 - static int enable_gpe(struct device *dev) 123 - { 124 - #ifdef CONFIG_ACPI 125 - acpi_status acpi_sts; 126 - struct acpi_device *adev; 127 - struct acpi_device_wakeup *wakeup; 128 - 129 - adev = ACPI_COMPANION(dev); 130 - if (!adev) { 131 - dev_err(dev, "get acpi handle failed\n"); 132 - return -ENODEV; 133 - } 134 - wakeup = &adev->wakeup; 135 - 136 - /* 137 - * Call acpi_disable_gpe(), so that reference count 138 - * gpe_event_info->runtime_count doesn't overflow. 139 - * When gpe_event_info->runtime_count = 0, the call 140 - * to acpi_disable_gpe() simply return. 141 - */ 142 - acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); 143 - 144 - acpi_sts = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); 145 - if (ACPI_FAILURE(acpi_sts)) { 146 - dev_err(dev, "enable ose_gpe failed\n"); 147 - return -EIO; 148 - } 149 - 150 - return 0; 151 - #else 152 - return -ENODEV; 153 - #endif 154 - } 155 - 156 - static void enable_pme_wake(struct pci_dev *pdev) 157 - { 158 - if ((pci_pme_capable(pdev, PCI_D0) || 159 - pci_pme_capable(pdev, PCI_D3hot) || 160 - pci_pme_capable(pdev, PCI_D3cold)) && !enable_gpe(&pdev->dev)) { 161 - pci_pme_active(pdev, true); 162 - dev_dbg(&pdev->dev, "ish ipc driver pme wake enabled\n"); 163 - } 164 - } 165 - 166 122 /** 167 123 * ish_probe() - PCI driver probe callback 168 124 * @pdev: pci device ··· 189 233 190 234 /* Enable PME for EHL */ 191 235 if (pdev->device == EHL_Ax_DEVICE_ID) 192 - enable_pme_wake(pdev); 236 + device_init_wakeup(dev, true); 193 237 194 238 ret = ish_init(ishtp); 195 239 if (ret) ··· 210 254 211 255 ishtp_bus_remove_all_clients(ishtp_dev, false); 212 256 ish_device_disable(ishtp_dev); 257 + } 258 + 259 + 260 + /** 261 + * ish_shutdown() - PCI driver shutdown callback 262 + * @pdev: pci device 263 + * 264 + * This function sets up wakeup for S5 265 + */ 266 + static void ish_shutdown(struct pci_dev *pdev) 267 + { 268 + if (pdev->device == EHL_Ax_DEVICE_ID) 269 + pci_prepare_to_sleep(pdev); 213 270 } 214 271 215 272 static struct device __maybe_unused *ish_resume_device; ··· 347 378 struct pci_dev *pdev = to_pci_dev(device); 348 379 struct ishtp_device *dev = pci_get_drvdata(pdev); 349 380 350 - /* add this to finish power flow for EHL */ 351 - if (dev->pdev->device == EHL_Ax_DEVICE_ID) { 352 - pci_set_power_state(pdev, PCI_D0); 353 - enable_pme_wake(pdev); 354 - dev_dbg(dev->devc, "set power state to D0 for ehl\n"); 355 - } 356 - 357 381 ish_resume_device = device; 358 382 dev->resume_flag = 1; 359 383 ··· 362 400 .id_table = ish_pci_tbl, 363 401 .probe = ish_probe, 364 402 .remove = ish_remove, 403 + .shutdown = ish_shutdown, 365 404 .driver.pm = &ish_pm_ops, 366 405 }; 367 406
+12 -48
drivers/hid/intel-ish-hid/ishtp-fw-loader.c
··· 840 840 * 841 841 * Return: 0 for success, negative error code for failure 842 842 */ 843 - static int loader_init(struct ishtp_cl *loader_ishtp_cl, int reset) 843 + static int loader_init(struct ishtp_cl *loader_ishtp_cl, bool reset) 844 844 { 845 845 int rv; 846 - struct ishtp_fw_client *fw_client; 847 846 struct ishtp_cl_data *client_data = 848 847 ishtp_get_client_data(loader_ishtp_cl); 849 848 850 849 dev_dbg(cl_data_to_dev(client_data), "reset flag: %d\n", reset); 851 850 852 - rv = ishtp_cl_link(loader_ishtp_cl); 853 - if (rv < 0) { 854 - dev_err(cl_data_to_dev(client_data), "ishtp_cl_link failed\n"); 855 - return rv; 856 - } 857 - 858 - /* Connect to firmware client */ 859 - ishtp_set_tx_ring_size(loader_ishtp_cl, LOADER_CL_TX_RING_SIZE); 860 - ishtp_set_rx_ring_size(loader_ishtp_cl, LOADER_CL_RX_RING_SIZE); 861 - 862 - fw_client = 863 - ishtp_fw_cl_get_client(ishtp_get_ishtp_device(loader_ishtp_cl), 864 - &loader_ishtp_id_table[0].guid); 865 - if (!fw_client) { 866 - dev_err(cl_data_to_dev(client_data), 867 - "ISH client uuid not found\n"); 868 - rv = -ENOENT; 869 - goto err_cl_unlink; 870 - } 871 - 872 - ishtp_cl_set_fw_client_id(loader_ishtp_cl, 873 - ishtp_get_fw_client_id(fw_client)); 874 - ishtp_set_connection_state(loader_ishtp_cl, ISHTP_CL_CONNECTING); 875 - 876 - rv = ishtp_cl_connect(loader_ishtp_cl); 851 + rv = ishtp_cl_establish_connection(loader_ishtp_cl, 852 + &loader_ishtp_id_table[0].guid, 853 + LOADER_CL_TX_RING_SIZE, 854 + LOADER_CL_RX_RING_SIZE, 855 + reset); 877 856 if (rv < 0) { 878 857 dev_err(cl_data_to_dev(client_data), "Client connect fail\n"); 879 - goto err_cl_unlink; 858 + goto err_cl_disconnect; 880 859 } 881 860 882 861 dev_dbg(cl_data_to_dev(client_data), "Client connected\n"); ··· 864 885 865 886 return 0; 866 887 867 - err_cl_unlink: 868 - ishtp_cl_unlink(loader_ishtp_cl); 888 + err_cl_disconnect: 889 + ishtp_cl_destroy_connection(loader_ishtp_cl, reset); 869 890 return rv; 870 891 } 871 892 872 893 static void loader_deinit(struct ishtp_cl *loader_ishtp_cl) 873 894 { 874 - ishtp_set_connection_state(loader_ishtp_cl, ISHTP_CL_DISCONNECTING); 875 - ishtp_cl_disconnect(loader_ishtp_cl); 876 - ishtp_cl_unlink(loader_ishtp_cl); 877 - ishtp_cl_flush_queues(loader_ishtp_cl); 895 + ishtp_cl_destroy_connection(loader_ishtp_cl, false); 878 896 879 897 /* Disband and free all Tx and Rx client-level rings */ 880 898 ishtp_cl_free(loader_ishtp_cl); ··· 890 914 loader_ishtp_cl = client_data->loader_ishtp_cl; 891 915 cl_device = client_data->cl_device; 892 916 893 - /* Unlink, flush queues & start again */ 894 - ishtp_cl_unlink(loader_ishtp_cl); 895 - ishtp_cl_flush_queues(loader_ishtp_cl); 896 - ishtp_cl_free(loader_ishtp_cl); 897 - 898 - loader_ishtp_cl = ishtp_cl_allocate(cl_device); 899 - if (!loader_ishtp_cl) 900 - return; 901 - 902 - ishtp_set_drvdata(cl_device, loader_ishtp_cl); 903 - ishtp_set_client_data(loader_ishtp_cl, client_data); 904 - client_data->loader_ishtp_cl = loader_ishtp_cl; 905 - client_data->cl_device = cl_device; 917 + ishtp_cl_destroy_connection(loader_ishtp_cl, true); 906 918 907 919 rv = loader_init(loader_ishtp_cl, 1); 908 920 if (rv < 0) { ··· 938 974 INIT_WORK(&client_data->work_fw_load, 939 975 load_fw_from_host_handler); 940 976 941 - rv = loader_init(loader_ishtp_cl, 0); 977 + rv = loader_init(loader_ishtp_cl, false); 942 978 if (rv < 0) { 943 979 ishtp_cl_free(loader_ishtp_cl); 944 980 return rv;
+13 -50
drivers/hid/intel-ish-hid/ishtp-hid-client.c
··· 639 639 * 640 640 * Return: 0 on success, non zero on error 641 641 */ 642 - static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset) 642 + static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, bool reset) 643 643 { 644 - struct ishtp_device *dev; 645 644 struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl); 646 - struct ishtp_fw_client *fw_client; 647 645 int i; 648 646 int rv; 649 647 650 648 dev_dbg(cl_data_to_dev(client_data), "%s\n", __func__); 651 649 hid_ishtp_trace(client_data, "%s reset flag: %d\n", __func__, reset); 652 650 653 - rv = ishtp_cl_link(hid_ishtp_cl); 654 - if (rv) { 655 - dev_err(cl_data_to_dev(client_data), 656 - "ishtp_cl_link failed\n"); 657 - return -ENOMEM; 658 - } 659 - 660 651 client_data->init_done = 0; 661 652 662 - dev = ishtp_get_ishtp_device(hid_ishtp_cl); 663 - 664 - /* Connect to FW client */ 665 - ishtp_set_tx_ring_size(hid_ishtp_cl, HID_CL_TX_RING_SIZE); 666 - ishtp_set_rx_ring_size(hid_ishtp_cl, HID_CL_RX_RING_SIZE); 667 - 668 - fw_client = ishtp_fw_cl_get_client(dev, &hid_ishtp_id_table[0].guid); 669 - if (!fw_client) { 670 - dev_err(cl_data_to_dev(client_data), 671 - "ish client uuid not found\n"); 672 - return -ENOENT; 673 - } 674 - ishtp_cl_set_fw_client_id(hid_ishtp_cl, 675 - ishtp_get_fw_client_id(fw_client)); 676 - ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_CONNECTING); 677 - 678 - rv = ishtp_cl_connect(hid_ishtp_cl); 653 + rv = ishtp_cl_establish_connection(hid_ishtp_cl, 654 + &hid_ishtp_id_table[0].guid, 655 + HID_CL_TX_RING_SIZE, 656 + HID_CL_RX_RING_SIZE, 657 + reset); 679 658 if (rv) { 680 659 dev_err(cl_data_to_dev(client_data), 681 660 "client connect fail\n"); 682 - goto err_cl_unlink; 661 + goto err_cl_disconnect; 683 662 } 684 663 685 664 hid_ishtp_trace(client_data, "%s client connected\n", __func__); ··· 702 723 return 0; 703 724 704 725 err_cl_disconnect: 705 - ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING); 706 - ishtp_cl_disconnect(hid_ishtp_cl); 707 - err_cl_unlink: 708 - ishtp_cl_unlink(hid_ishtp_cl); 726 + ishtp_cl_destroy_connection(hid_ishtp_cl, reset); 709 727 return rv; 710 728 } 711 729 ··· 714 738 */ 715 739 static void hid_ishtp_cl_deinit(struct ishtp_cl *hid_ishtp_cl) 716 740 { 717 - ishtp_cl_unlink(hid_ishtp_cl); 718 - ishtp_cl_flush_queues(hid_ishtp_cl); 741 + ishtp_cl_destroy_connection(hid_ishtp_cl, false); 719 742 720 743 /* disband and free all Tx and Rx client-level rings */ 721 744 ishtp_cl_free(hid_ishtp_cl); ··· 724 749 { 725 750 struct ishtp_cl_data *client_data; 726 751 struct ishtp_cl *hid_ishtp_cl; 727 - struct ishtp_cl_device *cl_device; 728 752 int retry; 729 753 int rv; 730 754 731 755 client_data = container_of(work, struct ishtp_cl_data, work); 732 756 733 757 hid_ishtp_cl = client_data->hid_ishtp_cl; 734 - cl_device = client_data->cl_device; 735 758 736 759 hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, 737 760 hid_ishtp_cl); 738 761 dev_dbg(ishtp_device(client_data->cl_device), "%s\n", __func__); 739 762 740 - hid_ishtp_cl_deinit(hid_ishtp_cl); 741 - 742 - hid_ishtp_cl = ishtp_cl_allocate(cl_device); 743 - if (!hid_ishtp_cl) 744 - return; 745 - 746 - ishtp_set_drvdata(cl_device, hid_ishtp_cl); 747 - ishtp_set_client_data(hid_ishtp_cl, client_data); 748 - client_data->hid_ishtp_cl = hid_ishtp_cl; 763 + ishtp_cl_destroy_connection(hid_ishtp_cl, true); 749 764 750 765 client_data->num_hid_devices = 0; 751 766 752 767 for (retry = 0; retry < 3; ++retry) { 753 - rv = hid_ishtp_cl_init(hid_ishtp_cl, 1); 768 + rv = hid_ishtp_cl_init(hid_ishtp_cl, true); 754 769 if (!rv) 755 770 break; 756 771 dev_err(cl_data_to_dev(client_data), "Retry reset init\n"); ··· 806 841 807 842 ishtp_hid_print_trace = ishtp_trace_callback(cl_device); 808 843 809 - rv = hid_ishtp_cl_init(hid_ishtp_cl, 0); 844 + rv = hid_ishtp_cl_init(hid_ishtp_cl, false); 810 845 if (rv) { 811 846 ishtp_cl_free(hid_ishtp_cl); 812 847 return rv; ··· 833 868 hid_ishtp_cl); 834 869 835 870 dev_dbg(ishtp_device(cl_device), "%s\n", __func__); 836 - ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING); 837 - ishtp_cl_disconnect(hid_ishtp_cl); 871 + hid_ishtp_cl_deinit(hid_ishtp_cl); 838 872 ishtp_put_device(cl_device); 839 873 ishtp_hid_remove(client_data); 840 - hid_ishtp_cl_deinit(hid_ishtp_cl); 841 874 842 875 hid_ishtp_cl = NULL; 843 876
+1 -1
drivers/hid/intel-ish-hid/ishtp/bus.c
··· 378 378 .restore = ishtp_cl_device_resume, 379 379 }; 380 380 381 - static struct bus_type ishtp_cl_bus_type = { 381 + static const struct bus_type ishtp_cl_bus_type = { 382 382 .name = "ishtp", 383 383 .dev_groups = ishtp_cl_dev_groups, 384 384 .probe = ishtp_cl_device_probe,
+174 -11
drivers/hid/intel-ish-hid/ishtp/client.c
··· 339 339 } 340 340 341 341 /** 342 - * ishtp_cl_connect() - Send connect request to firmware 342 + * ishtp_cl_connect_to_fw() - Send connect request to firmware 343 343 * @cl: client device instance 344 344 * 345 - * Send a connect request for a client to firmware. If successful it will 346 - * RX and TX ring buffers 345 + * Send a connect request to the firmware and wait for firmware response. 346 + * If there is successful connection response from the firmware, change 347 + * client state to ISHTP_CL_CONNECTED, and bind client to related 348 + * firmware client_id. 347 349 * 348 - * Return: 0 if successful connect response from the firmware and able 349 - * to bind and allocate ring buffers or error code on failure 350 + * Return: 0 for success and error code on failure 350 351 */ 351 - int ishtp_cl_connect(struct ishtp_cl *cl) 352 + static int ishtp_cl_connect_to_fw(struct ishtp_cl *cl) 352 353 { 353 354 struct ishtp_device *dev; 354 355 int rets; ··· 358 357 return -ENODEV; 359 358 360 359 dev = cl->dev; 361 - 362 - dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state); 363 360 364 361 if (ishtp_cl_is_other_connecting(cl)) { 365 362 dev->print_log(dev, "%s() Busy\n", __func__); ··· 404 405 return rets; 405 406 } 406 407 408 + return rets; 409 + } 410 + 411 + /** 412 + * ishtp_cl_connect() - Build connection with firmware 413 + * @cl: client device instance 414 + * 415 + * Call ishtp_cl_connect_to_fw() to connect and bind to firmware. If successful, 416 + * allocate RX and TX ring buffers, and start flow control with firmware to 417 + * start communication. 418 + * 419 + * Return: 0 if there is successful connection to the firmware, allocate 420 + * ring buffers. 421 + */ 422 + int ishtp_cl_connect(struct ishtp_cl *cl) 423 + { 424 + struct ishtp_device *dev; 425 + int rets; 426 + 427 + if (!cl || !cl->dev) 428 + return -ENODEV; 429 + 430 + dev = cl->dev; 431 + 432 + dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state); 433 + 434 + rets = ishtp_cl_connect_to_fw(cl); 435 + if (rets) { 436 + dev->print_log(dev, "%s() Connect to fw failed\n", __func__); 437 + return rets; 438 + } 439 + 407 440 rets = ishtp_cl_alloc_rx_ring(cl); 408 441 if (rets) { 409 442 dev->print_log(dev, "%s() Alloc RX ring failed\n", __func__); ··· 453 422 return rets; 454 423 } 455 424 456 - /* Upon successful connection and allocation, emit flow-control */ 425 + /* 426 + * Upon successful connection and allocation, start flow-control. 427 + */ 457 428 rets = ishtp_cl_read_start(cl); 458 - 459 - dev->print_log(dev, "%s() successful\n", __func__); 460 429 461 430 return rets; 462 431 } 463 432 EXPORT_SYMBOL(ishtp_cl_connect); 433 + 434 + /** 435 + * ishtp_cl_establish_connection() - Establish connection with the firmware 436 + * @cl: client device instance 437 + * @uuid: uuid of the client to search 438 + * @tx_size: TX ring buffer size 439 + * @rx_size: RX ring buffer size 440 + * @reset: true if called for reset connection, otherwise for first connection 441 + * 442 + * This is a helper function for client driver to build connection with firmware. 443 + * If it's first time connecting to the firmware, set reset to false, this 444 + * function will link client to bus, find client id and send connect request to 445 + * the firmware. 446 + * 447 + * If it's called for reset handler where client lost connection after 448 + * firmware reset, set reset to true, this function will reinit client state and 449 + * establish connection again. In this case, this function reuses current client 450 + * structure and ring buffers to avoid allocation failure and memory fragments. 451 + * 452 + * Return: 0 for successful connection with the firmware, 453 + * or error code on failure 454 + */ 455 + int ishtp_cl_establish_connection(struct ishtp_cl *cl, const guid_t *uuid, 456 + int tx_size, int rx_size, bool reset) 457 + { 458 + struct ishtp_device *dev; 459 + struct ishtp_fw_client *fw_client; 460 + int rets; 461 + 462 + if (!cl || !cl->dev) 463 + return -ENODEV; 464 + 465 + dev = cl->dev; 466 + 467 + ishtp_set_connection_state(cl, ISHTP_CL_INITIALIZING); 468 + 469 + /* reinit ishtp_cl structure if call for reset */ 470 + if (reset) { 471 + cl->host_client_id = 0; 472 + cl->fw_client_id = 0; 473 + cl->ishtp_flow_ctrl_creds = 0; 474 + cl->out_flow_ctrl_creds = 0; 475 + 476 + cl->last_tx_path = CL_TX_PATH_IPC; 477 + cl->last_dma_acked = 1; 478 + cl->last_dma_addr = NULL; 479 + cl->last_ipc_acked = 1; 480 + 481 + cl->sending = 0; 482 + cl->err_send_msg = 0; 483 + cl->err_send_fc = 0; 484 + 485 + cl->send_msg_cnt_ipc = 0; 486 + cl->send_msg_cnt_dma = 0; 487 + cl->recv_msg_cnt_ipc = 0; 488 + cl->recv_msg_cnt_dma = 0; 489 + cl->recv_msg_num_frags = 0; 490 + cl->ishtp_flow_ctrl_cnt = 0; 491 + cl->out_flow_ctrl_cnt = 0; 492 + } 493 + 494 + /* link to bus */ 495 + rets = ishtp_cl_link(cl); 496 + if (rets) { 497 + dev->print_log(dev, "%s() ishtp_cl_link failed\n", __func__); 498 + return rets; 499 + } 500 + 501 + /* find firmware client */ 502 + fw_client = ishtp_fw_cl_get_client(dev, uuid); 503 + if (!fw_client) { 504 + dev->print_log(dev, 505 + "%s() ish client uuid not found\n", __func__); 506 + return -ENOENT; 507 + } 508 + 509 + ishtp_set_tx_ring_size(cl, tx_size); 510 + ishtp_set_rx_ring_size(cl, rx_size); 511 + 512 + ishtp_cl_set_fw_client_id(cl, ishtp_get_fw_client_id(fw_client)); 513 + 514 + ishtp_set_connection_state(cl, ISHTP_CL_CONNECTING); 515 + 516 + /* 517 + * For reset case, not allocate tx/rx ring buffer which are already 518 + * done in ishtp_cl_connect() during first connection. 519 + */ 520 + if (reset) { 521 + rets = ishtp_cl_connect_to_fw(cl); 522 + if (!rets) 523 + rets = ishtp_cl_read_start(cl); 524 + else 525 + dev->print_log(dev, 526 + "%s() connect to fw failed\n", __func__); 527 + } else { 528 + rets = ishtp_cl_connect(cl); 529 + } 530 + 531 + return rets; 532 + } 533 + EXPORT_SYMBOL(ishtp_cl_establish_connection); 534 + 535 + /** 536 + * ishtp_cl_destroy_connection() - Disconnect with the firmware 537 + * @cl: client device instance 538 + * @reset: true if called for firmware reset, false for normal disconnection 539 + * 540 + * This is a helper function for client driver to disconnect with firmware, 541 + * unlink to bus and flush message queue. 542 + */ 543 + void ishtp_cl_destroy_connection(struct ishtp_cl *cl, bool reset) 544 + { 545 + if (!cl) 546 + return; 547 + 548 + if (reset) { 549 + /* 550 + * For reset case, connection is already lost during fw reset. 551 + * Just set state to DISCONNECTED is enough. 552 + */ 553 + ishtp_set_connection_state(cl, ISHTP_CL_DISCONNECTED); 554 + } else { 555 + if (cl->state != ISHTP_CL_DISCONNECTED) { 556 + ishtp_set_connection_state(cl, ISHTP_CL_DISCONNECTING); 557 + ishtp_cl_disconnect(cl); 558 + } 559 + } 560 + 561 + ishtp_cl_unlink(cl); 562 + ishtp_cl_flush_queues(cl); 563 + } 564 + EXPORT_SYMBOL(ishtp_cl_destroy_connection); 464 565 465 566 /** 466 567 * ishtp_cl_read_start() - Prepare to read client message
+1
drivers/hid/wacom.h
··· 164 164 struct work_struct battery_work; 165 165 struct work_struct remote_work; 166 166 struct delayed_work init_work; 167 + struct delayed_work aes_battery_work; 167 168 struct wacom_remote *remote; 168 169 struct work_struct mode_change_work; 169 170 struct timer_list idleprox_timer;
+8
drivers/hid/wacom_sys.c
··· 1813 1813 } 1814 1814 } 1815 1815 1816 + static void wacom_aes_battery_handler(struct work_struct *work) 1817 + { 1818 + struct wacom *wacom = container_of(work, struct wacom, aes_battery_work.work); 1819 + 1820 + wacom_destroy_battery(wacom); 1821 + } 1822 + 1816 1823 static ssize_t wacom_show_speed(struct device *dev, 1817 1824 struct device_attribute 1818 1825 *attr, char *buf) ··· 2801 2794 2802 2795 mutex_init(&wacom->lock); 2803 2796 INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work); 2797 + INIT_DELAYED_WORK(&wacom->aes_battery_work, wacom_aes_battery_handler); 2804 2798 INIT_WORK(&wacom->wireless_work, wacom_wireless_work); 2805 2799 INIT_WORK(&wacom->battery_work, wacom_battery_work); 2806 2800 INIT_WORK(&wacom->remote_work, wacom_remote_work);
+15 -29
drivers/hid/wacom_wac.c
··· 2528 2528 struct input_dev *input = wacom_wac->pen_input; 2529 2529 bool range = wacom_wac->hid_data.inrange_state; 2530 2530 bool sense = wacom_wac->hid_data.sense_state; 2531 + bool entering_range = !wacom_wac->tool[0] && range; 2531 2532 2532 2533 if (wacom_wac->is_invalid_bt_frame) 2533 2534 return; 2534 2535 2535 - if (!wacom_wac->tool[0] && range) { /* first in range */ 2536 + if (entering_range) { /* first in range */ 2536 2537 /* Going into range select tool */ 2537 2538 if (wacom_wac->hid_data.invert_state) 2538 2539 wacom_wac->tool[0] = BTN_TOOL_RUBBER; ··· 2582 2581 wacom_wac->hid_data.tipswitch = false; 2583 2582 2584 2583 input_sync(input); 2584 + } 2585 + 2586 + /* Handle AES battery timeout behavior */ 2587 + if (wacom_wac->features.quirks & WACOM_QUIRK_AESPEN) { 2588 + if (entering_range) 2589 + cancel_delayed_work(&wacom->aes_battery_work); 2590 + if (!sense) 2591 + schedule_delayed_work(&wacom->aes_battery_work, 2592 + msecs_to_jiffies(WACOM_AES_BATTERY_TIMEOUT)); 2585 2593 } 2586 2594 2587 2595 if (!sense) { ··· 2659 2649 { 2660 2650 struct hid_data *hid_data = &wacom_wac->hid_data; 2661 2651 bool mt = wacom_wac->features.touch_max > 1; 2662 - bool prox = hid_data->tipswitch && 2663 - report_touch_events(wacom_wac); 2652 + bool touch_down = hid_data->tipswitch && hid_data->confidence; 2653 + bool prox = touch_down && report_touch_events(wacom_wac); 2664 2654 2665 2655 if (touch_is_muted(wacom_wac)) { 2666 2656 if (!wacom_wac->shared->touch_down) ··· 2708 2698 input_report_abs(input, ABS_MT_ORIENTATION, hid_data->width <= hid_data->height ? 0 : 1); 2709 2699 } 2710 2700 } 2711 - } 2712 - 2713 - static bool wacom_wac_slot_is_active(struct input_dev *dev, int key) 2714 - { 2715 - struct input_mt *mt = dev->mt; 2716 - struct input_mt_slot *s; 2717 - 2718 - if (!mt) 2719 - return false; 2720 - 2721 - for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { 2722 - if (s->key == key && 2723 - input_mt_get_value(s, ABS_MT_TRACKING_ID) >= 0) { 2724 - return true; 2725 - } 2726 - } 2727 - 2728 - return false; 2729 2701 } 2730 2702 2731 2703 static void wacom_wac_finger_event(struct hid_device *hdev, ··· 2760 2768 } 2761 2769 2762 2770 if (usage->usage_index + 1 == field->report_count) { 2763 - if (equivalent_usage == wacom_wac->hid_data.last_slot_field) { 2764 - bool touch_removed = wacom_wac_slot_is_active(wacom_wac->touch_input, 2765 - wacom_wac->hid_data.id) && !wacom_wac->hid_data.tipswitch; 2766 - 2767 - if (wacom_wac->hid_data.confidence || touch_removed) { 2768 - wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input); 2769 - } 2770 - } 2771 + if (equivalent_usage == wacom_wac->hid_data.last_slot_field) 2772 + wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input); 2771 2773 } 2772 2774 } 2773 2775
+1
drivers/hid/wacom_wac.h
··· 14 14 #define WACOM_MAX_REMOTES 5 15 15 #define WACOM_STATUS_UNKNOWN 255 16 16 #define WACOM_REMOTE_BATTERY_TIMEOUT 21000000000ll 17 + #define WACOM_AES_BATTERY_TIMEOUT 1800000 17 18 18 19 /* packet length for individual models */ 19 20 #define WACOM_PKGLEN_BBFUN 9
+15 -59
drivers/platform/chrome/cros_ec_ishtp.c
··· 367 367 /** 368 368 * cros_ish_init() - Init function for ISHTP client 369 369 * @cros_ish_cl: ISHTP client instance 370 + * @reset: true if called from reset handler 370 371 * 371 372 * This function complete the initializtion of the client. 372 373 * 373 374 * Return: 0 for success, negative error code for failure. 374 375 */ 375 - static int cros_ish_init(struct ishtp_cl *cros_ish_cl) 376 + static int cros_ish_init(struct ishtp_cl *cros_ish_cl, bool reset) 376 377 { 377 378 int rv; 378 - struct ishtp_device *dev; 379 - struct ishtp_fw_client *fw_client; 380 379 struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl); 381 380 382 - rv = ishtp_cl_link(cros_ish_cl); 383 - if (rv) { 384 - dev_err(cl_data_to_dev(client_data), 385 - "ishtp_cl_link failed\n"); 386 - return rv; 387 - } 388 - 389 - dev = ishtp_get_ishtp_device(cros_ish_cl); 390 - 391 - /* Connect to firmware client */ 392 - ishtp_set_tx_ring_size(cros_ish_cl, CROS_ISH_CL_TX_RING_SIZE); 393 - ishtp_set_rx_ring_size(cros_ish_cl, CROS_ISH_CL_RX_RING_SIZE); 394 - 395 - fw_client = ishtp_fw_cl_get_client(dev, &cros_ec_ishtp_id_table[0].guid); 396 - if (!fw_client) { 397 - dev_err(cl_data_to_dev(client_data), 398 - "ish client uuid not found\n"); 399 - rv = -ENOENT; 400 - goto err_cl_unlink; 401 - } 402 - 403 - ishtp_cl_set_fw_client_id(cros_ish_cl, 404 - ishtp_get_fw_client_id(fw_client)); 405 - ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_CONNECTING); 406 - 407 - rv = ishtp_cl_connect(cros_ish_cl); 381 + rv = ishtp_cl_establish_connection(cros_ish_cl, 382 + &cros_ec_ishtp_id_table[0].guid, 383 + CROS_ISH_CL_TX_RING_SIZE, 384 + CROS_ISH_CL_RX_RING_SIZE, 385 + reset); 408 386 if (rv) { 409 387 dev_err(cl_data_to_dev(client_data), 410 388 "client connect fail\n"); 411 - goto err_cl_unlink; 389 + goto err_cl_disconnect; 412 390 } 413 391 414 392 ishtp_register_event_cb(client_data->cl_device, ish_event_cb); 415 393 return 0; 416 394 417 - err_cl_unlink: 418 - ishtp_cl_unlink(cros_ish_cl); 395 + err_cl_disconnect: 396 + ishtp_cl_destroy_connection(cros_ish_cl, reset); 419 397 return rv; 420 398 } 421 399 ··· 405 427 */ 406 428 static void cros_ish_deinit(struct ishtp_cl *cros_ish_cl) 407 429 { 408 - ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_DISCONNECTING); 409 - ishtp_cl_disconnect(cros_ish_cl); 410 - ishtp_cl_unlink(cros_ish_cl); 411 - ishtp_cl_flush_queues(cros_ish_cl); 430 + ishtp_cl_destroy_connection(cros_ish_cl, false); 412 431 413 432 /* Disband and free all Tx and Rx client-level rings */ 414 433 ishtp_cl_free(cros_ish_cl); ··· 567 592 int rv; 568 593 struct device *dev; 569 594 struct ishtp_cl *cros_ish_cl; 570 - struct ishtp_cl_device *cl_device; 571 595 struct ishtp_cl_data *client_data = 572 596 container_of(work, struct ishtp_cl_data, work_ishtp_reset); 573 597 ··· 574 600 down_write(&init_lock); 575 601 576 602 cros_ish_cl = client_data->cros_ish_cl; 577 - cl_device = client_data->cl_device; 578 603 579 - /* Unlink, flush queues & start again */ 580 - ishtp_cl_unlink(cros_ish_cl); 581 - ishtp_cl_flush_queues(cros_ish_cl); 582 - ishtp_cl_free(cros_ish_cl); 604 + ishtp_cl_destroy_connection(cros_ish_cl, true); 583 605 584 - cros_ish_cl = ishtp_cl_allocate(cl_device); 585 - if (!cros_ish_cl) { 586 - up_write(&init_lock); 587 - return; 588 - } 589 - 590 - ishtp_set_drvdata(cl_device, cros_ish_cl); 591 - ishtp_set_client_data(cros_ish_cl, client_data); 592 - client_data->cros_ish_cl = cros_ish_cl; 593 - 594 - rv = cros_ish_init(cros_ish_cl); 606 + rv = cros_ish_init(cros_ish_cl, true); 595 607 if (rv) { 596 - ishtp_cl_free(cros_ish_cl); 597 608 dev_err(cl_data_to_dev(client_data), "Reset Failed\n"); 598 609 up_write(&init_lock); 599 610 return; ··· 631 672 INIT_WORK(&client_data->work_ec_evt, 632 673 ish_evt_handler); 633 674 634 - rv = cros_ish_init(cros_ish_cl); 675 + rv = cros_ish_init(cros_ish_cl, false); 635 676 if (rv) 636 677 goto end_ishtp_cl_init_error; 637 678 ··· 649 690 return 0; 650 691 651 692 end_cros_ec_dev_init_error: 652 - ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_DISCONNECTING); 653 - ishtp_cl_disconnect(cros_ish_cl); 654 - ishtp_cl_unlink(cros_ish_cl); 655 - ishtp_cl_flush_queues(cros_ish_cl); 693 + ishtp_cl_destroy_connection(cros_ish_cl, false); 656 694 ishtp_put_device(cl_device); 657 695 end_ishtp_cl_init_error: 658 696 ishtp_cl_free(cros_ish_cl);
+50
include/linux/amd-pmf-io.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * AMD Platform Management Framework Interface 4 + * 5 + * Copyright (c) 2023, Advanced Micro Devices, Inc. 6 + * All Rights Reserved. 7 + * 8 + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 9 + * Basavaraj Natikar <Basavaraj.Natikar@amd.com> 10 + */ 11 + 12 + #ifndef AMD_PMF_IO_H 13 + #define AMD_PMF_IO_H 14 + 15 + #include <linux/types.h> 16 + 17 + /** 18 + * enum sfh_message_type - Query the SFH message type 19 + * @MT_HPD: Message ID to know the Human presence info from MP2 FW 20 + * @MT_ALS: Message ID to know the Ambient light info from MP2 FW 21 + */ 22 + enum sfh_message_type { 23 + MT_HPD, 24 + MT_ALS, 25 + }; 26 + 27 + /** 28 + * enum sfh_hpd_info - Query the Human presence information 29 + * @SFH_NOT_DETECTED: Check the HPD connection information from MP2 FW 30 + * @SFH_USER_PRESENT: Check if the user is present from HPD sensor 31 + * @SFH_USER_AWAY: Check if the user is away from HPD sensor 32 + */ 33 + enum sfh_hpd_info { 34 + SFH_NOT_DETECTED, 35 + SFH_USER_PRESENT, 36 + SFH_USER_AWAY, 37 + }; 38 + 39 + /** 40 + * struct amd_sfh_info - get HPD sensor info from MP2 FW 41 + * @ambient_light: Populates the ambient light information 42 + * @user_present: Populates the user presence information 43 + */ 44 + struct amd_sfh_info { 45 + u32 ambient_light; 46 + u8 user_present; 47 + }; 48 + 49 + int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op); 50 + #endif
+1 -1
include/linux/hid.h
··· 912 912 extern int hid_add_device(struct hid_device *); 913 913 extern void hid_destroy_device(struct hid_device *); 914 914 915 - extern struct bus_type hid_bus_type; 915 + extern const struct bus_type hid_bus_type; 916 916 917 917 extern int __must_check __hid_register_driver(struct hid_driver *, 918 918 struct module *, const char *mod_name);
+1 -1
include/linux/hid_bpf.h
··· 115 115 size_t len, enum hid_report_type rtype, 116 116 enum hid_class_request reqtype); 117 117 struct module *owner; 118 - struct bus_type *bus_type; 118 + const struct bus_type *bus_type; 119 119 }; 120 120 121 121 extern struct hid_bpf_ops *hid_bpf_ops;
+3
include/linux/intel-ish-client-if.h
··· 94 94 void ishtp_cl_unlink(struct ishtp_cl *cl); 95 95 int ishtp_cl_disconnect(struct ishtp_cl *cl); 96 96 int ishtp_cl_connect(struct ishtp_cl *cl); 97 + int ishtp_cl_establish_connection(struct ishtp_cl *cl, const guid_t *uuid, 98 + int tx_size, int rx_size, bool reset); 99 + void ishtp_cl_destroy_connection(struct ishtp_cl *cl, bool reset); 97 100 int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length); 98 101 int ishtp_cl_flush_queues(struct ishtp_cl *cl); 99 102 int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb);
+3 -4
tools/testing/selftests/hid/tests/base.py
··· 14 14 15 15 from hidtools.device.base_device import BaseDevice, EvdevMatch, SysfsFile 16 16 from pathlib import Path 17 - from typing import Final 17 + from typing import Final, List, Tuple 18 18 19 19 logger = logging.getLogger("hidtools.test.base") 20 20 ··· 155 155 # if any module is not available (not compiled), the test will skip. 156 156 # Each element is a tuple '(kernel driver name, kernel module)', 157 157 # for example ("playstation", "hid-playstation") 158 - kernel_modules = [] 158 + kernel_modules: List[Tuple[str, str]] = [] 159 159 160 160 def assertInputEventsIn(self, expected_events, effective_events): 161 161 effective_events = effective_events.copy() ··· 238 238 try: 239 239 with HIDTestUdevRule.instance(): 240 240 with new_uhdev as self.uhdev: 241 - skip_cond = request.node.get_closest_marker("skip_if_uhdev") 242 - if skip_cond: 241 + for skip_cond in request.node.iter_markers("skip_if_uhdev"): 243 242 test, message, *rest = skip_cond.args 244 243 245 244 if test(self.uhdev):
+7 -7
tools/testing/selftests/hid/tests/test_mouse.py
··· 52 52 :param reportID: the numeric report ID for this report, if needed 53 53 """ 54 54 if buttons is not None: 55 - l, r, m = buttons 56 - if l is not None: 57 - self.left = l 58 - if r is not None: 59 - self.right = r 60 - if m is not None: 61 - self.middle = m 55 + left, right, middle = buttons 56 + if left is not None: 57 + self.left = left 58 + if right is not None: 59 + self.right = right 60 + if middle is not None: 61 + self.middle = middle 62 62 left = self.left 63 63 right = self.right 64 64 middle = self.middle
+534 -242
tools/testing/selftests/hid/tests/test_tablet.py
··· 13 13 import libevdev 14 14 import logging 15 15 import pytest 16 - from typing import Dict, Tuple 16 + from typing import Dict, List, Optional, Tuple 17 17 18 18 logger = logging.getLogger("hidtools.test.tablet") 19 + 20 + 21 + class BtnTouch(Enum): 22 + """Represents whether the BTN_TOUCH event is set to True or False""" 23 + 24 + DOWN = True 25 + UP = False 26 + 27 + 28 + class ToolType(Enum): 29 + PEN = libevdev.EV_KEY.BTN_TOOL_PEN 30 + RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER 31 + 32 + 33 + class BtnPressed(Enum): 34 + """Represents whether a button is pressed on the stylus""" 35 + 36 + PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS 37 + SECONDARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS2 19 38 20 39 21 40 class PenState(Enum): 22 41 """Pen states according to Microsoft reference: 23 42 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 43 + 44 + We extend it with the various buttons when we need to check them. 24 45 """ 25 46 26 - PEN_IS_OUT_OF_RANGE = (False, None) 27 - PEN_IS_IN_RANGE = (False, libevdev.EV_KEY.BTN_TOOL_PEN) 28 - PEN_IS_IN_CONTACT = (True, libevdev.EV_KEY.BTN_TOOL_PEN) 29 - PEN_IS_IN_RANGE_WITH_ERASING_INTENT = (False, libevdev.EV_KEY.BTN_TOOL_RUBBER) 30 - PEN_IS_ERASING = (True, libevdev.EV_KEY.BTN_TOOL_RUBBER) 47 + PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, None 48 + PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, None 49 + PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, BtnPressed.PRIMARY_PRESSED 50 + PEN_IS_IN_RANGE_WITH_SECOND_BUTTON = ( 51 + BtnTouch.UP, 52 + ToolType.PEN, 53 + BtnPressed.SECONDARY_PRESSED, 54 + ) 55 + PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, None 56 + PEN_IS_IN_CONTACT_WITH_BUTTON = ( 57 + BtnTouch.DOWN, 58 + ToolType.PEN, 59 + BtnPressed.PRIMARY_PRESSED, 60 + ) 61 + PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON = ( 62 + BtnTouch.DOWN, 63 + ToolType.PEN, 64 + BtnPressed.SECONDARY_PRESSED, 65 + ) 66 + PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, None 67 + PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = ( 68 + BtnTouch.UP, 69 + ToolType.RUBBER, 70 + BtnPressed.PRIMARY_PRESSED, 71 + ) 72 + PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_SECOND_BUTTON = ( 73 + BtnTouch.UP, 74 + ToolType.RUBBER, 75 + BtnPressed.SECONDARY_PRESSED, 76 + ) 77 + PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, None 78 + PEN_IS_ERASING_WITH_BUTTON = ( 79 + BtnTouch.DOWN, 80 + ToolType.RUBBER, 81 + BtnPressed.PRIMARY_PRESSED, 82 + ) 83 + PEN_IS_ERASING_WITH_SECOND_BUTTON = ( 84 + BtnTouch.DOWN, 85 + ToolType.RUBBER, 86 + BtnPressed.SECONDARY_PRESSED, 87 + ) 31 88 32 - def __init__(self, touch, tool): 33 - self.touch = touch 34 - self.tool = tool 89 + def __init__(self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[BtnPressed]): 90 + self.touch = touch # type: ignore 91 + self.tool = tool # type: ignore 92 + self.button = button # type: ignore 35 93 36 94 @classmethod 37 95 def from_evdev(cls, evdev) -> "PenState": 38 - touch = bool(evdev.value[libevdev.EV_KEY.BTN_TOUCH]) 96 + touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH]) 39 97 tool = None 98 + button = None 40 99 if ( 41 100 evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] 42 101 and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] 43 102 ): 44 - tool = libevdev.EV_KEY.BTN_TOOL_RUBBER 103 + tool = ToolType(libevdev.EV_KEY.BTN_TOOL_RUBBER) 45 104 elif ( 46 105 evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] 47 106 and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] 48 107 ): 49 - tool = libevdev.EV_KEY.BTN_TOOL_PEN 108 + tool = ToolType(libevdev.EV_KEY.BTN_TOOL_PEN) 50 109 elif ( 51 110 evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] 52 111 or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] 53 112 ): 54 113 raise ValueError("2 tools are not allowed") 55 114 56 - return cls((touch, tool)) 115 + # we take only the highest button in account 116 + for b in [libevdev.EV_KEY.BTN_STYLUS, libevdev.EV_KEY.BTN_STYLUS2]: 117 + if bool(evdev.value[b]): 118 + button = BtnPressed(b) 57 119 58 - def apply(self, events) -> "PenState": 120 + # the kernel tends to insert an EV_SYN once removing the tool, so 121 + # the button will be released after 122 + if tool is None: 123 + button = None 124 + 125 + return cls((touch, tool, button)) # type: ignore 126 + 127 + def apply(self, events: List[libevdev.InputEvent], strict: bool) -> "PenState": 59 128 if libevdev.EV_SYN.SYN_REPORT in events: 60 129 raise ValueError("EV_SYN is in the event sequence") 61 130 touch = self.touch 62 131 touch_found = False 63 132 tool = self.tool 64 133 tool_found = False 134 + button = self.button 135 + button_found = False 65 136 66 137 for ev in events: 67 138 if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH): 68 139 if touch_found: 69 140 raise ValueError(f"duplicated BTN_TOUCH in {events}") 70 141 touch_found = True 71 - touch = bool(ev.value) 142 + touch = BtnTouch(ev.value) 72 143 elif ev in ( 73 144 libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN), 74 145 libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER), ··· 147 76 if tool_found: 148 77 raise ValueError(f"duplicated BTN_TOOL_* in {events}") 149 78 tool_found = True 150 - if ev.value: 151 - tool = ev.code 152 - else: 153 - tool = None 79 + tool = ToolType(ev.code) if ev.value else None 80 + elif ev in ( 81 + libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS), 82 + libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS2), 83 + ): 84 + if button_found: 85 + raise ValueError(f"duplicated BTN_STYLUS* in {events}") 86 + button_found = True 87 + button = BtnPressed(ev.code) if ev.value else None 154 88 155 - new_state = PenState((touch, tool)) 156 - assert ( 157 - new_state in self.valid_transitions() 158 - ), f"moving from {self} to {new_state} is forbidden" 89 + # the kernel tends to insert an EV_SYN once removing the tool, so 90 + # the button will be released after 91 + if tool is None: 92 + button = None 93 + 94 + new_state = PenState((touch, tool, button)) # type: ignore 95 + if strict: 96 + assert ( 97 + new_state in self.valid_transitions() 98 + ), f"moving from {self} to {new_state} is forbidden" 99 + else: 100 + assert ( 101 + new_state in self.historically_tolerated_transitions() 102 + ), f"moving from {self} to {new_state} is forbidden" 159 103 160 104 return new_state 161 105 162 106 def valid_transitions(self) -> Tuple["PenState", ...]: 107 + """Following the state machine in the URL above. 108 + 109 + Note that those transitions are from the evdev point of view, not HID""" 110 + if self == PenState.PEN_IS_OUT_OF_RANGE: 111 + return ( 112 + PenState.PEN_IS_OUT_OF_RANGE, 113 + PenState.PEN_IS_IN_RANGE, 114 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 115 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 116 + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 117 + PenState.PEN_IS_IN_CONTACT, 118 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 119 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 120 + PenState.PEN_IS_ERASING, 121 + ) 122 + 123 + if self == PenState.PEN_IS_IN_RANGE: 124 + return ( 125 + PenState.PEN_IS_IN_RANGE, 126 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 127 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 128 + PenState.PEN_IS_OUT_OF_RANGE, 129 + PenState.PEN_IS_IN_CONTACT, 130 + ) 131 + 132 + if self == PenState.PEN_IS_IN_CONTACT: 133 + return ( 134 + PenState.PEN_IS_IN_CONTACT, 135 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 136 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 137 + PenState.PEN_IS_IN_RANGE, 138 + ) 139 + 140 + if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: 141 + return ( 142 + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 143 + PenState.PEN_IS_OUT_OF_RANGE, 144 + PenState.PEN_IS_ERASING, 145 + ) 146 + 147 + if self == PenState.PEN_IS_ERASING: 148 + return ( 149 + PenState.PEN_IS_ERASING, 150 + PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 151 + ) 152 + 153 + if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: 154 + return ( 155 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 156 + PenState.PEN_IS_IN_RANGE, 157 + PenState.PEN_IS_OUT_OF_RANGE, 158 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 159 + ) 160 + 161 + if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: 162 + return ( 163 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 164 + PenState.PEN_IS_IN_CONTACT, 165 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 166 + ) 167 + 168 + if self == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: 169 + return ( 170 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 171 + PenState.PEN_IS_IN_RANGE, 172 + PenState.PEN_IS_OUT_OF_RANGE, 173 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 174 + ) 175 + 176 + if self == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: 177 + return ( 178 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 179 + PenState.PEN_IS_IN_CONTACT, 180 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 181 + ) 182 + 183 + return tuple() 184 + 185 + def historically_tolerated_transitions(self) -> Tuple["PenState", ...]: 163 186 """Following the state machine in the URL above, with a couple of addition 164 187 for skipping the in-range state, due to historical reasons. 165 188 ··· 262 97 return ( 263 98 PenState.PEN_IS_OUT_OF_RANGE, 264 99 PenState.PEN_IS_IN_RANGE, 100 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 101 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 265 102 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 266 103 PenState.PEN_IS_IN_CONTACT, 104 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 105 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 267 106 PenState.PEN_IS_ERASING, 268 107 ) 269 108 270 109 if self == PenState.PEN_IS_IN_RANGE: 271 110 return ( 272 111 PenState.PEN_IS_IN_RANGE, 112 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 113 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 273 114 PenState.PEN_IS_OUT_OF_RANGE, 274 115 PenState.PEN_IS_IN_CONTACT, 275 116 ) ··· 283 112 if self == PenState.PEN_IS_IN_CONTACT: 284 113 return ( 285 114 PenState.PEN_IS_IN_CONTACT, 115 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 116 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 286 117 PenState.PEN_IS_IN_RANGE, 287 118 PenState.PEN_IS_OUT_OF_RANGE, 288 119 ) ··· 303 130 PenState.PEN_IS_OUT_OF_RANGE, 304 131 ) 305 132 133 + if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: 134 + return ( 135 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 136 + PenState.PEN_IS_IN_RANGE, 137 + PenState.PEN_IS_OUT_OF_RANGE, 138 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 139 + ) 140 + 141 + if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: 142 + return ( 143 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 144 + PenState.PEN_IS_IN_CONTACT, 145 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 146 + PenState.PEN_IS_OUT_OF_RANGE, 147 + ) 148 + 149 + if self == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: 150 + return ( 151 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 152 + PenState.PEN_IS_IN_RANGE, 153 + PenState.PEN_IS_OUT_OF_RANGE, 154 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 155 + ) 156 + 157 + if self == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: 158 + return ( 159 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 160 + PenState.PEN_IS_IN_CONTACT, 161 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 162 + PenState.PEN_IS_OUT_OF_RANGE, 163 + ) 164 + 306 165 return tuple() 307 166 308 - 309 - class Data(object): 310 - pass 311 - 312 - 313 - class Pen(object): 314 - def __init__(self, x, y): 315 - self.x = x 316 - self.y = y 317 - self.tipswitch = False 318 - self.tippressure = 15 319 - self.azimuth = 0 320 - self.inrange = False 321 - self.width = 10 322 - self.height = 10 323 - self.barrelswitch = False 324 - self.invert = False 325 - self.eraser = False 326 - self.x_tilt = 0 327 - self.y_tilt = 0 328 - self.twist = 0 329 - self._old_values = None 330 - self.current_state = None 331 - 332 - def _restore(self): 333 - if self._old_values is not None: 334 - for i in [ 335 - "x", 336 - "y", 337 - "tippressure", 338 - "azimuth", 339 - "width", 340 - "height", 341 - "twist", 342 - "x_tilt", 343 - "y_tilt", 344 - ]: 345 - setattr(self, i, getattr(self._old_values, i)) 346 - 347 - def move_to(self, state): 348 - # fill in the previous values 349 - if self.current_state == PenState.PEN_IS_OUT_OF_RANGE: 350 - self._restore() 351 - 352 - print(f"\n *** pen is moving to {state} ***") 353 - 354 - if state == PenState.PEN_IS_OUT_OF_RANGE: 355 - self._old_values = copy.copy(self) 356 - self.x = 0 357 - self.y = 0 358 - self.tipswitch = False 359 - self.tippressure = 0 360 - self.azimuth = 0 361 - self.inrange = False 362 - self.width = 0 363 - self.height = 0 364 - self.invert = False 365 - self.eraser = False 366 - self.x_tilt = 0 367 - self.y_tilt = 0 368 - self.twist = 0 369 - elif state == PenState.PEN_IS_IN_RANGE: 370 - self.tipswitch = False 371 - self.inrange = True 372 - self.invert = False 373 - self.eraser = False 374 - elif state == PenState.PEN_IS_IN_CONTACT: 375 - self.tipswitch = True 376 - self.inrange = True 377 - self.invert = False 378 - self.eraser = False 379 - elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: 380 - self.tipswitch = False 381 - self.inrange = True 382 - self.invert = True 383 - self.eraser = False 384 - elif state == PenState.PEN_IS_ERASING: 385 - self.tipswitch = False 386 - self.inrange = True 387 - self.invert = True 388 - self.eraser = True 389 - 390 - self.current_state = state 391 - 392 - def __assert_axis(self, evdev, axis, value): 393 - if ( 394 - axis == libevdev.EV_KEY.BTN_TOOL_RUBBER 395 - and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None 396 - ): 397 - return 398 - 399 - assert ( 400 - evdev.value[axis] == value 401 - ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}" 402 - 403 - def assert_expected_input_events(self, evdev): 404 - assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x 405 - assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y 406 - assert self.current_state == PenState.from_evdev(evdev) 407 - 408 167 @staticmethod 409 - def legal_transitions() -> Dict[str, Tuple[PenState, ...]]: 168 + def legal_transitions() -> Dict[str, Tuple["PenState", ...]]: 410 169 """This is the first half of the Windows Pen Implementation state machine: 411 170 we don't have Invert nor Erase bits, so just move in/out-of-range or proximity. 412 171 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states ··· 364 259 } 365 260 366 261 @staticmethod 367 - def legal_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]: 262 + def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]: 368 263 """This is the second half of the Windows Pen Implementation state machine: 369 264 we now have Invert and Erase bits, so move in/out or proximity with the intend 370 265 to erase. ··· 402 297 } 403 298 404 299 @staticmethod 405 - def tolerated_transitions() -> Dict[str, Tuple[PenState, ...]]: 300 + def legal_transitions_with_primary_button() -> Dict[str, Tuple["PenState", ...]]: 301 + """We revisit the Windows Pen Implementation state machine: 302 + we now have a primary button. 303 + """ 304 + return { 305 + "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,), 306 + "hover-button -> out-of-range": ( 307 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 308 + PenState.PEN_IS_OUT_OF_RANGE, 309 + ), 310 + "in-range -> button-press": ( 311 + PenState.PEN_IS_IN_RANGE, 312 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 313 + ), 314 + "in-range -> button-press -> button-release": ( 315 + PenState.PEN_IS_IN_RANGE, 316 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 317 + PenState.PEN_IS_IN_RANGE, 318 + ), 319 + "in-range -> touch -> button-press -> button-release": ( 320 + PenState.PEN_IS_IN_RANGE, 321 + PenState.PEN_IS_IN_CONTACT, 322 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 323 + PenState.PEN_IS_IN_CONTACT, 324 + ), 325 + "in-range -> touch -> button-press -> release -> button-release": ( 326 + PenState.PEN_IS_IN_RANGE, 327 + PenState.PEN_IS_IN_CONTACT, 328 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 329 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 330 + PenState.PEN_IS_IN_RANGE, 331 + ), 332 + "in-range -> button-press -> touch -> release -> button-release": ( 333 + PenState.PEN_IS_IN_RANGE, 334 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 335 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 336 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 337 + PenState.PEN_IS_IN_RANGE, 338 + ), 339 + "in-range -> button-press -> touch -> button-release -> release": ( 340 + PenState.PEN_IS_IN_RANGE, 341 + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 342 + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 343 + PenState.PEN_IS_IN_CONTACT, 344 + PenState.PEN_IS_IN_RANGE, 345 + ), 346 + } 347 + 348 + @staticmethod 349 + def legal_transitions_with_secondary_button() -> Dict[str, Tuple["PenState", ...]]: 350 + """We revisit the Windows Pen Implementation state machine: 351 + we now have a secondary button. 352 + Note: we don't looks for 2 buttons interactions. 353 + """ 354 + return { 355 + "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,), 356 + "hover-button -> out-of-range": ( 357 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 358 + PenState.PEN_IS_OUT_OF_RANGE, 359 + ), 360 + "in-range -> button-press": ( 361 + PenState.PEN_IS_IN_RANGE, 362 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 363 + ), 364 + "in-range -> button-press -> button-release": ( 365 + PenState.PEN_IS_IN_RANGE, 366 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 367 + PenState.PEN_IS_IN_RANGE, 368 + ), 369 + "in-range -> touch -> button-press -> button-release": ( 370 + PenState.PEN_IS_IN_RANGE, 371 + PenState.PEN_IS_IN_CONTACT, 372 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 373 + PenState.PEN_IS_IN_CONTACT, 374 + ), 375 + "in-range -> touch -> button-press -> release -> button-release": ( 376 + PenState.PEN_IS_IN_RANGE, 377 + PenState.PEN_IS_IN_CONTACT, 378 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 379 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 380 + PenState.PEN_IS_IN_RANGE, 381 + ), 382 + "in-range -> button-press -> touch -> release -> button-release": ( 383 + PenState.PEN_IS_IN_RANGE, 384 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 385 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 386 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 387 + PenState.PEN_IS_IN_RANGE, 388 + ), 389 + "in-range -> button-press -> touch -> button-release -> release": ( 390 + PenState.PEN_IS_IN_RANGE, 391 + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 392 + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 393 + PenState.PEN_IS_IN_CONTACT, 394 + PenState.PEN_IS_IN_RANGE, 395 + ), 396 + } 397 + 398 + @staticmethod 399 + def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]: 406 400 """This is not adhering to the Windows Pen Implementation state machine 407 401 but we should expect the kernel to behave properly, mostly for historical 408 402 reasons.""" ··· 514 310 } 515 311 516 312 @staticmethod 517 - def tolerated_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]: 313 + def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]: 518 314 """This is the second half of the Windows Pen Implementation state machine: 519 315 we now have Invert and Erase bits, so move in/out or proximity with the intend 520 316 to erase. ··· 529 325 } 530 326 531 327 @staticmethod 532 - def broken_transitions() -> Dict[str, Tuple[PenState, ...]]: 328 + def broken_transitions() -> Dict[str, Tuple["PenState", ...]]: 533 329 """Those tests are definitely not part of the Windows specification. 534 330 However, a half broken device might export those transitions. 535 331 For example, a pen that has the eraser button might wobble between ··· 567 363 } 568 364 569 365 366 + class Pen(object): 367 + def __init__(self, x, y): 368 + self.x = x 369 + self.y = y 370 + self.tipswitch = False 371 + self.tippressure = 15 372 + self.azimuth = 0 373 + self.inrange = False 374 + self.width = 10 375 + self.height = 10 376 + self.barrelswitch = False 377 + self.secondarybarrelswitch = False 378 + self.invert = False 379 + self.eraser = False 380 + self.xtilt = 1 381 + self.ytilt = 1 382 + self.twist = 1 383 + self._old_values = None 384 + self.current_state = None 385 + 386 + def restore(self): 387 + if self._old_values is not None: 388 + for i in [ 389 + "x", 390 + "y", 391 + "tippressure", 392 + "azimuth", 393 + "width", 394 + "height", 395 + "twist", 396 + "xtilt", 397 + "ytilt", 398 + ]: 399 + setattr(self, i, getattr(self._old_values, i)) 400 + 401 + def backup(self): 402 + self._old_values = copy.copy(self) 403 + 404 + def __assert_axis(self, evdev, axis, value): 405 + if ( 406 + axis == libevdev.EV_KEY.BTN_TOOL_RUBBER 407 + and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None 408 + ): 409 + return 410 + 411 + assert ( 412 + evdev.value[axis] == value 413 + ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}" 414 + 415 + def assert_expected_input_events(self, evdev): 416 + assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x 417 + assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y 418 + assert self.current_state == PenState.from_evdev(evdev) 419 + 420 + 570 421 class PenDigitizer(base.UHIDTestDevice): 571 422 def __init__( 572 423 self, ··· 646 387 if self.physical not in physicals and None not in physicals: 647 388 continue 648 389 self.fields = [f.usage_name for f in r] 390 + 391 + def move_to(self, pen, state): 392 + # fill in the previous values 393 + if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE: 394 + pen.restore() 395 + 396 + print(f"\n *** pen is moving to {state} ***") 397 + 398 + if state == PenState.PEN_IS_OUT_OF_RANGE: 399 + pen.backup() 400 + pen.x = 0 401 + pen.y = 0 402 + pen.tipswitch = False 403 + pen.tippressure = 0 404 + pen.azimuth = 0 405 + pen.inrange = False 406 + pen.width = 0 407 + pen.height = 0 408 + pen.invert = False 409 + pen.eraser = False 410 + pen.xtilt = 0 411 + pen.ytilt = 0 412 + pen.twist = 0 413 + pen.barrelswitch = False 414 + pen.secondarybarrelswitch = False 415 + elif state == PenState.PEN_IS_IN_RANGE: 416 + pen.tipswitch = False 417 + pen.inrange = True 418 + pen.invert = False 419 + pen.eraser = False 420 + pen.barrelswitch = False 421 + pen.secondarybarrelswitch = False 422 + elif state == PenState.PEN_IS_IN_CONTACT: 423 + pen.tipswitch = True 424 + pen.inrange = True 425 + pen.invert = False 426 + pen.eraser = False 427 + pen.barrelswitch = False 428 + pen.secondarybarrelswitch = False 429 + elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: 430 + pen.tipswitch = False 431 + pen.inrange = True 432 + pen.invert = False 433 + pen.eraser = False 434 + pen.barrelswitch = True 435 + pen.secondarybarrelswitch = False 436 + elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: 437 + pen.tipswitch = True 438 + pen.inrange = True 439 + pen.invert = False 440 + pen.eraser = False 441 + pen.barrelswitch = True 442 + pen.secondarybarrelswitch = False 443 + elif state == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: 444 + pen.tipswitch = False 445 + pen.inrange = True 446 + pen.invert = False 447 + pen.eraser = False 448 + pen.barrelswitch = False 449 + pen.secondarybarrelswitch = True 450 + elif state == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: 451 + pen.tipswitch = True 452 + pen.inrange = True 453 + pen.invert = False 454 + pen.eraser = False 455 + pen.barrelswitch = False 456 + pen.secondarybarrelswitch = True 457 + elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: 458 + pen.tipswitch = False 459 + pen.inrange = True 460 + pen.invert = True 461 + pen.eraser = False 462 + pen.barrelswitch = False 463 + pen.secondarybarrelswitch = False 464 + elif state == PenState.PEN_IS_ERASING: 465 + pen.tipswitch = False 466 + pen.inrange = True 467 + pen.invert = False 468 + pen.eraser = True 469 + pen.barrelswitch = False 470 + pen.secondarybarrelswitch = False 471 + 472 + pen.current_state = state 649 473 650 474 def event(self, pen): 651 475 rs = [] ··· 777 435 self.debug_reports(r, uhdev, events) 778 436 return events 779 437 780 - def validate_transitions(self, from_state, pen, evdev, events): 438 + def validate_transitions( 439 + self, from_state, pen, evdev, events, allow_intermediate_states 440 + ): 781 441 # check that the final state is correct 782 442 pen.assert_expected_input_events(evdev) 443 + 444 + state = from_state 783 445 784 446 # check that the transitions are valid 785 447 sync_events = [] ··· 794 448 events = events[idx + 1 :] 795 449 796 450 # now check for a valid transition 797 - from_state = from_state.apply(sync_events) 451 + state = state.apply(sync_events, not allow_intermediate_states) 798 452 799 453 if events: 800 - from_state = from_state.apply(sync_events) 454 + state = state.apply(sync_events, not allow_intermediate_states) 801 455 802 - def _test_states(self, state_list, scribble): 456 + def _test_states(self, state_list, scribble, allow_intermediate_states): 803 457 """Internal method to test against a list of 804 458 transition between states. 805 459 state_list is a list of PenState objects ··· 812 466 cur_state = PenState.PEN_IS_OUT_OF_RANGE 813 467 814 468 p = Pen(50, 60) 815 - p.move_to(PenState.PEN_IS_OUT_OF_RANGE) 469 + uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE) 816 470 events = self.post(uhdev, p) 817 - self.validate_transitions(cur_state, p, evdev, events) 471 + self.validate_transitions( 472 + cur_state, p, evdev, events, allow_intermediate_states 473 + ) 818 474 819 475 cur_state = p.current_state 820 476 ··· 825 477 p.x += 1 826 478 p.y -= 1 827 479 events = self.post(uhdev, p) 828 - self.validate_transitions(cur_state, p, evdev, events) 480 + self.validate_transitions( 481 + cur_state, p, evdev, events, allow_intermediate_states 482 + ) 829 483 assert len(events) >= 3 # X, Y, SYN 830 - p.move_to(state) 484 + uhdev.move_to(p, state) 831 485 if scribble and state != PenState.PEN_IS_OUT_OF_RANGE: 832 486 p.x += 1 833 487 p.y -= 1 834 488 events = self.post(uhdev, p) 835 - self.validate_transitions(cur_state, p, evdev, events) 489 + self.validate_transitions( 490 + cur_state, p, evdev, events, allow_intermediate_states 491 + ) 836 492 cur_state = p.current_state 837 493 838 494 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 839 495 @pytest.mark.parametrize( 840 496 "state_list", 841 - [pytest.param(v, id=k) for k, v in Pen.legal_transitions().items()], 497 + [pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()], 842 498 ) 843 499 def test_valid_pen_states(self, state_list, scribble): 844 500 """This is the first half of the Windows Pen Implementation state machine: 845 501 we don't have Invert nor Erase bits, so just move in/out-of-range or proximity. 846 502 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 847 503 """ 848 - self._test_states(state_list, scribble) 504 + self._test_states(state_list, scribble, allow_intermediate_states=False) 849 505 850 506 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 851 507 @pytest.mark.parametrize( 852 508 "state_list", 853 - [pytest.param(v, id=k) for k, v in Pen.tolerated_transitions().items()], 509 + [ 510 + pytest.param(v, id=k) 511 + for k, v in PenState.tolerated_transitions().items() 512 + ], 854 513 ) 855 514 def test_tolerated_pen_states(self, state_list, scribble): 856 515 """This is not adhering to the Windows Pen Implementation state machine 857 516 but we should expect the kernel to behave properly, mostly for historical 858 517 reasons.""" 859 - self._test_states(state_list, scribble) 518 + self._test_states(state_list, scribble, allow_intermediate_states=True) 519 + 520 + @pytest.mark.skip_if_uhdev( 521 + lambda uhdev: "Barrel Switch" not in uhdev.fields, 522 + "Device not compatible, missing Barrel Switch usage", 523 + ) 524 + @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 525 + @pytest.mark.parametrize( 526 + "state_list", 527 + [ 528 + pytest.param(v, id=k) 529 + for k, v in PenState.legal_transitions_with_primary_button().items() 530 + ], 531 + ) 532 + def test_valid_primary_button_pen_states(self, state_list, scribble): 533 + """Rework the transition state machine by adding the primary button.""" 534 + self._test_states(state_list, scribble, allow_intermediate_states=False) 535 + 536 + @pytest.mark.skip_if_uhdev( 537 + lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields, 538 + "Device not compatible, missing Secondary Barrel Switch usage", 539 + ) 540 + @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 541 + @pytest.mark.parametrize( 542 + "state_list", 543 + [ 544 + pytest.param(v, id=k) 545 + for k, v in PenState.legal_transitions_with_secondary_button().items() 546 + ], 547 + ) 548 + def test_valid_secondary_button_pen_states(self, state_list, scribble): 549 + """Rework the transition state machine by adding the secondary button.""" 550 + self._test_states(state_list, scribble, allow_intermediate_states=False) 860 551 861 552 @pytest.mark.skip_if_uhdev( 862 553 lambda uhdev: "Invert" not in uhdev.fields, ··· 906 519 "state_list", 907 520 [ 908 521 pytest.param(v, id=k) 909 - for k, v in Pen.legal_transitions_with_invert().items() 522 + for k, v in PenState.legal_transitions_with_invert().items() 910 523 ], 911 524 ) 912 525 def test_valid_invert_pen_states(self, state_list, scribble): ··· 915 528 to erase. 916 529 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 917 530 """ 918 - self._test_states(state_list, scribble) 531 + self._test_states(state_list, scribble, allow_intermediate_states=False) 919 532 920 533 @pytest.mark.skip_if_uhdev( 921 534 lambda uhdev: "Invert" not in uhdev.fields, ··· 926 539 "state_list", 927 540 [ 928 541 pytest.param(v, id=k) 929 - for k, v in Pen.tolerated_transitions_with_invert().items() 542 + for k, v in PenState.tolerated_transitions_with_invert().items() 930 543 ], 931 544 ) 932 545 def test_tolerated_invert_pen_states(self, state_list, scribble): ··· 935 548 to erase. 936 549 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 937 550 """ 938 - self._test_states(state_list, scribble) 551 + self._test_states(state_list, scribble, allow_intermediate_states=True) 939 552 940 553 @pytest.mark.skip_if_uhdev( 941 554 lambda uhdev: "Invert" not in uhdev.fields, ··· 944 557 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 945 558 @pytest.mark.parametrize( 946 559 "state_list", 947 - [pytest.param(v, id=k) for k, v in Pen.broken_transitions().items()], 560 + [pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()], 948 561 ) 949 562 def test_tolerated_broken_pen_states(self, state_list, scribble): 950 563 """Those tests are definitely not part of the Windows specification. ··· 952 565 For example, a pen that has the eraser button might wobble between 953 566 touching and erasing if the tablet doesn't enforce the Windows 954 567 state machine.""" 955 - self._test_states(state_list, scribble) 956 - 957 - @pytest.mark.skip_if_uhdev( 958 - lambda uhdev: "Barrel Switch" not in uhdev.fields, 959 - "Device not compatible, missing Barrel Switch usage", 960 - ) 961 - def test_primary_button(self): 962 - """Primary button (stylus) pressed, reports as pressed even while hovering. 963 - Actual reporting from the device: hid=TIPSWITCH,BARRELSWITCH,INRANGE (code=TOUCH,STYLUS,PEN): 964 - { 0, 0, 1 } <- hover 965 - { 0, 1, 1 } <- primary button pressed 966 - { 0, 1, 1 } <- liftoff 967 - { 0, 0, 0 } <- leaves 968 - """ 969 - 970 - uhdev = self.uhdev 971 - evdev = uhdev.get_evdev() 972 - 973 - p = Pen(50, 60) 974 - p.inrange = True 975 - events = self.post(uhdev, p) 976 - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1) in events 977 - assert evdev.value[libevdev.EV_ABS.ABS_X] == 50 978 - assert evdev.value[libevdev.EV_ABS.ABS_Y] == 60 979 - assert not evdev.value[libevdev.EV_KEY.BTN_STYLUS] 980 - 981 - p.barrelswitch = True 982 - events = self.post(uhdev, p) 983 - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 1) in events 984 - 985 - p.x += 1 986 - p.y -= 1 987 - events = self.post(uhdev, p) 988 - assert len(events) == 3 # X, Y, SYN 989 - assert libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 51) in events 990 - assert libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 59) in events 991 - 992 - p.barrelswitch = False 993 - events = self.post(uhdev, p) 994 - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 0) in events 995 - 996 - p.inrange = False 997 - events = self.post(uhdev, p) 998 - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 0) in events 999 - 1000 - @pytest.mark.skip_if_uhdev( 1001 - lambda uhdev: "Barrel Switch" not in uhdev.fields, 1002 - "Device not compatible, missing Barrel Switch usage", 1003 - ) 1004 - def test_contact_primary_button(self): 1005 - """Primary button (stylus) pressed, reports as pressed even while hovering. 1006 - Actual reporting from the device: hid=TIPSWITCH,BARRELSWITCH,INRANGE (code=TOUCH,STYLUS,PEN): 1007 - { 0, 0, 1 } <- hover 1008 - { 0, 1, 1 } <- primary button pressed 1009 - { 1, 1, 1 } <- touch-down 1010 - { 1, 1, 1 } <- still touch, scribble on the screen 1011 - { 0, 1, 1 } <- liftoff 1012 - { 0, 0, 0 } <- leaves 1013 - """ 1014 - 1015 - uhdev = self.uhdev 1016 - evdev = uhdev.get_evdev() 1017 - 1018 - p = Pen(50, 60) 1019 - p.inrange = True 1020 - events = self.post(uhdev, p) 1021 - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1) in events 1022 - assert evdev.value[libevdev.EV_ABS.ABS_X] == 50 1023 - assert evdev.value[libevdev.EV_ABS.ABS_Y] == 60 1024 - assert not evdev.value[libevdev.EV_KEY.BTN_STYLUS] 1025 - 1026 - p.barrelswitch = True 1027 - events = self.post(uhdev, p) 1028 - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 1) in events 1029 - 1030 - p.tipswitch = True 1031 - events = self.post(uhdev, p) 1032 - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events 1033 - assert evdev.value[libevdev.EV_KEY.BTN_STYLUS] 1034 - 1035 - p.x += 1 1036 - p.y -= 1 1037 - events = self.post(uhdev, p) 1038 - assert len(events) == 3 # X, Y, SYN 1039 - assert libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 51) in events 1040 - assert libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 59) in events 1041 - 1042 - p.tipswitch = False 1043 - events = self.post(uhdev, p) 1044 - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events 1045 - 1046 - p.barrelswitch = False 1047 - p.inrange = False 1048 - events = self.post(uhdev, p) 1049 - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 0) in events 1050 - assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 0) in events 568 + self._test_states(state_list, scribble, allow_intermediate_states=True) 1051 569 1052 570 1053 571 class GXTP_pen(PenDigitizer):
+278 -2
tools/testing/selftests/hid/tests/test_wacom_generic.py
··· 27 27 ) 28 28 29 29 import attr 30 + from collections import namedtuple 30 31 from enum import Enum 31 32 from hidtools.hut import HUT 32 33 from hidtools.hid import HidUnit ··· 863 862 864 863 865 864 class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest): 865 + ContactIds = namedtuple("ContactIds", "contact_id, tracking_id, slot_num") 866 + 866 867 def create_device(self): 867 868 return test_multitouch.Digitizer( 868 869 "DTH 2452", 869 870 rdesc="05 0d 09 04 a1 01 85 0c 95 01 75 08 15 00 26 ff 00 81 03 09 54 81 02 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 27 ff ff 00 00 75 10 95 01 09 56 81 02 75 08 95 0e 81 03 09 55 26 ff 00 75 08 b1 02 85 0a 06 00 ff 09 c5 96 00 01 b1 02 c0 06 00 ff 09 01 a1 01 09 01 85 13 15 00 26 ff 00 75 08 95 3f 81 02 06 00 ff 09 01 15 00 26 ff 00 75 08 95 3f 91 02 c0", 870 871 input_info=(0x3, 0x056A, 0x0383), 871 872 ) 873 + 874 + def make_contact(self, contact_id=0, t=0): 875 + """ 876 + Make a single touch contact that can move over time. 877 + 878 + Creates a touch object that has a well-known position in space that 879 + does not overlap with other contacts. The value of `t` may be 880 + incremented over time to move the point along a linear path. 881 + """ 882 + x = 50 + 10 * contact_id + t 883 + y = 100 + 100 * contact_id + t 884 + return test_multitouch.Touch(contact_id, x, y) 885 + 886 + def make_contacts(self, n, t=0): 887 + """ 888 + Make multiple touch contacts that can move over time. 889 + 890 + Returns a list of `n` touch objects that are positioned at well-known 891 + locations. The value of `t` may be incremented over time to move the 892 + points along a linear path. 893 + """ 894 + return [ self.make_contact(id, t) for id in range(0, n) ] 895 + 896 + def assert_contact(self, uhdev, evdev, contact_ids, t=0): 897 + """ 898 + Assert properties of a contact generated by make_contact. 899 + """ 900 + contact_id = contact_ids.contact_id 901 + tracking_id = contact_ids.tracking_id 902 + slot_num = contact_ids.slot_num 903 + 904 + x = 50 + 10 * contact_id + t 905 + y = 100 + 100 * contact_id + t 906 + 907 + # If the data isn't supposed to be stored in any slots, there is 908 + # nothing we can check for in the evdev stream. 909 + if slot_num is None: 910 + assert tracking_id == -1 911 + return 912 + 913 + assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == tracking_id 914 + if tracking_id != -1: 915 + assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_X] == x 916 + assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_Y] == y 917 + 918 + def assert_contacts(self, uhdev, evdev, data, t=0): 919 + """ 920 + Assert properties of a list of contacts generated by make_contacts. 921 + """ 922 + for contact_ids in data: 923 + self.assert_contact(uhdev, evdev, contact_ids, t) 872 924 873 925 def test_contact_id_0(self): 874 926 """ ··· 963 909 Ensure that the confidence bit being set to false should not result in a touch event. 964 910 """ 965 911 uhdev = self.uhdev 966 - evdev = uhdev.get_evdev() 912 + _evdev = uhdev.get_evdev() 967 913 968 914 t0 = test_multitouch.Touch(1, 50, 100) 969 915 t0.confidence = False ··· 971 917 events = uhdev.next_sync_events() 972 918 self.debug_reports(r, uhdev, events) 973 919 974 - slot = self.get_slot(uhdev, t0, 0) 920 + _slot = self.get_slot(uhdev, t0, 0) 975 921 976 922 assert not events 923 + 924 + def test_confidence_multitouch(self): 925 + """ 926 + Bring multiple fingers in contact with the tablet, some with the 927 + confidence bit set, and some without. 928 + 929 + Ensure that all confident touches are reported and that all non- 930 + confident touches are ignored. 931 + """ 932 + uhdev = self.uhdev 933 + evdev = uhdev.get_evdev() 934 + 935 + touches = self.make_contacts(5) 936 + touches[0].confidence = False 937 + touches[2].confidence = False 938 + touches[4].confidence = False 939 + 940 + r = uhdev.event(touches) 941 + events = uhdev.next_sync_events() 942 + self.debug_reports(r, uhdev, events) 943 + 944 + assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events 945 + 946 + self.assert_contacts(uhdev, evdev, 947 + [ self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), 948 + self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), 949 + self.ContactIds(contact_id = 2, tracking_id = -1, slot_num = None), 950 + self.ContactIds(contact_id = 3, tracking_id = 1, slot_num = 1), 951 + self.ContactIds(contact_id = 4, tracking_id = -1, slot_num = None) ]) 952 + 953 + def confidence_change_assert_playback(self, uhdev, evdev, timeline): 954 + """ 955 + Assert proper behavior of contacts that move and change tipswitch / 956 + confidence status over time. 957 + 958 + Given a `timeline` list of touch states to iterate over, verify 959 + that the contacts move and are reported as up/down as expected 960 + by the state of the tipswitch and confidence bits. 961 + """ 962 + t = 0 963 + 964 + for state in timeline: 965 + touches = self.make_contacts(len(state), t) 966 + 967 + for item in zip(touches, state): 968 + item[0].tipswitch = item[1][1] 969 + item[0].confidence = item[1][2] 970 + 971 + r = uhdev.event(touches) 972 + events = uhdev.next_sync_events() 973 + self.debug_reports(r, uhdev, events) 974 + 975 + ids = [ x[0] for x in state ] 976 + self.assert_contacts(uhdev, evdev, ids, t) 977 + 978 + t += 1 979 + 980 + def test_confidence_loss_a(self): 981 + """ 982 + Transition a confident contact to a non-confident contact by 983 + first clearing the tipswitch. 984 + 985 + Ensure that the driver reports the transitioned contact as 986 + being removed and that other contacts continue to report 987 + normally. This mode of confidence loss is used by the 988 + DTH-2452. 989 + """ 990 + uhdev = self.uhdev 991 + evdev = uhdev.get_evdev() 992 + 993 + self.confidence_change_assert_playback(uhdev, evdev, [ 994 + # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident 995 + # Both fingers confidently in contact 996 + [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True), 997 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 998 + 999 + # t=1: Contact 0 == !Down + confident; Contact 1 == Down + confident 1000 + # First finger looses confidence and clears only the tipswitch flag 1001 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, True), 1002 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1003 + 1004 + # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident 1005 + # First finger has lost confidence and has both flags cleared 1006 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), 1007 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1008 + 1009 + # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident 1010 + # First finger has lost confidence and has both flags cleared 1011 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), 1012 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)] 1013 + ]) 1014 + 1015 + def test_confidence_loss_b(self): 1016 + """ 1017 + Transition a confident contact to a non-confident contact by 1018 + cleraing both tipswitch and confidence bits simultaneously. 1019 + 1020 + Ensure that the driver reports the transitioned contact as 1021 + being removed and that other contacts continue to report 1022 + normally. This mode of confidence loss is used by some 1023 + AES devices. 1024 + """ 1025 + uhdev = self.uhdev 1026 + evdev = uhdev.get_evdev() 1027 + 1028 + self.confidence_change_assert_playback(uhdev, evdev, [ 1029 + # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident 1030 + # Both fingers confidently in contact 1031 + [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True), 1032 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1033 + 1034 + # t=1: Contact 0 == !Down + !confident; Contact 1 == Down + confident 1035 + # First finger looses confidence and has both flags cleared simultaneously 1036 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), 1037 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1038 + 1039 + # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident 1040 + # First finger has lost confidence and has both flags cleared 1041 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), 1042 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1043 + 1044 + # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident 1045 + # First finger has lost confidence and has both flags cleared 1046 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), 1047 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)] 1048 + ]) 1049 + 1050 + def test_confidence_loss_c(self): 1051 + """ 1052 + Transition a confident contact to a non-confident contact by 1053 + clearing only the confidence bit. 1054 + 1055 + Ensure that the driver reports the transitioned contact as 1056 + being removed and that other contacts continue to report 1057 + normally. 1058 + """ 1059 + uhdev = self.uhdev 1060 + evdev = uhdev.get_evdev() 1061 + 1062 + self.confidence_change_assert_playback(uhdev, evdev, [ 1063 + # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident 1064 + # Both fingers confidently in contact 1065 + [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True), 1066 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1067 + 1068 + # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident 1069 + # First finger looses confidence and clears only the confidence flag 1070 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), True, False), 1071 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1072 + 1073 + # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident 1074 + # First finger has lost confidence and has both flags cleared 1075 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), 1076 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1077 + 1078 + # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident 1079 + # First finger has lost confidence and has both flags cleared 1080 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), 1081 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)] 1082 + ]) 1083 + 1084 + def test_confidence_gain_a(self): 1085 + """ 1086 + Transition a contact that was always non-confident to confident. 1087 + 1088 + Ensure that the confident contact is reported normally. 1089 + """ 1090 + uhdev = self.uhdev 1091 + evdev = uhdev.get_evdev() 1092 + 1093 + self.confidence_change_assert_playback(uhdev, evdev, [ 1094 + # t=0: Contact 0 == Down + !confident; Contact 1 == Down + confident 1095 + # Only second finger is confidently in contact 1096 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), True, False), 1097 + (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)], 1098 + 1099 + # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident 1100 + # First finger gains confidence 1101 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), True, False), 1102 + (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)], 1103 + 1104 + # t=2: Contact 0 == Down + confident; Contact 1 == Down + confident 1105 + # First finger remains confident 1106 + [(self.ContactIds(contact_id = 0, tracking_id = 1, slot_num = 1), True, True), 1107 + (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)], 1108 + 1109 + # t=3: Contact 0 == Down + confident; Contact 1 == Down + confident 1110 + # First finger remains confident 1111 + [(self.ContactIds(contact_id = 0, tracking_id = 1, slot_num = 1), True, True), 1112 + (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)] 1113 + ]) 1114 + 1115 + def test_confidence_gain_b(self): 1116 + """ 1117 + Transition a contact from non-confident to confident. 1118 + 1119 + Ensure that the confident contact is reported normally. 1120 + """ 1121 + uhdev = self.uhdev 1122 + evdev = uhdev.get_evdev() 1123 + 1124 + self.confidence_change_assert_playback(uhdev, evdev, [ 1125 + # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident 1126 + # First and second finger confidently in contact 1127 + [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True), 1128 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1129 + 1130 + # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident 1131 + # Firtst finger looses confidence 1132 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), True, False), 1133 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1134 + 1135 + # t=2: Contact 0 == Down + confident; Contact 1 == Down + confident 1136 + # First finger gains confidence 1137 + [(self.ContactIds(contact_id = 0, tracking_id = 2, slot_num = 0), True, True), 1138 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], 1139 + 1140 + # t=3: Contact 0 == !Down + confident; Contact 1 == Down + confident 1141 + # First finger goes up 1142 + [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, True), 1143 + (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)] 1144 + ])
+28 -22
tools/testing/selftests/hid/vmtest.sh
··· 19 19 SCRIPT_DIR="$(dirname $(realpath $0))" 20 20 OUTPUT_DIR="$SCRIPT_DIR/results" 21 21 KCONFIG_REL_PATHS=("${SCRIPT_DIR}/config" "${SCRIPT_DIR}/config.common" "${SCRIPT_DIR}/config.${ARCH}") 22 - B2C_URL="https://gitlab.freedesktop.org/mupuf/boot2container/-/raw/master/vm2c.py" 22 + B2C_URL="https://gitlab.freedesktop.org/gfx-ci/boot2container/-/raw/main/vm2c.py" 23 23 NUM_COMPILE_JOBS="$(nproc)" 24 24 LOG_FILE_BASE="$(date +"hid_selftests.%Y-%m-%d_%H-%M-%S")" 25 25 LOG_FILE="${LOG_FILE_BASE}.log" 26 26 EXIT_STATUS_FILE="${LOG_FILE_BASE}.exit_status" 27 - CONTAINER_IMAGE="registry.freedesktop.org/libevdev/hid-tools/fedora/37:2023-02-17.1" 27 + CONTAINER_IMAGE="registry.freedesktop.org/bentiss/hid/fedora/39:2023-11-22.1" 28 28 29 29 TARGETS="${TARGETS:=$(basename ${SCRIPT_DIR})}" 30 30 DEFAULT_COMMAND="pip3 install hid-tools; make -C tools/testing/selftests TARGETS=${TARGETS} run_tests" ··· 32 32 usage() 33 33 { 34 34 cat <<EOF 35 - Usage: $0 [-i] [-s] [-d <output_dir>] -- [<command>] 35 + Usage: $0 [-j N] [-s] [-b] [-d <output_dir>] -- [<command>] 36 36 37 37 <command> is the command you would normally run when you are in 38 38 the source kernel direcory. e.g: ··· 55 55 56 56 -u) Update the boot2container script to a newer version. 57 57 -d) Update the output directory (default: ${OUTPUT_DIR}) 58 + -b) Run only the build steps for the kernel and the selftests 58 59 -j) Number of jobs for compilation, similar to -j in make 59 60 (default: ${NUM_COMPILE_JOBS}) 60 61 -s) Instead of powering off the VM, start an interactive ··· 192 191 local command="${DEFAULT_COMMAND}" 193 192 local update_b2c="no" 194 193 local debug_shell="no" 194 + local build_only="no" 195 195 196 - while getopts ':hsud:j:' opt; do 196 + while getopts ':hsud:j:b' opt; do 197 197 case ${opt} in 198 198 u) 199 199 update_b2c="yes" ··· 208 206 s) 209 207 command="/bin/sh" 210 208 debug_shell="yes" 209 + ;; 210 + b) 211 + build_only="yes" 211 212 ;; 212 213 h) 213 214 usage ··· 231 226 shift $((OPTIND -1)) 232 227 233 228 # trap 'catch "$?"' EXIT 234 - 235 - if [[ "${debug_shell}" == "no" ]]; then 229 + if [[ "${build_only}" == "no" && "${debug_shell}" == "no" ]]; then 236 230 if [[ $# -eq 0 ]]; then 237 231 echo "No command specified, will run ${DEFAULT_COMMAND} in the vm" 238 232 else ··· 271 267 update_kconfig "${kernel_checkout}" "${kconfig_file}" 272 268 273 269 recompile_kernel "${kernel_checkout}" "${make_command}" 274 - 275 - if [[ "${update_b2c}" == "no" && ! -f "${b2c}" ]]; then 276 - echo "vm2c script not found in ${b2c}" 277 - update_b2c="yes" 278 - fi 279 - 280 - if [[ "${update_b2c}" == "yes" ]]; then 281 - download $B2C_URL $b2c 282 - chmod +x $b2c 283 - fi 284 - 285 270 update_selftests "${kernel_checkout}" "${make_command}" 286 - run_vm "${kernel_checkout}" $b2c "${kernel_bzimage}" "${command}" 287 - if [[ "${debug_shell}" != "yes" ]]; then 288 - echo "Logs saved in ${OUTPUT_DIR}/${LOG_FILE}" 289 - fi 290 271 291 - exit $(cat ${OUTPUT_DIR}/${EXIT_STATUS_FILE}) 272 + if [[ "${build_only}" == "no" ]]; then 273 + if [[ "${update_b2c}" == "no" && ! -f "${b2c}" ]]; then 274 + echo "vm2c script not found in ${b2c}" 275 + update_b2c="yes" 276 + fi 277 + 278 + if [[ "${update_b2c}" == "yes" ]]; then 279 + download $B2C_URL $b2c 280 + chmod +x $b2c 281 + fi 282 + 283 + run_vm "${kernel_checkout}" $b2c "${kernel_bzimage}" "${command}" 284 + if [[ "${debug_shell}" != "yes" ]]; then 285 + echo "Logs saved in ${OUTPUT_DIR}/${LOG_FILE}" 286 + fi 287 + 288 + exit $(cat ${OUTPUT_DIR}/${EXIT_STATUS_FILE}) 289 + fi 292 290 } 293 291 294 292 main "$@"