@@ -317,20 +317,26 @@ static int cps_claim(HIDDevice_t *hd) {
317317 }
318318}
319319
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.
323323 * Additionally the Input Voltage LogMax is set incorrectly for EU models.
324324 * This corrects them by finding and applying fixed
325325 * voltage limits as being more appropriate.
326326 */
327327
328328static int cps_fix_report_desc (HIDDevice_t * pDev , HIDDesc_t * pDesc_arg ) {
329329 HIDData_t * pData ;
330+ int retval = 0 ;
330331
331332 int vendorID = pDev -> VendorID ;
332333 int productID = pDev -> ProductID ;
333334 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 );
334340 return 0 ;
335341 }
336342
@@ -343,43 +349,168 @@ static int cps_fix_report_desc(HIDDevice_t *pDev, HIDDesc_t *pDesc_arg) {
343349 return 0 ;
344350 }
345351
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 );
347354
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.
351362 */
352363
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 ))) {
354365 long hvt_logmin = pData -> LogMin ;
355366 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 );
357369
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 ))) {
359371 long output_logmin = pData -> LogMin ;
360372 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 );
363376
364377 if (hvt_logmin == output_logmin && hvt_logmax == output_logmax ) {
365378 pData -> LogMin = CPS_VOLTAGE_LOGMIN ;
366379 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 ))) {
370385 long input_logmin = pData -> LogMin ;
371386 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 );
376396 }
377397
378- return 1 ;
398+ retval = 1 ;
379399 }
380400 }
381401 }
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 ;
383514}
384515
385516subdriver_t cps_subdriver = {
0 commit comments