* [PATCH][next] input: ti_am335x_tsc: remove redundant assignment to variable config
From: Colin Ian King @ 2024-02-05 21:59 UTC (permalink / raw)
To: Dmitry Torokhov, linux-input; +Cc: kernel-janitors, linux-kernel
The variable config is being initialized with a value that is never
read, it is being re-assigned in the next statement. The initialization
is redundant and can be removed.
Cleans up clang scan build warning:
drivers/input/touchscreen/ti_am335x_tsc.c:160:2: warning: Value stored
to 'config' is never read [deadcode.DeadStores]
Signed-off-by: Colin Ian King <colin.i.king@gmail.com>
---
drivers/input/touchscreen/ti_am335x_tsc.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 34324f8512ac..294b7ceded27 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -157,7 +157,6 @@ static void titsc_step_config(struct titsc *ts_dev)
n++ == 0 ? STEPCONFIG_OPENDLY : 0);
}
- config = 0;
config = STEPCONFIG_MODE_HWSYNC |
STEPCONFIG_AVG_16 | ts_dev->bit_yn |
STEPCONFIG_INM_ADCREFM;
--
2.39.2
^ permalink raw reply related
* Re: (subset) [PATCH 00/42] Fix coccicheck warnings
From: Martin K. Petersen @ 2024-02-06 2:07 UTC (permalink / raw)
To: linux-kernel, Li Zhijian
Cc: Martin K . Petersen, Adaptec OEM Raid Solutions, Adrian Hunter,
Alexander Shishkin, Alistar Popple, Aneesh Kumar K.V,
Arnaldo Carvalho de Melo, Artur Paszkiewicz, Benjamin Tissoires,
Borislav Petkov, Bruno Prémont, Chandrakanth patil,
Christian Gromm, Christophe Leroy, cocci, Dave Hansen, Don Brace,
dri-devel, Eddie James, GR-QLogic-Storage-Upstream,
Hannes Reinecke, Hannes Reinecke, Hans de Goede, Helge Deller,
HighPoint Linux Team, H. Peter Anvin, Ian Rogers,
Ilpo Järvinen, Ingo Molnar, Jack Wang, James E.J. Bottomley,
James E.J. Bottomley, James Morse, Jeremy Kerr, Jiri Kosina,
Jiri Olsa, Joel Stanley, Jonathan Cameron, Julia Lawall,
Karan Tilak Kumar, Kashyap Desai, Ketan Mukadam, Laurentiu Tudor,
linux-arm-kernel, linux-edac, linux-fbdev, linux-fsi, linux-iio,
linux-input, linux-perf-users, linuxppc-dev, linux-scsi,
Manish Rangankar, Mark Rutland, Mauro Carvalho Chehab,
megaraidlinux.pdl, Michael Cyr, Michael Ellerman,
Michal Januszewski, MPT-FusionLinux.pdl, Namhyung Kim,
Naveen N. Rao, netdev, Nicholas Piggin, Nicolas Palix,
Nilesh Javali, Parthiban Veerasooran, Peter Zijlstra,
platform-driver-x86, Richard Cochran, Robert Richter,
Russell King, Sathya Prakash, Satish Kharat, Sesidhar Baddela,
Shivasharan S, Sreekanth Reddy, Srinivas Pandruvada,
Stefan Achatz, storagedev, Stuart Yoder, Suganath Prabu Subramani,
Sumit Saxena, target-devel, Thomas Gleixner, Tony Luck,
Tyrel Datwyler, Vadim Pasternak, x86
In-Reply-To: <20240116041129.3937800-1-lizhijian@fujitsu.com>
On Tue, 16 Jan 2024 12:10:47 +0800, Li Zhijian wrote:
> make coccicheck COCCI=$PWD/scripts/coccinelle/api/device_attr_show.cocci`
> complians some warnnings as following[1]:
>
> Not sure if someone had tried these fixes, feel free to ignore this
> patch set if we have come to a *NOT-FIX* conclusion before :)
>
> This patch set also fix a few snprintf() beside coccicheck reported.
> For example, some thing like
> xxx_show() {
> rc = snprintf();
> ...
> return rc;
> }
>
> [...]
Applied to 6.9/scsi-queue, thanks!
[22/42] drivers/scsi/fnic: Convert snprintf to sysfs_emit
https://git.kernel.org/mkp/scsi/c/1ad717c92925
[25/42] drivers/scsi/ibmvscsi: Convert snprintf to sysfs_emit
https://git.kernel.org/mkp/scsi/c/29ff822f466e
[26/42] drivers/scsi/ibmvscsi_tgt: Convert snprintf to sysfs_emit
https://git.kernel.org/mkp/scsi/c/01105c23de42
[27/42] drivers/scsi/isci: Convert snprintf to sysfs_emit
https://git.kernel.org/mkp/scsi/c/5fbf37e53091
[34/42] drivers/scsi/pm8001: Convert snprintf to sysfs_emit
https://git.kernel.org/mkp/scsi/c/8179041f801d
--
Martin K. Petersen Oracle Linux Engineering
^ permalink raw reply
* Re: Suspected bug in hid-microsoft.c
From: Taco Jerkface @ 2024-02-06 5:25 UTC (permalink / raw)
To: Benjamin Tissoires; +Cc: Siarhei Vishniakou, linux-input, jikos
In-Reply-To: <CAO-hwJJKmFFt2YkenJ0RxsH_nFCu1oPGMvgbF4Tz0CsyKGZB2A@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 3397 bytes --]
Thanks!
> 1. (easiest) tune your udev rule to also give user access to the
> hidraw subsystem on this device. SDL should be able to read it
> directly, and handle it properly, but this won't solve for future
> users
This udev rule does in fact "fix" the problem
KERNELS=="*:045E:0B22.*", MODE="0666"
> 2. (no kernel compilation required) we can try to fix the report
> descriptor of the device through HID-BPF. Assuming you have
> CONFIG_HID_BPF enabled in your kernel, we can relatively easily change
> the way the device is exported/handled by the kernel, to make it
> useful hopefully
> 3. (hardest IMO as you'll have to recompile your kernel for the tests)
> we can try to tune hid-microsoft.c to properly export these buttons
>
> For 2 and 3, I'll need some events from your device with hid-recorder.
> You only gave me the report descriptor, but no events which are hard
> to deduce based on the long report descriptor.
With the udev rule, I attached the hid-recorder output when pressing
the paddles. I see the 01 02 04 08 showing up at the end of the line.
> Also for 2 and 3 we need to have a BTN_* button code to use, and I
> don't know which ones should be used from the top of my head. HID-BPF
> would be easiest to use as we can let the user decide of it, while
> we'll need to have a more formal usage in case we fix hid-microsoft.
When connected with USB, evemu-record shows button names
"BTN_TRIGGER_HAPPY5" "BTN_TRIGGER_HAPPY6" "BTN_TRIGGER_HAPPY7"
"BTN_TRIGGER_HAPPY8". I assume these are the button codes we can use?
################################
# Waiting for events #
################################
E: 0.000001 0001 02c4 0001 # EV_KEY / BTN_TRIGGER_HAPPY5 1
E: 0.000001 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +0ms
E: 0.143950 0001 02c4 0000 # EV_KEY / BTN_TRIGGER_HAPPY5 0
E: 0.143950 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +143ms
E: 6.543984 0001 02c5 0001 # EV_KEY / BTN_TRIGGER_HAPPY6 1
E: 6.543984 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +6400ms
E: 6.615981 0001 02c5 0000 # EV_KEY / BTN_TRIGGER_HAPPY6 0
E: 6.615981 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +72ms
E: 7.520034 0001 02c6 0001 # EV_KEY / BTN_TRIGGER_HAPPY7 1
E: 7.520034 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +905ms
E: 7.648127 0001 02c6 0000 # EV_KEY / BTN_TRIGGER_HAPPY7 0
E: 7.648127 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +128ms
E: 8.344035 0001 02c7 0001 # EV_KEY / BTN_TRIGGER_HAPPY8 1
E: 8.344035 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +696ms
E: 8.480049 0001 02c7 0000 # EV_KEY / BTN_TRIGGER_HAPPY8 0
E: 8.480049 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +136ms
>
> For 1, maybe SDL (or Steam) already ships some udev rules, and
> submitting a fix there would make things working for everybody.
>
> Anyway, depending on how much you want this to be fixed and what you
> can do (is CONFIG_HID_BPF enabled in your distro? and can you
> recompile a kernel module?) we can figure out the next step.
Yes HID-BPF is configured in my kernel:
cat /proc/config.gz | gunzip
#
# HID-BPF support
#
CONFIG_HID_BPF=y
# end of HID-BPF support
I've never recompiled a module before, but I've compiled lots of other
stuff before. How hard can it be?
Cheers
[-- Attachment #2: recorder.txt --]
[-- Type: text/plain, Size: 74307 bytes --]
# Xbox Wireless Controller
# 0x05, 0x01, // Usage Page (Generic Desktop) 0
# 0x09, 0x05, // Usage (Game Pad) 2
# 0xa1, 0x01, // Collection (Application) 4
# 0x85, 0x01, // Report ID (1) 6
# 0x09, 0x01, // Usage (Pointer) 8
# 0xa1, 0x00, // Collection (Physical) 10
# 0x09, 0x30, // Usage (X) 12
# 0x09, 0x31, // Usage (Y) 14
# 0x15, 0x00, // Logical Minimum (0) 16
# 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 18
# 0x95, 0x02, // Report Count (2) 23
# 0x75, 0x10, // Report Size (16) 25
# 0x81, 0x02, // Input (Data,Var,Abs) 27
# 0xc0, // End Collection 29
# 0x09, 0x01, // Usage (Pointer) 30
# 0xa1, 0x00, // Collection (Physical) 32
# 0x09, 0x32, // Usage (Z) 34
# 0x09, 0x35, // Usage (Rz) 36
# 0x15, 0x00, // Logical Minimum (0) 38
# 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 40
# 0x95, 0x02, // Report Count (2) 45
# 0x75, 0x10, // Report Size (16) 47
# 0x81, 0x02, // Input (Data,Var,Abs) 49
# 0xc0, // End Collection 51
# 0x05, 0x02, // Usage Page (Simulation Controls) 52
# 0x09, 0xc5, // Usage (Brake) 54
# 0x15, 0x00, // Logical Minimum (0) 56
# 0x26, 0xff, 0x03, // Logical Maximum (1023) 58
# 0x95, 0x01, // Report Count (1) 61
# 0x75, 0x0a, // Report Size (10) 63
# 0x81, 0x02, // Input (Data,Var,Abs) 65
# 0x15, 0x00, // Logical Minimum (0) 67
# 0x25, 0x00, // Logical Maximum (0) 69
# 0x75, 0x06, // Report Size (6) 71
# 0x95, 0x01, // Report Count (1) 73
# 0x81, 0x03, // Input (Cnst,Var,Abs) 75
# 0x05, 0x02, // Usage Page (Simulation Controls) 77
# 0x09, 0xc4, // Usage (Accelerator) 79
# 0x15, 0x00, // Logical Minimum (0) 81
# 0x26, 0xff, 0x03, // Logical Maximum (1023) 83
# 0x95, 0x01, // Report Count (1) 86
# 0x75, 0x0a, // Report Size (10) 88
# 0x81, 0x02, // Input (Data,Var,Abs) 90
# 0x15, 0x00, // Logical Minimum (0) 92
# 0x25, 0x00, // Logical Maximum (0) 94
# 0x75, 0x06, // Report Size (6) 96
# 0x95, 0x01, // Report Count (1) 98
# 0x81, 0x03, // Input (Cnst,Var,Abs) 100
# 0x05, 0x01, // Usage Page (Generic Desktop) 102
# 0x09, 0x39, // Usage (Hat switch) 104
# 0x15, 0x01, // Logical Minimum (1) 106
# 0x25, 0x08, // Logical Maximum (8) 108
# 0x35, 0x00, // Physical Minimum (0) 110
# 0x46, 0x3b, 0x01, // Physical Maximum (315) 112
# 0x66, 0x14, 0x00, // Unit (EnglishRotation: deg) 115
# 0x75, 0x04, // Report Size (4) 118
# 0x95, 0x01, // Report Count (1) 120
# 0x81, 0x42, // Input (Data,Var,Abs,Null) 122
# 0x75, 0x04, // Report Size (4) 124
# 0x95, 0x01, // Report Count (1) 126
# 0x15, 0x00, // Logical Minimum (0) 128
# 0x25, 0x00, // Logical Maximum (0) 130
# 0x35, 0x00, // Physical Minimum (0) 132
# 0x45, 0x00, // Physical Maximum (0) 134
# 0x65, 0x00, // Unit (None) 136
# 0x81, 0x03, // Input (Cnst,Var,Abs) 138
# 0x05, 0x09, // Usage Page (Button) 140
# 0x19, 0x01, // Usage Minimum (1) 142
# 0x29, 0x0f, // Usage Maximum (15) 144
# 0x15, 0x00, // Logical Minimum (0) 146
# 0x25, 0x01, // Logical Maximum (1) 148
# 0x75, 0x01, // Report Size (1) 150
# 0x95, 0x0f, // Report Count (15) 152
# 0x81, 0x02, // Input (Data,Var,Abs) 154
# 0x15, 0x00, // Logical Minimum (0) 156
# 0x25, 0x00, // Logical Maximum (0) 158
# 0x75, 0x01, // Report Size (1) 160
# 0x95, 0x01, // Report Count (1) 162
# 0x81, 0x03, // Input (Cnst,Var,Abs) 164
# 0x05, 0x0c, // Usage Page (Consumer Devices) 166
# 0x0a, 0xb2, 0x00, // Usage (Record) 168
# 0x15, 0x00, // Logical Minimum (0) 171
# 0x25, 0x01, // Logical Maximum (1) 173
# 0x95, 0x01, // Report Count (1) 175
# 0x75, 0x01, // Report Size (1) 177
# 0x81, 0x02, // Input (Data,Var,Abs) 179
# 0x15, 0x00, // Logical Minimum (0) 181
# 0x25, 0x00, // Logical Maximum (0) 183
# 0x75, 0x07, // Report Size (7) 185
# 0x95, 0x01, // Report Count (1) 187
# 0x81, 0x03, // Input (Cnst,Var,Abs) 189
# 0x05, 0x0c, // Usage Page (Consumer Devices) 191
# 0x09, 0x01, // Usage (Consumer Control) 193
# 0xa1, 0x01, // Collection (Application) 195
# 0x0a, 0x85, 0x00, // Usage (Order Movie) 197
# 0x15, 0x00, // Logical Minimum (0) 200
# 0x26, 0xff, 0x00, // Logical Maximum (255) 202
# 0x95, 0x01, // Report Count (1) 205
# 0x75, 0x08, // Report Size (8) 207
# 0x81, 0x02, // Input (Data,Var,Abs) 209
# 0x0a, 0x99, 0x00, // Usage (Media Select Security) 211
# 0x15, 0x00, // Logical Minimum (0) 214
# 0x26, 0xff, 0x00, // Logical Maximum (255) 216
# 0x95, 0x01, // Report Count (1) 219
# 0x75, 0x04, // Report Size (4) 221
# 0x81, 0x02, // Input (Data,Var,Abs) 223
# 0x15, 0x00, // Logical Minimum (0) 225
# 0x25, 0x00, // Logical Maximum (0) 227
# 0x95, 0x01, // Report Count (1) 229
# 0x75, 0x04, // Report Size (4) 231
# 0x81, 0x03, // Input (Cnst,Var,Abs) 233
# 0x0a, 0x81, 0x00, // Usage (Assign Selection) 235
# 0x15, 0x00, // Logical Minimum (0) 238
# 0x26, 0xff, 0x00, // Logical Maximum (255) 240
# 0x95, 0x01, // Report Count (1) 243
# 0x75, 0x04, // Report Size (4) 245
# 0x81, 0x02, // Input (Data,Var,Abs) 247
# 0x15, 0x00, // Logical Minimum (0) 249
# 0x25, 0x00, // Logical Maximum (0) 251
# 0x95, 0x01, // Report Count (1) 253
# 0x75, 0x04, // Report Size (4) 255
# 0x81, 0x03, // Input (Cnst,Var,Abs) 257
# 0xc0, // End Collection 259
# 0x05, 0x0f, // Usage Page (Vendor Usage Page 0x0f) 260
# 0x09, 0x21, // Usage (Vendor Usage 0x21) 262
# 0x85, 0x03, // Report ID (3) 264
# 0xa1, 0x02, // Collection (Logical) 266
# 0x09, 0x97, // Usage (Vendor Usage 0x97) 268
# 0x15, 0x00, // Logical Minimum (0) 270
# 0x25, 0x01, // Logical Maximum (1) 272
# 0x75, 0x04, // Report Size (4) 274
# 0x95, 0x01, // Report Count (1) 276
# 0x91, 0x02, // Output (Data,Var,Abs) 278
# 0x15, 0x00, // Logical Minimum (0) 280
# 0x25, 0x00, // Logical Maximum (0) 282
# 0x75, 0x04, // Report Size (4) 284
# 0x95, 0x01, // Report Count (1) 286
# 0x91, 0x03, // Output (Cnst,Var,Abs) 288
# 0x09, 0x70, // Usage (Vendor Usage 0x70) 290
# 0x15, 0x00, // Logical Minimum (0) 292
# 0x25, 0x64, // Logical Maximum (100) 294
# 0x75, 0x08, // Report Size (8) 296
# 0x95, 0x04, // Report Count (4) 298
# 0x91, 0x02, // Output (Data,Var,Abs) 300
# 0x09, 0x50, // Usage (Vendor Usage 0x50) 302
# 0x66, 0x01, 0x10, // Unit (SILinear: s) 304
# 0x55, 0x0e, // Unit Exponent (-2) 307
# 0x15, 0x00, // Logical Minimum (0) 309
# 0x26, 0xff, 0x00, // Logical Maximum (255) 311
# 0x75, 0x08, // Report Size (8) 314
# 0x95, 0x01, // Report Count (1) 316
# 0x91, 0x02, // Output (Data,Var,Abs) 318
# 0x09, 0xa7, // Usage (Vendor Usage 0xa7) 320
# 0x15, 0x00, // Logical Minimum (0) 322
# 0x26, 0xff, 0x00, // Logical Maximum (255) 324
# 0x75, 0x08, // Report Size (8) 327
# 0x95, 0x01, // Report Count (1) 329
# 0x91, 0x02, // Output (Data,Var,Abs) 331
# 0x65, 0x00, // Unit (None) 333
# 0x55, 0x00, // Unit Exponent (0) 335
# 0x09, 0x7c, // Usage (Vendor Usage 0x7c) 337
# 0x15, 0x00, // Logical Minimum (0) 339
# 0x26, 0xff, 0x00, // Logical Maximum (255) 341
# 0x75, 0x08, // Report Size (8) 344
# 0x95, 0x01, // Report Count (1) 346
# 0x91, 0x02, // Output (Data,Var,Abs) 348
# 0xc0, // End Collection 350
# 0x05, 0x0c, // Usage Page (Consumer Devices) 351
# 0x09, 0x01, // Usage (Consumer Control) 353
# 0x85, 0x0c, // Report ID (12) 355
# 0xa1, 0x01, // Collection (Application) 357
# 0x0a, 0x9e, 0x00, // Usage (Media Select SAP) 359
# 0x15, 0x00, // Logical Minimum (0) 362
# 0x26, 0xff, 0x00, // Logical Maximum (255) 364
# 0x95, 0x01, // Report Count (1) 367
# 0x75, 0x08, // Report Size (8) 369
# 0x81, 0x02, // Input (Data,Var,Abs) 371
# 0x0a, 0xa1, 0x00, // Usage (Once) 373
# 0x15, 0x00, // Logical Minimum (0) 376
# 0x26, 0xff, 0x00, // Logical Maximum (255) 378
# 0x95, 0x01, // Report Count (1) 381
# 0x75, 0x08, // Report Size (8) 383
# 0x81, 0x02, // Input (Data,Var,Abs) 385
# 0x0a, 0xa2, 0x00, // Usage (Daily) 387
# 0x15, 0x00, // Logical Minimum (0) 390
# 0x26, 0xff, 0x00, // Logical Maximum (255) 392
# 0x95, 0x01, // Report Count (1) 395
# 0x75, 0x08, // Report Size (8) 397
# 0x81, 0x02, // Input (Data,Var,Abs) 399
# 0x0a, 0xa3, 0x00, // Usage (Weekly) 401
# 0x15, 0x00, // Logical Minimum (0) 404
# 0x26, 0xff, 0x00, // Logical Maximum (255) 406
# 0x95, 0x01, // Report Count (1) 409
# 0x75, 0x08, // Report Size (8) 411
# 0x81, 0x02, // Input (Data,Var,Abs) 413
# 0xc0, // End Collection 415
# 0xc0, // End Collection 416
# 0x05, 0x01, // Usage Page (Generic Desktop) 417
# 0x09, 0x06, // Usage (Keyboard) 419
# 0xa1, 0x01, // Collection (Application) 421
# 0x85, 0x05, // Report ID (5) 423
# 0x05, 0x07, // Usage Page (Keyboard) 425
# 0x19, 0xe0, // Usage Minimum (224) 427
# 0x29, 0xe7, // Usage Maximum (231) 429
# 0x15, 0x00, // Logical Minimum (0) 431
# 0x25, 0x01, // Logical Maximum (1) 433
# 0x75, 0x01, // Report Size (1) 435
# 0x95, 0x08, // Report Count (8) 437
# 0x81, 0x02, // Input (Data,Var,Abs) 439
# 0x95, 0x01, // Report Count (1) 441
# 0x75, 0x08, // Report Size (8) 443
# 0x81, 0x03, // Input (Cnst,Var,Abs) 445
# 0x95, 0x06, // Report Count (6) 447
# 0x75, 0x08, // Report Size (8) 449
# 0x15, 0x00, // Logical Minimum (0) 451
# 0x25, 0x65, // Logical Maximum (101) 453
# 0x05, 0x07, // Usage Page (Keyboard) 455
# 0x19, 0x00, // Usage Minimum (0) 457
# 0x29, 0x65, // Usage Maximum (101) 459
# 0x81, 0x00, // Input (Data,Arr,Abs) 461
# 0xc0, // End Collection 463
#
R: 464 05 01 09 05 a1 01 85 01 09 01 a1 00 09 30 09 31 15 00 27 ff ff 00 00 95 02 75 10 81 02 c0 09 01 a1 00 09 32 09 35 15 00 27 ff ff 00 00 95 02 75 10 81 02 c0 05 02 09 c5 15 00 26 ff 03 95 01 75 0a 81 02 15 00 25 00 75 06 95 01 81 03 05 02 09 c4 15 00 26 ff 03 95 01 75 0a 81 02 15 00 25 00 75 06 95 01 81 03 05 01 09 39 15 01 25 08 35 00 46 3b 01 66 14 00 75 04 95 01 81 42 75 04 95 01 15 00 25 00 35 00 45 00 65 00 81 03 05 09 19 01 29 0f 15 00 25 01 75 01 95 0f 81 02 15 00 25 00 75 01 95 01 81 03 05 0c 0a b2 00 15 00 25 01 95 01 75 01 81 02 15 00 25 00 75 07 95 01 81 03 05 0c 09 01 a1 01 0a 85 00 15 00 26 ff 00 95 01 75 08 81 02 0a 99 00 15 00 26 ff 00 95 01 75 04 81 02 15 00 25 00 95 01 75 04 81 03 0a 81 00 15 00 26 ff 00 95 01 75 04 81 02 15 00 25 00 95 01 75 04 81 03 c0 05 0f 09 21 85 03 a1 02 09 97 15 00 25 01 75 04 95 01 91 02 15 00 25 00 75 04 95 01 91 03 09 70 15 00 25 64 75 08 95 04 91 02 09 50 66 01 10 55 0e 15 00 26 ff 00 75 08 95 01 91 02 09 a7 15 00 26 ff 00 75 08 95 01 91 02 65 00 55 00 09 7c 15 00 26 ff 00 75 08 95 01 91 02 c0 05 0c 09 01 85 0c a1 01 0a 9e 00 15 00 26 ff 00 95 01 75 08 81 02 0a a1 00 15 00 26 ff 00 95 01 75 08 81 02 0a a2 00 15 00 26 ff 00 95 01 75 08 81 02 0a a3 00 15 00 26 ff 00 95 01 75 08 81 02 c0 c0 05 01 09 06 a1 01 85 05 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 95 01 75 08 81 03 95 06 75 08 15 00 25 65 05 07 19 00 29 65 81 00 c0
N: Xbox Wireless Controller
I: 5 045e 0b22
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.000000 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.001002 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.001487 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.001944 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.002401 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.003336 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.010494 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.016620 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.023255 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.033284 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 1 | #
E: 000000.039948 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 01
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.046600 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.056677 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.063620 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.073157 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.073711 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.083320 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.093276 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.103210 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.103891 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.117791 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.133279 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.134209 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.143369 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.153267 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.159926 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.173627 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.186719 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.187266 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.196578 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.203336 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.413335 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.423378 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.433206 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.434185 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.453308 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.460009 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.466556 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.473368 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.486648 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.496628 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.503236 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.513234 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.519980 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.528029 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.543356 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.549991 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 4 | #
E: 000000.556775 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 04
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.563271 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.576754 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.586634 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.593355 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.603294 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.613284 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.613894 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.633298 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.639968 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.646683 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.653367 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.666572 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.679970 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.680646 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.693323 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.699952 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.706553 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.723333 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.729987 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000000.736639 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000000.973282 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000000.973883 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000000.983383 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000000.999860 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.006571 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.013303 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.023189 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.033175 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.043514 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.053294 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.059868 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.066690 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.073317 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.089934 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.096787 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 2 | #
E: 000001.103274 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 02
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.116579 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.117185 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.133264 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.143185 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.150028 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.156670 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.163196 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.179880 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.186607 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.193301 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.203312 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.209939 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.226528 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.233199 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.239894 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.246626 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.253891 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.273225 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.273986 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.283576 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.596755 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.597405 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.606664 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.626760 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.627411 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.639868 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.641139 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.656668 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.666639 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.673331 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.686863 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.687476 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.696778 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.713192 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.720053 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.729948 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.730582 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 8 | #
E: 000001.743267 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 08
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.760250 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.760849 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.773285 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.780042 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.786815 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.803881 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.810231 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.816563 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.823188 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.833173 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.846500 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.853433 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.863161 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.870132 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.876784 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.893328 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.899992 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.906572 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.916636 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 1 / X: 33591 | Y: 32360
# | Z: 33117 | Rz: 31898 | Brake: 0 | # | Accelerator: 0 | # | Hat switch: 0 | # | Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | # | Record: 0 | #
# | Order Movie: 0 | Media Select Security: 0 | # | Assign Selection: 0 | #
E: 000001.926641 20 01 37 83 68 7e 5d 81 9a 7c 00 00 00 00 00 00 00 00 00 00 00
^ permalink raw reply
* Re: Re: [PATCH v4 1/3] dt-bindings: HID: i2c-hid: Document reset-related properties
From: Johan Hovold @ 2024-02-06 11:02 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Bjorn Andersson, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Benjamin Tissoires,
Jiri Kosina, Konrad Dybcio, Johan Hovold, linux-arm-msm,
linux-input, devicetree, linux-kernel, Konrad Dybcio,
Krzysztof Kozlowski, Rob Herring
In-Reply-To: <luzkdel2hshufku2gjgbsvfhxkmpg5eo6ekythuawaiz6kibvs@lsajkktmetkv>
On Thu, Feb 01, 2024 at 04:08:05PM -0600, Bjorn Andersson wrote:
> On Thu, Feb 01, 2024 at 11:05:47AM +0100, Johan Hovold wrote:
> > On Wed, Jan 31, 2024 at 07:07:26PM -0800, Bjorn Andersson wrote:
> > > + post-reset-deassert-delay-ms:
> > > + description: Time required by the device after reset has been deasserted,
> > > + before it is ready for communication.
> >
> > I know that Rob reluctantly acked this, but re-reading the commit
> > message for the commit that added support for the reset gpio to the
> > driver, and added a comment about this not having been added to the
> > devicetree binding, it becomes obvious that the latter was done on
> > purpose and that we probably should not be adding the
> > 'post-reset-deassert-delay-ms' property after all:
> >
> > For now the new "post-reset-deassert-delay-ms" property is only
> > used on x86/ACPI (non devicetree) devs. IOW it is not used in
> > actual devicetree files and the same goes for the reset GPIO.
> > The devicetree-bindings maintainers have requested properties
> > like these to not be added to the devicetree-bindings, so the
> > new property + GPIO are deliberately not added to the existing
> > devicetree-bindings.
> >
> > 2be404486c05 ("HID: i2c-hid-of: Add reset GPIO support to i2c-hid-of")
> >
> > So perhaps we should just do this properly and add a new compatible
> > property for X13s touchscreen which can be used to determine these
> > delays (e.g. for cases where some default values are insufficient).
>
> So we should add a new binding, with a device-specific compatible and
> add a reset-gpios only for that (and not the generic hid-over-i2c
> binding), and then in the i2c-hid driver encode the two delays?
Right.
> I can try to rewrite these patches, if you can provide me with a
> compatible.
My X13s doesn't have a touchscreen, but the ACPI tables says "ELAN901C".
You can look at the current binding and work with the HID and DT
maintainers to come up with something appropriate. There is one
device-specific compatible in the DT schema currently:
wacom,w9013
so something like
elan,<product>
where <product> is a name for the device with product id 0x901c (or you
use the HID product id directly somehow).
Johan
^ permalink raw reply
* Re: [PATCH v10 3/3] HID: cp2112: Fwnode Support
From: Andy Shevchenko @ 2024-02-06 14:05 UTC (permalink / raw)
To: Danny Kaehn
Cc: robh+dt, krzysztof.kozlowski+dt, bentiss, jikos,
bartosz.golaszewski, niyas.sait, dmitry.torokhov, devicetree,
linux-input, ethan.twardy
In-Reply-To: <20240205170920.93499-4-danny.kaehn@plexus.com>
On Mon, Feb 05, 2024 at 11:09:22AM -0600, Danny Kaehn wrote:
> Support describing the CP2112's I2C and GPIO interfaces in firmware.
>
> I2C and GPIO child nodes can either be children with names "i2c" and
> "gpio", or, for ACPI, device nodes with _ADR Zero and One,
> respectively.
> Additionally, support configuring the I2C bus speed from the
> clock-frequency device property.
This has to be in a separate patch, which may predecess this one.
...
> + name = fwnode_get_name(child);
> + if (name) {
> + ret = match_string(cp2112_cell_names,
> + ARRAY_SIZE(cp2112_cell_names), name);
> + if (ret >= 0)
> + addr = ret;
> + }
> + if (!name || ret < 0)
> + ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &addr);
> +
> + if (ret < 0)
> + continue;
I don't like this piece (esp. due to possible matching with node name which
may not be so reliable), but I have no better solution right now.
Maybe this way (this doesn't particularly solve the issue but seems better
to me)?
ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &addr);
if (ret) {
/* If no ACPI given or compiled, fallback to matching names */
name = fwnode_get_name(child);
if (!name)
continue;
ret = match_string(cp2112_cell_names, ARRAY_SIZE(cp2112_cell_names), name);
if (ret < 0)
continue;
addr = ret;
}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH] HID: logitech-hidpp: Do not flood kernel log
From: Jiri Kosina @ 2024-02-06 15:11 UTC (permalink / raw)
To: Hans de Goede
Cc: Oleksandr Natalenko, linux-kernel, linux-input, Filipe Laíns,
Bastien Nocera, Benjamin Tissoires
In-Reply-To: <4bd022b8-e4a9-4269-a261-65fddc791ec5@redhat.com>
On Mon, 29 Jan 2024, Hans de Goede wrote:
> > Since commit 680ee411a98e ("HID: logitech-hidpp: Fix connect event race")
> > the following messages appear in the kernel log from time to time:
> >
> > logitech-hidpp-device 0003:046D:408A.0005: HID++ 4.5 device connected.
> > logitech-hidpp-device 0003:046D:408A.0005: HID++ 4.5 device connected.
> > logitech-hidpp-device 0003:046D:4051.0006: Disconnected
> > logitech-hidpp-device 0003:046D:408A.0005: Disconnected
> >
> > As discussed, print the first per-device "device connected" message
> > at info level, demoting subsequent messages to debug level. Also,
> > demote the "Disconnected message" to debug level unconditionally.
> >
> > Link: https://lore.kernel.org/lkml/3277085.44csPzL39Z@natalenko.name/
> > Signed-off-by: Oleksandr Natalenko <oleksandr@natalenko.name>
>
> Thanks, patch looks good to me:
>
> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Applied to hid.git#for-6.8/upstream-fixes. Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: Suspected bug in hid-microsoft.c
From: Benjamin Tissoires @ 2024-02-06 15:10 UTC (permalink / raw)
To: Taco Jerkface; +Cc: Siarhei Vishniakou, linux-input, jikos
In-Reply-To: <CAEQPD4SZCFf5vj+Dyji9UzOg7M+3GPMRgTesUb2d9w8_Gm9XZg@mail.gmail.com>
On Tue, Feb 6, 2024 at 6:25 AM Taco Jerkface <tacodog311@gmail.com> wrote:
>
> Thanks!
>
> > 1. (easiest) tune your udev rule to also give user access to the
> > hidraw subsystem on this device. SDL should be able to read it
> > directly, and handle it properly, but this won't solve for future
> > users
>
> This udev rule does in fact "fix" the problem
>
> KERNELS=="*:045E:0B22.*", MODE="0666"
Right :)
Well you could restrict it further by using the recommendations from SDL:
https://github.com/libsdl-org/SDL/blob/main/src/hidapi/udev/69-hid.rules
# HIDAPI/hidraw
KERNEL=="hidraw*", ATTRS{idVendor}=="045E", ATTRS{idProduct}=="0B22",
TAG+="uaccess"
(not entirely sure about the capitals in vendor/product)
>
>
> > 2. (no kernel compilation required) we can try to fix the report
> > descriptor of the device through HID-BPF. Assuming you have
> > CONFIG_HID_BPF enabled in your kernel, we can relatively easily change
> > the way the device is exported/handled by the kernel, to make it
> > useful hopefully
> > 3. (hardest IMO as you'll have to recompile your kernel for the tests)
> > we can try to tune hid-microsoft.c to properly export these buttons
> >
> > For 2 and 3, I'll need some events from your device with hid-recorder.
> > You only gave me the report descriptor, but no events which are hard
> > to deduce based on the long report descriptor.
>
> With the udev rule, I attached the hid-recorder output when pressing
> the paddles. I see the 01 02 04 08 showing up at the end of the line.
Thanks for that. And as you can see, they are using the "Assign
Selection" usage, which is... new to me :)
>
>
> > Also for 2 and 3 we need to have a BTN_* button code to use, and I
> > don't know which ones should be used from the top of my head. HID-BPF
> > would be easiest to use as we can let the user decide of it, while
> > we'll need to have a more formal usage in case we fix hid-microsoft.
>
> When connected with USB, evemu-record shows button names
> "BTN_TRIGGER_HAPPY5" "BTN_TRIGGER_HAPPY6" "BTN_TRIGGER_HAPPY7"
> "BTN_TRIGGER_HAPPY8". I assume these are the button codes we can use?
>
> ################################
> # Waiting for events #
> ################################
> E: 0.000001 0001 02c4 0001 # EV_KEY / BTN_TRIGGER_HAPPY5 1
> E: 0.000001 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +0ms
> E: 0.143950 0001 02c4 0000 # EV_KEY / BTN_TRIGGER_HAPPY5 0
> E: 0.143950 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +143ms
> E: 6.543984 0001 02c5 0001 # EV_KEY / BTN_TRIGGER_HAPPY6 1
> E: 6.543984 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +6400ms
> E: 6.615981 0001 02c5 0000 # EV_KEY / BTN_TRIGGER_HAPPY6 0
> E: 6.615981 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +72ms
> E: 7.520034 0001 02c6 0001 # EV_KEY / BTN_TRIGGER_HAPPY7 1
> E: 7.520034 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +905ms
> E: 7.648127 0001 02c6 0000 # EV_KEY / BTN_TRIGGER_HAPPY7 0
> E: 7.648127 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +128ms
> E: 8.344035 0001 02c7 0001 # EV_KEY / BTN_TRIGGER_HAPPY8 1
> E: 8.344035 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +696ms
> E: 8.480049 0001 02c7 0000 # EV_KEY / BTN_TRIGGER_HAPPY8 0
> E: 8.480049 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +136ms
>
Good point. Then we can easily tweak the device to use those BTN_* instead
>
> >
> > For 1, maybe SDL (or Steam) already ships some udev rules, and
> > submitting a fix there would make things working for everybody.
> >
> > Anyway, depending on how much you want this to be fixed and what you
> > can do (is CONFIG_HID_BPF enabled in your distro? and can you
> > recompile a kernel module?) we can figure out the next step.
>
> Yes HID-BPF is configured in my kernel:
>
> cat /proc/config.gz | gunzip
> #
> # HID-BPF support
> #
> CONFIG_HID_BPF=y
> # end of HID-BPF support
Even better, it'll be way easier for the tests :)
I've opened a new MR with your device fix:
https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/32
You should be able to head to the last job in latest pipeline (in the
pipeline tab) and download the artifact:
https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/jobs/54687597/artifacts/browse
Then unpack and run `sudo ./install --verbose`.
Then reconnect the device over Bluetooth, and see in evemu-record that
the paddles are now reporting BTN_TRIGGER_HAPPY[5-8].
I'd then be curious about 2 things:
- are the paddle now reporting the same events over USB and Bluetooth?
(is there no inversions between the BTN_TRIGGER*?, and are all the
buttons correctly handled?)
- does this mess up with SDL over hidraw (so keeping your udev rule in place)
>
> I've never recompiled a module before, but I've compiled lots of other
> stuff before. How hard can it be?
>
Technically it's not hard, I'm sure there is a proper Arch howto
available. But it's painful because you'll have to maintain &
recompile your kernel until your fix gets in the standard kernel of
your distribution (archlinux if I'm not wrong).
But the good point is that with HID-BPF that pain is relieved: I can
provide you with the binary, you can check it if you like (the loader
is in rust and the bpf itself is C), and then once installed you can
forget about it.
Cheers,
Benjamin
^ permalink raw reply
* Re: [PATCH] HID: wacom: Do not register input devices until after hid_hw_start
From: Jiri Kosina @ 2024-02-06 15:12 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Gerecke, Jason, linux-input, Benjamin Tissoires, Ping Cheng,
Joshua Dickens, Aaron Armstrong Skomra, Tobita, Tatsunosuke,
stable, Jason Gerecke
In-Reply-To: <Zbg8yxO91S9_DZl9@google.com>
On Mon, 29 Jan 2024, Dmitry Torokhov wrote:
> > From: Jason Gerecke <killertofu@gmail.com>
> >
> > If a input device is opened before hid_hw_start is called, events may
> > not be received from the hardware. In the case of USB-backed devices,
> > for example, the hid_hw_start function is responsible for filling in
> > the URB which is submitted when the input device is opened. If a device
> > is opened prematurely, polling will never start because the device will
> > not have been in the correct state to send the URB.
> >
> > Because the wacom driver registers its input devices before calling
> > hid_hw_start, there is a window of time where a device can be opened
> > and end up in an inoperable state. Some ARM-based Chromebooks in particular
> > reliably trigger this bug.
> >
> > This commit splits the wacom_register_inputs function into two pieces.
> > One which is responsible for setting up the allocated inputs (and runs
> > prior to hid_hw_start so that devices are ready for any input events
> > they may end up receiving) and another which only registers the devices
> > (and runs after hid_hw_start to ensure devices can be immediately opened
> > without issue). Note that the functions to initialize the LEDs and remotes
> > are also moved after hid_hw_start to maintain their own dependency chains.
> >
> > Fixes: 7704ac937345 ("HID: wacom: implement generic HID handling for pen generic devices")
> > Cc: stable@vger.kernel.org # v3.18+
> > Suggested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
>
> Tested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Applied, thanks!
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH v10 3/3] HID: cp2112: Fwnode Support
From: kernel test robot @ 2024-02-06 15:54 UTC (permalink / raw)
To: Danny Kaehn, robh+dt, krzysztof.kozlowski+dt, andriy.shevchenko,
bentiss
Cc: oe-kbuild-all, jikos, bartosz.golaszewski, niyas.sait,
dmitry.torokhov, devicetree, linux-input, ethan.twardy,
Danny Kaehn
In-Reply-To: <20240205170920.93499-4-danny.kaehn@plexus.com>
Hi Danny,
kernel test robot noticed the following build warnings:
[auto build test WARNING on hid/for-next]
[also build test WARNING on robh/for-next andi-shyti/i2c/i2c-host linus/master v6.8-rc3 next-20240206]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Danny-Kaehn/dt-bindings-i2c-Add-CP2112-HID-USB-to-SMBus-Bridge/20240206-015922
base: https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git for-next
patch link: https://lore.kernel.org/r/20240205170920.93499-4-danny.kaehn%40plexus.com
patch subject: [PATCH v10 3/3] HID: cp2112: Fwnode Support
config: x86_64-randconfig-102-20240206 (https://download.01.org/0day-ci/archive/20240206/202402062306.UUQJhqxi-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240206/202402062306.UUQJhqxi-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202402062306.UUQJhqxi-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/hid/hid-cp2112.c:41: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
* CP2112 Fwnode child names.
vim +41 drivers/hid/hid-cp2112.c
39
40 /**
> 41 * CP2112 Fwnode child names.
42 * CP2112 sub-functions can be described by named fwnode children or by ACPI _ADR
43 */
44 static const char * const cp2112_cell_names[] = {
45 [CP2112_I2C_ADR] = "i2c",
46 [CP2112_GPIO_ADR] = "gpio",
47 };
48
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] Input: uinput - Add UI_SET_UNIQ ioctl handler
From: Chris Morgan @ 2024-02-06 17:17 UTC (permalink / raw)
To: Luiz Augusto von Dentz
Cc: Pali Rohár, Dmitry Torokhov, Abhishek Pandit-Subedi,
linux-input, Bluez mailing list, Enric Balletbo i Serra, LKML,
Thomas Gleixner, Logan Gunthorpe, Andrey Smirnov, Kirill Smelkov
In-Reply-To: <CABBYNZ+E3knrqWpNDKfX9qQOrrh=VLUSQAgUB=kXgK7=jwgQ9w@mail.gmail.com>
On Mon, Jun 13, 2022 at 02:36:18PM -0700, Luiz Augusto von Dentz wrote:
> Hi,
>
> On Sun, Mar 22, 2020 at 8:47 AM Pali Rohár <pali.rohar@gmail.com> wrote:
> >
> > On Wednesday 18 December 2019 12:26:59 Pali Rohár wrote:
> > > On Wednesday 18 December 2019 12:02:24 Pali Rohár wrote:
> > > > On Friday 06 December 2019 09:40:48 Dmitry Torokhov wrote:
> > > > > On Fri, Dec 06, 2019 at 10:11:14AM +0100, Pali Rohár wrote:
> > > > > > On Thursday 05 December 2019 12:03:05 Abhishek Pandit-Subedi wrote:
> > > > > > > On Thu, Dec 5, 2019 at 2:52 AM Pali Rohár <pali.rohar@gmail.com> wrote:
> > > > > > > >
> > > > > > > > On Tuesday 03 December 2019 11:11:12 Dmitry Torokhov wrote:
> > > > > > > > > On Tue, Dec 03, 2019 at 06:38:21PM +0100, Pali Rohár wrote:
> > > > > > > > > > On Tuesday 03 December 2019 00:09:47 Pali Rohár wrote:
> > > > > > > > > >
> > > > > > > > > > Hi Dmitry!
> > > > > > > > > >
> > > > > > > > > > I was looking again at those _IOW defines for ioctl calls and I have
> > > > > > > > > > another argument why not specify 'char *' in _IOW:
> > > > > > > > > >
> > > > > > > > > > All ioctls in _IOW() specify as a third macro argument type which is
> > > > > > > > > > passed as pointer to the third argument for ioctl() syscall.
> > > > > > > > > >
> > > > > > > > > > So e.g.:
> > > > > > > > > >
> > > > > > > > > > #define EVIOCSCLOCKID _IOW('E', 0xa0, int)
> > > > > > > > > >
> > > > > > > > > > is called from userspace as:
> > > > > > > > > >
> > > > > > > > > > int val;
> > > > > > > > > > ioctl(fd, EVIOCSCLOCKID, &val);
> > > > > > > > > >
> > > > > > > > > > Or
> > > > > > > > > >
> > > > > > > > > > #define EVIOCSMASK _IOW('E', 0x93, struct input_mask)
> > > > > > > > > >
> > > > > > > > > > is called as:
> > > > > > > > > >
> > > > > > > > > > struct input_mask val;
> > > > > > > > > > ioctl(fd, EVIOCSMASK, &val);
> > > > > > > > > >
> > > > > > > > > > So basically third argument for _IOW specify size of byte buffer passed
> > > > > > > > > > as third argument for ioctl(). In _IOW is not specified pointer to
> > > > > > > > > > struct input_mask, but struct input_mask itself.
> > > > > > > > > >
> > > > > > > > > > And in case you define
> > > > > > > > > >
> > > > > > > > > > #define MY_NEW_IOCTL _IOW(UINPUT_IOCTL_BASE, 200, char*)
> > > > > > > > > >
> > > > > > > > > > then you by above usage you should pass data as:
> > > > > > > > > >
> > > > > > > > > > char *val = "DATA";
> > > > > > > > > > ioctl(fd, MY_NEW_IOCTL, &val);
> > > > > > > > > >
> > > > > > > > > > Which is not same as just:
> > > > > > > > > >
> > > > > > > > > > ioctl(fd, MY_NEW_IOCTL, "DATA");
> > > > > > > > > >
> > > > > > > > > > As in former case you passed pointer to pointer to data and in later
> > > > > > > > > > case you passed only pointer to data.
> > > > > > > > > >
> > > > > > > > > > It just mean that UI_SET_PHYS is already defined inconsistently which is
> > > > > > > > > > also reason why compat ioctl for it was introduced.
> > > > > > > > >
> > > > > > > > > Yes, you are right. UI_SET_PHYS is messed up. I guess the question is
> > > > > > > > > what to do with all of this...
> > > > > > > > >
> > > > > > > > > Maybe we should define
> > > > > > > > >
> > > > > > > > > #define UI_SET_PHYS_STR(len) _IOC(_IOC_WRITE, UINPUT_IOCTL_BASE, 111, len)
> > > > > > > > > #define UI_SET_UNIQ_STR(len) _IOC(_IOC_WRITE, UINPUT_IOCTL_BASE, 112, len)
> > > > > > > >
> > > > > > > > I'm not sure if this is ideal. Normally in C strings are nul-termined,
> > > > > > > > so functions/macros do not take buffer length.
> > > > > > > Except strncpy, strndup, snprintf, etc. all expect a buffer length. At
> > > > > >
> > > > > > This is something different as for these functions you pass buffer and
> > > > > > length of buffer which is used in write mode -- not for read mode.
> > > > > >
> > > > > > > the user to kernel boundary of ioctl, I think we should require size
> > > > > > > of the user buffer regardless of the data type.
> > > > > > >
> > > > > > > > _STR therefore in names looks inconsistent.
> > > > > > > The _STR suffix is odd (what to name UI_SET_PHYS_STR then??) but
> > > > > > > requiring the length seems to be common across various ioctls.
> > > > > > > * input.h requires a length when requesting the phys and uniq
> > > > > > > (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input.h#n138)
> > > > > > > * Same with HIDRAW when setting and getting features:
> > > > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/hidraw.h#n40,
> > > > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/hidraw/hid-example.c#n88
> > > > > >
> > > > > > All these ioctls where is passed length are in opposite direction
> > > > > > (_IOC_READ) as our PHYS and UNIQ (_IOC_WRITE).
> > > > > >
> > > > > > I fully agree that when you need to read something from kernel
> > > > > > (_IOC_READ) and then writing it to userspace, you need to specify length
> > > > > > of userspace buffer. Exactly same as with userspace functions like
> > > > > > memcpy, snprintf, etc... as you pointed. Otherwise you get buffer
> > > > > > overflow as callee does not know length of buffer.
> > > > > >
> > > > > > But here we we have there quite different problem, we need to write
> > > > > > something to kernel from userspace (_IOC_WRITE) and we are passing
> > > > > > nul-term string. So in this case specifying size is not required as it
> > > > > > is implicitly specified as part of passed string.
> > > > >
> > > > > With the new IOCTL definitions it does not need to be a NULL-terminated
> > > > > string. It can be a buffer of characters with given length, and kernel
> > > > > will NULL-terminate as this it what it wants, not what the caller has to
> > > > > give.
> > > >
> > > > Hi Dmitry! I was thinking more about this problem and I will propose
> > > > alternative solution, but first with details...
> > > >
> > > > I think that we should use NULL terminated strings. Or better disallow
> > > > NULL byte inside string. Reason: all userspace application expects that
> > > > input device name would be NULL terminated which implies that in the
> > > > middle of name cannot be NULL byte.
> > > >
> > > > So this must apply also for new PHYS / UNIQ ioctl API. If we want in our
> > > > ioctl API to use buffer + size (with upper bound limit for size) instead
> > > > of passing NULL term string (with upper bound limit for string size)
> > > > then kernel have to add a leading NULL byte to string, plus check that
> > > > in the buffer there is no NULL byte. I guess this a very little
> > > > complicate code, but nothing which is problematic.
> > > >
> > > > And on the userspace part. Now when userspace want to pass constant
> > > > string for device name, it just call
> > > >
> > > > ioctl(fd, UI_SET_PHYS, "my name of device");
> > > >
> > > > After adding a new ioctl with buffer + size API, userspace would have to
> > > > call:
> > > >
> > > > ioctl(fd, UI_SET_PHYS_STR(strlen("my name of device")), "my name of device");
> > > >
> > > > which looks strange, so programmers would had to move device name into
> > > > new variable:
> > > >
> > > > const char *name = "my name of device";
> > > > ioctl(fd, UI_SET_PHYS_STR(strlen(name)), name);
> > > >
> > > > For me the old ioctl API looks easier to use (no need for strlen() or
> > > > extra variable), but this is just my preference of usage -- as it is
> > > > simpler for me. Maybe you would have different opinion...
> > > >
> > > > And now question: Why we have uinput_compat_ioctl()? It is there only
> > > > because size part of IOCTL number is different on 32bit and 64bit
> > > > systems. As we know size part of UI_SET_PHYS is wrong and does not make
> > > > sense...
> > > >
> > > > Would not it be better to change size of UI_SET_PHYS to just zero and
> > > > then when matching ioctl number just ignore size for this UI_SET_PHYS
> > > > ioctl? Same for UI_BEGIN_FF_UPLOAD_COMPAT and UI_END_FF_UPLOAD_COMPAT
> > > > added in: https://git.kernel.org/tip/tip/c/7c7da40
> > > >
> > > > And we would not have to deal with uinput_compat_ioctl() at all.
> > >
> > > Below is example how change for removing UI_SET_PHYS_COMPAT may look
> > > like. As header file is not changed and UI_SET_PHYS accepts any size
> > > argument, it therefore accept also 32bit and 64bit integer. So no
> > > existing 32bit applications which use UI_SET_PHYS on 64bit kernel would
> > > not be broken...
> > >
> > > Is not this better change then introducing a new UI_SET_PHYS_STR ioctl
> > > number? Because introduction of new IOCTL number has one big
> > > disadvantage: Userspace applications needs to support fallback to old
> > > number as older versions of kernels would be in use for a long time. And
> > > because kernel does not have to remove old IOCTL number for backward
> > > compatibility there is basically no need for userspace application to
> > > user new UI_SET_PHYS_STR IOCTL number...
> >
> > Hello! I would like to remind this discussion as problem around a new
> > UI_SET_UNIQ ioctl is not solved yet and uniq property is really useful
> > for e.g. bluetooth (uinput) devices.
> >
> > Dmitry, when you have a time, could you please look at this discussion
> > and decide how to go ahead?
>
> Have we decided not to move further with these changes? I actually
> have a bug in BlueZ related to it since right now we are inconsistent
> with respect to how we handle uhid vs uinput:
>
> https://github.com/bluez/bluez/issues/352
>
> > > diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
> > > index fd253781b..b645210d5 100644
> > > --- a/drivers/input/misc/uinput.c
> > > +++ b/drivers/input/misc/uinput.c
> > > @@ -915,22 +915,6 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
> > > retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
> > > goto out;
> > >
> > > - case UI_SET_PHYS:
> > > - if (udev->state == UIST_CREATED) {
> > > - retval = -EINVAL;
> > > - goto out;
> > > - }
> > > -
> > > - phys = strndup_user(p, 1024);
> > > - if (IS_ERR(phys)) {
> > > - retval = PTR_ERR(phys);
> > > - goto out;
> > > - }
> > > -
> > > - kfree(udev->dev->phys);
> > > - udev->dev->phys = phys;
> > > - goto out;
> > > -
> > > case UI_BEGIN_FF_UPLOAD:
> > > retval = uinput_ff_upload_from_user(p, &ff_up);
> > > if (retval)
> > > @@ -1023,6 +1007,22 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
> > > case UI_ABS_SETUP & ~IOCSIZE_MASK:
> > > retval = uinput_abs_setup(udev, p, size);
> > > goto out;
> > > +
> > > + case UI_SET_PHYS & ~IOCSIZE_MASK:
> > > + if (udev->state == UIST_CREATED) {
> > > + retval = -EINVAL;
> > > + goto out;
> > > + }
> > > +
> > > + phys = strndup_user(p, 1024);
> > > + if (IS_ERR(phys)) {
> > > + retval = PTR_ERR(phys);
> > > + goto out;
> > > + }
> > > +
> > > + kfree(udev->dev->phys);
> > > + udev->dev->phys = phys;
> > > + goto out;
> > > }
> > >
> > > retval = -EINVAL;
> > > @@ -1042,8 +1042,6 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> > > * These IOCTLs change their size and thus their numbers between
> > > * 32 and 64 bits.
> > > */
> > > -#define UI_SET_PHYS_COMPAT \
> > > - _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t)
> > > #define UI_BEGIN_FF_UPLOAD_COMPAT \
> > > _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload_compat)
> > > #define UI_END_FF_UPLOAD_COMPAT \
> > > @@ -1053,9 +1051,6 @@ static long uinput_compat_ioctl(struct file *file,
> > > unsigned int cmd, unsigned long arg)
> > > {
> > > switch (cmd) {
> > > - case UI_SET_PHYS_COMPAT:
> > > - cmd = UI_SET_PHYS;
> > > - break;
> > > case UI_BEGIN_FF_UPLOAD_COMPAT:
> > > cmd = UI_BEGIN_FF_UPLOAD;
> > > break;
> > > diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
> > > index c9e677e3a..6bda2a142 100644
> > > --- a/include/uapi/linux/uinput.h
> > > +++ b/include/uapi/linux/uinput.h
> > > @@ -142,6 +142,8 @@ struct uinput_abs_setup {
> > > #define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
> > > #define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
> > > #define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
> > > +/* Argument is nul-term string and for backward compatibility is there
> > > + * specified char*, but size argument (char *) is ignored by this ioctl */
> > > #define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
> > > #define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
> > > #define UI_SET_PROPBIT _IOW(UINPUT_IOCTL_BASE, 110, int)
> > >
> > >
> >
> > --
> > Pali Rohár
> > pali.rohar@gmail.com
>
>
>
> --
> Luiz Augusto von Dentz
Hate to dig a post up from the dead, but I have a use case for this
ioctl just like the bluez team and would like to see if I can help
push it across the finish line.
Unlike this patch series mimicking what is done with the UI_SET_PHYS
ioctl, I'd like to simply have a fixed size of 64 characters allowed.
I'm choosing 64 because that's the same size as the uniq value in the
hid_device struct (specifically it's set as `char uniq[64]`).
Would such a specific limit be acceptable, and if so it shouldn't have
all the messy compatible bits like the proposed method here, would it?
Thank you,
Chris
^ permalink raw reply
* Re: [PATCH] Input: uinput - Add UI_SET_UNIQ ioctl handler
From: Pali Rohár @ 2024-02-06 17:44 UTC (permalink / raw)
To: Chris Morgan
Cc: Luiz Augusto von Dentz, Dmitry Torokhov, Abhishek Pandit-Subedi,
linux-input, Bluez mailing list, Enric Balletbo i Serra, LKML,
Thomas Gleixner, Logan Gunthorpe, Andrey Smirnov, Kirill Smelkov
In-Reply-To: <65c2699a.4a0a0220.5cd9c.2ff7@mx.google.com>
On Tuesday 06 February 2024 11:17:12 Chris Morgan wrote:
> On Mon, Jun 13, 2022 at 02:36:18PM -0700, Luiz Augusto von Dentz wrote:
> > Hi,
> >
> > On Sun, Mar 22, 2020 at 8:47 AM Pali Rohár <pali.rohar@gmail.com> wrote:
> > >
> > > On Wednesday 18 December 2019 12:26:59 Pali Rohár wrote:
> > > > On Wednesday 18 December 2019 12:02:24 Pali Rohár wrote:
> > > > > On Friday 06 December 2019 09:40:48 Dmitry Torokhov wrote:
> > > > > > On Fri, Dec 06, 2019 at 10:11:14AM +0100, Pali Rohár wrote:
> > > > > > > On Thursday 05 December 2019 12:03:05 Abhishek Pandit-Subedi wrote:
> > > > > > > > On Thu, Dec 5, 2019 at 2:52 AM Pali Rohár <pali.rohar@gmail.com> wrote:
> > > > > > > > >
> > > > > > > > > On Tuesday 03 December 2019 11:11:12 Dmitry Torokhov wrote:
> > > > > > > > > > On Tue, Dec 03, 2019 at 06:38:21PM +0100, Pali Rohár wrote:
> > > > > > > > > > > On Tuesday 03 December 2019 00:09:47 Pali Rohár wrote:
> > > > > > > > > > >
> > > > > > > > > > > Hi Dmitry!
> > > > > > > > > > >
> > > > > > > > > > > I was looking again at those _IOW defines for ioctl calls and I have
> > > > > > > > > > > another argument why not specify 'char *' in _IOW:
> > > > > > > > > > >
> > > > > > > > > > > All ioctls in _IOW() specify as a third macro argument type which is
> > > > > > > > > > > passed as pointer to the third argument for ioctl() syscall.
> > > > > > > > > > >
> > > > > > > > > > > So e.g.:
> > > > > > > > > > >
> > > > > > > > > > > #define EVIOCSCLOCKID _IOW('E', 0xa0, int)
> > > > > > > > > > >
> > > > > > > > > > > is called from userspace as:
> > > > > > > > > > >
> > > > > > > > > > > int val;
> > > > > > > > > > > ioctl(fd, EVIOCSCLOCKID, &val);
> > > > > > > > > > >
> > > > > > > > > > > Or
> > > > > > > > > > >
> > > > > > > > > > > #define EVIOCSMASK _IOW('E', 0x93, struct input_mask)
> > > > > > > > > > >
> > > > > > > > > > > is called as:
> > > > > > > > > > >
> > > > > > > > > > > struct input_mask val;
> > > > > > > > > > > ioctl(fd, EVIOCSMASK, &val);
> > > > > > > > > > >
> > > > > > > > > > > So basically third argument for _IOW specify size of byte buffer passed
> > > > > > > > > > > as third argument for ioctl(). In _IOW is not specified pointer to
> > > > > > > > > > > struct input_mask, but struct input_mask itself.
> > > > > > > > > > >
> > > > > > > > > > > And in case you define
> > > > > > > > > > >
> > > > > > > > > > > #define MY_NEW_IOCTL _IOW(UINPUT_IOCTL_BASE, 200, char*)
> > > > > > > > > > >
> > > > > > > > > > > then you by above usage you should pass data as:
> > > > > > > > > > >
> > > > > > > > > > > char *val = "DATA";
> > > > > > > > > > > ioctl(fd, MY_NEW_IOCTL, &val);
> > > > > > > > > > >
> > > > > > > > > > > Which is not same as just:
> > > > > > > > > > >
> > > > > > > > > > > ioctl(fd, MY_NEW_IOCTL, "DATA");
> > > > > > > > > > >
> > > > > > > > > > > As in former case you passed pointer to pointer to data and in later
> > > > > > > > > > > case you passed only pointer to data.
> > > > > > > > > > >
> > > > > > > > > > > It just mean that UI_SET_PHYS is already defined inconsistently which is
> > > > > > > > > > > also reason why compat ioctl for it was introduced.
> > > > > > > > > >
> > > > > > > > > > Yes, you are right. UI_SET_PHYS is messed up. I guess the question is
> > > > > > > > > > what to do with all of this...
> > > > > > > > > >
> > > > > > > > > > Maybe we should define
> > > > > > > > > >
> > > > > > > > > > #define UI_SET_PHYS_STR(len) _IOC(_IOC_WRITE, UINPUT_IOCTL_BASE, 111, len)
> > > > > > > > > > #define UI_SET_UNIQ_STR(len) _IOC(_IOC_WRITE, UINPUT_IOCTL_BASE, 112, len)
> > > > > > > > >
> > > > > > > > > I'm not sure if this is ideal. Normally in C strings are nul-termined,
> > > > > > > > > so functions/macros do not take buffer length.
> > > > > > > > Except strncpy, strndup, snprintf, etc. all expect a buffer length. At
> > > > > > >
> > > > > > > This is something different as for these functions you pass buffer and
> > > > > > > length of buffer which is used in write mode -- not for read mode.
> > > > > > >
> > > > > > > > the user to kernel boundary of ioctl, I think we should require size
> > > > > > > > of the user buffer regardless of the data type.
> > > > > > > >
> > > > > > > > > _STR therefore in names looks inconsistent.
> > > > > > > > The _STR suffix is odd (what to name UI_SET_PHYS_STR then??) but
> > > > > > > > requiring the length seems to be common across various ioctls.
> > > > > > > > * input.h requires a length when requesting the phys and uniq
> > > > > > > > (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input.h#n138)
> > > > > > > > * Same with HIDRAW when setting and getting features:
> > > > > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/hidraw.h#n40,
> > > > > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/hidraw/hid-example.c#n88
> > > > > > >
> > > > > > > All these ioctls where is passed length are in opposite direction
> > > > > > > (_IOC_READ) as our PHYS and UNIQ (_IOC_WRITE).
> > > > > > >
> > > > > > > I fully agree that when you need to read something from kernel
> > > > > > > (_IOC_READ) and then writing it to userspace, you need to specify length
> > > > > > > of userspace buffer. Exactly same as with userspace functions like
> > > > > > > memcpy, snprintf, etc... as you pointed. Otherwise you get buffer
> > > > > > > overflow as callee does not know length of buffer.
> > > > > > >
> > > > > > > But here we we have there quite different problem, we need to write
> > > > > > > something to kernel from userspace (_IOC_WRITE) and we are passing
> > > > > > > nul-term string. So in this case specifying size is not required as it
> > > > > > > is implicitly specified as part of passed string.
> > > > > >
> > > > > > With the new IOCTL definitions it does not need to be a NULL-terminated
> > > > > > string. It can be a buffer of characters with given length, and kernel
> > > > > > will NULL-terminate as this it what it wants, not what the caller has to
> > > > > > give.
> > > > >
> > > > > Hi Dmitry! I was thinking more about this problem and I will propose
> > > > > alternative solution, but first with details...
> > > > >
> > > > > I think that we should use NULL terminated strings. Or better disallow
> > > > > NULL byte inside string. Reason: all userspace application expects that
> > > > > input device name would be NULL terminated which implies that in the
> > > > > middle of name cannot be NULL byte.
> > > > >
> > > > > So this must apply also for new PHYS / UNIQ ioctl API. If we want in our
> > > > > ioctl API to use buffer + size (with upper bound limit for size) instead
> > > > > of passing NULL term string (with upper bound limit for string size)
> > > > > then kernel have to add a leading NULL byte to string, plus check that
> > > > > in the buffer there is no NULL byte. I guess this a very little
> > > > > complicate code, but nothing which is problematic.
> > > > >
> > > > > And on the userspace part. Now when userspace want to pass constant
> > > > > string for device name, it just call
> > > > >
> > > > > ioctl(fd, UI_SET_PHYS, "my name of device");
> > > > >
> > > > > After adding a new ioctl with buffer + size API, userspace would have to
> > > > > call:
> > > > >
> > > > > ioctl(fd, UI_SET_PHYS_STR(strlen("my name of device")), "my name of device");
> > > > >
> > > > > which looks strange, so programmers would had to move device name into
> > > > > new variable:
> > > > >
> > > > > const char *name = "my name of device";
> > > > > ioctl(fd, UI_SET_PHYS_STR(strlen(name)), name);
> > > > >
> > > > > For me the old ioctl API looks easier to use (no need for strlen() or
> > > > > extra variable), but this is just my preference of usage -- as it is
> > > > > simpler for me. Maybe you would have different opinion...
> > > > >
> > > > > And now question: Why we have uinput_compat_ioctl()? It is there only
> > > > > because size part of IOCTL number is different on 32bit and 64bit
> > > > > systems. As we know size part of UI_SET_PHYS is wrong and does not make
> > > > > sense...
> > > > >
> > > > > Would not it be better to change size of UI_SET_PHYS to just zero and
> > > > > then when matching ioctl number just ignore size for this UI_SET_PHYS
> > > > > ioctl? Same for UI_BEGIN_FF_UPLOAD_COMPAT and UI_END_FF_UPLOAD_COMPAT
> > > > > added in: https://git.kernel.org/tip/tip/c/7c7da40
> > > > >
> > > > > And we would not have to deal with uinput_compat_ioctl() at all.
> > > >
> > > > Below is example how change for removing UI_SET_PHYS_COMPAT may look
> > > > like. As header file is not changed and UI_SET_PHYS accepts any size
> > > > argument, it therefore accept also 32bit and 64bit integer. So no
> > > > existing 32bit applications which use UI_SET_PHYS on 64bit kernel would
> > > > not be broken...
> > > >
> > > > Is not this better change then introducing a new UI_SET_PHYS_STR ioctl
> > > > number? Because introduction of new IOCTL number has one big
> > > > disadvantage: Userspace applications needs to support fallback to old
> > > > number as older versions of kernels would be in use for a long time. And
> > > > because kernel does not have to remove old IOCTL number for backward
> > > > compatibility there is basically no need for userspace application to
> > > > user new UI_SET_PHYS_STR IOCTL number...
> > >
> > > Hello! I would like to remind this discussion as problem around a new
> > > UI_SET_UNIQ ioctl is not solved yet and uniq property is really useful
> > > for e.g. bluetooth (uinput) devices.
> > >
> > > Dmitry, when you have a time, could you please look at this discussion
> > > and decide how to go ahead?
> >
> > Have we decided not to move further with these changes? I actually
> > have a bug in BlueZ related to it since right now we are inconsistent
> > with respect to how we handle uhid vs uinput:
> >
> > https://github.com/bluez/bluez/issues/352
> >
> > > > diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
> > > > index fd253781b..b645210d5 100644
> > > > --- a/drivers/input/misc/uinput.c
> > > > +++ b/drivers/input/misc/uinput.c
> > > > @@ -915,22 +915,6 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
> > > > retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
> > > > goto out;
> > > >
> > > > - case UI_SET_PHYS:
> > > > - if (udev->state == UIST_CREATED) {
> > > > - retval = -EINVAL;
> > > > - goto out;
> > > > - }
> > > > -
> > > > - phys = strndup_user(p, 1024);
> > > > - if (IS_ERR(phys)) {
> > > > - retval = PTR_ERR(phys);
> > > > - goto out;
> > > > - }
> > > > -
> > > > - kfree(udev->dev->phys);
> > > > - udev->dev->phys = phys;
> > > > - goto out;
> > > > -
> > > > case UI_BEGIN_FF_UPLOAD:
> > > > retval = uinput_ff_upload_from_user(p, &ff_up);
> > > > if (retval)
> > > > @@ -1023,6 +1007,22 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
> > > > case UI_ABS_SETUP & ~IOCSIZE_MASK:
> > > > retval = uinput_abs_setup(udev, p, size);
> > > > goto out;
> > > > +
> > > > + case UI_SET_PHYS & ~IOCSIZE_MASK:
> > > > + if (udev->state == UIST_CREATED) {
> > > > + retval = -EINVAL;
> > > > + goto out;
> > > > + }
> > > > +
> > > > + phys = strndup_user(p, 1024);
> > > > + if (IS_ERR(phys)) {
> > > > + retval = PTR_ERR(phys);
> > > > + goto out;
> > > > + }
> > > > +
> > > > + kfree(udev->dev->phys);
> > > > + udev->dev->phys = phys;
> > > > + goto out;
> > > > }
> > > >
> > > > retval = -EINVAL;
> > > > @@ -1042,8 +1042,6 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> > > > * These IOCTLs change their size and thus their numbers between
> > > > * 32 and 64 bits.
> > > > */
> > > > -#define UI_SET_PHYS_COMPAT \
> > > > - _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t)
> > > > #define UI_BEGIN_FF_UPLOAD_COMPAT \
> > > > _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload_compat)
> > > > #define UI_END_FF_UPLOAD_COMPAT \
> > > > @@ -1053,9 +1051,6 @@ static long uinput_compat_ioctl(struct file *file,
> > > > unsigned int cmd, unsigned long arg)
> > > > {
> > > > switch (cmd) {
> > > > - case UI_SET_PHYS_COMPAT:
> > > > - cmd = UI_SET_PHYS;
> > > > - break;
> > > > case UI_BEGIN_FF_UPLOAD_COMPAT:
> > > > cmd = UI_BEGIN_FF_UPLOAD;
> > > > break;
> > > > diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
> > > > index c9e677e3a..6bda2a142 100644
> > > > --- a/include/uapi/linux/uinput.h
> > > > +++ b/include/uapi/linux/uinput.h
> > > > @@ -142,6 +142,8 @@ struct uinput_abs_setup {
> > > > #define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
> > > > #define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
> > > > #define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
> > > > +/* Argument is nul-term string and for backward compatibility is there
> > > > + * specified char*, but size argument (char *) is ignored by this ioctl */
> > > > #define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
> > > > #define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
> > > > #define UI_SET_PROPBIT _IOW(UINPUT_IOCTL_BASE, 110, int)
> > > >
> > > >
> > >
> > > --
> > > Pali Rohár
> > > pali.rohar@gmail.com
> >
> >
> >
> > --
> > Luiz Augusto von Dentz
>
> Hate to dig a post up from the dead, but I have a use case for this
> ioctl just like the bluez team and would like to see if I can help
> push it across the finish line.
>
> Unlike this patch series mimicking what is done with the UI_SET_PHYS
> ioctl, I'd like to simply have a fixed size of 64 characters allowed.
> I'm choosing 64 because that's the same size as the uniq value in the
> hid_device struct (specifically it's set as `char uniq[64]`).
>
> Would such a specific limit be acceptable, and if so it shouldn't have
> all the messy compatible bits like the proposed method here, would it?
>
> Thank you,
> Chris
In email <20191218112659.crabhqkbcnxd6fo6@pali> (quoted above) I sent a
patch proposal for this issue. But nobody reacted for it yet.
^ permalink raw reply
* [dtor-input:next] BUILD SUCCESS a0835e67031d9dc27eac7355243aefa2702ffbc3
From: kernel test robot @ 2024-02-06 20:42 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
branch HEAD: a0835e67031d9dc27eac7355243aefa2702ffbc3 input: gameport: make gameport_bus const
elapsed time: 1507m
configs tested: 236
configs skipped: 3
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc
alpha allyesconfig gcc
alpha defconfig gcc
arc alldefconfig gcc
arc allmodconfig gcc
arc allnoconfig gcc
arc allyesconfig gcc
arc defconfig gcc
arc haps_hs_smp_defconfig gcc
arc hsdk_defconfig gcc
arc randconfig-001-20240206 gcc
arc randconfig-001-20240207 gcc
arc randconfig-002-20240206 gcc
arc randconfig-002-20240207 gcc
arc tb10x_defconfig gcc
arm allmodconfig gcc
arm allnoconfig clang
arm allyesconfig gcc
arm aspeed_g5_defconfig gcc
arm collie_defconfig gcc
arm defconfig clang
arm mmp2_defconfig gcc
arm mvebu_v5_defconfig gcc
arm neponset_defconfig gcc
arm randconfig-002-20240206 gcc
arm randconfig-003-20240206 gcc
arm randconfig-004-20240207 gcc
arm sp7021_defconfig gcc
arm spitz_defconfig gcc
arm64 allmodconfig clang
arm64 allnoconfig gcc
arm64 defconfig gcc
arm64 randconfig-001-20240206 gcc
arm64 randconfig-003-20240206 gcc
arm64 randconfig-004-20240206 gcc
csky allmodconfig gcc
csky allnoconfig gcc
csky allyesconfig gcc
csky defconfig gcc
csky randconfig-001-20240206 gcc
csky randconfig-001-20240207 gcc
csky randconfig-002-20240206 gcc
csky randconfig-002-20240207 gcc
hexagon allmodconfig clang
hexagon allnoconfig clang
hexagon allyesconfig clang
hexagon defconfig clang
i386 allmodconfig gcc
i386 allnoconfig gcc
i386 allyesconfig gcc
i386 buildonly-randconfig-001-20240206 clang
i386 buildonly-randconfig-002-20240206 clang
i386 buildonly-randconfig-003-20240206 gcc
i386 buildonly-randconfig-004-20240206 clang
i386 buildonly-randconfig-005-20240206 gcc
i386 buildonly-randconfig-006-20240206 gcc
i386 defconfig clang
i386 randconfig-001-20240206 clang
i386 randconfig-001-20240207 gcc
i386 randconfig-002-20240206 clang
i386 randconfig-003-20240206 clang
i386 randconfig-003-20240207 gcc
i386 randconfig-004-20240206 clang
i386 randconfig-004-20240207 gcc
i386 randconfig-005-20240206 clang
i386 randconfig-005-20240207 gcc
i386 randconfig-006-20240206 clang
i386 randconfig-011-20240206 clang
i386 randconfig-011-20240207 gcc
i386 randconfig-012-20240206 gcc
i386 randconfig-012-20240207 gcc
i386 randconfig-013-20240206 clang
i386 randconfig-013-20240207 gcc
i386 randconfig-014-20240206 gcc
i386 randconfig-014-20240207 gcc
i386 randconfig-015-20240206 gcc
i386 randconfig-015-20240207 gcc
i386 randconfig-016-20240206 gcc
i386 randconfig-016-20240207 gcc
loongarch allmodconfig gcc
loongarch allnoconfig gcc
loongarch allyesconfig gcc
loongarch defconfig gcc
loongarch randconfig-001-20240206 gcc
loongarch randconfig-001-20240207 gcc
loongarch randconfig-002-20240206 gcc
loongarch randconfig-002-20240207 gcc
m68k allmodconfig gcc
m68k allnoconfig gcc
m68k allyesconfig gcc
m68k atari_defconfig gcc
m68k defconfig gcc
m68k m5249evb_defconfig gcc
m68k mac_defconfig gcc
m68k mvme147_defconfig gcc
m68k mvme16x_defconfig gcc
m68k q40_defconfig gcc
microblaze allmodconfig gcc
microblaze allnoconfig gcc
microblaze allyesconfig gcc
microblaze defconfig gcc
mips allmodconfig gcc
mips allnoconfig gcc
mips allyesconfig gcc
mips cavium_octeon_defconfig gcc
mips decstation_defconfig gcc
mips decstation_r4k_defconfig gcc
mips fuloong2e_defconfig gcc
mips malta_defconfig gcc
mips malta_qemu_32r6_defconfig gcc
mips maltasmvp_defconfig gcc
mips maltaup_xpa_defconfig gcc
mips rs90_defconfig gcc
nios2 allmodconfig gcc
nios2 allnoconfig gcc
nios2 allyesconfig gcc
nios2 defconfig gcc
nios2 randconfig-001-20240206 gcc
nios2 randconfig-001-20240207 gcc
nios2 randconfig-002-20240206 gcc
nios2 randconfig-002-20240207 gcc
openrisc allmodconfig gcc
openrisc allnoconfig gcc
openrisc allyesconfig gcc
openrisc defconfig gcc
parisc allmodconfig gcc
parisc allnoconfig gcc
parisc allyesconfig gcc
parisc defconfig gcc
parisc generic-32bit_defconfig gcc
parisc randconfig-001-20240206 gcc
parisc randconfig-001-20240207 gcc
parisc randconfig-002-20240206 gcc
parisc randconfig-002-20240207 gcc
parisc64 defconfig gcc
powerpc allmodconfig gcc
powerpc allnoconfig gcc
powerpc allyesconfig clang
powerpc iss476-smp_defconfig gcc
powerpc microwatt_defconfig gcc
powerpc powernv_defconfig gcc
powerpc ppa8548_defconfig gcc
powerpc ppc64e_defconfig gcc
powerpc randconfig-002-20240206 gcc
powerpc randconfig-003-20240207 gcc
powerpc sam440ep_defconfig gcc
powerpc storcenter_defconfig gcc
powerpc walnut_defconfig gcc
powerpc wii_defconfig gcc
powerpc64 randconfig-001-20240206 gcc
powerpc64 randconfig-002-20240207 gcc
powerpc64 randconfig-003-20240206 gcc
powerpc64 randconfig-003-20240207 gcc
riscv alldefconfig gcc
riscv allmodconfig clang
riscv allnoconfig gcc
riscv allyesconfig clang
riscv defconfig clang
riscv randconfig-001-20240206 gcc
riscv randconfig-002-20240207 gcc
riscv rv32_defconfig clang
s390 allmodconfig clang
s390 allnoconfig clang
s390 allyesconfig gcc
s390 defconfig clang
s390 randconfig-001-20240207 gcc
s390 randconfig-002-20240207 gcc
sh allmodconfig gcc
sh allnoconfig gcc
sh allyesconfig gcc
sh defconfig gcc
sh kfr2r09_defconfig gcc
sh randconfig-001-20240206 gcc
sh randconfig-001-20240207 gcc
sh randconfig-002-20240206 gcc
sh randconfig-002-20240207 gcc
sh rsk7201_defconfig gcc
sh sdk7780_defconfig gcc
sh se7722_defconfig gcc
sh sh2007_defconfig gcc
sh sh7770_generic_defconfig gcc
sparc allmodconfig gcc
sparc allnoconfig gcc
sparc allyesconfig gcc
sparc defconfig gcc
sparc64 allmodconfig gcc
sparc64 allyesconfig gcc
sparc64 defconfig gcc
sparc64 randconfig-001-20240206 gcc
sparc64 randconfig-001-20240207 gcc
sparc64 randconfig-002-20240206 gcc
sparc64 randconfig-002-20240207 gcc
um allmodconfig clang
um allnoconfig clang
um allyesconfig gcc
um defconfig clang
um randconfig-002-20240206 gcc
um randconfig-002-20240207 gcc
um x86_64_defconfig clang
x86_64 allnoconfig clang
x86_64 allyesconfig clang
x86_64 buildonly-randconfig-001-20240206 gcc
x86_64 buildonly-randconfig-002-20240206 clang
x86_64 buildonly-randconfig-003-20240206 gcc
x86_64 buildonly-randconfig-004-20240206 gcc
x86_64 buildonly-randconfig-005-20240206 gcc
x86_64 buildonly-randconfig-006-20240206 gcc
x86_64 defconfig gcc
x86_64 randconfig-001-20240206 clang
x86_64 randconfig-002-20240206 clang
x86_64 randconfig-003-20240206 gcc
x86_64 randconfig-004-20240206 gcc
x86_64 randconfig-005-20240206 gcc
x86_64 randconfig-006-20240206 clang
x86_64 randconfig-011-20240206 gcc
x86_64 randconfig-012-20240206 clang
x86_64 randconfig-013-20240206 gcc
x86_64 randconfig-014-20240206 clang
x86_64 randconfig-015-20240206 gcc
x86_64 randconfig-016-20240206 clang
x86_64 randconfig-071-20240206 gcc
x86_64 randconfig-072-20240206 gcc
x86_64 randconfig-073-20240206 gcc
x86_64 randconfig-074-20240206 gcc
x86_64 randconfig-075-20240206 clang
x86_64 randconfig-076-20240206 gcc
x86_64 rhel-8.3-rust clang
x86_64 rhel-8.3 gcc
xtensa alldefconfig gcc
xtensa allnoconfig gcc
xtensa allyesconfig gcc
xtensa randconfig-001-20240206 gcc
xtensa randconfig-001-20240207 gcc
xtensa randconfig-002-20240206 gcc
xtensa randconfig-002-20240207 gcc
xtensa virt_defconfig gcc
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] Input: psmouse - add resync_on_resume dmi check
From: Dmitry Torokhov @ 2024-02-06 22:04 UTC (permalink / raw)
To: Jonathan Denose
Cc: LKML, jefferymiller, Jonathan Denose, Raul Rangel, linux-input
In-Reply-To: <20231102075243.1.Idb37ff8043a29f607beab6440c32b9ae52525825@changeid>
Hi Jonathan,
On Thu, Nov 02, 2023 at 07:52:47AM -0500, Jonathan Denose wrote:
> Some elantech touchpads consistently fail after resuming from
> suspend at sanity_check in elantech_packet_check_v4. This means
> the touchpad is completely unusable after suspend resume.
>
> With different permutations of i8042 nomux, nopnp, reset, and noloop
> kernel options enabled, and with crc_enabled the touchpad fails in
> the same way.
>
> Resyncing the touchpad after receiving the
> PACKET_UNKNOWN/PSMOUSE_BAD_DATA return code allows the touchpad to
> function correctly on resume. The touchpad fails to reconnect with
> the serio reconnect no matter how many times it retries, so this
> change skips over that retry sequence and goes directly to resync.
Why can't we do this in elantech_reconnect()? I am sure we can make it
simpler and more robust than what the generic handler is trying to do
with polling and everything.
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCH v6 0/5] Add support for CS40L50
From: James Ogletree @ 2024-02-07 0:36 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt, lee,
broonie, jeff
Cc: patches, linux-sound, linux-input, devicetree, James Ogletree
Changes in v6:
- Updated write sequencer interface to be control-name based
- Fix 1. a race condition and 2. non-handling of repeats in playback callback
- Stylistic and logical improvements all around
Changes in v5:
- Added a codec sub-device to support I2S streaming
- Moved write sequencer code from cirrus_haptics to cs_dsp
- Reverted cirrus_haptics library; future Cirrus input
drivers will export and utilize cs40l50_vibra functions
- Added more comments
- Many small stylistic and logical improvements
Changes in v4:
- Moved from Input to MFD
- Moved common Cirrus haptic functions to a library
- Incorporated runtime PM framework
- Many style improvements
Changes in v3:
- YAML formatting corrections
- Fixed typo in MAINTAINERS
- Used generic node name "haptic-driver"
- Fixed probe error code paths
- Switched to "sizeof(*)"
- Removed tree reference in MAINTAINERS
Changes in v2:
- Fixed checkpatch warnings
James Ogletree (5):
firmware: cs_dsp: Add write sequencer interface
dt-bindings: input: cirrus,cs40l50: Add initial DT binding
mfd: cs40l50: Add support for CS40L50 core driver
Input: cs40l50 - Add support for the CS40L50 haptic driver
ASoC: cs40l50: Support I2S streaming to CS40L50
.../bindings/input/cirrus,cs40l50.yaml | 70 +++
MAINTAINERS | 12 +
drivers/firmware/cirrus/cs_dsp.c | 263 ++++++++
drivers/input/misc/Kconfig | 10 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/cs40l50-vibra.c | 571 ++++++++++++++++++
drivers/mfd/Kconfig | 30 +
drivers/mfd/Makefile | 3 +
drivers/mfd/cs40l50-core.c | 537 ++++++++++++++++
drivers/mfd/cs40l50-i2c.c | 69 +++
drivers/mfd/cs40l50-spi.c | 69 +++
include/linux/firmware/cirrus/cs_dsp.h | 29 +
include/linux/mfd/cs40l50.h | 134 ++++
sound/soc/codecs/Kconfig | 11 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/cs40l50-codec.c | 311 ++++++++++
16 files changed, 2122 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml
create mode 100644 drivers/input/misc/cs40l50-vibra.c
create mode 100644 drivers/mfd/cs40l50-core.c
create mode 100644 drivers/mfd/cs40l50-i2c.c
create mode 100644 drivers/mfd/cs40l50-spi.c
create mode 100644 include/linux/mfd/cs40l50.h
create mode 100644 sound/soc/codecs/cs40l50-codec.c
--
2.25.1
^ permalink raw reply
* [PATCH v6 2/5] dt-bindings: input: cirrus,cs40l50: Add initial DT binding
From: James Ogletree @ 2024-02-07 0:36 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt, lee,
broonie, jeff
Cc: patches, linux-sound, linux-input, devicetree, James Ogletree,
Krzysztof Kozlowski
In-Reply-To: <20240207003612.4187370-1-jogletre@opensource.cirrus.com>
The CS40L50 is a haptic driver with waveform memory,
integrated DSP, and closed-loop algorithms.
Add a YAML DT binding document for this device.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: James Ogletree <jogletre@opensource.cirrus.com>
---
.../bindings/input/cirrus,cs40l50.yaml | 70 +++++++++++++++++++
MAINTAINERS | 8 +++
2 files changed, 78 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml
diff --git a/Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml b/Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml
new file mode 100644
index 000000000000..6a5bdafed56b
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/cirrus,cs40l50.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus Logic CS40L50 Advanced Haptic Driver
+
+maintainers:
+ - James Ogletree <james.ogletree@cirrus.com>
+
+description:
+ CS40L50 is a haptic driver with waveform memory,
+ integrated DSP, and closed-loop algorithms.
+
+properties:
+ compatible:
+ enum:
+ - cirrus,cs40l50
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+ va-supply:
+ description: Power supply for internal analog circuits.
+
+ vp-supply:
+ description: Power supply for always-on circuits.
+
+ vio-supply:
+ description: Power supply for digital input/output.
+
+ vamp-supply:
+ description: Power supply for the Class D amplifier.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - reset-gpios
+ - vp-supply
+ - vio-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ haptic-driver@34 {
+ compatible = "cirrus,cs40l50";
+ reg = <0x34>;
+ interrupt-parent = <&gpio>;
+ interrupts = <113 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&gpio 112 GPIO_ACTIVE_LOW>;
+ vp-supply = <&vreg>;
+ vio-supply = <&vreg>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index dd5de540ec0b..b71017a187f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4933,6 +4933,14 @@ F: sound/pci/hda/cs*
F: sound/pci/hda/hda_cs_dsp_ctl.*
F: sound/soc/codecs/cs*
+CIRRUS LOGIC HAPTIC DRIVERS
+M: James Ogletree <james.ogletree@cirrus.com>
+M: Fred Treven <fred.treven@cirrus.com>
+M: Ben Bright <ben.bright@cirrus.com>
+L: patches@opensource.cirrus.com
+S: Supported
+F: Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml
+
CIRRUS LOGIC DSP FIRMWARE DRIVER
M: Simon Trimmer <simont@opensource.cirrus.com>
M: Charles Keepax <ckeepax@opensource.cirrus.com>
--
2.25.1
^ permalink raw reply related
* [PATCH v6 1/5] firmware: cs_dsp: Add write sequencer interface
From: James Ogletree @ 2024-02-07 0:36 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt, lee,
broonie, jeff
Cc: patches, linux-sound, linux-input, devicetree, James Ogletree
In-Reply-To: <20240207003612.4187370-1-jogletre@opensource.cirrus.com>
A write sequencer is a sequence of register addresses
and values executed by some Cirrus DSPs following
power state transitions.
Add support for Cirrus drivers to update or add to a
write sequencer present in firmware.
Signed-off-by: James Ogletree <jogletre@opensource.cirrus.com>
---
drivers/firmware/cirrus/cs_dsp.c | 263 +++++++++++++++++++++++++
include/linux/firmware/cirrus/cs_dsp.h | 29 +++
2 files changed, 292 insertions(+)
diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c
index 79d4254d1f9b..bf6aab16ddc4 100644
--- a/drivers/firmware/cirrus/cs_dsp.c
+++ b/drivers/firmware/cirrus/cs_dsp.c
@@ -275,6 +275,12 @@
#define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff
#define HALO_MPU_VIO_ERR_SRC_SHIFT 0
+/*
+ * Write Sequence
+ */
+#define WSEQ_OP_MAX_WORDS 3
+#define WSEQ_END_OF_SCRIPT 0xFFFFFF
+
struct cs_dsp_ops {
bool (*validate_version)(struct cs_dsp *dsp, unsigned int version);
unsigned int (*parse_sizes)(struct cs_dsp *dsp,
@@ -3339,6 +3345,263 @@ int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits)
}
EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_read, FW_CS_DSP);
+
+struct cs_dsp_wseq_op {
+ struct list_head list;
+ u32 address;
+ u32 data;
+ u16 offset;
+ u8 operation;
+};
+
+static int cs_dsp_populate_wseq(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq)
+{
+ struct cs_dsp_wseq_op *op = NULL;
+ struct cs_dsp_chunk ch;
+ u8 *words;
+ int ret;
+
+ if (!wseq->ctl) {
+ cs_dsp_err(dsp, "No control for write sequence\n");
+ return -EINVAL;
+ }
+
+ words = kzalloc(wseq->ctl->len, GFP_KERNEL);
+ if (!words)
+ return -ENOMEM;
+
+ ret = cs_dsp_coeff_read_ctrl(wseq->ctl, 0, words, wseq->ctl->len);
+ if (ret) {
+ cs_dsp_err(dsp, "Failed to read %s: %d\n", wseq->name, ret);
+ goto err_free;
+ }
+
+ INIT_LIST_HEAD(&wseq->ops);
+
+ ch = cs_dsp_chunk(words, wseq->ctl->len);
+
+ while (!cs_dsp_chunk_end(&ch)) {
+ op = devm_kzalloc(dsp->dev, sizeof(*op), GFP_KERNEL);
+ if (!op) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ op->offset = cs_dsp_chunk_bytes(&ch);
+ op->operation = cs_dsp_chunk_read(&ch, 8);
+
+ switch (op->operation) {
+ case CS_DSP_WSEQ_END:
+ op->data = WSEQ_END_OF_SCRIPT;
+ break;
+ case CS_DSP_WSEQ_UNLOCK:
+ op->data = cs_dsp_chunk_read(&ch, 16);
+ break;
+ case CS_DSP_WSEQ_ADDR8:
+ op->address = cs_dsp_chunk_read(&ch, 8);
+ op->data = cs_dsp_chunk_read(&ch, 32);
+ break;
+ case CS_DSP_WSEQ_H16:
+ case CS_DSP_WSEQ_L16:
+ op->address = cs_dsp_chunk_read(&ch, 24);
+ op->data = cs_dsp_chunk_read(&ch, 16);
+ break;
+ case CS_DSP_WSEQ_FULL:
+ op->address = cs_dsp_chunk_read(&ch, 32);
+ op->data = cs_dsp_chunk_read(&ch, 32);
+ break;
+ default:
+ ret = -EINVAL;
+ cs_dsp_err(dsp, "Unsupported op: %X\n", op->operation);
+ goto err_free;
+ }
+
+ list_add(&op->list, &wseq->ops);
+
+ if (op->operation == CS_DSP_WSEQ_END)
+ break;
+ }
+
+ if (op && op->operation != CS_DSP_WSEQ_END) {
+ cs_dsp_err(dsp, "Write sequence missing end terminator\n");
+ ret = -ENOENT;
+ }
+
+err_free:
+ kfree(words);
+
+ return ret;
+}
+
+/**
+ * cs_dsp_wseq_init() - Initialize write sequences contained within the loaded DSP firmware
+ * @dsp: Pointer to DSP structure
+ * @wseqs: List of write sequences to initialize
+ * @num_wseqs: Number of write sequences to initialize
+ *
+ * Return: Zero for success, a negative number on error.
+ */
+int cs_dsp_wseq_init(struct cs_dsp *dsp, struct cs_dsp_wseq *wseqs, unsigned int num_wseqs)
+{
+ int i, ret = 0;
+
+ mutex_lock(&dsp->pwr_lock);
+
+ for (i = 0; i < num_wseqs; i++) {
+ ret = cs_dsp_populate_wseq(dsp, &wseqs[i]);
+ if (ret)
+ break;
+ }
+
+ mutex_unlock(&dsp->pwr_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cs_dsp_wseq_init);
+
+static struct cs_dsp_wseq_op *cs_dsp_wseq_find_op(u32 addr, u8 op_code,
+ struct list_head *wseq_ops)
+{
+ struct cs_dsp_wseq_op *op;
+
+ list_for_each_entry(op, wseq_ops, list) {
+ if (op->operation == op_code && op->address == addr)
+ return op;
+ }
+
+ return NULL;
+}
+
+/**
+ * cs_dsp_wseq_write() - Add or update an entry in a write sequence
+ * @dsp: Pointer to a DSP structure
+ * @wseq: Write sequence to write to
+ * @addr: Address of the register to be written to
+ * @data: Data to be written
+ * @op_code: The type of operation of the new entry
+ * @update: If true, searches for the first entry in the write sequence with
+ * the same address and op_code, and replaces it. If false, creates a new entry
+ * at the tail.
+ *
+ * This function formats register address and value pairs into the format
+ * required for write sequence entries, and either updates or adds the
+ * new entry into the write sequence.
+ *
+ * Return: Zero for success, a negative number on error.
+ */
+int cs_dsp_wseq_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq,
+ u32 addr, u32 data, u8 op_code, bool update)
+{
+ struct cs_dsp_wseq_op *op_end, *op_new = NULL;
+ u32 words[WSEQ_OP_MAX_WORDS];
+ struct cs_dsp_chunk ch;
+ int new_op_size, ret;
+
+ if (update)
+ op_new = cs_dsp_wseq_find_op(addr, op_code, &wseq->ops);
+
+ /* If entry to update is not found, treat it as a new operation */
+ if (!op_new) {
+ op_end = cs_dsp_wseq_find_op(0, CS_DSP_WSEQ_END, &wseq->ops);
+ if (!op_end) {
+ cs_dsp_err(dsp, "Missing write sequence list terminator\n");
+ return -EINVAL;
+ }
+
+ op_new = devm_kzalloc(dsp->dev, sizeof(*op_new), GFP_KERNEL);
+ if (!op_new)
+ return -ENOMEM;
+
+ op_new->operation = op_code;
+ op_new->address = addr;
+ op_new->offset = op_end->offset;
+ update = false;
+ }
+
+ op_new->data = data;
+
+ ch = cs_dsp_chunk(words, sizeof(words));
+ cs_dsp_chunk_write(&ch, 8, op_new->operation);
+ switch (op_code) {
+ case CS_DSP_WSEQ_FULL:
+ cs_dsp_chunk_write(&ch, 32, op_new->address);
+ cs_dsp_chunk_write(&ch, 32, op_new->data);
+ break;
+ case CS_DSP_WSEQ_L16:
+ case CS_DSP_WSEQ_H16:
+ cs_dsp_chunk_write(&ch, 24, op_new->address);
+ cs_dsp_chunk_write(&ch, 16, op_new->data);
+ break;
+ default:
+ ret = -EINVAL;
+ cs_dsp_err(dsp, "Op code not supported: %X\n", op_code);
+ goto op_new_free;
+ }
+
+ new_op_size = cs_dsp_chunk_bytes(&ch);
+
+ if (!update) {
+ if (wseq->ctl->len - op_end->offset < new_op_size) {
+ cs_dsp_err(dsp, "Not enough memory in write sequence for entry\n");
+ ret = -ENOMEM;
+ goto op_new_free;
+ }
+
+ op_end->offset += new_op_size;
+
+ ret = cs_dsp_coeff_write_ctrl(wseq->ctl, op_end->offset / sizeof(u32),
+ &op_end->data, sizeof(u32));
+ if (ret)
+ goto op_new_free;
+
+ list_add(&op_new->list, &wseq->ops);
+ }
+
+ ret = cs_dsp_coeff_write_ctrl(wseq->ctl, op_new->offset / sizeof(u32),
+ words, new_op_size);
+ if (ret)
+ goto op_new_free;
+
+ return 0;
+
+op_new_free:
+ devm_kfree(dsp->dev, op_new);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cs_dsp_wseq_write);
+
+/**
+ * cs_dsp_wseq_multi_write() - Add or update multiple entries in the write sequence
+ * @dsp: Pointer to a DSP structure
+ * @wseq: Write sequence to write to
+ * @reg_seq: List of address-data pairs
+ * @num_regs: Number of address-data pairs
+ * @op_code: The types of operations of the new entries
+ * @update: If true, searches for the first entry in the write sequence with the same
+ * address and op code, and replaces it. If false, creates a new entry at the tail.
+ *
+ * This function calls cs_dsp_wseq_write() for multiple address-data pairs.
+ *
+ * Return: Zero for success, a negative number on error.
+ */
+int cs_dsp_wseq_multi_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq,
+ const struct reg_sequence *reg_seq, int num_regs,
+ u8 op_code, bool update)
+{
+ int ret, i;
+
+ for (i = 0; i < num_regs; i++) {
+ ret = cs_dsp_wseq_write(dsp, wseq, reg_seq[i].reg,
+ reg_seq[i].def, update, op_code);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cs_dsp_wseq_multi_write);
+
MODULE_DESCRIPTION("Cirrus Logic DSP Support");
MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
MODULE_LICENSE("GPL v2");
diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h
index 29cd11d5a3cf..8190f12d3620 100644
--- a/include/linux/firmware/cirrus/cs_dsp.h
+++ b/include/linux/firmware/cirrus/cs_dsp.h
@@ -42,6 +42,16 @@
#define CS_DSP_ACKED_CTL_MIN_VALUE 0
#define CS_DSP_ACKED_CTL_MAX_VALUE 0xFFFFFF
+/*
+ * Write sequence operation codes
+ */
+#define CS_DSP_WSEQ_FULL 0x00
+#define CS_DSP_WSEQ_ADDR8 0x02
+#define CS_DSP_WSEQ_L16 0x04
+#define CS_DSP_WSEQ_H16 0x05
+#define CS_DSP_WSEQ_UNLOCK 0xFD
+#define CS_DSP_WSEQ_END 0xFF
+
/**
* struct cs_dsp_region - Describes a logical memory region in DSP address space
* @type: Memory region type
@@ -255,6 +265,25 @@ struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp,
const char *cs_dsp_mem_region_name(unsigned int type);
+/**
+ * struct cs_dsp_wseq - Describes a write sequence
+ * @name: Name of cs_dsp control
+ * @ctl: Write sequence cs_dsp control
+ * @ops: Operations contained within this write sequence
+ */
+struct cs_dsp_wseq {
+ const char *name;
+ struct cs_dsp_coeff_ctl *ctl;
+ struct list_head ops;
+};
+
+int cs_dsp_wseq_init(struct cs_dsp *dsp, struct cs_dsp_wseq *wseqs, unsigned int num_wseqs);
+int cs_dsp_wseq_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq, u32 addr, u32 data,
+ u8 op_code, bool update);
+int cs_dsp_wseq_multi_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq,
+ const struct reg_sequence *reg_seq, int num_regs,
+ u8 op_code, bool update);
+
/**
* struct cs_dsp_chunk - Describes a buffer holding data formatted for the DSP
* @data: Pointer to underlying buffer memory
--
2.25.1
^ permalink raw reply related
* [PATCH v6 3/5] mfd: cs40l50: Add support for CS40L50 core driver
From: James Ogletree @ 2024-02-07 0:36 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt, lee,
broonie, jeff
Cc: patches, linux-sound, linux-input, devicetree, James Ogletree
In-Reply-To: <20240207003612.4187370-1-jogletre@opensource.cirrus.com>
Introduce support for Cirrus Logic Device CS40L50: a
haptic driver with waveform memory, integrated DSP,
and closed-loop algorithms.
The MFD component registers and initializes the device.
Signed-off-by: James Ogletree <jogletre@opensource.cirrus.com>
---
MAINTAINERS | 2 +
drivers/mfd/Kconfig | 30 ++
drivers/mfd/Makefile | 3 +
drivers/mfd/cs40l50-core.c | 537 ++++++++++++++++++++++++++++++++++++
drivers/mfd/cs40l50-i2c.c | 69 +++++
drivers/mfd/cs40l50-spi.c | 69 +++++
include/linux/mfd/cs40l50.h | 134 +++++++++
7 files changed, 844 insertions(+)
create mode 100644 drivers/mfd/cs40l50-core.c
create mode 100644 drivers/mfd/cs40l50-i2c.c
create mode 100644 drivers/mfd/cs40l50-spi.c
create mode 100644 include/linux/mfd/cs40l50.h
diff --git a/MAINTAINERS b/MAINTAINERS
index b71017a187f8..69a9e0a3b968 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4940,6 +4940,8 @@ M: Ben Bright <ben.bright@cirrus.com>
L: patches@opensource.cirrus.com
S: Supported
F: Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml
+F: drivers/mfd/cs40l*
+F: include/linux/mfd/cs40l*
CIRRUS LOGIC DSP FIRMWARE DRIVER
M: Simon Trimmer <simont@opensource.cirrus.com>
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 90ce58fd629e..5efab06a9a50 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -237,6 +237,36 @@ config MFD_CROS_EC_DEV
To compile this driver as a module, choose M here: the module will be
called cros-ec-dev.
+config MFD_CS40L50_CORE
+ tristate
+ select MFD_CORE
+ select FW_CS_DSP
+ select REGMAP_IRQ
+
+config MFD_CS40L50_I2C
+ tristate "Cirrus Logic CS40L50 (I2C)"
+ select REGMAP_I2C
+ select MFD_CS40L50_CORE
+ depends on I2C
+ help
+ Select this to support the Cirrus Logic CS40L50 Haptic
+ Driver over I2C.
+
+ This driver can be built as a module. If built as a module it will be
+ called "cs40l50-i2c".
+
+config MFD_CS40L50_SPI
+ tristate "Cirrus Logic CS40L50 (SPI)"
+ select REGMAP_SPI
+ select MFD_CS40L50_CORE
+ depends on SPI
+ help
+ Select this to support the Cirrus Logic CS40L50 Haptic
+ Driver over SPI.
+
+ This driver can be built as a module. If built as a module it will be
+ called "cs40l50-spi".
+
config MFD_CS42L43
tristate
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c66f07edcd0e..a7a0e50d83c3 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -13,6 +13,9 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o
obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o
obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o
+obj-$(CONFIG_MFD_CS40L50_CORE) += cs40l50-core.o
+obj-$(CONFIG_MFD_CS40L50_I2C) += cs40l50-i2c.o
+obj-$(CONFIG_MFD_CS40L50_SPI) += cs40l50-spi.o
obj-$(CONFIG_MFD_CS42L43) += cs42l43.o
obj-$(CONFIG_MFD_CS42L43_I2C) += cs42l43-i2c.o
obj-$(CONFIG_MFD_CS42L43_SDW) += cs42l43-sdw.o
diff --git a/drivers/mfd/cs40l50-core.c b/drivers/mfd/cs40l50-core.c
new file mode 100644
index 000000000000..22c16a273b7c
--- /dev/null
+++ b/drivers/mfd/cs40l50-core.c
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CS40L50 Advanced Haptic Driver with waveform memory,
+ * integrated DSP, and closed-loop algorithms
+ *
+ * Copyright 2024 Cirrus Logic, Inc.
+ *
+ * Author: James Ogletree <james.ogletree@cirrus.com>
+ */
+
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/firmware/cirrus/wmfw.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/cs40l50.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+static const struct mfd_cell cs40l50_devs[] = {
+ { .name = "cs40l50-codec", },
+ { .name = "cs40l50-vibra", },
+};
+
+const struct regmap_config cs40l50_regmap = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+EXPORT_SYMBOL_GPL(cs40l50_regmap);
+
+static const char * const cs40l50_supplies[] = {
+ "vp", "vio",
+};
+
+static const struct regmap_irq cs40l50_reg_irqs[] = {
+ REGMAP_IRQ_REG(CS40L50_DSP_QUEUE_IRQ, CS40L50_IRQ1_INT_2_OFFSET,
+ CS40L50_DSP_QUEUE_MASK),
+ REGMAP_IRQ_REG(CS40L50_AMP_SHORT_IRQ, CS40L50_IRQ1_INT_1_OFFSET,
+ CS40L50_AMP_SHORT_MASK),
+ REGMAP_IRQ_REG(CS40L50_TEMP_ERR_IRQ, CS40L50_IRQ1_INT_8_OFFSET,
+ CS40L50_TEMP_ERR_MASK),
+ REGMAP_IRQ_REG(CS40L50_BST_UVP_IRQ, CS40L50_IRQ1_INT_9_OFFSET,
+ CS40L50_BST_UVP_MASK),
+ REGMAP_IRQ_REG(CS40L50_BST_SHORT_IRQ, CS40L50_IRQ1_INT_9_OFFSET,
+ CS40L50_BST_SHORT_MASK),
+ REGMAP_IRQ_REG(CS40L50_BST_ILIMIT_IRQ, CS40L50_IRQ1_INT_9_OFFSET,
+ CS40L50_BST_ILIMIT_MASK),
+ REGMAP_IRQ_REG(CS40L50_UVLO_VDDBATT_IRQ, CS40L50_IRQ1_INT_10_OFFSET,
+ CS40L50_UVLO_VDDBATT_MASK),
+ REGMAP_IRQ_REG(CS40L50_GLOBAL_ERROR_IRQ, CS40L50_IRQ1_INT_18_OFFSET,
+ CS40L50_GLOBAL_ERROR_MASK),
+};
+
+static struct regmap_irq_chip cs40l50_irq_chip = {
+ .name = "CS40L50 IRQ Controller",
+
+ .status_base = CS40L50_IRQ1_INT_1,
+ .mask_base = CS40L50_IRQ1_MASK_1,
+ .ack_base = CS40L50_IRQ1_INT_1,
+ .num_regs = 22,
+
+ .irqs = cs40l50_reg_irqs,
+ .num_irqs = ARRAY_SIZE(cs40l50_reg_irqs),
+
+ .runtime_pm = true,
+};
+
+int cs40l50_dsp_write(struct device *dev, struct regmap *regmap, u32 val)
+{
+ int err, i;
+ u32 ack;
+
+ /* Device NAKs if exiting hibernation, so optionally retry here */
+ for (i = 0; i < CS40L50_DSP_TIMEOUT_COUNT; i++) {
+ err = regmap_write(regmap, CS40L50_DSP_QUEUE, val);
+ if (!err)
+ break;
+
+ usleep_range(CS40L50_DSP_POLL_US, CS40L50_DSP_POLL_US + 100);
+ }
+
+ /* If we never wrote, don't bother checking for ACK */
+ if (i == CS40L50_DSP_TIMEOUT_COUNT) {
+ dev_err(dev, "Timed out writing %#X to DSP: %d\n", val, err);
+ return err;
+ }
+
+ err = regmap_read_poll_timeout(regmap, CS40L50_DSP_QUEUE, ack, !ack,
+ CS40L50_DSP_POLL_US,
+ CS40L50_DSP_POLL_US * CS40L50_DSP_TIMEOUT_COUNT);
+ if (err)
+ dev_err(dev, "DSP did not ack %#X: %d\n", val, err);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(cs40l50_dsp_write);
+
+static const struct cs_dsp_region cs40l50_dsp_regions[] = {
+ { .type = WMFW_HALO_PM_PACKED, .base = CS40L50_PMEM_0 },
+ { .type = WMFW_HALO_XM_PACKED, .base = CS40L50_XMEM_PACKED_0 },
+ { .type = WMFW_HALO_YM_PACKED, .base = CS40L50_YMEM_PACKED_0 },
+ { .type = WMFW_ADSP2_XM, .base = CS40L50_XMEM_UNPACKED24_0 },
+ { .type = WMFW_ADSP2_YM, .base = CS40L50_YMEM_UNPACKED24_0 },
+};
+
+static void cs40l50_dsp_remove(void *data)
+{
+ cs_dsp_remove((struct cs_dsp *)data);
+}
+
+static const struct cs_dsp_client_ops cs40l50_client_ops;
+
+static int cs40l50_dsp_init(struct cs40l50 *cs40l50)
+{
+ int err;
+
+ cs40l50->dsp.num = 1;
+ cs40l50->dsp.type = WMFW_HALO;
+ cs40l50->dsp.dev = cs40l50->dev;
+ cs40l50->dsp.regmap = cs40l50->regmap;
+ cs40l50->dsp.base = CS40L50_CORE_BASE;
+ cs40l50->dsp.base_sysinfo = CS40L50_SYS_INFO_ID;
+ cs40l50->dsp.mem = cs40l50_dsp_regions;
+ cs40l50->dsp.num_mems = ARRAY_SIZE(cs40l50_dsp_regions);
+ cs40l50->dsp.no_core_startstop = true;
+ cs40l50->dsp.client_ops = &cs40l50_client_ops;
+
+ err = cs_dsp_halo_init(&cs40l50->dsp);
+ if (err)
+ return err;
+
+ return devm_add_action_or_reset(cs40l50->dev, cs40l50_dsp_remove,
+ &cs40l50->dsp);
+}
+
+struct cs40l50_irq {
+ const char *name;
+ int virq;
+};
+
+static struct cs40l50_irq cs40l50_irqs[] = {
+ { "DSP", },
+ { "Global", },
+ { "Boost UVLO", },
+ { "Boost current limit", },
+ { "Boost short", },
+ { "Boost undervolt", },
+ { "Overtemp", },
+ { "Amp short", },
+};
+
+static const struct reg_sequence cs40l50_err_rls[] = {
+ { CS40L50_ERR_RLS, CS40L50_GLOBAL_ERR_RLS_SET },
+ { CS40L50_ERR_RLS, CS40L50_GLOBAL_ERR_RLS_CLEAR },
+};
+
+static irqreturn_t cs40l50_hw_err(int irq, void *data)
+{
+ struct cs40l50 *cs40l50 = data;
+ int err = 0, i;
+
+ mutex_lock(&cs40l50->lock);
+
+ /* Log hardware interrupt and execute error release sequence */
+ for (i = 1; i < ARRAY_SIZE(cs40l50_irqs); i++) {
+ if (cs40l50_irqs[i].virq == irq) {
+ dev_err(cs40l50->dev, "%s error\n", cs40l50_irqs[i].name);
+ err = regmap_multi_reg_write(cs40l50->regmap, cs40l50_err_rls,
+ ARRAY_SIZE(cs40l50_err_rls));
+ goto exit;
+ }
+ }
+exit:
+ mutex_unlock(&cs40l50->lock);
+ return IRQ_RETVAL(!err);
+}
+
+static irqreturn_t cs40l50_dsp_queue(int irq, void *data)
+{
+ struct cs40l50 *cs40l50 = data;
+ u32 rd_ptr, val, wt_ptr;
+ int err = 0;
+
+ mutex_lock(&cs40l50->lock);
+
+ /* Read from DSP queue and update read pointer */
+ while (!err) {
+ err = regmap_read(cs40l50->regmap, CS40L50_DSP_QUEUE_WT, &wt_ptr);
+ if (err)
+ goto exit;
+
+ err = regmap_read(cs40l50->regmap, CS40L50_DSP_QUEUE_RD, &rd_ptr);
+ if (err)
+ goto exit;
+
+ /* Check if queue is empty */
+ if (wt_ptr == rd_ptr)
+ goto exit;
+
+ err = regmap_read(cs40l50->regmap, rd_ptr, &val);
+ if (err)
+ goto exit;
+
+ dev_dbg(cs40l50->dev, "DSP payload: %#X", val);
+
+ rd_ptr += sizeof(u32);
+
+ if (rd_ptr > CS40L50_DSP_QUEUE_END)
+ rd_ptr = CS40L50_DSP_QUEUE_BASE;
+
+ err = regmap_write(cs40l50->regmap, CS40L50_DSP_QUEUE_RD, rd_ptr);
+ if (err)
+ goto exit;
+ }
+exit:
+ mutex_unlock(&cs40l50->lock);
+
+ return IRQ_RETVAL(!err);
+}
+
+static int cs40l50_irq_init(struct cs40l50 *cs40l50)
+{
+ struct device *dev = cs40l50->dev;
+ int err, i, virq;
+
+ err = devm_regmap_add_irq_chip(dev, cs40l50->regmap, cs40l50->irq,
+ IRQF_ONESHOT | IRQF_SHARED, 0,
+ &cs40l50_irq_chip, &cs40l50->irq_data);
+ if (err) {
+ dev_err(dev, "Failed adding IRQ chip\n");
+ return err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cs40l50_irqs); i++) {
+ virq = regmap_irq_get_virq(cs40l50->irq_data, i);
+ if (virq < 0) {
+ dev_err(dev, "Failed getting %s\n", cs40l50_irqs[i].name);
+ return virq;
+ }
+
+ cs40l50_irqs[i].virq = virq;
+
+ /* Handle DSP and non-DSP interrupts separately */
+ err = devm_request_threaded_irq(dev, virq, NULL,
+ i ? cs40l50_hw_err : cs40l50_dsp_queue,
+ IRQF_ONESHOT | IRQF_SHARED,
+ cs40l50_irqs[i].name, cs40l50);
+ if (err) {
+ dev_err(dev, "Failed requesting %s IRQ\n", cs40l50_irqs[i].name);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static const struct reg_sequence cs40l50_stop_core[] = {
+ { CS40L50_CCM_CORE_CONTROL, CS40L50_CLOCK_DISABLE},
+ { CS40L50_RAM_INIT, CS40L50_RAM_INIT_FLAG},
+ { CS40L50_PWRMGT_CTL, CS40L50_MEM_RDY_HW},
+};
+
+static const struct reg_sequence cs40l50_internal_vamp_config[] = {
+ { CS40L50_BST_LPMODE_SEL, CS40L50_DCM_LOW_POWER },
+ { CS40L50_BLOCK_ENABLES2, CS40L50_OVERTEMP_WARN },
+};
+
+static const struct reg_sequence cs40l50_irq_mask_override[] = {
+ { CS40L50_IRQ1_MASK_2, CS40L50_IRQ_MASK_2_OVERRIDE },
+ { CS40L50_IRQ1_MASK_20, CS40L50_IRQ_MASK_20_OVERRIDE },
+};
+
+static void cs40l50_dsp_power_down(void *data)
+{
+ cs_dsp_power_down((struct cs_dsp *)data);
+}
+
+static int cs40l50_power_up_dsp(struct cs40l50 *cs40l50)
+{
+ int err;
+
+ mutex_lock(&cs40l50->lock);
+
+ /* Stop and resume core to load patch file */
+ err = regmap_multi_reg_write(cs40l50->regmap, cs40l50_stop_core,
+ ARRAY_SIZE(cs40l50_stop_core));
+ if (err)
+ goto err_mutex;
+
+ err = cs_dsp_power_up(&cs40l50->dsp, cs40l50->patch, "cs40l50.wmfw",
+ cs40l50->bin, "cs40l50.bin", "cs40l50");
+ if (err)
+ goto err_mutex;
+
+ err = devm_add_action_or_reset(cs40l50->dev, cs40l50_dsp_power_down,
+ &cs40l50->dsp);
+ if (err)
+ goto err_mutex;
+
+ err = regmap_write(cs40l50->regmap, CS40L50_CCM_CORE_CONTROL,
+ CS40L50_CLOCK_ENABLE);
+
+err_mutex:
+ mutex_unlock(&cs40l50->lock);
+
+ return err;
+}
+
+static struct cs_dsp_wseq cs40l50_wseqs[] = {
+ { "PM_PWR_ON_SEQ" },
+};
+
+static int cs40l50_configure_dsp(struct cs40l50 *cs40l50)
+{
+ u32 nwaves;
+ int err, i;
+
+ if (cs40l50->bin) {
+ /* Log number of effects if wavetable was loaded */
+ err = regmap_read(cs40l50->regmap, CS40L50_NUM_WAVES, &nwaves);
+ if (err)
+ return err;
+
+ dev_info(cs40l50->dev, "Loaded with %u effects\n", nwaves);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cs40l50_wseqs); i++) {
+ mutex_lock(&cs40l50->dsp.pwr_lock);
+ cs40l50_wseqs[i].ctl = cs_dsp_get_ctl(&cs40l50->dsp,
+ cs40l50_wseqs[i].name,
+ WMFW_ADSP2_XM,
+ CS40L50_PM_ALGO_ID);
+ mutex_unlock(&cs40l50->dsp.pwr_lock);
+ if (!cs40l50_wseqs[i].ctl) {
+ dev_err(cs40l50->dev, "No control: %s\n", cs40l50_wseqs[i].name);
+ return -ENOENT;
+ }
+ }
+
+ err = cs_dsp_wseq_init(&cs40l50->dsp, cs40l50_wseqs,
+ ARRAY_SIZE(cs40l50_wseqs));
+ if (err) {
+ dev_err(cs40l50->dev, "Failed to initialize write sequences\n");
+ return err;
+ }
+
+ /* Use internal V_AMP supply */
+ err = regmap_multi_reg_write(cs40l50->regmap, cs40l50_internal_vamp_config,
+ ARRAY_SIZE(cs40l50_internal_vamp_config));
+ if (err)
+ return err;
+
+ err = cs_dsp_wseq_multi_write(&cs40l50->dsp, &cs40l50_wseqs[0],
+ cs40l50_internal_vamp_config, CS_DSP_WSEQ_FULL,
+ ARRAY_SIZE(cs40l50_internal_vamp_config), false);
+ if (err)
+ return err;
+
+ /* Override firmware defaults for IRQ masks */
+ err = regmap_multi_reg_write(cs40l50->regmap, cs40l50_irq_mask_override,
+ ARRAY_SIZE(cs40l50_irq_mask_override));
+ if (err)
+ return err;
+
+ return cs_dsp_wseq_multi_write(&cs40l50->dsp, &cs40l50_wseqs[0],
+ cs40l50_irq_mask_override, CS_DSP_WSEQ_FULL,
+ ARRAY_SIZE(cs40l50_irq_mask_override), false);
+}
+
+static void cs40l50_start_dsp(const struct firmware *bin, void *context)
+{
+ struct cs40l50 *cs40l50 = context;
+ int err;
+
+ /* Wavetable is optional; power up DSP regardless */
+ cs40l50->bin = bin;
+
+ err = cs40l50_power_up_dsp(cs40l50);
+ if (err) {
+ dev_err(cs40l50->dev, "Failed to power up DSP: %d\n", err);
+ goto err_fw;
+ }
+
+ err = cs40l50_configure_dsp(cs40l50);
+ if (err)
+ dev_err(cs40l50->dev, "Failed to configure DSP: %d\n", err);
+
+ err = devm_mfd_add_devices(cs40l50->dev, PLATFORM_DEVID_NONE, cs40l50_devs,
+ ARRAY_SIZE(cs40l50_devs), NULL, 0, NULL);
+ if (err)
+ dev_err(cs40l50->dev, "Failed to add sub devices: %d\n", err);
+
+err_fw:
+ release_firmware(cs40l50->bin);
+ release_firmware(cs40l50->patch);
+}
+
+static void cs40l50_request_patch(const struct firmware *patch, void *context)
+{
+ struct cs40l50 *cs40l50 = context;
+
+ if (!patch) {
+ dev_err(cs40l50->dev, "Failed to request patch file\n");
+ return;
+ }
+
+ cs40l50->patch = patch;
+
+ if (request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, CS40L50_WT,
+ cs40l50->dev, GFP_KERNEL, cs40l50,
+ cs40l50_start_dsp)) {
+ dev_err(cs40l50->dev, "Failed to request %s\n", CS40L50_WT);
+ release_firmware(cs40l50->patch);
+ }
+}
+
+static int cs40l50_get_model(struct cs40l50 *cs40l50)
+{
+ int err;
+
+ err = regmap_read(cs40l50->regmap, CS40L50_DEVID, &cs40l50->devid);
+ if (err)
+ return err;
+
+ if (cs40l50->devid != CS40L50_DEVID_A)
+ return -EINVAL;
+
+ err = regmap_read(cs40l50->regmap, CS40L50_REVID, &cs40l50->revid);
+ if (err)
+ return err;
+
+ if (cs40l50->revid < CS40L50_REVID_B0)
+ return -EINVAL;
+
+ dev_info(cs40l50->dev, "Cirrus Logic CS40L50 rev. %02X\n", cs40l50->revid);
+
+ return 0;
+}
+
+static int cs40l50_pm_runtime_setup(struct device *dev)
+{
+ int err;
+
+ pm_runtime_set_autosuspend_delay(dev, CS40L50_AUTOSUSPEND_MS);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_get_noresume(dev);
+ err = pm_runtime_set_active(dev);
+ if (err)
+ return err;
+
+ return devm_pm_runtime_enable(dev);
+}
+
+int cs40l50_probe(struct cs40l50 *cs40l50)
+{
+ struct device *dev = cs40l50->dev;
+ int err;
+
+ mutex_init(&cs40l50->lock);
+
+ cs40l50->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(cs40l50->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(cs40l50->reset_gpio),
+ "Failed getting reset GPIO\n");
+
+ err = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(cs40l50_supplies),
+ cs40l50_supplies);
+ if (err)
+ return dev_err_probe(dev, err, "Failed getting supplies\n");
+
+ /* Ensure minimum reset pulse width */
+ usleep_range(CS40L50_RESET_PULSE_US, CS40L50_RESET_PULSE_US + 100);
+
+ gpiod_set_value_cansleep(cs40l50->reset_gpio, 0);
+
+ /* Wait for control port to be ready */
+ usleep_range(CS40L50_CP_READY_US, CS40L50_CP_READY_US + 100);
+
+ err = cs40l50_dsp_init(cs40l50);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to initialize DSP\n");
+
+ err = cs40l50_pm_runtime_setup(dev);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to initialize runtime PM\n");
+
+ err = cs40l50_get_model(cs40l50);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to get part number\n");
+
+ err = cs40l50_irq_init(cs40l50);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to request IRQs\n");
+
+ err = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, CS40L50_FW,
+ dev, GFP_KERNEL, cs40l50, cs40l50_request_patch);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to request %s\n", CS40L50_FW);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cs40l50_probe);
+
+int cs40l50_remove(struct cs40l50 *cs40l50)
+{
+ gpiod_set_value_cansleep(cs40l50->reset_gpio, 1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cs40l50_remove);
+
+static int cs40l50_runtime_suspend(struct device *dev)
+{
+ struct cs40l50 *cs40l50 = dev_get_drvdata(dev);
+
+ return regmap_write(cs40l50->regmap, CS40L50_DSP_QUEUE, CS40L50_ALLOW_HIBER);
+}
+
+static int cs40l50_runtime_resume(struct device *dev)
+{
+ struct cs40l50 *cs40l50 = dev_get_drvdata(dev);
+
+ return cs40l50_dsp_write(dev, cs40l50->regmap, CS40L50_PREVENT_HIBER);
+}
+
+EXPORT_GPL_DEV_PM_OPS(cs40l50_pm_ops) = {
+ RUNTIME_PM_OPS(cs40l50_runtime_suspend, cs40l50_runtime_resume, NULL)
+};
+
+MODULE_DESCRIPTION("CS40L50 Advanced Haptic Driver");
+MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(FW_CS_DSP);
diff --git a/drivers/mfd/cs40l50-i2c.c b/drivers/mfd/cs40l50-i2c.c
new file mode 100644
index 000000000000..e18938dbddaa
--- /dev/null
+++ b/drivers/mfd/cs40l50-i2c.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CS40L50 Advanced Haptic Driver with waveform memory,
+ * integrated DSP, and closed-loop algorithms
+ *
+ * Copyright 2024 Cirrus Logic, Inc.
+ *
+ * Author: James Ogletree <james.ogletree@cirrus.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/mfd/cs40l50.h>
+
+static int cs40l50_i2c_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct cs40l50 *cs40l50;
+
+ cs40l50 = devm_kzalloc(dev, sizeof(*cs40l50), GFP_KERNEL);
+ if (!cs40l50)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, cs40l50);
+
+ cs40l50->regmap = devm_regmap_init_i2c(client, &cs40l50_regmap);
+ if (IS_ERR(cs40l50->regmap))
+ return dev_err_probe(cs40l50->dev, PTR_ERR(cs40l50->regmap),
+ "Failed to initialize register map\n");
+
+ cs40l50->dev = dev;
+ cs40l50->irq = client->irq;
+
+ return cs40l50_probe(cs40l50);
+}
+
+static void cs40l50_i2c_remove(struct i2c_client *client)
+{
+ struct cs40l50 *cs40l50 = i2c_get_clientdata(client);
+
+ cs40l50_remove(cs40l50);
+}
+
+static const struct i2c_device_id cs40l50_id_i2c[] = {
+ {"cs40l50"},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs40l50_id_i2c);
+
+static const struct of_device_id cs40l50_of_match[] = {
+ { .compatible = "cirrus,cs40l50" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cs40l50_of_match);
+
+static struct i2c_driver cs40l50_i2c_driver = {
+ .driver = {
+ .name = "cs40l50",
+ .of_match_table = cs40l50_of_match,
+ .pm = pm_ptr(&cs40l50_pm_ops),
+ },
+ .id_table = cs40l50_id_i2c,
+ .probe = cs40l50_i2c_probe,
+ .remove = cs40l50_i2c_remove,
+};
+module_i2c_driver(cs40l50_i2c_driver);
+
+MODULE_DESCRIPTION("CS40L50 I2C Driver");
+MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/cs40l50-spi.c b/drivers/mfd/cs40l50-spi.c
new file mode 100644
index 000000000000..9e18bb74eae0
--- /dev/null
+++ b/drivers/mfd/cs40l50-spi.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CS40L50 Advanced Haptic Driver with waveform memory,
+ * integrated DSP, and closed-loop algorithms
+ *
+ * Copyright 2024 Cirrus Logic, Inc.
+ *
+ * Author: James Ogletree <james.ogletree@cirrus.com>
+ */
+
+#include <linux/mfd/cs40l50.h>
+#include <linux/spi/spi.h>
+
+static int cs40l50_spi_probe(struct spi_device *spi)
+{
+ struct cs40l50 *cs40l50;
+ struct device *dev = &spi->dev;
+
+ cs40l50 = devm_kzalloc(dev, sizeof(*cs40l50), GFP_KERNEL);
+ if (!cs40l50)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, cs40l50);
+
+ cs40l50->regmap = devm_regmap_init_spi(spi, &cs40l50_regmap);
+ if (IS_ERR(cs40l50->regmap))
+ return dev_err_probe(cs40l50->dev, PTR_ERR(cs40l50->regmap),
+ "Failed to initialize register map\n");
+
+ cs40l50->dev = dev;
+ cs40l50->irq = spi->irq;
+
+ return cs40l50_probe(cs40l50);
+}
+
+static void cs40l50_spi_remove(struct spi_device *spi)
+{
+ struct cs40l50 *cs40l50 = spi_get_drvdata(spi);
+
+ cs40l50_remove(cs40l50);
+}
+
+static const struct spi_device_id cs40l50_id_spi[] = {
+ {"cs40l50"},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, cs40l50_id_spi);
+
+static const struct of_device_id cs40l50_of_match[] = {
+ { .compatible = "cirrus,cs40l50" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cs40l50_of_match);
+
+static struct spi_driver cs40l50_spi_driver = {
+ .driver = {
+ .name = "cs40l50",
+ .of_match_table = cs40l50_of_match,
+ .pm = pm_ptr(&cs40l50_pm_ops),
+ },
+ .id_table = cs40l50_id_spi,
+ .probe = cs40l50_spi_probe,
+ .remove = cs40l50_spi_remove,
+};
+module_spi_driver(cs40l50_spi_driver);
+
+MODULE_DESCRIPTION("CS40L50 SPI Driver");
+MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/cs40l50.h b/include/linux/mfd/cs40l50.h
new file mode 100644
index 000000000000..0e6240df6d1c
--- /dev/null
+++ b/include/linux/mfd/cs40l50.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * CS40L50 Advanced Haptic Driver with waveform memory,
+ * integrated DSP, and closed-loop algorithms
+ *
+ * Copyright 2024 Cirrus Logic, Inc.
+ *
+ * Author: James Ogletree <james.ogletree@cirrus.com>
+ */
+
+#ifndef __CS40L50_H__
+#define __CS40L50_H__
+
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/gpio/consumer.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+/* Power Supply Configuration */
+#define CS40L50_BLOCK_ENABLES2 0x201C
+#define CS40L50_ERR_RLS 0x2034
+#define CS40L50_PWRMGT_CTL 0x2900
+#define CS40L50_BST_LPMODE_SEL 0x3810
+#define CS40L50_DCM_LOW_POWER 0x1
+#define CS40L50_OVERTEMP_WARN 0x4000010
+
+/* Interrupts */
+#define CS40L50_IRQ1_INT_1 0xE010
+#define CS40L50_IRQ1_BASE CS40L50_IRQ1_INT_1
+#define CS40L50_IRQ1_INT_2 0xE014
+#define CS40L50_IRQ1_INT_8 0xE02C
+#define CS40L50_IRQ1_INT_9 0xE030
+#define CS40L50_IRQ1_INT_10 0xE034
+#define CS40L50_IRQ1_INT_18 0xE054
+#define CS40L50_IRQ1_MASK_1 0xE090
+#define CS40L50_IRQ1_MASK_2 0xE094
+#define CS40L50_IRQ1_MASK_20 0xE0DC
+#define CS40L50_IRQ1_INT_1_OFFSET (CS40L50_IRQ1_INT_1 - CS40L50_IRQ1_BASE)
+#define CS40L50_IRQ1_INT_2_OFFSET (CS40L50_IRQ1_INT_2 - CS40L50_IRQ1_BASE)
+#define CS40L50_IRQ1_INT_8_OFFSET (CS40L50_IRQ1_INT_8 - CS40L50_IRQ1_BASE)
+#define CS40L50_IRQ1_INT_9_OFFSET (CS40L50_IRQ1_INT_9 - CS40L50_IRQ1_BASE)
+#define CS40L50_IRQ1_INT_10_OFFSET (CS40L50_IRQ1_INT_10 - CS40L50_IRQ1_BASE)
+#define CS40L50_IRQ1_INT_18_OFFSET (CS40L50_IRQ1_INT_18 - CS40L50_IRQ1_BASE)
+#define CS40L50_IRQ_MASK_2_OVERRIDE 0xFFDF7FFF
+#define CS40L50_IRQ_MASK_20_OVERRIDE 0x15C01000
+#define CS40L50_AMP_SHORT_MASK BIT(31)
+#define CS40L50_DSP_QUEUE_MASK BIT(21)
+#define CS40L50_TEMP_ERR_MASK BIT(31)
+#define CS40L50_BST_UVP_MASK BIT(6)
+#define CS40L50_BST_SHORT_MASK BIT(7)
+#define CS40L50_BST_ILIMIT_MASK BIT(18)
+#define CS40L50_UVLO_VDDBATT_MASK BIT(16)
+#define CS40L50_GLOBAL_ERROR_MASK BIT(15)
+
+enum cs40l50_irq_list {
+ CS40L50_DSP_QUEUE_IRQ,
+ CS40L50_GLOBAL_ERROR_IRQ,
+ CS40L50_UVLO_VDDBATT_IRQ,
+ CS40L50_BST_ILIMIT_IRQ,
+ CS40L50_BST_SHORT_IRQ,
+ CS40L50_BST_UVP_IRQ,
+ CS40L50_TEMP_ERR_IRQ,
+ CS40L50_AMP_SHORT_IRQ,
+};
+
+/* DSP */
+#define CS40L50_XMEM_PACKED_0 0x2000000
+#define CS40L50_XMEM_UNPACKED24_0 0x2800000
+#define CS40L50_SYS_INFO_ID 0x25E0000
+#define CS40L50_RAM_INIT 0x28021DC
+#define CS40L50_DSP_QUEUE_WT 0x28042C8
+#define CS40L50_DSP_QUEUE_RD 0x28042CC
+#define CS40L50_NUM_WAVES 0x2805C18
+#define CS40L50_CORE_BASE 0x2B80000
+#define CS40L50_CCM_CORE_CONTROL 0x2BC1000
+#define CS40L50_YMEM_PACKED_0 0x2C00000
+#define CS40L50_YMEM_UNPACKED24_0 0x3400000
+#define CS40L50_PMEM_0 0x3800000
+#define CS40L50_MEM_RDY_HW 0x2
+#define CS40L50_RAM_INIT_FLAG 0x1
+#define CS40L50_CLOCK_DISABLE 0x80
+#define CS40L50_CLOCK_ENABLE 0x281
+#define CS40L50_DSP_POLL_US 1000
+#define CS40L50_DSP_TIMEOUT_COUNT 100
+#define CS40L50_RESET_PULSE_US 2200
+#define CS40L50_CP_READY_US 3100
+#define CS40L50_AUTOSUSPEND_MS 2000
+#define CS40L50_PM_ALGO_ID 0x9F206
+#define CS40L50_GLOBAL_ERR_RLS_SET BIT(11)
+#define CS40L50_GLOBAL_ERR_RLS_CLEAR 0
+
+/* DSP Commands */
+#define CS40L50_DSP_QUEUE_BASE 0x11004
+#define CS40L50_DSP_QUEUE_END 0x1101C
+#define CS40L50_DSP_QUEUE 0x11020
+#define CS40L50_PREVENT_HIBER 0x2000003
+#define CS40L50_ALLOW_HIBER 0x2000004
+#define CS40L50_START_I2S 0x3000002
+#define CS40L50_OWT_PUSH 0x3000008
+#define CS40L50_STOP_PLAYBACK 0x5000000
+#define CS40L50_OWT_DELETE 0xD000000
+
+/* Firmware files */
+#define CS40L50_FW "cs40l50.wmfw"
+#define CS40L50_WT "cs40l50.bin"
+
+/* Device */
+#define CS40L50_DEVID 0x0
+#define CS40L50_REVID 0x4
+#define CS40L50_DEVID_A 0x40A50
+#define CS40L50_REVID_B0 0xB0
+
+struct cs40l50 {
+ struct device *dev;
+ struct regmap *regmap;
+ struct mutex lock;
+ struct cs_dsp dsp;
+ struct gpio_desc *reset_gpio;
+ struct regmap_irq_chip_data *irq_data;
+ const struct firmware *patch;
+ const struct firmware *bin;
+ int irq;
+ u32 devid;
+ u32 revid;
+};
+
+int cs40l50_dsp_write(struct device *dev, struct regmap *regmap, u32 val);
+int cs40l50_probe(struct cs40l50 *cs40l50);
+int cs40l50_remove(struct cs40l50 *cs40l50);
+
+extern const struct regmap_config cs40l50_regmap;
+extern const struct dev_pm_ops cs40l50_pm_ops;
+
+#endif /* __CS40L50_H__ */
--
2.25.1
^ permalink raw reply related
* [PATCH v6 4/5] Input: cs40l50 - Add support for the CS40L50 haptic driver
From: James Ogletree @ 2024-02-07 0:36 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt, lee,
broonie, jeff
Cc: patches, linux-sound, linux-input, devicetree, James Ogletree
In-Reply-To: <20240207003612.4187370-1-jogletre@opensource.cirrus.com>
Introduce support for Cirrus Logic Device CS40L50: a
haptic driver with waveform memory, integrated DSP,
and closed-loop algorithms.
The input driver provides the interface for control of
haptic effects through the device.
Signed-off-by: James Ogletree <jogletre@opensource.cirrus.com>
---
v6:
Please advise if playback stop is still misused with respect to not
specifying an effect, and if so what the best solution would be. The
device can only play one effect at a time, but setting max effects
for the EVIOCGEFFECTS ioctl to 1 would restrict the number of
uploads to 1 as well. Is there an alternative solution here? And
please correct my wrong assumptions if there are any.
MAINTAINERS | 1 +
drivers/input/misc/Kconfig | 10 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/cs40l50-vibra.c | 571 +++++++++++++++++++++++++++++
4 files changed, 583 insertions(+)
create mode 100644 drivers/input/misc/cs40l50-vibra.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 69a9e0a3b968..24cfb4f017bb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4940,6 +4940,7 @@ M: Ben Bright <ben.bright@cirrus.com>
L: patches@opensource.cirrus.com
S: Supported
F: Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml
+F: drivers/input/misc/cs40l*
F: drivers/mfd/cs40l*
F: include/linux/mfd/cs40l*
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 6ba984d7f0b1..ee45dbb0636e 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -140,6 +140,16 @@ config INPUT_BMA150
To compile this driver as a module, choose M here: the
module will be called bma150.
+config INPUT_CS40L50_VIBRA
+ tristate "CS40L50 Haptic Driver support"
+ depends on MFD_CS40L50_CORE
+ help
+ Say Y here to enable support for Cirrus Logic's CS40L50
+ haptic driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cs40l50-vibra.
+
config INPUT_E3X0_BUTTON
tristate "NI Ettus Research USRP E3xx Button support."
default n
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 04296a4abe8e..88279de6d3d5 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_CPCAP_PWRBUTTON) += cpcap-pwrbutton.o
+obj-$(CONFIG_INPUT_CS40L50_VIBRA) += cs40l50-vibra.o
obj-$(CONFIG_INPUT_DA7280_HAPTICS) += da7280.o
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
diff --git a/drivers/input/misc/cs40l50-vibra.c b/drivers/input/misc/cs40l50-vibra.c
new file mode 100644
index 000000000000..9089b90c31a9
--- /dev/null
+++ b/drivers/input/misc/cs40l50-vibra.c
@@ -0,0 +1,571 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CS40L50 Advanced Haptic Driver with waveform memory,
+ * integrated DSP, and closed-loop algorithms
+ *
+ * Copyright 2024 Cirrus Logic, Inc.
+ *
+ * Author: James Ogletree <james.ogletree@cirrus.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/input.h>
+#include <linux/mfd/cs40l50.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+/* Wavetables */
+#define CS40L50_RAM_INDEX_START 0x1000000
+#define CS40L50_RAM_INDEX_END 0x100007F
+#define CS40L50_RTH_INDEX_START 0x1400000
+#define CS40L50_RTH_INDEX_END 0x1400001
+#define CS40L50_ROM_INDEX_START 0x1800000
+#define CS40L50_ROM_INDEX_END 0x180001A
+#define CS40L50_TYPE_PCM 8
+#define CS40L50_TYPE_PWLE 12
+#define CS40L50_PCM_ID 0x0
+#define CS40L50_OWT_CUSTOM_DATA_SIZE 2
+
+/* DSP */
+#define CS40L50_GPIO_BASE 0x2804140
+#define CS40L50_OWT_BASE 0x2805C34
+#define CS40L50_OWT_SIZE 0x2805C38
+#define CS40L50_OWT_NEXT 0x2805C3C
+
+/* GPIO */
+#define CS40L50_GPIO_NUM_MASK GENMASK(14, 12)
+#define CS40L50_GPIO_EDGE_MASK BIT(15)
+#define CS40L50_GPIO_MAPPING_NONE 0
+#define CS40L50_GPIO_DISABLE 0x1FF
+
+enum vibra_bank_type {
+ WVFRM_BANK_RAM,
+ WVFRM_BANK_ROM,
+ WVFRM_BANK_OWT,
+ WVFRM_BANK_NUM,
+};
+
+/* Describes an area in DSP memory populated by effects */
+struct vibra_bank {
+ enum vibra_bank_type bank;
+ u32 base_index;
+ u32 max_index;
+};
+
+struct vibra_effect {
+ enum vibra_bank_type bank;
+ struct list_head list;
+ u32 gpio_reg;
+ u32 index;
+ int id;
+};
+
+/* Describes haptic interface of loaded DSP firmware */
+struct vibra_dsp {
+ struct vibra_bank *banks;
+ u32 gpio_base_reg;
+ u32 owt_offset_reg;
+ u32 owt_size_reg;
+ u32 owt_base_reg;
+ int (*write)(struct device *dev, struct regmap *regmap, u32 val);
+ u32 push_owt_cmd;
+ u32 delete_owt_cmd;
+ u32 stop_cmd;
+};
+
+/* Describes configuration and state of haptic operations */
+struct vibra_info {
+ struct device *dev;
+ struct regmap *regmap;
+ struct input_dev *input;
+ struct mutex lock;
+ struct workqueue_struct *vibe_wq;
+ struct list_head effect_head;
+ struct vibra_dsp dsp;
+};
+
+struct vibra_work {
+ struct vibra_info *info;
+ struct ff_effect *effect;
+ struct work_struct work;
+ s16 *custom_data;
+ int count;
+ int error;
+};
+
+static struct vibra_bank cs40l50_banks[] = {
+ {
+ .bank = WVFRM_BANK_RAM,
+ .base_index = CS40L50_RAM_INDEX_START,
+ .max_index = CS40L50_RAM_INDEX_END,
+ },
+ {
+ .bank = WVFRM_BANK_ROM,
+ .base_index = CS40L50_ROM_INDEX_START,
+ .max_index = CS40L50_ROM_INDEX_END,
+ },
+ {
+ .bank = WVFRM_BANK_OWT,
+ .base_index = CS40L50_RTH_INDEX_START,
+ .max_index = CS40L50_RTH_INDEX_END,
+ },
+};
+
+static struct vibra_dsp cs40l50_dsp = {
+ .banks = cs40l50_banks,
+ .gpio_base_reg = CS40L50_GPIO_BASE,
+ .owt_base_reg = CS40L50_OWT_BASE,
+ .owt_offset_reg = CS40L50_OWT_NEXT,
+ .owt_size_reg = CS40L50_OWT_SIZE,
+
+ .push_owt_cmd = CS40L50_OWT_PUSH,
+ .delete_owt_cmd = CS40L50_OWT_DELETE,
+ .stop_cmd = CS40L50_STOP_PLAYBACK,
+
+ .write = cs40l50_dsp_write,
+};
+
+static struct vibra_effect *vibra_find_effect(int id, struct list_head *effect_head)
+{
+ struct vibra_effect *effect;
+
+ list_for_each_entry(effect, effect_head, list)
+ if (effect->id == id)
+ return effect;
+
+ return NULL;
+}
+
+static int vibra_effect_bank_set(struct vibra_work *work_data,
+ struct vibra_effect *effect)
+{
+ unsigned int len = work_data->effect->u.periodic.custom_len;
+ s16 bank = work_data->custom_data[0] & 0xffffu;
+
+ if (bank >= WVFRM_BANK_NUM) {
+ dev_err(work_data->info->dev, "Invalid waveform bank: %d\n", bank);
+ return -EINVAL;
+ }
+
+ effect->bank = len > CS40L50_OWT_CUSTOM_DATA_SIZE ? WVFRM_BANK_OWT : bank;
+
+ return 0;
+}
+
+static int vibra_effect_gpio_mapping_set(struct vibra_work *work_data,
+ struct vibra_effect *effect)
+{
+ u16 button = work_data->effect->trigger.button;
+ struct vibra_info *info = work_data->info;
+ u32 gpio_num, gpio_edge;
+
+ if (button) {
+ gpio_num = FIELD_GET(CS40L50_GPIO_NUM_MASK, button);
+ gpio_edge = FIELD_GET(CS40L50_GPIO_EDGE_MASK, button);
+ effect->gpio_reg = info->dsp.gpio_base_reg + (gpio_num * 8) - gpio_edge;
+
+ return regmap_write(info->regmap, effect->gpio_reg, button);
+ }
+
+ effect->gpio_reg = CS40L50_GPIO_MAPPING_NONE;
+
+ return 0;
+}
+
+static int vibra_effect_index_set(struct vibra_work *work_data,
+ struct vibra_effect *effect)
+{
+ struct vibra_info *info = work_data->info;
+ struct vibra_effect *owt_effect;
+ u32 base_index, max_index;
+
+ base_index = info->dsp.banks[effect->bank].base_index;
+ max_index = info->dsp.banks[effect->bank].max_index;
+
+ effect->index = base_index;
+
+ switch (effect->bank) {
+ case WVFRM_BANK_OWT:
+ list_for_each_entry(owt_effect, &info->effect_head, list)
+ if (owt_effect->bank == WVFRM_BANK_OWT)
+ effect->index++;
+ break;
+ case WVFRM_BANK_ROM:
+ case WVFRM_BANK_RAM:
+ effect->index += work_data->custom_data[1] & 0xffffu;
+ break;
+ default:
+ dev_err(info->dev, "Bank not supported: %d\n", effect->bank);
+ return -EINVAL;
+ }
+
+ if (effect->index > max_index || effect->index < base_index) {
+ dev_err(info->dev, "Index out of bounds: %u\n", effect->index);
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+/* Describes a header for an OWT effect */
+struct owt_header {
+ u32 type;
+ u32 data_words;
+ u32 offset;
+} __packed;
+
+static int vibra_upload_owt(struct vibra_work *work_data, struct vibra_effect *effect)
+{
+ struct ff_periodic_effect add_effect = work_data->effect->u.periodic;
+ u32 len = 2 * add_effect.custom_len, wt_offset, wt_size;
+ struct vibra_info *info = work_data->info;
+ struct owt_header header;
+ u8 *out_data;
+ int error;
+
+ error = regmap_read(info->regmap, info->dsp.owt_size_reg, &wt_size);
+ if (error)
+ return error;
+
+ if ((wt_size * sizeof(u32)) < sizeof(header) + len) {
+ dev_err(info->dev, "No space in OWT bank for effect\n");
+ return -ENOSPC;
+ }
+
+ out_data = kzalloc(sizeof(header) + len, GFP_KERNEL);
+ if (!out_data)
+ return -ENOMEM;
+
+ header.type = add_effect.custom_data[0] == CS40L50_PCM_ID ? CS40L50_TYPE_PCM :
+ CS40L50_TYPE_PWLE;
+ header.offset = sizeof(header) / sizeof(u32);
+ header.data_words = len / sizeof(u32);
+
+ memcpy(out_data, &header, sizeof(header));
+ memcpy(out_data + sizeof(header), add_effect.custom_data, len);
+
+ error = regmap_read(info->regmap, info->dsp.owt_offset_reg, &wt_offset);
+ if (error)
+ return error;
+
+ error = regmap_bulk_write(info->regmap, info->dsp.owt_base_reg +
+ (wt_offset * sizeof(u32)), out_data,
+ sizeof(header) + len);
+ if (error)
+ goto err_free;
+
+ error = info->dsp.write(info->dev, info->regmap, info->dsp.push_owt_cmd);
+err_free:
+ kfree(out_data);
+
+ return error;
+}
+
+static void vibra_add_worker(struct work_struct *work)
+{
+ struct vibra_work *work_data = container_of(work, struct vibra_work, work);
+ struct vibra_info *info = work_data->info;
+ struct vibra_effect *effect;
+ bool is_new = false;
+ int error;
+
+ error = pm_runtime_resume_and_get(info->dev);
+ if (error < 0)
+ goto exit;
+
+ mutex_lock(&info->lock);
+
+ effect = vibra_find_effect(work_data->effect->id, &info->effect_head);
+ if (!effect) {
+ effect = kzalloc(sizeof(*effect), GFP_KERNEL);
+ if (!effect) {
+ error = -ENOMEM;
+ goto err_mutex;
+ }
+
+ effect->id = work_data->effect->id;
+ is_new = true;
+ }
+
+ error = vibra_effect_bank_set(work_data, effect);
+ if (error)
+ goto err_free;
+
+ error = vibra_effect_index_set(work_data, effect);
+ if (error)
+ goto err_free;
+
+ error = vibra_effect_gpio_mapping_set(work_data, effect);
+ if (error)
+ goto err_free;
+
+ if (effect->bank == WVFRM_BANK_OWT)
+ error = vibra_upload_owt(work_data, effect);
+err_free:
+ if (is_new) {
+ if (error)
+ kfree(effect);
+ else
+ list_add(&effect->list, &info->effect_head);
+ }
+err_mutex:
+ mutex_unlock(&info->lock);
+
+ pm_runtime_mark_last_busy(info->dev);
+ pm_runtime_put_autosuspend(info->dev);
+exit:
+ work_data->error = error;
+}
+
+static int vibra_add(struct input_dev *dev, struct ff_effect *effect,
+ struct ff_effect *old)
+{
+ struct ff_periodic_effect *periodic = &effect->u.periodic;
+ struct vibra_info *info = input_get_drvdata(dev);
+ struct vibra_work work_data = { info, effect, };
+ u32 len = effect->u.periodic.custom_len;
+
+ if (effect->type != FF_PERIODIC || periodic->waveform != FF_CUSTOM) {
+ dev_err(info->dev, "Type (%#X) or waveform (%#X) unsupported\n",
+ effect->type, periodic->waveform);
+ return -EINVAL;
+ }
+
+ work_data.custom_data = kcalloc(len, sizeof(s16), GFP_KERNEL);
+ if (!work_data.custom_data)
+ return -ENOMEM;
+
+ if (copy_from_user(work_data.custom_data, effect->u.periodic.custom_data,
+ sizeof(s16) * len)) {
+ work_data.error = -EFAULT;
+ goto out_free;
+ }
+
+ INIT_WORK(&work_data.work, vibra_add_worker);
+
+ /* Push to the workqueue to serialize with playbacks */
+ queue_work(info->vibe_wq, &work_data.work);
+ flush_work(&work_data.work);
+out_free:
+ kfree(work_data.custom_data);
+
+ return work_data.error;
+}
+
+static void vibra_start_worker(struct work_struct *work)
+{
+ struct vibra_work *work_data = container_of(work, struct vibra_work, work);
+ struct vibra_info *info = work_data->info;
+ struct vibra_effect *start_effect;
+
+ if (pm_runtime_resume_and_get(info->dev) < 0)
+ goto error;
+
+ mutex_lock(&info->lock);
+
+ start_effect = vibra_find_effect(work_data->effect->id, &info->effect_head);
+ if (start_effect) {
+ while (--work_data->count >= 0) {
+ info->dsp.write(info->dev, info->regmap, start_effect->index);
+ usleep_range(work_data->effect->replay.length,
+ work_data->effect->replay.length + 100);
+ }
+ }
+
+ mutex_unlock(&info->lock);
+
+ if (!start_effect)
+ dev_err(info->dev, "Effect to play not found\n");
+
+ pm_runtime_mark_last_busy(info->dev);
+ pm_runtime_put_autosuspend(info->dev);
+error:
+ kfree(work_data);
+}
+
+static void vibra_stop_worker(struct work_struct *work)
+{
+ struct vibra_work *work_data = container_of(work, struct vibra_work, work);
+ struct vibra_info *info = work_data->info;
+
+ if (pm_runtime_resume_and_get(info->dev) < 0)
+ return;
+
+ mutex_lock(&info->lock);
+
+ info->dsp.write(info->dev, info->regmap, info->dsp.stop_cmd);
+
+ mutex_unlock(&info->lock);
+
+ pm_runtime_mark_last_busy(info->dev);
+ pm_runtime_put_autosuspend(info->dev);
+
+ kfree(work_data);
+}
+
+static int vibra_playback(struct input_dev *dev, int effect_id, int val)
+{
+ struct vibra_info *info = input_get_drvdata(dev);
+ struct vibra_work *work_data;
+
+ work_data = kzalloc(sizeof(*work_data), GFP_ATOMIC);
+ if (!work_data)
+ return -ENOMEM;
+
+ work_data->info = info;
+
+ if (val > 0) {
+ work_data->effect = &dev->ff->effects[effect_id];
+ work_data->count = val;
+ INIT_WORK(&work_data->work, vibra_start_worker);
+ } else {
+ /* Stop the amplifier as device can only drive one effect */
+ INIT_WORK(&work_data->work, vibra_stop_worker);
+ }
+
+ queue_work(info->vibe_wq, &work_data->work);
+
+ return 0;
+}
+
+static void vibra_erase_worker(struct work_struct *work)
+{
+ struct vibra_work *work_data = container_of(work, struct vibra_work, work);
+ struct vibra_effect *owt_effect, *erase_effect;
+ struct vibra_info *info = work_data->info;
+ int error;
+
+ error = pm_runtime_resume_and_get(info->dev);
+ if (error < 0)
+ goto exit;
+
+ mutex_lock(&info->lock);
+
+ erase_effect = vibra_find_effect(work_data->effect->id, &info->effect_head);
+ if (!erase_effect) {
+ dev_err(info->dev, "Effect to erase not found\n");
+ error = -EINVAL;
+ goto error;
+ }
+
+ if (erase_effect->gpio_reg != CS40L50_GPIO_MAPPING_NONE) {
+ error = regmap_write(info->regmap, erase_effect->gpio_reg,
+ CS40L50_GPIO_DISABLE);
+ if (error)
+ goto error;
+ }
+
+ if (erase_effect->bank == WVFRM_BANK_OWT) {
+ error = info->dsp.write(info->dev, info->regmap,
+ info->dsp.delete_owt_cmd |
+ erase_effect->index);
+ if (error)
+ goto error;
+
+ list_for_each_entry(owt_effect, &info->effect_head, list)
+ if (owt_effect->bank == WVFRM_BANK_OWT &&
+ owt_effect->index > erase_effect->index)
+ owt_effect->index--;
+ }
+
+ list_del(&erase_effect->list);
+ kfree(erase_effect);
+error:
+ mutex_unlock(&info->lock);
+
+ pm_runtime_mark_last_busy(info->dev);
+ pm_runtime_put_autosuspend(info->dev);
+exit:
+ work_data->error = error;
+}
+
+static int vibra_erase(struct input_dev *dev, int effect_id)
+{
+ struct vibra_info *info = input_get_drvdata(dev);
+ struct vibra_work work_data = { info, &dev->ff->effects[effect_id], };
+
+ INIT_WORK(&work_data.work, vibra_erase_worker);
+
+ /* Push to workqueue to serialize with playbacks */
+ queue_work(info->vibe_wq, &work_data.work);
+ flush_work(&work_data.work);
+
+ return work_data.error;
+}
+
+static void vibra_remove_wq(void *data)
+{
+ struct vibra_info *info = data;
+
+ flush_workqueue(info->vibe_wq);
+ destroy_workqueue(info->vibe_wq);
+}
+
+static int cs40l50_vibra_probe(struct platform_device *pdev)
+{
+ struct cs40l50 *cs40l50 = dev_get_drvdata(pdev->dev.parent);
+ struct vibra_info *info;
+ int error;
+
+ info = devm_kzalloc(pdev->dev.parent, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ mutex_init(&info->lock);
+
+ info->dev = cs40l50->dev;
+ info->regmap = cs40l50->regmap;
+ info->dsp = cs40l50_dsp;
+
+ info->input = devm_input_allocate_device(info->dev);
+ if (!info->input)
+ return -ENOMEM;
+ info->input->id.product = cs40l50->devid & 0xFFFF;
+ info->input->id.version = cs40l50->revid;
+ info->input->name = "cs40l50_vibra";
+
+ input_set_drvdata(info->input, info);
+ input_set_capability(info->input, EV_FF, FF_PERIODIC);
+ input_set_capability(info->input, EV_FF, FF_CUSTOM);
+
+ error = input_ff_create(info->input, FF_MAX_EFFECTS);
+ if (error) {
+ dev_err(info->dev, "Failed to create input device\n");
+ return error;
+ }
+
+ info->input->ff->upload = vibra_add;
+ info->input->ff->playback = vibra_playback;
+ info->input->ff->erase = vibra_erase;
+
+ INIT_LIST_HEAD(&info->effect_head);
+
+ info->vibe_wq = alloc_ordered_workqueue("vibe_wq", WQ_HIGHPRI);
+ if (!info->vibe_wq)
+ return -ENOMEM;
+
+ error = devm_add_action_or_reset(info->dev, vibra_remove_wq, info);
+ if (error)
+ return error;
+
+ return input_register_device(info->input);
+}
+
+static const struct platform_device_id vibra_id_match[] = {
+ { "cs40l50-vibra", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, vibra_id_match);
+
+static struct platform_driver cs40l50_vibra_driver = {
+ .probe = cs40l50_vibra_probe,
+ .id_table = vibra_id_match,
+ .driver = {
+ .name = "cs40l50-vibra",
+ },
+};
+module_platform_driver(cs40l50_vibra_driver);
+
+MODULE_DESCRIPTION("CS40L50 Advanced Haptic Driver");
+MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>");
+MODULE_LICENSE("GPL");
--
2.25.1
^ permalink raw reply related
* [PATCH v6 5/5] ASoC: cs40l50: Support I2S streaming to CS40L50
From: James Ogletree @ 2024-02-07 0:36 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt, lee,
broonie, jeff
Cc: patches, linux-sound, linux-input, devicetree, James Ogletree
In-Reply-To: <20240207003612.4187370-1-jogletre@opensource.cirrus.com>
Introduce support for Cirrus Logic Device CS40L50: a
haptic driver with waveform memory, integrated DSP,
and closed-loop algorithms.
The ASoC driver enables I2S streaming to the device.
Signed-off-by: James Ogletree <jogletre@opensource.cirrus.com>
---
MAINTAINERS | 1 +
sound/soc/codecs/Kconfig | 11 ++
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/cs40l50-codec.c | 311 +++++++++++++++++++++++++++++++
4 files changed, 325 insertions(+)
create mode 100644 sound/soc/codecs/cs40l50-codec.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 24cfb4f017bb..fca2454a7a38 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4943,6 +4943,7 @@ F: Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml
F: drivers/input/misc/cs40l*
F: drivers/mfd/cs40l*
F: include/linux/mfd/cs40l*
+F: sound/soc/codecs/cs40l*
CIRRUS LOGIC DSP FIRMWARE DRIVER
M: Simon Trimmer <simont@opensource.cirrus.com>
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index f1e1dbc509f6..1a81bedfdbe3 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -73,6 +73,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_CS35L56_I2C
imply SND_SOC_CS35L56_SPI
imply SND_SOC_CS35L56_SDW
+ imply SND_SOC_CS40L50
imply SND_SOC_CS42L42
imply SND_SOC_CS42L42_SDW
imply SND_SOC_CS42L43
@@ -800,6 +801,16 @@ config SND_SOC_CS35L56_SDW
help
Enable support for Cirrus Logic CS35L56 boosted amplifier with SoundWire control
+config SND_SOC_CS40L50
+ tristate "Cirrus Logic CS40L50 CODEC"
+ depends on MFD_CS40L50_CORE
+ help
+ This option enables support for I2S streaming to Cirrus Logic CS40L50.
+
+ CS40L50 is a haptic driver with waveform memory, an integrated
+ DSP, and closed-loop algorithms. If built as a module, it will be
+ called snd-soc-cs40l50.
+
config SND_SOC_CS42L42_CORE
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index a87e56938ce5..7e31f000774a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -74,6 +74,7 @@ snd-soc-cs35l56-shared-objs := cs35l56-shared.o
snd-soc-cs35l56-i2c-objs := cs35l56-i2c.o
snd-soc-cs35l56-spi-objs := cs35l56-spi.o
snd-soc-cs35l56-sdw-objs := cs35l56-sdw.o
+snd-soc-cs40l50-objs := cs40l50-codec.o
snd-soc-cs42l42-objs := cs42l42.o
snd-soc-cs42l42-i2c-objs := cs42l42-i2c.o
snd-soc-cs42l42-sdw-objs := cs42l42-sdw.o
@@ -460,6 +461,7 @@ obj-$(CONFIG_SND_SOC_CS35L56_SHARED) += snd-soc-cs35l56-shared.o
obj-$(CONFIG_SND_SOC_CS35L56_I2C) += snd-soc-cs35l56-i2c.o
obj-$(CONFIG_SND_SOC_CS35L56_SPI) += snd-soc-cs35l56-spi.o
obj-$(CONFIG_SND_SOC_CS35L56_SDW) += snd-soc-cs35l56-sdw.o
+obj-$(CONFIG_SND_SOC_CS40L50) += snd-soc-cs40l50.o
obj-$(CONFIG_SND_SOC_CS42L42_CORE) += snd-soc-cs42l42.o
obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42-i2c.o
obj-$(CONFIG_SND_SOC_CS42L42_SDW) += snd-soc-cs42l42-sdw.o
diff --git a/sound/soc/codecs/cs40l50-codec.c b/sound/soc/codecs/cs40l50-codec.c
new file mode 100644
index 000000000000..3632069d6091
--- /dev/null
+++ b/sound/soc/codecs/cs40l50-codec.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CS40L50 Advanced Haptic Driver with waveform memory,
+ * integrated DSP, and closed-loop algorithms
+ *
+ * Copyright 2024 Cirrus Logic, Inc.
+ *
+ * Author: James Ogletree <james.ogletree@cirrus.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/mfd/cs40l50.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define CS40L50_REFCLK_INPUT 0x2C04
+#define CS40L50_ASP_CONTROL2 0x4808
+#define CS40L50_ASP_DATA_CONTROL5 0x4840
+
+/* PLL Config */
+#define CS40L50_PLL_CLK_CFG_32768 0x00
+#define CS40L50_PLL_CLK_CFG_1536000 0x1B
+#define CS40L50_PLL_CLK_CFG_3072000 0x21
+#define CS40L50_PLL_CLK_CFG_6144000 0x28
+#define CS40L50_PLL_CLK_CFG_9600000 0x30
+#define CS40L50_PLL_CLK_CFG_12288000 0x33
+#define CS40L50_PLL_CLK_FRQ_32768 32768
+#define CS40L50_PLL_CLK_FRQ_1536000 1536000
+#define CS40L50_PLL_CLK_FRQ_3072000 3072000
+#define CS40L50_PLL_CLK_FRQ_6144000 6144000
+#define CS40L50_PLL_CLK_FRQ_9600000 9600000
+#define CS40L50_PLL_CLK_FRQ_12288000 12288000
+#define CS40L50_PLL_REFCLK_BCLK 0x0
+#define CS40L50_PLL_REFCLK_MCLK 0x5
+#define CS40L50_PLL_REFCLK_LOOP_MASK BIT(11)
+#define CS40L50_PLL_REFCLK_OPEN_LOOP 1
+#define CS40L50_PLL_REFCLK_CLOSED_LOOP 0
+#define CS40L50_PLL_REFCLK_LOOP_SHIFT 11
+#define CS40L50_PLL_REFCLK_FREQ_MASK GENMASK(10, 5)
+#define CS40L50_PLL_REFCLK_FREQ_SHIFT 5
+#define CS40L50_PLL_REFCLK_SEL_MASK GENMASK(2, 0)
+
+/* ASP Config */
+#define CS40L50_ASP_RX_WIDTH_SHIFT 24
+#define CS40L50_ASP_RX_WIDTH_MASK GENMASK(31, 24)
+#define CS40L50_ASP_RX_WL_MASK GENMASK(5, 0)
+#define CS40L50_ASP_FSYNC_INV_MASK BIT(2)
+#define CS40L50_ASP_BCLK_INV_MASK BIT(6)
+#define CS40L50_ASP_FMT_MASK GENMASK(10, 8)
+#define CS40L50_ASP_FMT_I2S 0x2
+#define CS40L50_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+struct cs40l50_pll_sysclk_config {
+ unsigned int freq;
+ unsigned int clk_cfg;
+};
+
+struct cs40l50_codec {
+ struct device *dev;
+ struct regmap *regmap;
+ unsigned int sysclk_rate;
+ unsigned int daifmt;
+};
+
+static const struct cs40l50_pll_sysclk_config cs40l50_pll_sysclk[] = {
+ {CS40L50_PLL_CLK_FRQ_32768, CS40L50_PLL_CLK_CFG_32768},
+ {CS40L50_PLL_CLK_FRQ_1536000, CS40L50_PLL_CLK_CFG_1536000},
+ {CS40L50_PLL_CLK_FRQ_3072000, CS40L50_PLL_CLK_CFG_3072000},
+ {CS40L50_PLL_CLK_FRQ_6144000, CS40L50_PLL_CLK_CFG_6144000},
+ {CS40L50_PLL_CLK_FRQ_9600000, CS40L50_PLL_CLK_CFG_9600000},
+ {CS40L50_PLL_CLK_FRQ_12288000, CS40L50_PLL_CLK_CFG_12288000},
+};
+
+static int cs40l50_get_clk_config(unsigned int freq, unsigned int *clk_cfg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cs40l50_pll_sysclk); i++) {
+ if (cs40l50_pll_sysclk[i].freq == freq) {
+ *clk_cfg = cs40l50_pll_sysclk[i].clk_cfg;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int cs40l50_swap_ext_clk(struct cs40l50_codec *codec, unsigned int clk_src)
+{
+ unsigned int clk_cfg;
+ int ret;
+
+ switch (clk_src) {
+ case CS40L50_PLL_REFCLK_BCLK:
+ ret = cs40l50_get_clk_config(codec->sysclk_rate, &clk_cfg);
+ if (ret)
+ return ret;
+ break;
+ case CS40L50_PLL_REFCLK_MCLK:
+ clk_cfg = CS40L50_PLL_CLK_CFG_32768;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT,
+ CS40L50_PLL_REFCLK_LOOP_MASK,
+ CS40L50_PLL_REFCLK_OPEN_LOOP <<
+ CS40L50_PLL_REFCLK_LOOP_SHIFT);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT,
+ CS40L50_PLL_REFCLK_FREQ_MASK |
+ CS40L50_PLL_REFCLK_SEL_MASK,
+ (clk_cfg << CS40L50_PLL_REFCLK_FREQ_SHIFT) | clk_src);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT,
+ CS40L50_PLL_REFCLK_LOOP_MASK,
+ CS40L50_PLL_REFCLK_CLOSED_LOOP <<
+ CS40L50_PLL_REFCLK_LOOP_SHIFT);
+}
+
+static int cs40l50_clk_en(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct cs40l50_codec *codec = snd_soc_component_get_drvdata(comp);
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ ret = cs40l50_dsp_write(codec->dev, codec->regmap, CS40L50_STOP_PLAYBACK);
+ if (ret)
+ return ret;
+
+ ret = cs40l50_dsp_write(codec->dev, codec->regmap, CS40L50_START_I2S);
+ if (ret)
+ return ret;
+
+ ret = cs40l50_swap_ext_clk(codec, CS40L50_PLL_REFCLK_BCLK);
+ if (ret)
+ return ret;
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ ret = cs40l50_swap_ext_clk(codec, CS40L50_PLL_REFCLK_MCLK);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget cs40l50_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY_S("ASP PLL", 0, SND_SOC_NOPM, 0, 0, cs40l50_clk_en,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route cs40l50_dapm_routes[] = {
+ { "ASP Playback", NULL, "ASP PLL" },
+ { "ASPRX1", NULL, "ASP Playback" },
+ { "ASPRX2", NULL, "ASP Playback" },
+
+ { "OUT", NULL, "ASPRX1" },
+ { "OUT", NULL, "ASPRX2" },
+};
+
+static int cs40l50_component_set_sysclk(struct snd_soc_component *component,
+ int clk_id, int source, unsigned int freq, int dir)
+{
+ struct cs40l50_codec *codec = snd_soc_component_get_drvdata(component);
+
+ codec->sysclk_rate = freq;
+
+ return 0;
+}
+
+static int cs40l50_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct cs40l50_codec *codec = snd_soc_component_get_drvdata(codec_dai->component);
+
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+ return -EINVAL;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ codec->daifmt = 0;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ codec->daifmt = CS40L50_ASP_FSYNC_INV_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ codec->daifmt = CS40L50_ASP_BCLK_INV_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ codec->daifmt = CS40L50_ASP_FSYNC_INV_MASK | CS40L50_ASP_BCLK_INV_MASK;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid clock invert\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ codec->daifmt |= FIELD_PREP(CS40L50_ASP_FMT_MASK, CS40L50_ASP_FMT_I2S);
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported DAI format\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs40l50_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct cs40l50_codec *codec = snd_soc_component_get_drvdata(dai->component);
+ unsigned int asp_rx_wl = params_width(params);
+ int ret;
+
+ ret = regmap_update_bits(codec->regmap, CS40L50_ASP_DATA_CONTROL5,
+ CS40L50_ASP_RX_WL_MASK, asp_rx_wl);
+ if (ret)
+ return ret;
+
+ codec->daifmt |= (asp_rx_wl << CS40L50_ASP_RX_WIDTH_SHIFT);
+
+ return regmap_update_bits(codec->regmap, CS40L50_ASP_CONTROL2,
+ CS40L50_ASP_FSYNC_INV_MASK |
+ CS40L50_ASP_BCLK_INV_MASK |
+ CS40L50_ASP_FMT_MASK |
+ CS40L50_ASP_RX_WIDTH_MASK, codec->daifmt);
+}
+
+static const struct snd_soc_dai_ops cs40l50_dai_ops = {
+ .set_fmt = cs40l50_set_dai_fmt,
+ .hw_params = cs40l50_hw_params,
+};
+
+static struct snd_soc_dai_driver cs40l50_dai[] = {
+ {
+ .name = "cs40l50-pcm",
+ .id = 0,
+ .playback = {
+ .stream_name = "ASP Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = CS40L50_FORMATS,
+ },
+ .ops = &cs40l50_dai_ops,
+ },
+};
+
+static int cs40l50_codec_probe(struct snd_soc_component *component)
+{
+ struct cs40l50_codec *codec = snd_soc_component_get_drvdata(component);
+
+ codec->sysclk_rate = CS40L50_PLL_CLK_FRQ_1536000;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_cs40l50 = {
+ .probe = cs40l50_codec_probe,
+ .set_sysclk = cs40l50_component_set_sysclk,
+ .dapm_widgets = cs40l50_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs40l50_dapm_widgets),
+ .dapm_routes = cs40l50_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(cs40l50_dapm_routes),
+};
+
+static int cs40l50_codec_driver_probe(struct platform_device *pdev)
+{
+ struct cs40l50 *cs40l50 = dev_get_drvdata(pdev->dev.parent);
+ struct cs40l50_codec *codec;
+
+ codec = devm_kzalloc(&pdev->dev, sizeof(*codec), GFP_KERNEL);
+ if (!codec)
+ return -ENOMEM;
+
+ codec->regmap = cs40l50->regmap;
+ codec->dev = &pdev->dev;
+
+ return devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cs40l50,
+ cs40l50_dai, ARRAY_SIZE(cs40l50_dai));
+}
+
+static struct platform_driver cs40l50_codec_driver = {
+ .probe = cs40l50_codec_driver_probe,
+ .driver = {
+ .name = "cs40l50-codec",
+ },
+};
+module_platform_driver(cs40l50_codec_driver);
+
+MODULE_DESCRIPTION("ASoC CS40L50 driver");
+MODULE_AUTHOR("James Ogletree <james.ogletree@cirrus.com>");
+MODULE_LICENSE("GPL");
--
2.25.1
^ permalink raw reply related
* Re: Requesting 3 patches for Apple Magic Keyboard 2021 to be merged to LTS kernels
From: Aseda Aboagye @ 2024-02-07 0:47 UTC (permalink / raw)
To: Greg KH; +Cc: stable, jikos, benjamin.tissoires, linux-input
In-Reply-To: <2024020217-immodest-reversion-407e@gregkh>
> On Fri, Feb 02, 2024 at 08:45:40PM -0600, Aseda Aboagye wrote:
>> Dear stable kernel maintainers,
>>
>> I am writing to request that 3 related patches be merged to various LTS kernels. I'm not sure if it would have
>> been preferable for me to send 3 separate emails, so please forgive me if I chose wrongly. (This is my first foray
>> into interacting with the kernel community) :)
>>
>> The patches are as follows:
>>
>> 1. 0cd3be51733f (HID: apple: Add support for the 2021 Magic Keyboard, 2021-10-08)
>> 2. 346338ef00d3 (HID: apple: Swap the Fn and Left Control keys on Apple keyboards, 2020-05-15)
>> 3. 531cb56972f2 (HID: apple: Add 2021 magic keyboard FN key mapping, 2021-11-08)
>>
>> These patches have all been merged to mainline, but I believe when they were submitted, backporting may not have been considered. The Apple Magic Keyboard 2021 (Model # A2450) seems to be a popular keyboard, and without these
>> patches, for users on certain LTS kernels that use this keyboard, the function keys do not behave as expected. e.g. Pressing the brightness down or brightness up key didn't work, and bizarrely pressing the globe/Fn key alone caused the brightness to decrease. None of the top row keys worked as expected.
>>
>> I checked to see where the patches were missing and figured that it would be good to have those patches in those
>> kernels.
>>
>> I would ask that patches 1 & 3 be merged to v4.19, v5.4, v5.10, and v5.15.
>> I would ask that patch 2 be merged to: v5.4 and v4.19.
>>
>> For patch 3 to apply cleanly, it needed patch 2 to be present in the tree.
>
> I've done so now, but really, adding support for a keyboard that wasn't
> even out when the kernel was released is odd, why not just use a newer
> kernel version? That's generally a good idea for all consumer devices,
> use the latest stable kernel please.
>
Thank you so much Greg! Yes, that would be the ideal, using a newer kernel. Our
team is in the process of updating the kernel version for our devices, but it's
a long process with many devices and hence wanting to get a fix in the interim.
Our goal is to eventually continuously ship the latest stable kernel versions.
Thanks,
--
Aseda Aboagye
> thanks,
>
> greg k-h
>
^ permalink raw reply
* [PATCH] dt-bindings: input: atmel,captouch: convert bindings to YAML
From: Dharma Balasubiramani @ 2024-02-07 9:08 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, dharma.b,
linux-input, devicetree, linux-arm-kernel, linux-kernel
Convert the Atmel capacitive touchscreen bindings to YAML format.
Signed-off-by: Dharma Balasubiramani <dharma.b@microchip.com>
---
.../bindings/input/atmel,captouch.txt | 36 -----------
.../bindings/input/atmel,captouch.yaml | 62 +++++++++++++++++++
2 files changed, 62 insertions(+), 36 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/input/atmel,captouch.txt
create mode 100644 Documentation/devicetree/bindings/input/atmel,captouch.yaml
diff --git a/Documentation/devicetree/bindings/input/atmel,captouch.txt b/Documentation/devicetree/bindings/input/atmel,captouch.txt
deleted file mode 100644
index fe9ee5c53bcc..000000000000
--- a/Documentation/devicetree/bindings/input/atmel,captouch.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-Device tree bindings for Atmel capacitive touch device, typically
-an Atmel touch sensor connected to AtmegaXX MCU running firmware
-based on Qtouch library.
-
-The node for this device must be a child of a I2C controller node, as the
-device communicates via I2C.
-
-Required properties:
-
- compatible: Must be "atmel,captouch".
- reg: The I2C slave address of the device.
- interrupts: Property describing the interrupt line the device
- is connected to. The device only has one interrupt
- source.
- linux,keycodes: Specifies an array of numeric keycode values to
- be used for reporting button presses. The array can
- contain up to 8 entries.
-
-Optional properties:
-
- autorepeat: Enables the Linux input system's autorepeat
- feature on the input device.
-
-Example:
-
- atmel-captouch@51 {
- compatible = "atmel,captouch";
- reg = <0x51>;
- interrupt-parent = <&tlmm>;
- interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
- linux,keycodes = <BTN_0>, <BTN_1>,
- <BTN_2>, <BTN_3>,
- <BTN_4>, <BTN_5>,
- <BTN_6>, <BTN_7>;
- autorepeat;
- };
diff --git a/Documentation/devicetree/bindings/input/atmel,captouch.yaml b/Documentation/devicetree/bindings/input/atmel,captouch.yaml
new file mode 100644
index 000000000000..5d5679896bc9
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/atmel,captouch.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/atmel,captouch.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Atmel capacitive touch device
+
+maintainers:
+ - Dharma balasubiramani <dharma.b@microchip.com>
+
+description:
+ Atmel capacitive touch device, typically an Atmel touch sensor connected to
+ AtmegaXX MCU running firmware based on Qtouch library.
+
+allOf:
+ - $ref: input.yaml#
+
+properties:
+ compatible:
+ const: atmel,captouch
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ linux,keycodes:
+ minItems: 1
+ maxItems: 8
+
+ autorepeat:
+ type: boolean
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - linux,keycodes
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/input/linux-event-codes.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ atmel-captouch@51 {
+ compatible = "atmel,captouch";
+ reg = <0x51>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
+ linux,keycodes = <BTN_0>, <BTN_1>,
+ <BTN_2>, <BTN_3>,
+ <BTN_4>, <BTN_5>,
+ <BTN_6>, <BTN_7>;
+ autorepeat;
+ };
+ };
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v6 1/5] firmware: cs_dsp: Add write sequencer interface
From: Charles Keepax @ 2024-02-07 10:56 UTC (permalink / raw)
To: James Ogletree
Cc: dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt, lee,
broonie, jeff, patches, linux-sound, linux-input, devicetree
In-Reply-To: <20240207003612.4187370-2-jogletre@opensource.cirrus.com>
On Wed, Feb 07, 2024 at 12:36:08AM +0000, James Ogletree wrote:
> A write sequencer is a sequence of register addresses
> and values executed by some Cirrus DSPs following
> power state transitions.
>
> Add support for Cirrus drivers to update or add to a
> write sequencer present in firmware.
>
> Signed-off-by: James Ogletree <jogletre@opensource.cirrus.com>
> ---
Mostly down to some very minor nit picks from me on this one,
only one comment on the list order.
> + ret = cs_dsp_coeff_read_ctrl(wseq->ctl, 0, words, wseq->ctl->len);
> + if (ret) {
> + cs_dsp_err(dsp, "Failed to read %s: %d\n", wseq->name, ret);
Use wseq->ctl->subname here should be the same string.
> + switch (op->operation) {
> + case CS_DSP_WSEQ_END:
> + op->data = WSEQ_END_OF_SCRIPT;
> + break;
> + case CS_DSP_WSEQ_UNLOCK:
> + op->data = cs_dsp_chunk_read(&ch, 16);
> + break;
> + case CS_DSP_WSEQ_ADDR8:
> + op->address = cs_dsp_chunk_read(&ch, 8);
> + op->data = cs_dsp_chunk_read(&ch, 32);
> + break;
> + case CS_DSP_WSEQ_H16:
> + case CS_DSP_WSEQ_L16:
> + op->address = cs_dsp_chunk_read(&ch, 24);
> + op->data = cs_dsp_chunk_read(&ch, 16);
> + break;
> + case CS_DSP_WSEQ_FULL:
> + op->address = cs_dsp_chunk_read(&ch, 32);
> + op->data = cs_dsp_chunk_read(&ch, 32);
> + break;
> + default:
> + ret = -EINVAL;
> + cs_dsp_err(dsp, "Unsupported op: %X\n", op->operation);
> + goto err_free;
> + }
> +
> + list_add(&op->list, &wseq->ops);
Unless I am mistaken, would be better to use list_add_tail
here. Which would keep the order of writes in the list matching
the order in the write sequence. Currently I think the list
holds the writes in reverse order, so your search for the
first write will actually find the last write.
> +EXPORT_SYMBOL_GPL(cs_dsp_wseq_init);
These should all be EXPORT_SYMBOL_NS_GPL(..., FW_CS_DSP).
> + * cs_dsp_wseq_write() - Add or update an entry in a write sequence
> + * @dsp: Pointer to a DSP structure
> + * @wseq: Write sequence to write to
> + * @addr: Address of the register to be written to
> + * @data: Data to be written
> + * @op_code: The type of operation of the new entry
> + * @update: If true, searches for the first entry in the write sequence with
> + * the same address and op_code, and replaces it. If false, creates a new entry
> + * at the tail.
This should now be expanded to note that it will also add a new
entry if no matching entry is found even when update is set to
true. The comment below says it but good to have it in the docs
too.
> + if (!update) {
> + if (wseq->ctl->len - op_end->offset < new_op_size) {
> + cs_dsp_err(dsp, "Not enough memory in write sequence for entry\n");
> + ret = -ENOMEM;
> + goto op_new_free;
> + }
> +
> + op_end->offset += new_op_size;
> +
> + ret = cs_dsp_coeff_write_ctrl(wseq->ctl, op_end->offset / sizeof(u32),
> + &op_end->data, sizeof(u32));
> + if (ret)
> + goto op_new_free;
> +
> + list_add(&op_new->list, &wseq->ops);
I think if you use list_add_tail(&op_new->list, &op_end->list),
that will also keep the list order matching the hardware order
here.
> +/**
> + * struct cs_dsp_wseq - Describes a write sequence
> + * @name: Name of cs_dsp control
> + * @ctl: Write sequence cs_dsp control
> + * @ops: Operations contained within this write sequence
> + */
> +struct cs_dsp_wseq {
> + const char *name;
Drop name from the struct here it is redundant the ctl pointer
precisely identifies a control.
Thanks,
Charles
^ permalink raw reply
* Re: [PATCH v6 3/5] mfd: cs40l50: Add support for CS40L50 core driver
From: Charles Keepax @ 2024-02-07 11:00 UTC (permalink / raw)
To: James Ogletree
Cc: dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt, lee,
broonie, jeff, patches, linux-sound, linux-input, devicetree
In-Reply-To: <20240207003612.4187370-4-jogletre@opensource.cirrus.com>
On Wed, Feb 07, 2024 at 12:36:10AM +0000, James Ogletree wrote:
> Introduce support for Cirrus Logic Device CS40L50: a
> haptic driver with waveform memory, integrated DSP,
> and closed-loop algorithms.
>
> The MFD component registers and initializes the device.
>
> Signed-off-by: James Ogletree <jogletre@opensource.cirrus.com>
> ---
> +static struct cs_dsp_wseq cs40l50_wseqs[] = {
> + { "PM_PWR_ON_SEQ" },
> +};
> +
> +static int cs40l50_configure_dsp(struct cs40l50 *cs40l50)
> +{
> + u32 nwaves;
> + int err, i;
> +
> + if (cs40l50->bin) {
> + /* Log number of effects if wavetable was loaded */
> + err = regmap_read(cs40l50->regmap, CS40L50_NUM_WAVES, &nwaves);
> + if (err)
> + return err;
> +
> + dev_info(cs40l50->dev, "Loaded with %u effects\n", nwaves);
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(cs40l50_wseqs); i++) {
> + mutex_lock(&cs40l50->dsp.pwr_lock);
> + cs40l50_wseqs[i].ctl = cs_dsp_get_ctl(&cs40l50->dsp,
> + cs40l50_wseqs[i].name,
> + WMFW_ADSP2_XM,
> + CS40L50_PM_ALGO_ID);
> + mutex_unlock(&cs40l50->dsp.pwr_lock);
> + if (!cs40l50_wseqs[i].ctl) {
> + dev_err(cs40l50->dev, "No control: %s\n", cs40l50_wseqs[i].name);
> + return -ENOENT;
> + }
> + }
In general this is a bad pattern to use, don't have global
structs that hold anything other than const data. Here if a
system with two cs40l50's was made they would end up over writing
each others ctl pointers. If the data is modified by the driver
put it in a private struct that is allocated during probe.
Thanks,
Charles
^ permalink raw reply
* Re: [PATCH] dt-bindings: input: atmel,captouch: convert bindings to YAML
From: Krzysztof Kozlowski @ 2024-02-07 15:15 UTC (permalink / raw)
To: Dharma Balasubiramani, dmitry.torokhov, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nicolas.ferre,
alexandre.belloni, claudiu.beznea, linux-input, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <20240207090853.188400-1-dharma.b@microchip.com>
On 07/02/2024 10:08, Dharma Balasubiramani wrote:
> Convert the Atmel capacitive touchscreen bindings to YAML format.
>
> Signed-off-by: Dharma Balasubiramani <dharma.b@microchip.co
Thank you for your patch. There is something to discuss/improve.
> +
> +properties:
> + compatible:
> + const: atmel,captouch
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + linux,keycodes:
> + minItems: 1
> + maxItems: 8
> +
> + autorepeat:
> + type: boolean
You can drop entire property, coming from input.yaml.
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - linux,keycodes
> +
> +additionalProperties: false
Instead:
unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/irq.h>
> + #include <dt-bindings/input/linux-event-codes.h>
> + i2c {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + atmel-captouch@51 {
Instead:
touchscreen? touchpad? if none of these, then just "touch@51"
> + compatible = "atmel,captouch";
> + reg = <0x51>;
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH v2 0/5] HID: playstation: DS4: LED bugfix, third-party gamepad support
From: Max Staudt @ 2024-02-07 16:36 UTC (permalink / raw)
To: Roderick Colenbrander, Jiri Kosina, Benjamin Tissoires
Cc: linux-input, linux-kernel, max
Dear hid-playstation maintainers,
Here is v2 of my patch series, with the discussed changes.
Differences since v1:
- Dropped patch for 7545:0104 (SZ-MYPOWER controllers)
- Dropped patch for DS4 clones without a MAC address on USB
- Changed hid_err() to hid_warn() where things are no longer fatal
- Simplified goto as return in minimal report parsing
I've included the patch to simplify the PID/VID mapping to controller
types, since the previous discussion made it sound useful for future
support of second-party controllers. Please feel free to drop it if you
don't think it's relevant now.
Thanks for your feedback!
Max
Patches in this series:
[PATCH v2 1/5] HID: playstation: DS4: Fix LED blinking
[PATCH v2 2/5] HID: playstation: DS4: Don't fail on FW/HW version
[PATCH v2 3/5] HID: playstation: DS4: Don't fail on calibration data
[PATCH v2 4/5] HID: playstation: DS4: Parse minimal report 0x01
[PATCH v2 5/5] HID: playstation: Simplify device type ID
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox