mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-04 03:19:02 +00:00
wacom-raw: Add a plugin to update Wacom embedded EMR and AES panels
This commit is contained in:
parent
3f243a9e9e
commit
367f4590d6
@ -293,6 +293,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg
|
||||
%endif
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_unifying.so
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_upower.so
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_raw.so
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_usb.so
|
||||
%ghost %{_localstatedir}/lib/fwupd/gnupg
|
||||
%if 0%{?have_uefi}
|
||||
|
@ -12,6 +12,7 @@ subdir('test')
|
||||
subdir('udev')
|
||||
subdir('unifying')
|
||||
subdir('upower')
|
||||
subdir('wacom-raw')
|
||||
subdir('wacom-usb')
|
||||
subdir('superio')
|
||||
|
||||
|
26
plugins/wacom-raw/README.md
Normal file
26
plugins/wacom-raw/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
Wacom RAW Support
|
||||
=================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This plugin updates integrated Wacom AES and EMR devices. They are typically
|
||||
connected using I²C and not USB.
|
||||
|
||||
GUID Generation
|
||||
---------------
|
||||
|
||||
The HID DeviceInstanceId values are used, e.g. `HIDRAW\VEN_056A&DEV_4875`.
|
||||
|
||||
Additionally, for supported AES devices an extra GUID is added for the hardware
|
||||
ID (e.g. `WACOM\HWID_%04X`) to further disambiguate the panels.
|
||||
|
||||
Quirk use
|
||||
---------
|
||||
This plugin uses the following plugin-specific quirks:
|
||||
|
||||
| Quirk | Description | Minimum fwupd version |
|
||||
|-------------------------|-------------------------------------|-----------------------|
|
||||
| `WacomI2cFlashBlockSize`| Block size to transfer firmware | 1.2.4 |
|
||||
| `WacomI2cFlashBaseAddr` | Base address for firmware | 1.2.4 |
|
||||
| `WacomI2cFlashSize` | Maximum size of the firmware zone | 1.2.4 |
|
470
plugins/wacom-raw/data/hid-recorder.txt
Normal file
470
plugins/wacom-raw/data/hid-recorder.txt
Normal file
@ -0,0 +1,470 @@
|
||||
# WCOM4875:00 056A:4875
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 0
|
||||
# 0x09, 0x04, // Usage (Touch Screen) 2
|
||||
# 0xa1, 0x01, // Collection (Application) 4
|
||||
# 0x85, 0x0c, // Report ID (12) 6
|
||||
# 0x95, 0x01, // Report Count (1) 8
|
||||
# 0x75, 0x08, // Report Size (8) 10
|
||||
# 0x26, 0xff, 0x00, // Logical Maximum (255) 12
|
||||
# 0x15, 0x00, // Logical Minimum (0) 15
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 17
|
||||
# 0x09, 0x54, // Usage (Contact Count) 19
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 21
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 23
|
||||
# 0x09, 0x22, // Usage (Finger) 25
|
||||
# 0xa1, 0x02, // Collection (Logical) 27
|
||||
# 0x09, 0x42, // Usage (Tip Switch) 29
|
||||
# 0x15, 0x00, // Logical Minimum (0) 31
|
||||
# 0x25, 0x01, // Logical Maximum (1) 33
|
||||
# 0x75, 0x01, // Report Size (1) 35
|
||||
# 0x95, 0x01, // Report Count (1) 37
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 39
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 41
|
||||
# 0x09, 0x47, // Usage (Confidence) 43
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 45
|
||||
# 0x95, 0x05, // Report Count (5) 47
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 49
|
||||
# 0x75, 0x10, // Report Size (16) 51
|
||||
# 0x09, 0x51, // Usage (Contact Id) 53
|
||||
# 0x95, 0x01, // Report Count (1) 55
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 57
|
||||
# 0x05, 0x01, // Usage Page (Generic Desktop) 59
|
||||
# 0x75, 0x10, // Report Size (16) 61
|
||||
# 0x95, 0x01, // Report Count (1) 63
|
||||
# 0x55, 0x0e, // Unit Exponent (-2) 65
|
||||
# 0x65, 0x11, // Unit (Centimeter,SILinear) 67
|
||||
# 0x09, 0x30, // Usage (X) 69
|
||||
# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 71
|
||||
# 0x35, 0x00, // Physical Minimum (0) 74
|
||||
# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 76
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 79
|
||||
# 0x46, 0x90, 0x07, // Physical Maximum (1936) 81
|
||||
# 0x09, 0x31, // Usage (Y) 84
|
||||
# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 86
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 89
|
||||
# 0xc0, // End Collection 91
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 92
|
||||
# 0x09, 0x22, // Usage (Finger) 94
|
||||
# 0xa1, 0x02, // Collection (Logical) 96
|
||||
# 0x09, 0x42, // Usage (Tip Switch) 98
|
||||
# 0x15, 0x00, // Logical Minimum (0) 100
|
||||
# 0x25, 0x01, // Logical Maximum (1) 102
|
||||
# 0x75, 0x01, // Report Size (1) 104
|
||||
# 0x95, 0x01, // Report Count (1) 106
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 108
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 110
|
||||
# 0x09, 0x47, // Usage (Confidence) 112
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 114
|
||||
# 0x95, 0x05, // Report Count (5) 116
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 118
|
||||
# 0x75, 0x10, // Report Size (16) 120
|
||||
# 0x09, 0x51, // Usage (Contact Id) 122
|
||||
# 0x95, 0x01, // Report Count (1) 124
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 126
|
||||
# 0x05, 0x01, // Usage Page (Generic Desktop) 128
|
||||
# 0x75, 0x10, // Report Size (16) 130
|
||||
# 0x95, 0x01, // Report Count (1) 132
|
||||
# 0x55, 0x0e, // Unit Exponent (-2) 134
|
||||
# 0x65, 0x11, // Unit (Centimeter,SILinear) 136
|
||||
# 0x09, 0x30, // Usage (X) 138
|
||||
# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 140
|
||||
# 0x35, 0x00, // Physical Minimum (0) 143
|
||||
# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 145
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 148
|
||||
# 0x46, 0x90, 0x07, // Physical Maximum (1936) 150
|
||||
# 0x09, 0x31, // Usage (Y) 153
|
||||
# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 155
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 158
|
||||
# 0xc0, // End Collection 160
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 161
|
||||
# 0x09, 0x22, // Usage (Finger) 163
|
||||
# 0xa1, 0x02, // Collection (Logical) 165
|
||||
# 0x09, 0x42, // Usage (Tip Switch) 167
|
||||
# 0x15, 0x00, // Logical Minimum (0) 169
|
||||
# 0x25, 0x01, // Logical Maximum (1) 171
|
||||
# 0x75, 0x01, // Report Size (1) 173
|
||||
# 0x95, 0x01, // Report Count (1) 175
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 177
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 179
|
||||
# 0x09, 0x47, // Usage (Confidence) 181
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 183
|
||||
# 0x95, 0x05, // Report Count (5) 185
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 187
|
||||
# 0x75, 0x10, // Report Size (16) 189
|
||||
# 0x09, 0x51, // Usage (Contact Id) 191
|
||||
# 0x95, 0x01, // Report Count (1) 193
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 195
|
||||
# 0x05, 0x01, // Usage Page (Generic Desktop) 197
|
||||
# 0x75, 0x10, // Report Size (16) 199
|
||||
# 0x95, 0x01, // Report Count (1) 201
|
||||
# 0x55, 0x0e, // Unit Exponent (-2) 203
|
||||
# 0x65, 0x11, // Unit (Centimeter,SILinear) 205
|
||||
# 0x09, 0x30, // Usage (X) 207
|
||||
# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 209
|
||||
# 0x35, 0x00, // Physical Minimum (0) 212
|
||||
# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 214
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 217
|
||||
# 0x46, 0x90, 0x07, // Physical Maximum (1936) 219
|
||||
# 0x09, 0x31, // Usage (Y) 222
|
||||
# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 224
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 227
|
||||
# 0xc0, // End Collection 229
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 230
|
||||
# 0x09, 0x22, // Usage (Finger) 232
|
||||
# 0xa1, 0x02, // Collection (Logical) 234
|
||||
# 0x09, 0x42, // Usage (Tip Switch) 236
|
||||
# 0x15, 0x00, // Logical Minimum (0) 238
|
||||
# 0x25, 0x01, // Logical Maximum (1) 240
|
||||
# 0x75, 0x01, // Report Size (1) 242
|
||||
# 0x95, 0x01, // Report Count (1) 244
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 246
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 248
|
||||
# 0x09, 0x47, // Usage (Confidence) 250
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 252
|
||||
# 0x95, 0x05, // Report Count (5) 254
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 256
|
||||
# 0x75, 0x10, // Report Size (16) 258
|
||||
# 0x09, 0x51, // Usage (Contact Id) 260
|
||||
# 0x95, 0x01, // Report Count (1) 262
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 264
|
||||
# 0x05, 0x01, // Usage Page (Generic Desktop) 266
|
||||
# 0x75, 0x10, // Report Size (16) 268
|
||||
# 0x95, 0x01, // Report Count (1) 270
|
||||
# 0x55, 0x0e, // Unit Exponent (-2) 272
|
||||
# 0x65, 0x11, // Unit (Centimeter,SILinear) 274
|
||||
# 0x09, 0x30, // Usage (X) 276
|
||||
# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 278
|
||||
# 0x35, 0x00, // Physical Minimum (0) 281
|
||||
# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 283
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 286
|
||||
# 0x46, 0x90, 0x07, // Physical Maximum (1936) 288
|
||||
# 0x09, 0x31, // Usage (Y) 291
|
||||
# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 293
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 296
|
||||
# 0xc0, // End Collection 298
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 299
|
||||
# 0x09, 0x22, // Usage (Finger) 301
|
||||
# 0xa1, 0x02, // Collection (Logical) 303
|
||||
# 0x09, 0x42, // Usage (Tip Switch) 305
|
||||
# 0x15, 0x00, // Logical Minimum (0) 307
|
||||
# 0x25, 0x01, // Logical Maximum (1) 309
|
||||
# 0x75, 0x01, // Report Size (1) 311
|
||||
# 0x95, 0x01, // Report Count (1) 313
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 315
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 317
|
||||
# 0x09, 0x47, // Usage (Confidence) 319
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 321
|
||||
# 0x95, 0x05, // Report Count (5) 323
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 325
|
||||
# 0x75, 0x10, // Report Size (16) 327
|
||||
# 0x09, 0x51, // Usage (Contact Id) 329
|
||||
# 0x95, 0x01, // Report Count (1) 331
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 333
|
||||
# 0x05, 0x01, // Usage Page (Generic Desktop) 335
|
||||
# 0x75, 0x10, // Report Size (16) 337
|
||||
# 0x95, 0x01, // Report Count (1) 339
|
||||
# 0x55, 0x0e, // Unit Exponent (-2) 341
|
||||
# 0x65, 0x11, // Unit (Centimeter,SILinear) 343
|
||||
# 0x09, 0x30, // Usage (X) 345
|
||||
# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 347
|
||||
# 0x35, 0x00, // Physical Minimum (0) 350
|
||||
# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 352
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 355
|
||||
# 0x46, 0x90, 0x07, // Physical Maximum (1936) 357
|
||||
# 0x09, 0x31, // Usage (Y) 360
|
||||
# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 362
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 365
|
||||
# 0xc0, // End Collection 367
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 368
|
||||
# 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 370
|
||||
# 0x75, 0x10, // Report Size (16) 375
|
||||
# 0x95, 0x01, // Report Count (1) 377
|
||||
# 0x09, 0x56, // Usage (Scan Time) 379
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 381
|
||||
# 0x85, 0x0c, // Report ID (12) 383
|
||||
# 0x09, 0x55, // Usage (Contact Max) 385
|
||||
# 0x75, 0x08, // Report Size (8) 387
|
||||
# 0x95, 0x01, // Report Count (1) 389
|
||||
# 0x26, 0xff, 0x00, // Logical Maximum (255) 391
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 394
|
||||
# 0x85, 0x0a, // Report ID (10) 396
|
||||
# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 398
|
||||
# 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 401
|
||||
# 0x96, 0x00, 0x01, // Report Count (256) 403
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 406
|
||||
# 0xc0, // End Collection 408
|
||||
# 0x06, 0x11, 0xff, // Usage Page (Vendor Usage Page 0xff11) 409
|
||||
# 0x09, 0x11, // Usage (Vendor Usage 0x11) 412
|
||||
# 0xa1, 0x01, // Collection (Application) 414
|
||||
# 0x85, 0x03, // Report ID (3) 416
|
||||
# 0xa1, 0x02, // Collection (Logical) 418
|
||||
# 0x09, 0x00, // Usage (Vendor Usage 0x00) 420
|
||||
# 0x75, 0x08, // Report Size (8) 422
|
||||
# 0x15, 0x00, // Logical Minimum (0) 424
|
||||
# 0x26, 0xff, 0x00, // Logical Maximum (255) 426
|
||||
# 0x95, 0x27, // Report Count (39) 429
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 431
|
||||
# 0xc0, // End Collection 433
|
||||
# 0x85, 0x02, // Report ID (2) 434
|
||||
# 0x09, 0x00, // Usage (Vendor Usage 0x00) 436
|
||||
# 0x95, 0x01, // Report Count (1) 438
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 440
|
||||
# 0x85, 0x03, // Report ID (3) 442
|
||||
# 0x09, 0x00, // Usage (Vendor Usage 0x00) 444
|
||||
# 0x95, 0x3f, // Report Count (63) 446
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 448
|
||||
# 0x85, 0x04, // Report ID (4) 450
|
||||
# 0x09, 0x00, // Usage (Vendor Usage 0x00) 452
|
||||
# 0x95, 0x0f, // Report Count (15) 454
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 456
|
||||
# 0x85, 0x07, // Report ID (7) 458
|
||||
# 0x09, 0x00, // Usage (Vendor Usage 0x00) 460
|
||||
# 0x96, 0x00, 0x01, // Report Count (256) 462
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 465
|
||||
# 0x85, 0x08, // Report ID (8) 467
|
||||
# 0x09, 0x00, // Usage (Vendor Usage 0x00) 469
|
||||
# 0x96, 0x87, 0x00, // Report Count (135) 471
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 474
|
||||
# 0x85, 0x09, // Report ID (9) 476
|
||||
# 0x09, 0x00, // Usage (Vendor Usage 0x00) 478
|
||||
# 0x96, 0x3f, 0x00, // Report Count (63) 480
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 483
|
||||
# 0x85, 0x0d, // Report ID (13) 485
|
||||
# 0x09, 0x00, // Usage (Vendor Usage 0x00) 487
|
||||
# 0x95, 0x07, // Report Count (7) 489
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 491
|
||||
# 0xc0, // End Collection 493
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 494
|
||||
# 0x09, 0x0e, // Usage (Device Configuration) 496
|
||||
# 0xa1, 0x01, // Collection (Application) 498
|
||||
# 0x85, 0x0e, // Report ID (14) 500
|
||||
# 0x09, 0x23, // Usage (Device Settings) 502
|
||||
# 0xa1, 0x02, // Collection (Logical) 504
|
||||
# 0x09, 0x52, // Usage (Inputmode) 506
|
||||
# 0x09, 0x53, // Usage (Device Index) 508
|
||||
# 0x15, 0x00, // Logical Minimum (0) 510
|
||||
# 0x25, 0x0a, // Logical Maximum (10) 512
|
||||
# 0x75, 0x08, // Report Size (8) 514
|
||||
# 0x95, 0x02, // Report Count (2) 516
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 518
|
||||
# 0xc0, // End Collection 520
|
||||
# 0xc0, // End Collection 521
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 522
|
||||
# 0x09, 0x02, // Usage (Pen) 524
|
||||
# 0xa1, 0x01, // Collection (Application) 526
|
||||
# 0x85, 0x06, // Report ID (6) 528
|
||||
# 0xa4, // Push 530
|
||||
# 0x09, 0x20, // Usage (Stylus) 531
|
||||
# 0xa1, 0x00, // Collection (Physical) 533
|
||||
# 0x09, 0x42, // Usage (Tip Switch) 535
|
||||
# 0x09, 0x44, // Usage (Barrel Switch) 537
|
||||
# 0x09, 0x45, // Usage (Eraser) 539
|
||||
# 0x09, 0x3c, // Usage (Invert) 541
|
||||
# 0x09, 0x5a, // Usage (Secondary Barrel Switch) 543
|
||||
# 0x09, 0x32, // Usage (In Range) 545
|
||||
# 0x15, 0x00, // Logical Minimum (0) 547
|
||||
# 0x25, 0x01, // Logical Maximum (1) 549
|
||||
# 0x75, 0x01, // Report Size (1) 551
|
||||
# 0x95, 0x06, // Report Count (6) 553
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 555
|
||||
# 0x95, 0x02, // Report Count (2) 557
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 559
|
||||
# 0x05, 0x01, // Usage Page (Generic Desktop) 561
|
||||
# 0x09, 0x30, // Usage (X) 563
|
||||
# 0x27, 0x70, 0x86, 0x00, 0x00, // Logical Maximum (34416) 565
|
||||
# 0x47, 0x70, 0x86, 0x00, 0x00, // Physical Maximum (34416) 570
|
||||
# 0x65, 0x11, // Unit (Centimeter,SILinear) 575
|
||||
# 0x55, 0x0d, // Unit Exponent (-3) 577
|
||||
# 0x75, 0x10, // Report Size (16) 579
|
||||
# 0x95, 0x01, // Report Count (1) 581
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 583
|
||||
# 0x09, 0x31, // Usage (Y) 585
|
||||
# 0x27, 0x9f, 0x4b, 0x00, 0x00, // Logical Maximum (19359) 587
|
||||
# 0x47, 0x9f, 0x4b, 0x00, 0x00, // Physical Maximum (19359) 592
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 597
|
||||
# 0x45, 0x00, // Physical Maximum (0) 599
|
||||
# 0x65, 0x00, // Unit (None) 601
|
||||
# 0x55, 0x00, // Unit Exponent (0) 603
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 605
|
||||
# 0x09, 0x30, // Usage (Tip Pressure) 607
|
||||
# 0x26, 0xff, 0x0f, // Logical Maximum (4095) 609
|
||||
# 0x75, 0x10, // Report Size (16) 612
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 614
|
||||
# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 616
|
||||
# 0x09, 0x5b, // Usage (Vendor Usage 0x5b) 619
|
||||
# 0x16, 0x00, 0x80, // Logical Minimum (-32768) 621
|
||||
# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 624
|
||||
# 0x75, 0x10, // Report Size (16) 627
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 629
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 631
|
||||
# 0x09, 0x5b, // Usage (Transducer Serial Number) 633
|
||||
# 0x17, 0x00, 0x00, 0x00, 0x80, // Logical Minimum (-2147483648) 635
|
||||
# 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 640
|
||||
# 0x75, 0x20, // Report Size (32) 645
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 647
|
||||
# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 649
|
||||
# 0x09, 0x00, // Usage (Undefined) 652
|
||||
# 0x75, 0x08, // Report Size (8) 654
|
||||
# 0x26, 0xff, 0x00, // Logical Maximum (255) 656
|
||||
# 0x15, 0x00, // Logical Minimum (0) 659
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 661
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 663
|
||||
# 0x09, 0x3b, // Usage (Battery Strength) 665
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 667
|
||||
# 0x65, 0x14, // Unit (Degrees,EngRotation) 669
|
||||
# 0x55, 0x00, // Unit Exponent (0) 671
|
||||
# 0x16, 0xa6, 0xff, // Logical Minimum (-90) 673
|
||||
# 0x26, 0x5a, 0x00, // Logical Maximum (90) 676
|
||||
# 0x36, 0xa6, 0xff, // Physical Minimum (-90) 679
|
||||
# 0x46, 0x5a, 0x00, // Physical Maximum (90) 682
|
||||
# 0x75, 0x08, // Report Size (8) 685
|
||||
# 0x09, 0x3d, // Usage (X Tilt) 687
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 689
|
||||
# 0x09, 0x3e, // Usage (Y Tilt) 691
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 693
|
||||
# 0xc0, // End Collection 695
|
||||
# 0xb4, // Pop 696
|
||||
# 0x85, 0x13, // Report ID (19) 697
|
||||
# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 699
|
||||
# 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 702
|
||||
# 0x96, 0x00, 0x01, // Report Count (256) 704
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 707
|
||||
# 0xc0, // End Collection 709
|
||||
# 0x06, 0x11, 0xff, // Usage Page (Vendor Usage Page 0xff11) 710
|
||||
# 0x09, 0x02, // Usage (Vendor Usage 0x02) 713
|
||||
# 0xa1, 0x01, // Collection (Application) 715
|
||||
# 0x85, 0x0b, // Report ID (11) 717
|
||||
# 0xa4, // Push 719
|
||||
# 0x09, 0x20, // Usage (Vendor Usage 0x20) 720
|
||||
# 0xa1, 0x00, // Collection (Physical) 722
|
||||
# 0x09, 0x42, // Usage (Vendor Usage 0x42) 724
|
||||
# 0x09, 0x44, // Usage (Vendor Usage 0x44) 726
|
||||
# 0x09, 0x45, // Usage (Vendor Usage 0x45) 728
|
||||
# 0x09, 0x3c, // Usage (Vendor Usage 0x3c) 730
|
||||
# 0x09, 0x5a, // Usage (Vendor Usage 0x5a) 732
|
||||
# 0x09, 0x32, // Usage (Vendor Usage 0x32) 734
|
||||
# 0x15, 0x00, // Logical Minimum (0) 736
|
||||
# 0x25, 0x01, // Logical Maximum (1) 738
|
||||
# 0x75, 0x01, // Report Size (1) 740
|
||||
# 0x95, 0x06, // Report Count (6) 742
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 744
|
||||
# 0x95, 0x02, // Report Count (2) 746
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 748
|
||||
# 0x05, 0x01, // Usage Page (Generic Desktop) 750
|
||||
# 0x09, 0x30, // Usage (X) 752
|
||||
# 0x27, 0x70, 0x86, 0x00, 0x00, // Logical Maximum (34416) 754
|
||||
# 0x47, 0x70, 0x86, 0x00, 0x00, // Physical Maximum (34416) 759
|
||||
# 0x65, 0x11, // Unit (Centimeter,SILinear) 764
|
||||
# 0x55, 0x0d, // Unit Exponent (-3) 766
|
||||
# 0x75, 0x10, // Report Size (16) 768
|
||||
# 0x95, 0x01, // Report Count (1) 770
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 772
|
||||
# 0x09, 0x31, // Usage (Y) 774
|
||||
# 0x27, 0x9f, 0x4b, 0x00, 0x00, // Logical Maximum (19359) 776
|
||||
# 0x47, 0x9f, 0x4b, 0x00, 0x00, // Physical Maximum (19359) 781
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 786
|
||||
# 0x45, 0x00, // Physical Maximum (0) 788
|
||||
# 0x65, 0x00, // Unit (None) 790
|
||||
# 0x55, 0x00, // Unit Exponent (0) 792
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 794
|
||||
# 0x09, 0x30, // Usage (Tip Pressure) 796
|
||||
# 0x26, 0xff, 0x0f, // Logical Maximum (4095) 798
|
||||
# 0x75, 0x10, // Report Size (16) 801
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 803
|
||||
# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 805
|
||||
# 0x09, 0x5b, // Usage (Vendor Usage 0x5b) 808
|
||||
# 0x16, 0x00, 0x80, // Logical Minimum (-32768) 810
|
||||
# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 813
|
||||
# 0x75, 0x10, // Report Size (16) 816
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 818
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 820
|
||||
# 0x09, 0x5b, // Usage (Transducer Serial Number) 822
|
||||
# 0x17, 0x00, 0x00, 0x00, 0x80, // Logical Minimum (-2147483648) 824
|
||||
# 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 829
|
||||
# 0x75, 0x20, // Report Size (32) 834
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 836
|
||||
# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 838
|
||||
# 0x09, 0x00, // Usage (Undefined) 841
|
||||
# 0x75, 0x08, // Report Size (8) 843
|
||||
# 0x26, 0xff, 0x00, // Logical Maximum (255) 845
|
||||
# 0x15, 0x00, // Logical Minimum (0) 848
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 850
|
||||
# 0x05, 0x0d, // Usage Page (Digitizers) 852
|
||||
# 0x09, 0x3b, // Usage (Battery Strength) 854
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 856
|
||||
# 0x65, 0x14, // Unit (Degrees,EngRotation) 858
|
||||
# 0x55, 0x00, // Unit Exponent (0) 860
|
||||
# 0x16, 0xa6, 0xff, // Logical Minimum (-90) 862
|
||||
# 0x26, 0x5a, 0x00, // Logical Maximum (90) 865
|
||||
# 0x36, 0xa6, 0xff, // Physical Minimum (-90) 868
|
||||
# 0x46, 0x5a, 0x00, // Physical Maximum (90) 871
|
||||
# 0x75, 0x08, // Report Size (8) 874
|
||||
# 0x09, 0x3d, // Usage (X Tilt) 876
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 878
|
||||
# 0x09, 0x3e, // Usage (Y Tilt) 880
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 882
|
||||
# 0xc0, // End Collection 884
|
||||
# 0xb4, // Pop 885
|
||||
# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 886
|
||||
# 0x75, 0x08, // Report Size (8) 889
|
||||
# 0x15, 0x00, // Logical Minimum (0) 891
|
||||
# 0x26, 0xff, 0x00, // Logical Maximum (255) 893
|
||||
# 0x85, 0x05, // Report ID (5) 896
|
||||
# 0x09, 0x00, // Usage (Undefined) 898
|
||||
# 0x95, 0x3a, // Report Count (58) 900
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 902
|
||||
# 0x85, 0x10, // Report ID (16) 904
|
||||
# 0x09, 0x00, // Usage (Undefined) 906
|
||||
# 0x95, 0x14, // Report Count (20) 908
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 910
|
||||
# 0x85, 0x0f, // Report ID (15) 912
|
||||
# 0x09, 0x00, // Usage (Undefined) 914
|
||||
# 0x95, 0x28, // Report Count (40) 916
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 918
|
||||
# 0x85, 0x0f, // Report ID (15) 920
|
||||
# 0x09, 0x00, // Usage (Undefined) 922
|
||||
# 0x95, 0x07, // Report Count (7) 924
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 926
|
||||
# 0x85, 0x11, // Report ID (17) 928
|
||||
# 0x09, 0x00, // Usage (Undefined) 930
|
||||
# 0x95, 0x09, // Report Count (9) 932
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 934
|
||||
# 0x85, 0x05, // Report ID (5) 936
|
||||
# 0x09, 0x00, // Usage (Undefined) 938
|
||||
# 0x95, 0x08, // Report Count (8) 940
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 942
|
||||
# 0x85, 0x10, // Report ID (16) 944
|
||||
# 0x09, 0x00, // Usage (Undefined) 946
|
||||
# 0x96, 0x3f, 0x00, // Report Count (63) 948
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 951
|
||||
# 0x85, 0x0b, // Report ID (11) 953
|
||||
# 0x09, 0x00, // Usage (Undefined) 955
|
||||
# 0x96, 0x3f, 0x00, // Report Count (63) 957
|
||||
# 0xb1, 0x02, // Feature (Data,Var,Abs) 960
|
||||
# 0xc0, // End Collection 962
|
||||
# 0x05, 0x01, // Usage Page (Generic Desktop) 963
|
||||
# 0x09, 0x02, // Usage (Mouse) 965
|
||||
# 0xa1, 0x01, // Collection (Application) 967
|
||||
# 0x85, 0x01, // Report ID (1) 969
|
||||
# 0x09, 0x01, // Usage (Pointer) 971
|
||||
# 0xa1, 0x00, // Collection (Physical) 973
|
||||
# 0x05, 0x09, // Usage Page (Button) 975
|
||||
# 0x19, 0x01, // Usage Minimum (1) 977
|
||||
# 0x29, 0x02, // Usage Maximum (2) 979
|
||||
# 0x15, 0x00, // Logical Minimum (0) 981
|
||||
# 0x25, 0x01, // Logical Maximum (1) 983
|
||||
# 0x95, 0x02, // Report Count (2) 985
|
||||
# 0x75, 0x01, // Report Size (1) 987
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 989
|
||||
# 0x95, 0x01, // Report Count (1) 991
|
||||
# 0x75, 0x06, // Report Size (6) 993
|
||||
# 0x81, 0x03, // Input (Cnst,Var,Abs) 995
|
||||
# 0x05, 0x01, // Usage Page (Generic Desktop) 997
|
||||
# 0x09, 0x30, // Usage (X) 999
|
||||
# 0x09, 0x31, // Usage (Y) 1001
|
||||
# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 1003
|
||||
# 0x75, 0x10, // Report Size (16) 1006
|
||||
# 0x95, 0x02, // Report Count (2) 1008
|
||||
# 0x81, 0x02, // Input (Data,Var,Abs) 1010
|
||||
# 0xc0, // End Collection 1012
|
||||
# 0xc0, // End Collection 1013
|
95
plugins/wacom-raw/fu-plugin-wacom-raw.c
Normal file
95
plugins/wacom-raw/fu-plugin-wacom-raw.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fu-plugin-vfuncs.h"
|
||||
#include "fu-wacom-aes-device.h"
|
||||
#include "fu-wacom-emr-device.h"
|
||||
#include "fu-wacom-common.h"
|
||||
|
||||
void
|
||||
fu_plugin_init (FuPlugin *plugin)
|
||||
{
|
||||
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
|
||||
fu_plugin_add_udev_subsystem (plugin, "hidraw");
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error)
|
||||
{
|
||||
g_autoptr(FuDeviceLocker) locker = NULL;
|
||||
if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER))
|
||||
return TRUE;
|
||||
locker = fu_device_locker_new (device, error);
|
||||
if (locker == NULL)
|
||||
return FALSE;
|
||||
return fu_device_detach (device, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error)
|
||||
{
|
||||
g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error);
|
||||
if (locker == NULL)
|
||||
return FALSE;
|
||||
return fu_device_attach (device, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error)
|
||||
{
|
||||
/* interesting device? */
|
||||
if (g_strcmp0 (fu_udev_device_get_subsystem (device), "hidraw") != 0)
|
||||
return TRUE;
|
||||
|
||||
/* wacom */
|
||||
if (fu_udev_device_get_vendor (device) != FU_WACOM_DEVICE_VID)
|
||||
return TRUE;
|
||||
|
||||
/* no actual device to open */
|
||||
if (g_udev_device_get_device_file (fu_udev_device_get_dev (device)) == NULL)
|
||||
return TRUE;
|
||||
|
||||
/* EMR */
|
||||
if (fu_device_has_guid (FU_DEVICE (device), "WacomEMR")) {
|
||||
g_autoptr(FuWacomEmrDevice) dev = fu_wacom_emr_device_new (device);
|
||||
g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (dev, error);
|
||||
if (locker == NULL)
|
||||
return FALSE;
|
||||
fu_plugin_device_add (plugin, FU_DEVICE (dev));
|
||||
}
|
||||
|
||||
/* AES */
|
||||
if (fu_device_has_guid (FU_DEVICE (device), "WacomAES")) {
|
||||
g_autoptr(FuWacomAesDevice) dev = fu_wacom_aes_device_new (device);
|
||||
g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (dev, error);
|
||||
if (locker == NULL)
|
||||
return FALSE;
|
||||
fu_plugin_device_add (plugin, FU_DEVICE (dev));
|
||||
}
|
||||
|
||||
/* not supported */
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Only EMR or AES devices are supported");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_plugin_update (FuPlugin *plugin,
|
||||
FuDevice *device,
|
||||
GBytes *blob_fw,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(FuDeviceLocker) locker = NULL;
|
||||
locker = fu_device_locker_new (device, error);
|
||||
if (locker == NULL)
|
||||
return FALSE;
|
||||
return fu_device_write_firmware (device, blob_fw, error);
|
||||
}
|
246
plugins/wacom-raw/fu-wacom-aes-device.c
Normal file
246
plugins/wacom-raw/fu-wacom-aes-device.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "fu-chunk.h"
|
||||
#include "fu-wacom-common.h"
|
||||
#include "fu-wacom-aes-device.h"
|
||||
|
||||
struct _FuWacomAesDevice {
|
||||
FuWacomDevice parent_instance;
|
||||
guint32 hwid;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FuWacomAesDevice, fu_wacom_aes_device, FU_TYPE_WACOM_DEVICE)
|
||||
|
||||
static gboolean
|
||||
fu_wacom_aes_device_obtain_hwid (FuWacomAesDevice *self, GError **error)
|
||||
{
|
||||
guint8 cmd[FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ] = { 0x0 };
|
||||
guint8 buf[FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ] = { 0x0 };
|
||||
|
||||
cmd[0] = FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID;
|
||||
cmd[1] = 0x01; /* ?? */
|
||||
cmd[2] = 0x01; /* ?? */
|
||||
cmd[3] = 0x0f; /* ?? */
|
||||
|
||||
if (!fu_wacom_device_set_feature (FU_WACOM_DEVICE (self),
|
||||
cmd, sizeof(cmd), error)) {
|
||||
g_prefix_error (error, "failed to send: ");
|
||||
return FALSE;
|
||||
}
|
||||
buf[0] = FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID;
|
||||
if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self),
|
||||
buf, sizeof(buf), error)) {
|
||||
g_prefix_error (error, "failed to receive: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (buf[1] == 0xff) {
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
"firmware does not support this feature");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* check magic number */
|
||||
if (memcmp (buf, "\x34\x12\x78\x56\x65\x87\x21\x43", 8) != 0) {
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
"incorrect magic number");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* format the value */
|
||||
self->hwid = ((guint32) buf[9]) << 24 |
|
||||
((guint32) buf[8]) << 16 |
|
||||
((guint32) buf[11]) << 8 |
|
||||
((guint32) buf[10]);
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_aes_query_operation_mode (FuWacomAesDevice *self, GError **error)
|
||||
{
|
||||
guint8 buf[FU_WACOM_RAW_FW_REPORT_SZ] = {
|
||||
FU_WACOM_RAW_FW_REPORT_ID,
|
||||
FU_WACOM_RAW_FW_CMD_QUERY_MODE,
|
||||
};
|
||||
|
||||
/* 0x00=runtime, 0x02=bootloader */
|
||||
if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), buf, sizeof(buf), error))
|
||||
return FALSE;
|
||||
if (buf[1] == 0x00) {
|
||||
fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||
return TRUE;
|
||||
}
|
||||
if (buf[1] == 0x02) {
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* unsupported */
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Failed to query operation mode, got 0x%x",
|
||||
buf[1]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_aes_device_setup (FuDevice *device, GError **error)
|
||||
{
|
||||
FuWacomAesDevice *self = FU_WACOM_AES_DEVICE (device);
|
||||
|
||||
/* find out if in bootloader mode already */
|
||||
if (!fu_wacom_aes_query_operation_mode (self, error))
|
||||
return FALSE;
|
||||
|
||||
/* get firmware version */
|
||||
if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
|
||||
fu_device_set_version (device, "0.0");
|
||||
} else {
|
||||
guint32 fw_ver;
|
||||
guint8 data[FU_WACOM_RAW_STATUS_REPORT_SZ] = {
|
||||
FU_WACOM_RAW_STATUS_REPORT_ID,
|
||||
0x0
|
||||
};
|
||||
g_autofree gchar *version = NULL;
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
|
||||
if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self),
|
||||
data, sizeof(data), error))
|
||||
return FALSE;
|
||||
fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN);
|
||||
version = g_strdup_printf ("%04x.%02x", fw_ver, data[13]);
|
||||
fu_device_set_version (device, version);
|
||||
|
||||
/* get the optional 32 byte HWID and add it as a GUID */
|
||||
if (!fu_wacom_aes_device_obtain_hwid (self, &error_local)) {
|
||||
g_debug ("failed to get HwID: %s", error_local->message);
|
||||
} else {
|
||||
g_autofree gchar *guid = NULL;
|
||||
guid = g_strdup_printf ("WACOM\\HWID_%04X", self->hwid);
|
||||
fu_device_add_guid (device, guid);
|
||||
}
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_aes_device_erase_all (FuWacomAesDevice *self, GError **error)
|
||||
{
|
||||
FuWacomRawRequest req = {
|
||||
.cmd = FU_WACOM_RAW_BL_CMD_ALL_ERASE,
|
||||
.echo = FU_WACOM_RAW_ECHO_DEFAULT,
|
||||
0x00
|
||||
};
|
||||
FuWacomRawResponse rsp = { 0x00 };
|
||||
if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp,
|
||||
2000 * 1000, /* this takes a long time */
|
||||
FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) {
|
||||
g_prefix_error (error, "failed to send eraseall command: ");
|
||||
return FALSE;
|
||||
}
|
||||
g_usleep (2 * G_USEC_PER_SEC);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_aes_device_write_block (FuWacomAesDevice *self,
|
||||
guint32 idx,
|
||||
guint32 address,
|
||||
const guint8 *data,
|
||||
guint16 datasz,
|
||||
GError **error)
|
||||
{
|
||||
guint blocksz = fu_wacom_device_get_block_sz (FU_WACOM_DEVICE (self));
|
||||
FuWacomRawRequest req = {
|
||||
.cmd = FU_WACOM_RAW_BL_CMD_WRITE_FLASH,
|
||||
.echo = (guint8) idx + 1,
|
||||
.addr = GUINT32_TO_LE(address),
|
||||
.size8 = datasz / 8,
|
||||
.data = { 0x00 },
|
||||
};
|
||||
FuWacomRawResponse rsp = { 0x00 };
|
||||
|
||||
/* check size */
|
||||
if (datasz != blocksz) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"block size 0x%x != 0x%x untested",
|
||||
datasz, (guint) blocksz);
|
||||
return FALSE;
|
||||
}
|
||||
memcpy (&req.data, data, datasz);
|
||||
|
||||
/* write */
|
||||
if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 1000,
|
||||
FU_WACOM_DEVICE_CMD_FLAG_NONE, error)) {
|
||||
g_prefix_error (error, "failed to write block %u: ", idx);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_aes_device_write_firmware (FuDevice *device, GPtrArray *chunks, GError **error)
|
||||
{
|
||||
FuWacomAesDevice *self = FU_WACOM_AES_DEVICE (device);
|
||||
|
||||
/* erase */
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
|
||||
if (!fu_wacom_aes_device_erase_all (self, error))
|
||||
return FALSE;
|
||||
|
||||
/* write */
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
|
||||
for (guint i = 0; i < chunks->len; i++) {
|
||||
FuChunk *chk = g_ptr_array_index (chunks, i);
|
||||
if (!fu_wacom_aes_device_write_block (self,
|
||||
chk->idx,
|
||||
chk->address,
|
||||
chk->data,
|
||||
chk->data_sz,
|
||||
error))
|
||||
return FALSE;
|
||||
fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_wacom_aes_device_init (FuWacomAesDevice *self)
|
||||
{
|
||||
fu_device_set_name (FU_DEVICE (self), "Embedded Wacom AES Device");
|
||||
}
|
||||
|
||||
static void
|
||||
fu_wacom_aes_device_class_init (FuWacomAesDeviceClass *klass)
|
||||
{
|
||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
||||
FuWacomDeviceClass *klass_wac_device = FU_WACOM_DEVICE_CLASS (klass);
|
||||
klass_device->setup = fu_wacom_aes_device_setup;
|
||||
klass_wac_device->write_firmware = fu_wacom_aes_device_write_firmware;
|
||||
}
|
||||
|
||||
FuWacomAesDevice *
|
||||
fu_wacom_aes_device_new (FuUdevDevice *device)
|
||||
{
|
||||
FuWacomAesDevice *self = g_object_new (FU_TYPE_WACOM_AES_DEVICE, NULL);
|
||||
fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device));
|
||||
return self;
|
||||
}
|
21
plugins/wacom-raw/fu-wacom-aes-device.h
Normal file
21
plugins/wacom-raw/fu-wacom-aes-device.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef __FU_WACOM_AES_DEVICE_H
|
||||
#define __FU_WACOM_AES_DEVICE_H
|
||||
|
||||
#include "fu-wacom-device.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FU_TYPE_WACOM_AES_DEVICE (fu_wacom_aes_device_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (FuWacomAesDevice, fu_wacom_aes_device, FU, WACOM_AES_DEVICE, FuWacomDevice)
|
||||
|
||||
FuWacomAesDevice *fu_wacom_aes_device_new (FuUdevDevice *device);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __FU_WACOM_AES_DEVICE_H */
|
108
plugins/wacom-raw/fu-wacom-common.c
Normal file
108
plugins/wacom-raw/fu-wacom-common.c
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "fu-wacom-common.h"
|
||||
|
||||
gboolean
|
||||
fu_wacom_common_check_reply (const FuWacomRawRequest *req,
|
||||
const FuWacomRawResponse *rsp,
|
||||
GError **error)
|
||||
{
|
||||
if (rsp->report_id != FU_WACOM_RAW_BL_REPORT_ID_GET) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"report ID failed, expected 0x%02x, got 0x%02x",
|
||||
(guint) FU_WACOM_RAW_BL_REPORT_ID_GET,
|
||||
req->report_id);
|
||||
return FALSE;
|
||||
}
|
||||
if (req->cmd != rsp->cmd) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"cmd failed, expected 0x%02x, got 0x%02x",
|
||||
req->cmd, rsp->cmd);
|
||||
return FALSE;
|
||||
}
|
||||
if (req->echo != rsp->echo) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"echo failed, expected 0x%02x, got 0x%02x",
|
||||
req->echo, rsp->echo);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_wacom_common_rc_set_error (const FuWacomRawResponse *rsp, GError **error)
|
||||
{
|
||||
if (rsp->resp == FU_WACOM_RAW_RC_OK)
|
||||
return TRUE;
|
||||
if (rsp->resp == FU_WACOM_RAW_RC_BUSY) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_BUSY,
|
||||
"device is busy");
|
||||
return FALSE;
|
||||
}
|
||||
if (rsp->resp == FU_WACOM_RAW_RC_MCUTYPE) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"MCU type does not match");
|
||||
return FALSE;
|
||||
}
|
||||
if (rsp->resp == FU_WACOM_RAW_RC_PID) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"PID does not match");
|
||||
return FALSE;
|
||||
}
|
||||
if (rsp->resp == FU_WACOM_RAW_RC_CHECKSUM1) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"checksum1 does not match");
|
||||
return FALSE;
|
||||
}
|
||||
if (rsp->resp == FU_WACOM_RAW_RC_CHECKSUM2) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"checksum2 does not match");
|
||||
return FALSE;
|
||||
}
|
||||
if (rsp->resp == FU_WACOM_RAW_RC_TIMEOUT) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_TIMED_OUT,
|
||||
"command timed out");
|
||||
return FALSE;
|
||||
}
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"unknown error 0x%02x", rsp->resp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_wacom_common_block_is_empty (const guint8 *data, guint16 datasz)
|
||||
{
|
||||
for (guint16 i = 0; i < datasz; i++) {
|
||||
if (data[i] != 0xff)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
80
plugins/wacom-raw/fu-wacom-common.h
Normal file
80
plugins/wacom-raw/fu-wacom-common.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef __FU_WACOM_COMMON_H
|
||||
#define __FU_WACOM_COMMON_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FU_WACOM_DEVICE_VID 0x056A
|
||||
#define FU_WACOM_RAW_CMD_RETRIES 1000
|
||||
|
||||
#define FU_WACOM_RAW_STATUS_REPORT_ID 0x04
|
||||
#define FU_WACOM_RAW_STATUS_REPORT_SZ 16
|
||||
|
||||
#define FU_WACOM_RAW_FW_REPORT_ID 0x02
|
||||
#define FU_WACOM_RAW_FW_CMD_QUERY_MODE 0x00
|
||||
#define FU_WACOM_RAW_FW_CMD_DETACH 0x02
|
||||
#define FU_WACOM_RAW_FW_REPORT_SZ 2
|
||||
|
||||
#define FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID 0x09
|
||||
#define FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ 64
|
||||
|
||||
#define FU_WACOM_RAW_BL_REPORT_ID_SET 0x07
|
||||
#define FU_WACOM_RAW_BL_REPORT_ID_GET 0x08
|
||||
|
||||
#define FU_WACOM_RAW_BL_CMD_ERASE_FLASH 0x00
|
||||
#define FU_WACOM_RAW_BL_CMD_WRITE_FLASH 0x01
|
||||
#define FU_WACOM_RAW_BL_CMD_VERIFY_FLASH 0x02
|
||||
#define FU_WACOM_RAW_BL_CMD_ATTACH 0x03
|
||||
#define FU_WACOM_RAW_BL_CMD_GET_BLVER 0x04
|
||||
#define FU_WACOM_RAW_BL_CMD_GET_MPUTYPE 0x05
|
||||
#define FU_WACOM_RAW_BL_CMD_CHECK_MODE 0x07
|
||||
#define FU_WACOM_RAW_BL_CMD_ERASE_DATAMEM 0x0e
|
||||
#define FU_WACOM_RAW_BL_CMD_ALL_ERASE 0x90
|
||||
|
||||
#define FU_WACOM_RAW_RC_OK 0x00
|
||||
#define FU_WACOM_RAW_RC_BUSY 0x80
|
||||
#define FU_WACOM_RAW_RC_MCUTYPE 0x0c
|
||||
#define FU_WACOM_RAW_RC_PID 0x0d
|
||||
#define FU_WACOM_RAW_RC_CHECKSUM1 0x81
|
||||
#define FU_WACOM_RAW_RC_CHECKSUM2 0x82
|
||||
#define FU_WACOM_RAW_RC_TIMEOUT 0x87
|
||||
#define FU_WACOM_RAW_RC_IN_PROGRESS 0xff
|
||||
|
||||
#define FU_WACOM_RAW_ECHO_DEFAULT g_random_int_range(0xa0,0xfe)
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
guint8 report_id;
|
||||
guint8 cmd;
|
||||
guint8 echo;
|
||||
guint32 addr;
|
||||
guint8 size8;
|
||||
guint8 data[128];
|
||||
guint8 data_unused[121];
|
||||
} FuWacomRawRequest;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
guint8 report_id;
|
||||
guint8 cmd;
|
||||
guint8 echo;
|
||||
guint8 resp;
|
||||
guint8 data_unused[132];
|
||||
} FuWacomRawResponse;
|
||||
|
||||
gboolean fu_wacom_common_rc_set_error (const FuWacomRawResponse *rsp,
|
||||
GError **error);
|
||||
gboolean fu_wacom_common_check_reply (const FuWacomRawRequest *req,
|
||||
const FuWacomRawResponse *rsp,
|
||||
GError **error);
|
||||
gboolean fu_wacom_common_block_is_empty (const guint8 *data,
|
||||
guint16 datasz);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __FU_WACOM_COMMON_H */
|
420
plugins/wacom-raw/fu-wacom-device.c
Normal file
420
plugins/wacom-raw/fu-wacom-device.c
Normal file
@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <linux/hidraw.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "fu-chunk.h"
|
||||
#include "fu-wacom-common.h"
|
||||
#include "fu-wacom-device.h"
|
||||
#include "dfu-firmware.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint fd;
|
||||
guint flash_block_size;
|
||||
guint32 flash_base_addr;
|
||||
guint32 flash_size;
|
||||
} FuWacomDevicePrivate;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (FuWacomDevice, fu_wacom_device, FU_TYPE_UDEV_DEVICE)
|
||||
|
||||
#define GET_PRIVATE(o) (fu_wacom_device_get_instance_private (o))
|
||||
|
||||
static void
|
||||
fu_wacom_device_to_string (FuDevice *device, GString *str)
|
||||
{
|
||||
FuWacomDevice *self = FU_WACOM_DEVICE (device);
|
||||
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
||||
g_string_append (str, " FuWacomDevice:\n");
|
||||
g_string_append_printf (str, " fd:\t\t\t%i\n", priv->fd);
|
||||
g_string_append_printf (str, " flash-block-size:\t0x%04x\n", priv->flash_block_size);
|
||||
g_string_append_printf (str, " flash-base-addr:\t0x%04x\n", priv->flash_base_addr);
|
||||
g_string_append_printf (str, " flash-size:\t\t0x%04x\n", priv->flash_size);
|
||||
}
|
||||
|
||||
guint
|
||||
fu_wacom_device_get_block_sz (FuWacomDevice *self)
|
||||
{
|
||||
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
||||
return priv->flash_block_size;
|
||||
}
|
||||
|
||||
guint
|
||||
fu_wacom_device_get_base_addr (FuWacomDevice *self)
|
||||
{
|
||||
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
||||
return priv->flash_base_addr;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_wacom_device_check_mpu (FuWacomDevice *self, GError **error)
|
||||
{
|
||||
FuWacomRawRequest req = {
|
||||
.cmd = FU_WACOM_RAW_BL_CMD_GET_MPUTYPE,
|
||||
.echo = FU_WACOM_RAW_ECHO_DEFAULT,
|
||||
0x00
|
||||
};
|
||||
FuWacomRawResponse rsp = { 0x00 };
|
||||
if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 0,
|
||||
FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) {
|
||||
g_prefix_error (error, "failed to get MPU type: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* W9013 */
|
||||
if (rsp.resp == 0x2e) {
|
||||
fu_device_add_guid (FU_DEVICE (self), "WacomEMR_W9013");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* W9021 */
|
||||
if (rsp.resp == 0x45) {
|
||||
fu_device_add_guid (FU_DEVICE (self), "WacomEMR_W9021");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* unsupported */
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"MPU is not W9013 or W9021: 0x%x",
|
||||
rsp.resp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_device_open (FuDevice *device, GError **error)
|
||||
{
|
||||
FuWacomDevice *self = FU_WACOM_DEVICE (device);
|
||||
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
||||
GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device));
|
||||
|
||||
/* open device */
|
||||
priv->fd = g_open (g_udev_device_get_device_file (udev_device), O_RDWR);
|
||||
if (priv->fd < 0) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"failed to open %s",
|
||||
g_udev_device_get_device_file (udev_device));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_device_close (FuDevice *device, GError **error)
|
||||
{
|
||||
FuWacomDevice *self = FU_WACOM_DEVICE (device);
|
||||
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
||||
if (!g_close (priv->fd, error))
|
||||
return FALSE;
|
||||
priv->fd = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_device_probe (FuUdevDevice *device, GError **error)
|
||||
{
|
||||
/* set the physical ID */
|
||||
if (!fu_udev_device_set_physical_id (device, "hid", error))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_device_detach (FuDevice *device, GError **error)
|
||||
{
|
||||
FuWacomDevice *self = FU_WACOM_DEVICE (device);
|
||||
guint8 buf[FU_WACOM_RAW_FW_REPORT_SZ] = {
|
||||
FU_WACOM_RAW_FW_REPORT_ID,
|
||||
FU_WACOM_RAW_FW_CMD_DETACH,
|
||||
};
|
||||
if (!fu_wacom_device_set_feature (self, buf, sizeof(buf), error)) {
|
||||
g_prefix_error (error, "failed to switch to bootloader mode: ");
|
||||
return FALSE;
|
||||
}
|
||||
g_usleep (300 * 1000);
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_device_attach (FuDevice *device, GError **error)
|
||||
{
|
||||
FuWacomDevice *self = FU_WACOM_DEVICE (device);
|
||||
FuWacomRawRequest req = {
|
||||
.report_id = FU_WACOM_RAW_BL_REPORT_ID_SET,
|
||||
.cmd = FU_WACOM_RAW_BL_CMD_ATTACH,
|
||||
.echo = FU_WACOM_RAW_ECHO_DEFAULT,
|
||||
0x00
|
||||
};
|
||||
if (!fu_wacom_device_set_feature (self, (const guint8 *) &req, sizeof(req), error)) {
|
||||
g_prefix_error (error, "failed to switch to runtime mode: ");
|
||||
return FALSE;
|
||||
}
|
||||
/* only required on AES, but harmless for EMR */
|
||||
g_usleep (300 * 1000);
|
||||
fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_device_check_mode (FuWacomDevice *self, GError **error)
|
||||
{
|
||||
FuWacomRawRequest req = {
|
||||
.cmd = FU_WACOM_RAW_BL_CMD_CHECK_MODE,
|
||||
.echo = FU_WACOM_RAW_ECHO_DEFAULT,
|
||||
0x00
|
||||
};
|
||||
FuWacomRawResponse rsp = { 0x00 };
|
||||
if (!fu_wacom_device_cmd (self, &req, &rsp, 0,
|
||||
FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) {
|
||||
g_prefix_error (error, "failed to check mode: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (rsp.resp != 0x06) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"check mode failed, mode=0x%02x",
|
||||
rsp.resp);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_device_set_version_bootloader (FuWacomDevice *self, GError **error)
|
||||
{
|
||||
FuWacomRawRequest req = {
|
||||
.cmd = FU_WACOM_RAW_BL_CMD_GET_BLVER,
|
||||
.echo = FU_WACOM_RAW_ECHO_DEFAULT,
|
||||
0x00
|
||||
};
|
||||
FuWacomRawResponse rsp = { 0x00 };
|
||||
g_autofree gchar *version = NULL;
|
||||
if (!fu_wacom_device_cmd (self, &req, &rsp, 0,
|
||||
FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) {
|
||||
g_prefix_error (error, "failed to get bootloader version: ");
|
||||
return FALSE;
|
||||
}
|
||||
version = g_strdup_printf ("%u", rsp.resp);
|
||||
fu_device_set_version_bootloader (FU_DEVICE (self), version);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_device_write_firmware (FuDevice *device, GBytes *fw, GError **error)
|
||||
{
|
||||
FuWacomDevice *self = FU_WACOM_DEVICE (device);
|
||||
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
||||
FuWacomDeviceClass *klass = FU_WACOM_DEVICE_GET_CLASS (device);
|
||||
DfuElement *element;
|
||||
DfuImage *image;
|
||||
GBytes *fw_new;
|
||||
g_autoptr(DfuFirmware) firmware = dfu_firmware_new ();
|
||||
g_autoptr(GPtrArray) chunks = NULL;
|
||||
|
||||
/* parse hex file */
|
||||
if (!dfu_firmware_parse_data (firmware, fw, DFU_FIRMWARE_PARSE_FLAG_NONE, error))
|
||||
return FALSE;
|
||||
if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_INTEL_HEX) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INTERNAL,
|
||||
"expected firmware format is 'ihex', got '%s'",
|
||||
dfu_firmware_format_to_string (dfu_firmware_get_format (firmware)));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* use the correct image from the firmware */
|
||||
image = dfu_firmware_get_image_default (firmware);
|
||||
if (image == NULL) {
|
||||
g_set_error_literal (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INTERNAL,
|
||||
"no firmware image");
|
||||
return FALSE;
|
||||
}
|
||||
element = dfu_image_get_element_default (image);
|
||||
if (element == NULL) {
|
||||
g_set_error_literal (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INTERNAL,
|
||||
"no element in image");
|
||||
return FALSE;
|
||||
}
|
||||
g_debug ("using element at addr 0x%0x",
|
||||
(guint) dfu_element_get_address (element));
|
||||
|
||||
/* check start address and size */
|
||||
if (dfu_element_get_address (element) != priv->flash_base_addr) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"base addr invalid: 0x%05x",
|
||||
(guint) dfu_element_get_address (element));
|
||||
return FALSE;
|
||||
}
|
||||
fw_new = dfu_element_get_contents (element);
|
||||
if (g_bytes_get_size (fw_new) > priv->flash_size) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"size is invalid: 0x%05x",
|
||||
(guint) g_bytes_get_size (fw_new));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* we're in bootloader mode now */
|
||||
if (!fu_wacom_device_check_mode (self, error))
|
||||
return FALSE;
|
||||
if (!fu_wacom_device_set_version_bootloader (self, error))
|
||||
return FALSE;
|
||||
|
||||
/* flash chunks */
|
||||
chunks = fu_chunk_array_new_from_bytes (fw_new, priv->flash_base_addr,
|
||||
0x00, /* page_sz */
|
||||
priv->flash_block_size);
|
||||
return klass->write_firmware (device, chunks, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_wacom_device_set_feature (FuWacomDevice *self,
|
||||
const guint8 *data,
|
||||
guint datasz,
|
||||
GError **error)
|
||||
{
|
||||
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
||||
|
||||
/* Set Feature */
|
||||
fu_common_dump_raw (G_LOG_DOMAIN, "SetFeature", data, datasz);
|
||||
if (ioctl (priv->fd, HIDIOCSFEATURE(datasz), data) < 0) {
|
||||
g_set_error_literal (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INTERNAL,
|
||||
"failed to SetFeature");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_wacom_device_get_feature (FuWacomDevice *self,
|
||||
guint8 *data,
|
||||
guint datasz,
|
||||
GError **error)
|
||||
{
|
||||
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
||||
if (ioctl (priv->fd, HIDIOCGFEATURE(datasz), data) < 0) {
|
||||
g_set_error_literal (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INTERNAL,
|
||||
"failed to GetFeature");
|
||||
return FALSE;
|
||||
}
|
||||
fu_common_dump_raw (G_LOG_DOMAIN, "GetFeature", data, datasz);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_wacom_device_cmd (FuWacomDevice *self,
|
||||
FuWacomRawRequest *req, FuWacomRawResponse *rsp,
|
||||
gulong delay_us, FuWacomDeviceCmdFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
req->report_id = FU_WACOM_RAW_BL_REPORT_ID_SET;
|
||||
if (!fu_wacom_device_set_feature (self, (const guint8 *)req, sizeof(*req), error)) {
|
||||
g_prefix_error (error, "failed to send: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (delay_us > 0)
|
||||
g_usleep (delay_us);
|
||||
rsp->report_id = FU_WACOM_RAW_BL_REPORT_ID_GET;
|
||||
if (!fu_wacom_device_get_feature (self, (guint8 *)rsp, sizeof(*rsp), error)) {
|
||||
g_prefix_error (error, "failed to receive: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (flags & FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK)
|
||||
return TRUE;
|
||||
if (!fu_wacom_common_check_reply (req, rsp, error))
|
||||
return FALSE;
|
||||
|
||||
/* wait for the command to complete */
|
||||
if (flags & FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING &&
|
||||
rsp->resp != FU_WACOM_RAW_RC_OK) {
|
||||
for (guint i = 0; i < FU_WACOM_RAW_CMD_RETRIES; i++) {
|
||||
if (delay_us > 0)
|
||||
g_usleep (delay_us);
|
||||
if (!fu_wacom_device_get_feature (self, (guint8 *)rsp, sizeof(*rsp), error))
|
||||
return FALSE;
|
||||
if (!fu_wacom_common_check_reply (req, rsp, error))
|
||||
return FALSE;
|
||||
if (rsp->resp != FU_WACOM_RAW_RC_IN_PROGRESS &&
|
||||
rsp->resp != FU_WACOM_RAW_RC_BUSY)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return fu_wacom_common_rc_set_error (rsp, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_device_set_quirk_kv (FuDevice *device,
|
||||
const gchar *key,
|
||||
const gchar *value,
|
||||
GError **error)
|
||||
{
|
||||
FuWacomDevice *self = FU_WACOM_DEVICE (device);
|
||||
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
||||
if (g_strcmp0 (key, "WacomI2cFlashBlockSize") == 0) {
|
||||
priv->flash_block_size = fu_common_strtoull (value);
|
||||
return TRUE;
|
||||
}
|
||||
if (g_strcmp0 (key, "WacomI2cFlashBaseAddr") == 0) {
|
||||
priv->flash_base_addr = fu_common_strtoull (value);
|
||||
return TRUE;
|
||||
}
|
||||
if (g_strcmp0 (key, "WacomI2cFlashSize") == 0) {
|
||||
priv->flash_size = fu_common_strtoull (value);
|
||||
return TRUE;
|
||||
}
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
"quirk key not supported");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_wacom_device_init (FuWacomDevice *self)
|
||||
{
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_wacom_device_class_init (FuWacomDeviceClass *klass)
|
||||
{
|
||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
||||
FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass);
|
||||
klass_device->to_string = fu_wacom_device_to_string;
|
||||
klass_device->open = fu_wacom_device_open;
|
||||
klass_device->close = fu_wacom_device_close;
|
||||
klass_device->write_firmware = fu_wacom_device_write_firmware;
|
||||
klass_device->attach = fu_wacom_device_attach;
|
||||
klass_device->detach = fu_wacom_device_detach;
|
||||
klass_device->set_quirk_kv = fu_wacom_device_set_quirk_kv;
|
||||
klass_device_udev->probe = fu_wacom_device_probe;
|
||||
}
|
56
plugins/wacom-raw/fu-wacom-device.h
Normal file
56
plugins/wacom-raw/fu-wacom-device.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef __FU_WACOM_DEVICE_H
|
||||
#define __FU_WACOM_DEVICE_H
|
||||
|
||||
#include "fu-wacom-common.h"
|
||||
#include "fu-udev-device.h"
|
||||
#include "dfu-element.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FU_TYPE_WACOM_DEVICE (fu_wacom_device_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (FuWacomDevice, fu_wacom_device, FU, WACOM_DEVICE, FuUdevDevice)
|
||||
|
||||
struct _FuWacomDeviceClass
|
||||
{
|
||||
FuUdevDeviceClass parent_class;
|
||||
gboolean (*write_firmware) (FuDevice *self,
|
||||
GPtrArray *chunks,
|
||||
GError **error);
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
FU_WACOM_DEVICE_CMD_FLAG_NONE = 0,
|
||||
FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING = 1 << 0,
|
||||
FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK = 1 << 1,
|
||||
} FuWacomDeviceCmdFlags;
|
||||
|
||||
gboolean fu_wacom_device_set_feature (FuWacomDevice *self,
|
||||
const guint8 *data,
|
||||
guint datasz,
|
||||
GError **error);
|
||||
gboolean fu_wacom_device_get_feature (FuWacomDevice *self,
|
||||
guint8 *data,
|
||||
guint datasz,
|
||||
GError **error);
|
||||
gboolean fu_wacom_device_cmd (FuWacomDevice *self,
|
||||
FuWacomRawRequest *req,
|
||||
FuWacomRawResponse *rsp,
|
||||
gulong delay_us,
|
||||
FuWacomDeviceCmdFlags flags,
|
||||
GError **error);
|
||||
gboolean fu_wacom_device_erase_all (FuWacomDevice *self,
|
||||
GError **error);
|
||||
gboolean fu_wacom_device_check_mpu (FuWacomDevice *self,
|
||||
GError **error);
|
||||
guint fu_wacom_device_get_block_sz (FuWacomDevice *self);
|
||||
guint fu_wacom_device_get_base_addr (FuWacomDevice *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __FU_WACOM_DEVICE_H */
|
246
plugins/wacom-raw/fu-wacom-emr-device.c
Normal file
246
plugins/wacom-raw/fu-wacom-emr-device.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "fu-chunk.h"
|
||||
#include "fu-wacom-common.h"
|
||||
#include "fu-wacom-emr-device.h"
|
||||
|
||||
struct _FuWacomEmrDevice {
|
||||
FuWacomDevice parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FuWacomEmrDevice, fu_wacom_emr_device, FU_TYPE_WACOM_DEVICE)
|
||||
|
||||
static gboolean
|
||||
fu_wacom_emr_device_setup (FuDevice *device, GError **error)
|
||||
{
|
||||
FuWacomEmrDevice *self = FU_WACOM_EMR_DEVICE (device);
|
||||
|
||||
/* check MPU type */
|
||||
if (!fu_wacom_device_check_mpu (FU_WACOM_DEVICE (self), error))
|
||||
return FALSE;
|
||||
|
||||
/* get firmware version */
|
||||
if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
|
||||
fu_device_set_version (device, "0.0");
|
||||
} else {
|
||||
guint16 fw_ver;
|
||||
guint8 data[19] = { 0x03, 0x0 }; /* 0x03 is an unknown ReportID */
|
||||
g_autofree gchar *version = NULL;
|
||||
if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self),
|
||||
data, sizeof(data), error))
|
||||
return FALSE;
|
||||
fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN);
|
||||
fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||
version = fu_common_version_from_uint16 (fw_ver, FU_VERSION_FORMAT_PAIR);
|
||||
fu_device_set_version (device, version);
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static guint8
|
||||
fu_wacom_emr_device_calc_checksum (guint8 init1, const guint8 *buf, guint8 bufsz)
|
||||
{
|
||||
guint8 sum = 0;
|
||||
sum += init1;
|
||||
for (guint i = 0; i < bufsz; i++)
|
||||
sum += buf[i];
|
||||
return ~sum + 1;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_emr_device_w9013_erase_data (FuWacomEmrDevice *self, GError **error)
|
||||
{
|
||||
FuWacomRawResponse rsp = { 0x00 };
|
||||
FuWacomRawRequest req = {
|
||||
.cmd = FU_WACOM_RAW_BL_CMD_ERASE_DATAMEM,
|
||||
.echo = FU_WACOM_RAW_ECHO_DEFAULT,
|
||||
0x00
|
||||
};
|
||||
guint8 *buf = (guint8 *) &req.addr;
|
||||
buf[0] = 0x00; /* erased block */
|
||||
buf[1] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x07 + 0x00,
|
||||
(const guint8 *) &req, 4);
|
||||
if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50,
|
||||
FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) {
|
||||
g_prefix_error (error, "failed to erase datamem: ");
|
||||
return FALSE;
|
||||
}
|
||||
g_usleep (50);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_emr_device_w9013_erase_code (FuWacomEmrDevice *self,
|
||||
guint8 idx,
|
||||
guint8 block_nr,
|
||||
GError **error)
|
||||
{
|
||||
FuWacomRawResponse rsp = { 0x00 };
|
||||
FuWacomRawRequest req = {
|
||||
.cmd = FU_WACOM_RAW_BL_CMD_ERASE_FLASH,
|
||||
.echo = idx,
|
||||
0x00
|
||||
};
|
||||
guint8 *buf = (guint8 *) &req.addr;
|
||||
buf[0] = block_nr;
|
||||
buf[1] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x07 + 0x00,
|
||||
(const guint8 *) &req, 4);
|
||||
if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50,
|
||||
FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) {
|
||||
g_prefix_error (error, "failed to erase codemem: ");
|
||||
return FALSE;
|
||||
}
|
||||
g_usleep (50);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_device_w9021_erase_all (FuWacomEmrDevice *self, GError **error)
|
||||
{
|
||||
FuWacomRawRequest req = {
|
||||
.cmd = FU_WACOM_RAW_BL_CMD_ALL_ERASE,
|
||||
.echo = 0x01,
|
||||
.addr = 0x00,
|
||||
};
|
||||
FuWacomRawResponse rsp = { 0x00 };
|
||||
if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp,
|
||||
2000 * 1000, /* this takes a long time */
|
||||
FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) {
|
||||
g_prefix_error (error, "failed to send eraseall command: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_wacom_common_rc_set_error (&rsp, error)) {
|
||||
g_prefix_error (error, "failed to erase");
|
||||
return FALSE;
|
||||
}
|
||||
g_usleep (50);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_emr_device_write_block (FuWacomEmrDevice *self,
|
||||
guint32 idx,
|
||||
guint32 address,
|
||||
const guint8 *data,
|
||||
guint16 datasz,
|
||||
GError **error)
|
||||
{
|
||||
guint blocksz = fu_wacom_device_get_block_sz (FU_WACOM_DEVICE (self));
|
||||
FuWacomRawRequest req = {
|
||||
.cmd = FU_WACOM_RAW_BL_CMD_WRITE_FLASH,
|
||||
.echo = (guint8) idx + 1,
|
||||
.addr = GUINT32_TO_LE(address),
|
||||
.size8 = datasz / 8,
|
||||
.data = { 0x00 },
|
||||
};
|
||||
FuWacomRawResponse rsp = { 0x00 };
|
||||
|
||||
/* check size */
|
||||
if (datasz > sizeof(req.data)) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"data size 0x%x too large for packet",
|
||||
datasz);
|
||||
return FALSE;
|
||||
}
|
||||
if (datasz != blocksz) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"block size 0x%x != 0x%x untested",
|
||||
datasz, (guint) blocksz);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* data */
|
||||
memcpy (&req.data, data, datasz);
|
||||
|
||||
/* cmd and data checksums */
|
||||
req.data[blocksz + 0] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x4c + 0x00,
|
||||
(const guint8 *) &req, 8);
|
||||
req.data[blocksz + 1] = fu_wacom_emr_device_calc_checksum (0x00, data, datasz);
|
||||
if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50,
|
||||
FU_WACOM_DEVICE_CMD_FLAG_NONE, error)) {
|
||||
g_prefix_error (error, "failed to write at 0x%x: ", address);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_wacom_emr_device_write_firmware (FuDevice *device, GPtrArray *chunks, GError **error)
|
||||
{
|
||||
FuWacomEmrDevice *self = FU_WACOM_EMR_DEVICE (device);
|
||||
guint8 idx = 0;
|
||||
|
||||
/* erase W9013 */
|
||||
if (fu_device_has_guid (device, "WacomEMR_W9013")) {
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
|
||||
if (!fu_wacom_emr_device_w9013_erase_data (self, error))
|
||||
return FALSE;
|
||||
for (guint i = 127; i >= 8; i--) {
|
||||
if (!fu_wacom_emr_device_w9013_erase_code (self, idx++, i, error))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* erase W9021 */
|
||||
if (fu_device_has_guid (device, "WacomEMR_W9021")) {
|
||||
if (!fu_wacom_device_w9021_erase_all (self, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* write */
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
|
||||
for (guint i = 0; i < chunks->len; i++) {
|
||||
FuChunk *chk = g_ptr_array_index (chunks, i);
|
||||
if (fu_wacom_common_block_is_empty (chk->data, chk->data_sz))
|
||||
continue;
|
||||
if (!fu_wacom_emr_device_write_block (self,
|
||||
chk->idx,
|
||||
chk->address,
|
||||
chk->data,
|
||||
chk->data_sz,
|
||||
error))
|
||||
return FALSE;
|
||||
fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len);
|
||||
}
|
||||
|
||||
fu_device_set_progress (device, 100);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_wacom_emr_device_init (FuWacomEmrDevice *self)
|
||||
{
|
||||
fu_device_set_name (FU_DEVICE (self), "Embedded Wacom EMR Device");
|
||||
}
|
||||
|
||||
static void
|
||||
fu_wacom_emr_device_class_init (FuWacomEmrDeviceClass *klass)
|
||||
{
|
||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
||||
FuWacomDeviceClass *klass_wac_device = FU_WACOM_DEVICE_CLASS (klass);
|
||||
klass_device->setup = fu_wacom_emr_device_setup;
|
||||
klass_wac_device->write_firmware = fu_wacom_emr_device_write_firmware;
|
||||
}
|
||||
|
||||
FuWacomEmrDevice *
|
||||
fu_wacom_emr_device_new (FuUdevDevice *device)
|
||||
{
|
||||
FuWacomEmrDevice *self = g_object_new (FU_TYPE_WACOM_EMR_DEVICE, NULL);
|
||||
fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device));
|
||||
return self;
|
||||
}
|
21
plugins/wacom-raw/fu-wacom-emr-device.h
Normal file
21
plugins/wacom-raw/fu-wacom-emr-device.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef __FU_WACOM_EMR_DEVICE_H
|
||||
#define __FU_WACOM_EMR_DEVICE_H
|
||||
|
||||
#include "fu-wacom-device.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FU_TYPE_WACOM_EMR_DEVICE (fu_wacom_emr_device_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (FuWacomEmrDevice, fu_wacom_emr_device, FU, WACOM_EMR_DEVICE, FuUdevDevice)
|
||||
|
||||
FuWacomEmrDevice *fu_wacom_emr_device_new (FuUdevDevice *device);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __FU_WACOM_EMR_DEVICE_H */
|
31
plugins/wacom-raw/meson.build
Normal file
31
plugins/wacom-raw/meson.build
Normal file
@ -0,0 +1,31 @@
|
||||
cargs = ['-DG_LOG_DOMAIN="FuPluginWacomRaw"']
|
||||
|
||||
install_data(['wacom-raw.quirk'],
|
||||
install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
|
||||
)
|
||||
|
||||
shared_module('fu_plugin_wacom_raw',
|
||||
fu_hash,
|
||||
sources : [
|
||||
'fu-plugin-wacom-raw.c',
|
||||
'fu-wacom-common.c',
|
||||
'fu-wacom-device.c',
|
||||
'fu-wacom-aes-device.c',
|
||||
'fu-wacom-emr-device.c',
|
||||
],
|
||||
include_directories : [
|
||||
include_directories('../..'),
|
||||
include_directories('../dfu'),
|
||||
include_directories('../../src'),
|
||||
include_directories('../../libfwupd'),
|
||||
],
|
||||
install : true,
|
||||
install_dir: plugin_dir,
|
||||
c_args : cargs,
|
||||
dependencies : [
|
||||
plugin_deps,
|
||||
],
|
||||
link_with : [
|
||||
dfu,
|
||||
],
|
||||
)
|
35
plugins/wacom-raw/wacom-raw.quirk
Normal file
35
plugins/wacom-raw/wacom-raw.quirk
Normal file
@ -0,0 +1,35 @@
|
||||
# Devices that do "replug" and thus don't change VID:PID to the bootloader
|
||||
# need to have an extra GUID of WacomAES or WacomEMR added so that the flash
|
||||
# constants are set correctly.
|
||||
|
||||
# Dell XPS-15 9575
|
||||
[DeviceInstanceId=HIDRAW\VEN_056A&DEV_4875]
|
||||
Plugin = wacom_raw
|
||||
Guid = WacomAES
|
||||
|
||||
# AES bootloader mode
|
||||
[DeviceInstanceId=HIDRAW\VEN_056A&DEV_0094]
|
||||
Plugin = wacom_raw
|
||||
Guid = WacomAES
|
||||
Flags = is-bootloader
|
||||
|
||||
# EMR bootloader mode
|
||||
[DeviceInstanceId=HIDRAW\VEN_056A&DEV_012B]
|
||||
Plugin = wacom_raw
|
||||
Guid = WacomEMR
|
||||
Flags = is-bootloader
|
||||
|
||||
[Guid=WacomEMR_W9013]
|
||||
WacomI2cFlashBlockSize=64
|
||||
WacomI2cFlashBaseAddr=0x2000
|
||||
WacomI2cFlashSize=0x1e000
|
||||
|
||||
[Guid=WacomEMR_W9021]
|
||||
WacomI2cFlashBlockSize=256
|
||||
WacomI2cFlashBaseAddr=0x3000
|
||||
WacomI2cFlashSize=0x3c000
|
||||
|
||||
[Guid=WacomAES]
|
||||
WacomI2cFlashBlockSize=128
|
||||
WacomI2cFlashBaseAddr=0x8000
|
||||
WacomI2cFlashSize=0x24000
|
Loading…
Reference in New Issue
Block a user