@@ -317,20 +317,26 @@ static int cps_claim(HIDDevice_t *hd) {
317
317
}
318
318
}
319
319
320
- /* CPS Models like CP900EPFCLCD/CP1500PFCLCDa return a syntactically legal but incorrect
321
- * Report Descriptor whereby the Input High Transfer Max/Min values
322
- * are used for the Output Voltage Usage Item limits.
320
+ /* CPS Models like CP900EPFCLCD/CP1500PFCLCDa return a syntactically
321
+ * legal but incorrect Report Descriptor whereby the Input High Transfer
322
+ * Max/Min values are used for the Output Voltage Usage Item limits.
323
323
* Additionally the Input Voltage LogMax is set incorrectly for EU models.
324
324
* This corrects them by finding and applying fixed
325
325
* voltage limits as being more appropriate.
326
326
*/
327
327
328
328
static int cps_fix_report_desc (HIDDevice_t * pDev , HIDDesc_t * pDesc_arg ) {
329
329
HIDData_t * pData ;
330
+ int retval = 0 ;
330
331
331
332
int vendorID = pDev -> VendorID ;
332
333
int productID = pDev -> ProductID ;
333
334
if (vendorID != CPS_VENDORID || (productID != 0x0501 && productID != 0x0601 )) {
335
+ upsdebugx (3 ,
336
+ "NOT Attempting Report Descriptor fix for UPS: "
337
+ "Vendor: %04x, Product: %04x "
338
+ "(vendor/product not matched)" ,
339
+ vendorID , productID );
334
340
return 0 ;
335
341
}
336
342
@@ -343,43 +349,168 @@ static int cps_fix_report_desc(HIDDevice_t *pDev, HIDDesc_t *pDesc_arg) {
343
349
return 0 ;
344
350
}
345
351
346
- upsdebugx (3 , "Attempting Report Descriptor fix for UPS: Vendor: %04x, Product: %04x" , vendorID , productID );
352
+ upsdebugx (3 , "Attempting Report Descriptor fix for UPS: "
353
+ "Vendor: %04x, Product: %04x" , vendorID , productID );
347
354
348
- /* Apply the fix cautiously by looking for input voltage, high voltage transfer and output voltage report usages.
349
- * If the output voltage log min/max equals high voltage transfer log min/max then the bug is present.
350
- * To fix it Set both the input and output voltages to pre-defined settings.
355
+ /* Apply the fix cautiously by looking for input voltage,
356
+ * high voltage transfer and output voltage report usages.
357
+ * If the output voltage log min/max equals high voltage
358
+ * transfer log min/max, then the bug is present.
359
+ *
360
+ * To fix it set both the input and output voltages to our
361
+ * pre-defined settings CPS_VOLTAGE_LOGMIN/CPS_VOLTAGE_LOGMAX.
351
362
*/
352
363
353
- if ((pData = FindObject_with_ID_Node (pDesc_arg , 16 , USAGE_POW_HIGH_VOLTAGE_TRANSFER ))) {
364
+ if ((pData = FindObject_with_ID_Node (pDesc_arg , 16 /* 0x10 */ , USAGE_POW_HIGH_VOLTAGE_TRANSFER ))) {
354
365
long hvt_logmin = pData -> LogMin ;
355
366
long hvt_logmax = pData -> LogMax ;
356
- upsdebugx (4 , "Report Descriptor: hvt input LogMin: %ld LogMax: %ld" , hvt_logmin , hvt_logmax );
367
+ upsdebugx (4 , "Original Report Descriptor: hvt input "
368
+ "LogMin: %ld LogMax: %ld" , hvt_logmin , hvt_logmax );
357
369
358
- if ((pData = FindObject_with_ID_Node (pDesc_arg , 18 , USAGE_POW_VOLTAGE ))) {
370
+ if ((pData = FindObject_with_ID_Node (pDesc_arg , 18 /* 0x12 */ , USAGE_POW_VOLTAGE ))) {
359
371
long output_logmin = pData -> LogMin ;
360
372
long output_logmax = pData -> LogMax ;
361
- upsdebugx (4 , "Report Descriptor: output LogMin: %ld LogMax: %ld" ,
362
- output_logmin , output_logmax );
373
+ upsdebugx (4 , "Original Report Descriptor: output "
374
+ "LogMin: %ld LogMax: %ld" ,
375
+ output_logmin , output_logmax );
363
376
364
377
if (hvt_logmin == output_logmin && hvt_logmax == output_logmax ) {
365
378
pData -> LogMin = CPS_VOLTAGE_LOGMIN ;
366
379
pData -> LogMax = CPS_VOLTAGE_LOGMAX ;
367
- upsdebugx (3 , "Fixing Report Descriptor. Set Output Voltage LogMin = %d, LogMax = %d" ,
368
- CPS_VOLTAGE_LOGMIN , CPS_VOLTAGE_LOGMAX );
369
- if ((pData = FindObject_with_ID_Node (pDesc_arg , 15 , USAGE_POW_VOLTAGE ))) {
380
+ upsdebugx (3 , "Fixing Report Descriptor: "
381
+ "set Output Voltage LogMin = %d, LogMax = %d" ,
382
+ CPS_VOLTAGE_LOGMIN , CPS_VOLTAGE_LOGMAX );
383
+
384
+ if ((pData = FindObject_with_ID_Node (pDesc_arg , 15 /* 0x0F */ , USAGE_POW_VOLTAGE ))) {
370
385
long input_logmin = pData -> LogMin ;
371
386
long input_logmax = pData -> LogMax ;
372
- upsdebugx (4 , "Report Descriptor: input LogMin: %ld LogMax: %ld" ,
373
- input_logmin , input_logmax );
374
- upsdebugx (3 , "Fixing Report Descriptor. Set Input Voltage LogMin = %d, LogMax = %d" ,
375
- CPS_VOLTAGE_LOGMIN , CPS_VOLTAGE_LOGMAX );
387
+ upsdebugx (4 , "Original Report Descriptor: input "
388
+ "LogMin: %ld LogMax: %ld" ,
389
+ input_logmin , input_logmax );
390
+
391
+ pData -> LogMin = CPS_VOLTAGE_LOGMIN ;
392
+ pData -> LogMax = CPS_VOLTAGE_LOGMAX ;
393
+ upsdebugx (3 , "Fixing Report Descriptor: "
394
+ "set Input Voltage LogMin = %d, LogMax = %d" ,
395
+ CPS_VOLTAGE_LOGMIN , CPS_VOLTAGE_LOGMAX );
376
396
}
377
397
378
- return 1 ;
398
+ retval = 1 ;
379
399
}
380
400
}
381
401
}
382
- return 0 ;
402
+
403
+ if ((pData = FindObject_with_ID_Node (pDesc_arg , 18 /* 0x12 */ , USAGE_POW_VOLTAGE ))) {
404
+ HIDData_t * output_pData = pData ;
405
+ long output_logmin = output_pData -> LogMin ;
406
+ long output_logmax = output_pData -> LogMax ;
407
+ bool output_logmax_assumed = output_pData -> assumed_LogMax ;
408
+
409
+ if ((pData = FindObject_with_ID_Node (pDesc_arg , 15 /* 0x0F */ , USAGE_POW_VOLTAGE ))) {
410
+ HIDData_t * input_pData = pData ;
411
+ long input_logmin = input_pData -> LogMin ;
412
+ long input_logmax = input_pData -> LogMax ;
413
+ bool input_logmax_assumed = input_pData -> assumed_LogMax ;
414
+
415
+ if ( (output_logmax_assumed || input_logmax_assumed )
416
+ /* && output_logmax != input_logmax */
417
+ ) {
418
+ /* We often get 0x0F ReportdId LogMax=65535
419
+ * and 0x12 ReportdId LogMax=255 because of
420
+ * wrong encoding. See e.g. analysis at
421
+ * https://github.com/networkupstools/nut/issues/1512#issuecomment-1224652911
422
+ */
423
+ upsdebugx (4 , "Original Report Descriptor: output 0x12 "
424
+ "LogMin: %ld LogMax: %ld (assumed: %s) Size: %" PRIu8 ,
425
+ output_logmin , output_logmax ,
426
+ output_logmax_assumed ? "yes" : "no" ,
427
+ output_pData -> Size );
428
+ upsdebugx (4 , "Original Report Descriptor: input 0x0f "
429
+ "LogMin: %ld LogMax: %ld (assumed: %s) Size: %" PRIu8 ,
430
+ input_logmin , input_logmax ,
431
+ input_logmax_assumed ? "yes" : "no" ,
432
+ input_pData -> Size );
433
+
434
+ /* First pass: try our hard-coded limits */
435
+ if (output_logmax_assumed && output_logmax < CPS_VOLTAGE_LOGMAX ) {
436
+ output_logmax = CPS_VOLTAGE_LOGMAX ;
437
+ }
438
+
439
+ if (input_logmax_assumed && input_logmax < CPS_VOLTAGE_LOGMAX ) {
440
+ input_logmax = CPS_VOLTAGE_LOGMAX ;
441
+ }
442
+
443
+ /* Second pass: align the two */
444
+ if (output_logmax_assumed && output_logmax < input_logmax ) {
445
+ output_logmax = input_logmax ;
446
+ } else if (input_logmax_assumed && input_logmax < output_logmax ) {
447
+ input_logmax = output_logmax ;
448
+ }
449
+
450
+ /* Second pass: cut off according to bit-size
451
+ * of each value */
452
+ if (input_logmax_assumed
453
+ && input_pData -> Size > 1
454
+ && input_pData -> Size <= sizeof (long )* 8
455
+ ) {
456
+ /* Note: usually values are signed, but
457
+ * here we are about compensating for
458
+ * poorly encoded maximums, so limit by
459
+ * 2^(size)-1, e.g. for "size==16" the
460
+ * limit should be "2^16 - 1 = 65535";
461
+ * note that in HIDParse() we likely
462
+ * set 65535 here in that case. See
463
+ * also comments there (hidparser.c)
464
+ * discussing signed/unsigned nuances.
465
+ */
466
+ /* long sizeMax = (1L << (input_pData->Size - 1)) - 1; */
467
+ long sizeMax = (1L << (input_pData -> Size )) - 1 ;
468
+ if (input_logmax > sizeMax ) {
469
+ input_logmax = sizeMax ;
470
+ }
471
+ }
472
+
473
+ if (output_logmax_assumed
474
+ && output_pData -> Size > 1
475
+ && output_pData -> Size <= sizeof (long )* 8
476
+ ) {
477
+ /* See comment above */
478
+ /* long sizeMax = (1L << (output_pData->Size - 1)) - 1; */
479
+ long sizeMax = (1L << (output_pData -> Size )) - 1 ;
480
+ if (output_logmax > sizeMax ) {
481
+ output_logmax = sizeMax ;
482
+ }
483
+ }
484
+
485
+ if (input_logmax != input_pData -> LogMax ) {
486
+ upsdebugx (3 , "Fixing Report Descriptor: "
487
+ "set Input Voltage LogMax = %ld" ,
488
+ input_logmax );
489
+ input_pData -> LogMax = input_logmax ;
490
+ retval = 1 ;
491
+ }
492
+
493
+ if (output_logmax != output_pData -> LogMax ) {
494
+ upsdebugx (3 , "Fixing Report Descriptor: "
495
+ "set Output Voltage LogMax = %ld" ,
496
+ output_logmax );
497
+ output_pData -> LogMax = output_logmax ;
498
+ retval = 1 ;
499
+ }
500
+ }
501
+ }
502
+ }
503
+
504
+ if (!retval ) {
505
+ /* We did not `return 1` above, so... */
506
+ upsdebugx (3 ,
507
+ "SKIPPED Report Descriptor fix for UPS: "
508
+ "Vendor: %04x, Product: %04x "
509
+ "(problematic conditions not matched)" ,
510
+ vendorID , productID );
511
+ }
512
+
513
+ return retval ;
383
514
}
384
515
385
516
subdriver_t cps_subdriver = {
0 commit comments