1 /*
2  * linux-usb.c
3  *
4  * Platform-specific interface to Linux hiddev USB HID driver.
5  *
6  * Parts of this code (especially the initialization and walking
7  * the reports) were derived from a test program hid-ups.c by:
8  *    Vojtech Pavlik <vojtech@ucw.cz>
9  *    Paul Stewart <hiddev@wetlogic.net>
10  */
11 
12 /*
13  * Copyright (C) 2001-2004 Kern Sibbald
14  * Copyright (C) 2004-2005 Adam Kropelin
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of version 2 of the GNU General
18  * Public License as published by the Free Software Foundation.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public
26  * License along with this program; if not, write to the Free
27  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
28  * MA 02110-1335, USA.
29  */
30 
31 /*
32  * The following is a work around for a problem in 2.6 kernel
33  *  linux/hiddev.h file that is fixed in 2.6.9
34  */
35 #define HID_MAX_USAGES 1024
36 
37 #include "apc.h"
38 #include "linux-usb.h"
39 #include <glob.h>
40 #include <linux/usbdevice_fs.h>
41 
42 /* RHEL has an out-of-date hiddev.h */
43 #ifndef HIDIOCGFLAG
44 # define HIDIOCSFLAG       _IOW('H', 0x0F, int)
45 #endif
46 #ifndef HIDDEV_FLAG_UREF
47 # define HIDDEV_FLAG_UREF  0x1
48 #endif
49 
50 /* Enable this to force Linux 2.4 compatability mode */
51 #define FORCE_COMPAT24  false
52 
Factory(UPSINFO * ups)53 UpsDriver *UsbUpsDriver::Factory(UPSINFO *ups)
54 {
55    return new LinuxUsbUpsDriver(ups);
56 }
57 
LinuxUsbUpsDriver(UPSINFO * ups)58 LinuxUsbUpsDriver::LinuxUsbUpsDriver(UPSINFO *ups) :
59    UsbUpsDriver(ups),
60    _fd(-1),
61    _compat24(false),
62    _linkcheck(false)
63 {
64    memset(_orig_device, 0, sizeof(_orig_device));
65    memset(_info, 0, sizeof(_info));
66 }
67 
reinitialize_private_structure()68 void LinuxUsbUpsDriver::reinitialize_private_structure()
69 {
70    int k;
71 
72    Dmsg(200, "Reinitializing private structure.\n");
73    /*
74     * We are being reinitialized, so clear the Cap
75     * array, and release previously allocated memory.
76     */
77    for (k = 0; k <= CI_MAXCI; k++) {
78       _ups->UPS_Cap[k] = false;
79       if (_info[k] != NULL) {
80          free(_info[k]);
81          _info[k] = NULL;
82       }
83    }
84 }
85 
86 /*
87  * Internal routine to attempt device open.
88  */
open_device(const char * dev)89 int LinuxUsbUpsDriver::open_device(const char *dev)
90 {
91    int flaguref = HIDDEV_FLAG_UREF;
92    int fd, ret, i;
93 
94    Dmsg(200, "Attempting to open \"%s\"\n", dev);
95 
96    /* Open the device port */
97    fd = open(dev, O_RDWR | O_NOCTTY);
98    if (fd >= 0) {
99       /* Check for the UPS application HID usage */
100       for (i = 0; (ret = ioctl(fd, HIDIOCAPPLICATION, i)) > 0; i++) {
101          if ((ret & 0xffff000) == (UPS_USAGE & 0xffff0000)) {
102             /* Request full uref reporting from read() */
103             if (FORCE_COMPAT24 || ioctl(fd, HIDIOCSFLAG, &flaguref)) {
104                Dmsg(100, "HIDIOCSFLAG failed; enabling linux-2.4 "
105                       "compatibility mode\n");
106                _compat24 = true;
107             }
108             /* Successfully opened the device */
109             Dmsg(200, "Successfully opened \"%s\"\n", dev);
110             return fd;
111          }
112       }
113       close(fd);
114    }
115 
116    /* Failed to open the device */
117    return -1;
118 }
119 
120 /*
121  * Routine to request that kernel driver attach to any APC USB UPSes
122  */
bind_upses()123 void LinuxUsbUpsDriver::bind_upses()
124 {
125 #ifdef USBDEVFS_CONNECT
126    // Find all USB devices in usbfs
127    glob_t g;
128    if (glob("/proc/bus/usb/[0-9][0-9][0-9]/[0-9][0-9][0-9]", 0, NULL, &g))
129       return;
130 
131    // Iterate over all USB devices...
132    for (size_t i = 0; i < g.gl_pathc; ++i)
133    {
134       // Open the device in usbfs
135       int fd = open(g.gl_pathv[i], O_RDWR);
136       if (fd == -1)
137          continue;
138 
139       struct usb_device_descriptor
140       {
141          uint8_t  bLength;
142          uint8_t  bDescriptorType;
143          uint16_t bcdUSB;
144          uint8_t  bDeviceClass;
145          uint8_t  bDeviceSubClass;
146          uint8_t  bDeviceProtocol;
147          uint8_t  bMaxPacketSize0;
148          uint16_t idVendor;
149          uint16_t idProduct;
150          uint16_t bcdDevice;
151          uint8_t  iManufacturer;
152          uint8_t  iProduct;
153          uint8_t  iSerialNumber;
154          uint8_t  bNumConfigurations;
155       } __attribute__ ((packed)) dd;
156 
157       // Fetch device descriptor, then verify device VID/PID are supported and
158       // no kernel driver is currently attached
159       struct usbdevfs_getdriver getdrv = {0};
160       if (read(fd, &dd, sizeof(dd)) == sizeof(dd) &&
161           MatchVidPid(dd.idVendor, dd.idProduct) &&
162           ioctl(fd, USBDEVFS_GETDRIVER, &getdrv))
163       {
164          // APC device with no kernel driver attached
165          // Issue command to attach kernel driver
166          struct usbdevfs_ioctl command = {0};
167          command.ioctl_code = USBDEVFS_CONNECT;
168          int rc = ioctl(fd, USBDEVFS_IOCTL, &command);
169          // Hard to tell if this succeeded because the return value of the
170          // ioctl was changed. In linux 2.4.37, 0 means success but in 3.4 it
171          // means failure. So...we're screwed. The only thing we know for sure
172          // is <0 is definitely failure.
173          if (rc >= 0)
174          {
175             Dmsg(100, "Reattached kernel driver to %s\n", g.gl_pathv[i]);
176          }
177          else
178          {
179             Dmsg(0, "Failed to attach kernel driver to %s (%d)\n",
180                g.gl_pathv[i], rc);
181          }
182       }
183 
184       close(fd);
185    }
186 
187    globfree(&g);
188 #endif // USBDEVFS_CONNECT
189 }
190 
191 /*
192  * Internal routine to open the device and ensure that there is
193  * a UPS application on the line.  This routine may be called
194  * many times because the device may be unplugged and plugged
195  * back in -- the joys of USB devices.
196  */
open_usb_device()197 bool LinuxUsbUpsDriver::open_usb_device()
198 {
199    char devname[MAXSTRING];
200    const char *hiddev[] =
201       { "/dev/usb/hiddev", "/dev/usb/hid/hiddev", "/dev/hiddev", NULL };
202    int i, j, k;
203 
204    /*
205     * Ensure any APC UPSes are utilizing the usbhid/hiddev kernel driver.
206     * This is necessary if they were detached from the kernel driver in order
207     * to use libusb (the apcctrl 'generic' USB driver).
208     */
209    bind_upses();
210 
211    /*
212     * Note, we set _ups->fd here so the "core" of apcctrl doesn't
213     * think we are a slave, which is what happens when it is -1.
214     * (ADK: Actually this only appears to be true for apctest as
215     * apcctrl proper uses the UPS_slave flag.)
216     * Internally, we use the fd in our own private space
217     */
218    _ups->fd = 1;
219 
220    /*
221     * If no device locating specified, we go autodetect it
222     * by searching known places.
223     */
224    if (_ups->device[0] == 0)
225       goto auto_detect;
226 
227    /*
228     * Also if specified device includes deprecated '[]' notation,
229     * just use the automatic search.
230     */
231    if (strchr(_ups->device, '[') &&
232        strchr(_ups->device, ']'))
233    {
234       _orig_device[0] = 0;
235       goto auto_detect;
236    }
237 
238    /*
239     * If we get here we know the user specified a device or we are
240     * trying to re-open a device that previously was open.
241     */
242 
243    /* Retry 10 times */
244    for (i = 0; i < 10; i++) {
245       _fd = open_device(_ups->device);
246       if (_fd != -1)
247          return true;
248       sleep(1);
249    }
250 
251    /*
252     * If user-specified device could not be opened, fail.
253     */
254    if (_orig_device[0] != 0)
255       return false;
256 
257    /*
258     * If we get here we failed to re-open a previously auto-detected
259     * device. We will fall thru and restart autodetection...
260     */
261 
262 auto_detect:
263 
264    for (i = 0; i < 10; i++) {           /* try 10 times */
265       for (j = 0; hiddev[j]; j++) {     /* loop over known device names */
266          for (k = 0; k < 16; k++) {     /* loop over devices */
267             asnprintf(devname, sizeof(devname), "%s%d", hiddev[j], k);
268             _fd = open_device(devname);
269             if (_fd != -1) {
270                /* Successful open, save device name and return */
271                strlcpy(_ups->device, devname, sizeof(_ups->device));
272                return true;
273             }
274          }
275       }
276       sleep(1);
277    }
278 
279    _ups->device[0] = '\0';
280    return false;
281 }
282 
283 /*
284  * Called if there is an ioctl() or read() error, we close() and
285  * re open() the port since the device was probably unplugged.
286  */
usb_link_check()287 bool LinuxUsbUpsDriver::usb_link_check()
288 {
289    bool comm_err = true;
290    int tlog;
291    bool once = true;
292 
293    if (_linkcheck)
294       return false;
295 
296    _linkcheck = true;               /* prevent recursion */
297 
298    _ups->set_commlost();
299    Dmsg(200, "link_check comm lost\n");
300 
301    /* Don't warn until we try to get it at least 2 times and fail */
302    for (tlog = LINK_RETRY_INTERVAL * 2; comm_err; tlog -= (LINK_RETRY_INTERVAL)) {
303       if (tlog <= 0) {
304          tlog = 10 * 60;           /* notify every 10 minutes */
305          log_event(_ups, event_msg[CMDCOMMFAILURE].level,
306             event_msg[CMDCOMMFAILURE].msg);
307          if (once) {               /* execute script once */
308             execute_command(_ups, ups_event[CMDCOMMFAILURE]);
309             once = false;
310          }
311       }
312 
313       /* Retry every LINK_RETRY_INTERVAL seconds */
314       sleep(LINK_RETRY_INTERVAL);
315       if (_fd >= 0) {
316          close(_fd);
317          _fd = -1;
318          reinitialize_private_structure();
319       }
320 
321       if (open_usb_device() && get_capabilities() &&
322          read_static_data()) {
323          comm_err = false;
324       } else {
325          continue;
326       }
327    }
328 
329    if (!comm_err) {
330       generate_event(_ups, CMDCOMMOK);
331       _ups->clear_commlost();
332       Dmsg(200, "link check comm OK.\n");
333    }
334 
335    _linkcheck = false;
336    return true;
337 }
338 
populate_uval(USB_INFO * info,USB_VALUE * uval)339 bool LinuxUsbUpsDriver::populate_uval(USB_INFO *info, USB_VALUE *uval)
340 {
341    struct hiddev_string_descriptor sdesc;
342    USB_VALUE val;
343    int exponent;
344 
345    exponent = info->unit_exponent;
346    if (exponent > 7)
347       exponent = exponent - 16;
348 
349    if (info->data_type == T_INDEX) {    /* get string */
350       if (info->uref.value == 0)
351          return false;
352 
353       sdesc.index = info->uref.value;
354       if (ioctl(_fd, HIDIOCGSTRING, &sdesc) < 0)
355          return false;
356 
357       strlcpy(val.sValue, sdesc.value, sizeof(val.sValue));
358       val.value_type = V_STRING;
359 
360       Dmsg(200, "Def val=%d exp=%d sVal=\"%s\" ci=%d\n", info->uref.value,
361          exponent, val.sValue, info->ci);
362    } else if (info->data_type == T_UNITS) {
363       val.value_type = V_DOUBLE;
364       switch (info->unit) {
365       case 0x00F0D121:
366          val.UnitName = "Volts";
367          exponent -= 7;            /* remove bias */
368          break;
369       case 0x00100001:
370          exponent += 2;            /* remove bias */
371          val.UnitName = "Amps";
372          break;
373       case 0xF001:
374          val.UnitName = "Hertz";
375          break;
376       case 0x1001:
377          val.UnitName = "Seconds";
378          break;
379       case 0xD121:
380          exponent -= 7;            /* remove bias */
381          val.UnitName = "Watts";
382          break;
383       case 0x010001:
384          val.UnitName = "Degrees K";
385          break;
386       case 0x0101001:
387          val.UnitName = "AmpSecs";
388          break;
389       default:
390          val.UnitName = "";
391          val.value_type = V_INTEGER;
392          val.iValue = info->uref.value;
393          break;
394       }
395 
396       if (exponent == 0)
397          val.dValue = info->uref.value;
398       else
399          val.dValue = ((double)info->uref.value) * pow_ten(exponent);
400 
401       // Store a (possibly truncated) copy of the floating point value in the
402       // integer field as well.
403       val.iValue = (int)val.dValue;
404 
405       Dmsg(200, "Def val=%d exp=%d dVal=%f ci=%d\n", info->uref.value,
406          exponent, val.dValue, info->ci);
407    } else {                        /* should be T_NONE */
408       val.UnitName = "";
409       val.value_type = V_INTEGER;
410       val.iValue = info->uref.value;
411 
412       if (exponent == 0)
413          val.dValue = info->uref.value;
414       else
415          val.dValue = ((double)info->uref.value) * pow_ten(exponent);
416 
417       Dmsg(200, "Def val=%d exp=%d dVal=%f ci=%d\n", info->uref.value,
418          exponent, val.dValue, info->ci);
419    }
420 
421    memcpy(uval, &val, sizeof(*uval));
422    return true;
423 }
424 
425 /*
426  * Get a field value
427  */
pusb_get_value(int ci,USB_VALUE * uval)428 bool LinuxUsbUpsDriver::pusb_get_value(int ci, USB_VALUE *uval)
429 {
430    struct hiddev_report_info rinfo;
431    USB_INFO *info;
432 
433    if (!_ups->UPS_Cap[ci] || !_info[ci])
434       return false;                /* UPS does not have capability */
435 
436    /* Fetch the new value from the UPS */
437 
438    info = _info[ci];       /* point to our info structure */
439    rinfo.report_type = info->uref.report_type;
440    rinfo.report_id = info->uref.report_id;
441    if (ioctl(_fd, HIDIOCGREPORT, &rinfo) < 0)   /* update Report */
442       return false;
443 
444    if (ioctl(_fd, HIDIOCGUSAGE, &info->uref) < 0)       /* update UPS value */
445       return false;
446 
447    /* Process the updated value */
448    return populate_uval(info, uval);
449 }
450 
451 /*
452  * Find the USB_INFO structure used for tracking a given usage. Searching
453  * by usage_code alone is insufficient since the same usage may appear in
454  * multiple reports or even multiple times in the same report.
455  */
find_info_by_uref(struct hiddev_usage_ref * uref)456 LinuxUsbUpsDriver::USB_INFO *LinuxUsbUpsDriver::find_info_by_uref(
457    struct hiddev_usage_ref *uref)
458 {
459    int i;
460 
461    for (i=0; i<CI_MAXCI; i++) {
462       if (_ups->UPS_Cap[i] && _info[i] &&
463           _info[i]->uref.report_id == uref->report_id &&
464           _info[i]->uref.field_index == uref->field_index &&
465           _info[i]->uref.usage_index == uref->usage_index &&
466           _info[i]->uref.usage_code == uref->usage_code) {
467             return _info[i];
468       }
469    }
470 
471    return NULL;
472 }
473 
474 /*
475  * Same as find_info_by_uref() but only checks the usage code. This is
476  * not entirely reliable, but it's the best we have on linux-2.4.
477  */
find_info_by_ucode(unsigned int ucode)478 LinuxUsbUpsDriver::USB_INFO *LinuxUsbUpsDriver::find_info_by_ucode(
479    unsigned int ucode)
480 {
481    int i;
482 
483    for (i=0; i<CI_MAXCI; i++) {
484       if (_ups->UPS_Cap[i] && _info[i] &&
485           _info[i]->uref.usage_code == ucode) {
486             return _info[i];
487       }
488    }
489 
490    return NULL;
491 }
492 
493 /*
494  * Read UPS events. I.e. state changes.
495  */
check_state()496 bool LinuxUsbUpsDriver::check_state()
497 {
498    int retval;
499    bool done = false;
500    struct hiddev_usage_ref uref;
501    struct hiddev_event hev;
502    USB_INFO* info;
503    USB_VALUE uval;
504 
505    struct timeval tv;
506    tv.tv_sec = _ups->wait_time;
507    tv.tv_usec = 0;
508 
509    while (!done) {
510       fd_set rfds;
511 
512       FD_ZERO(&rfds);
513       FD_SET(_fd, &rfds);
514 
515       retval = select(_fd + 1, &rfds, NULL, NULL, &tv);
516 
517       /*
518        * Note: We are relying on select() adjusting tv to the amount
519        * of time NOT waited. This is a Linux-specific feature but
520        * shouldn't be a problem since the driver is only intended for
521        * for Linux.
522        */
523 
524       switch (retval) {
525       case 0:                     /* No chars available in TIMER seconds. */
526          return false;
527       case -1:
528          if (errno == EINTR || errno == EAGAIN)         /* assume SIGCHLD */
529             continue;
530 
531          Dmsg(200, "select error: ERR=%s\n", strerror(errno));
532          usb_link_check();      /* link is down, wait */
533          return false;
534       default:
535          break;
536       }
537 
538       if (!_compat24) {
539          /* This is >= linux-2.6, so we can read a uref directly */
540          do {
541             retval = read(_fd, &uref, sizeof(uref));
542          } while (retval == -1 && (errno == EAGAIN || errno == EINTR));
543 
544          if (retval < 0) {            /* error */
545             Dmsg(200, "read error: ERR=%s\n", strerror(errno));
546             usb_link_check();      /* notify that link is down, wait */
547             return false;
548          }
549 
550          if (retval == 0 || retval < (int)sizeof(uref))
551             return false;
552 
553          /* Ignore events we don't recognize */
554          if ((info = find_info_by_uref(&uref)) == NULL) {
555             Dmsg(200, "Unrecognized usage (rpt=%d, usg=0x%08x, val=%d)\n",
556                uref.report_id, uref.usage_code, uref.value);
557             continue;
558          }
559       } else {
560          /*
561           * We're in linux-2.4 compatibility mode, so we read a
562           * hiddev_event and use it to construct a uref.
563           */
564          do {
565             retval = read(_fd, &hev, sizeof(hev));
566          } while (retval == -1 && (errno == EAGAIN || errno == EINTR));
567 
568          if (retval < 0) {            /* error */
569             Dmsg(200, "read error: ERR=%s\n", strerror(errno));
570             usb_link_check();      /* notify that link is down, wait */
571             return false;
572          }
573 
574          if (retval == 0 || retval < (int)sizeof(hev))
575             return false;
576 
577          /* Ignore events we don't recognize */
578          if ((info = find_info_by_ucode(hev.hid)) == NULL) {
579             Dmsg(200, "Unrecognized usage (usg=0x%08x, val=%d)\n",
580                hev.hid, hev.value);
581             continue;
582          }
583 
584          /*
585           * ADK FIXME: The info-> struct we have now is not guaranteed to
586           * actually be the right one, because linux-2.4 does not give us
587           * enough data in the event to make a positive match. We may need
588           * to filter out ambiguous usages here or manually fetch each CI
589           * that matches the given usage.
590           */
591 
592          /* Copy the stored uref, replacing its value */
593          uref = info->uref;
594          uref.value = hev.value;
595       }
596 
597       write_lock(_ups);
598 
599       /* Ignore events whose value is unchanged */
600       if (info->uref.value == uref.value) {
601          Dmsg(200, "Ignoring unchanged value (rpt=%d, usg=0x%08x, val=%d)\n",
602             uref.report_id, uref.usage_code, uref.value);
603          write_unlock(_ups);
604          continue;
605       }
606 
607       /* Update tracked value */
608       Dmsg(200, "Processing changed value (rpt=%d, usg=0x%08x, val=%d)\n",
609          uref.report_id, uref.usage_code, uref.value);
610       info->uref.value = uref.value;
611 
612       /* Populate a uval and report it to the upper layer */
613       populate_uval(info, &uval);
614       if (usb_report_event(info->ci, &uval)) {
615          /*
616           * The upper layer considers this an important event,
617           * so we will return immediately.
618           */
619          done = true;
620       }
621 
622       write_unlock(_ups);
623    }
624 
625    return true;
626 }
627 
628 /*
629  * Open usb port
630  * This is called once by the core code and is the first routine
631  * called.
632  */
Open()633 bool LinuxUsbUpsDriver::Open()
634 {
635    write_lock(_ups);
636 
637    if (_orig_device[0] == 0)
638       strlcpy(_orig_device, _ups->device, sizeof(_orig_device));
639 
640    bool rc = open_usb_device();
641 
642    _ups->clear_slave();
643    write_unlock(_ups);
644    return rc;
645 }
646 
647 /*
648  * This is the last routine called from apcctrl core code
649  */
Close()650 bool LinuxUsbUpsDriver::Close()
651 {
652    return 1;
653 }
654 
655 /*
656  * Setup capabilities structure for UPS
657  */
pusb_ups_get_capabilities()658 bool LinuxUsbUpsDriver::pusb_ups_get_capabilities()
659 {
660    int rtype[2] = { HID_REPORT_TYPE_FEATURE, HID_REPORT_TYPE_INPUT };
661    struct hiddev_report_info rinfo;
662    struct hiddev_field_info finfo;
663    struct hiddev_usage_ref uref;
664    unsigned int i, j, k, n;
665 
666    if (ioctl(_fd, HIDIOCINITREPORT, 0) < 0)
667       Error_abort("Cannot init USB HID report. ERR=%s\n", strerror(errno));
668 
669    write_lock(_ups);
670 
671    /*
672     * Walk through all available reports and determine
673     * what information we can use.
674     */
675    for (n = 0; n < sizeof(rtype)/sizeof(*rtype); n++) {
676       rinfo.report_type = rtype[n];
677       rinfo.report_id = HID_REPORT_ID_FIRST;
678 
679       while (ioctl(_fd, HIDIOCGREPORTINFO, &rinfo) >= 0) {
680          for (i = 0; i < rinfo.num_fields; i++) {
681             memset(&finfo, 0, sizeof(finfo));
682             finfo.report_type = rinfo.report_type;
683             finfo.report_id = rinfo.report_id;
684             finfo.field_index = i;
685 
686             if (ioctl(_fd, HIDIOCGFIELDINFO, &finfo) < 0)
687                continue;
688 
689             memset(&uref, 0, sizeof(uref));
690             for (j = 0; j < finfo.maxusage; j++) {
691                uref.report_type = finfo.report_type;
692                uref.report_id = finfo.report_id;
693                uref.field_index = i;
694                uref.usage_index = j;
695 
696                if (ioctl(_fd, HIDIOCGUCODE, &uref) < 0)
697                   continue;
698 
699                ioctl(_fd, HIDIOCGUSAGE, &uref);
700 
701                /*
702                 * We've got a UPS usage entry, now walk down our
703                 * know_info table and see if we have a match. If so,
704                 * allocate a new entry for it.
705                 */
706                for (k = 0; _known_info[k].usage_code; k++) {
707                   USB_INFO *info;
708                   int ci = _known_info[k].ci;
709 
710                   if (ci != CI_NONE &&
711                       uref.usage_code == _known_info[k].usage_code &&
712                       (_known_info[k].physical == P_ANY ||
713                          _known_info[k].physical == finfo.physical) &&
714                       (_known_info[k].logical == P_ANY ||
715                          _known_info[k].logical == finfo.logical)) {
716 
717                      // If we do not have any data saved for this report yet,
718                      // allocate an USB_INFO and populate the read uref.
719                      info = _info[ci];
720                      if (!info) {
721                         _ups->UPS_Cap[ci] = true;
722                         info = (USB_INFO *)malloc(sizeof(USB_INFO));
723 
724                         if (!info) {
725                            write_unlock(_ups);
726                            Error_abort("Out of memory.\n");
727                         }
728 
729                         _info[ci] = info;
730                         memset(info, 0, sizeof(*info));
731                         info->ci = ci;
732                         info->physical = finfo.physical;
733                         info->unit_exponent = finfo.unit_exponent;
734                         info->unit = finfo.unit;
735                         info->data_type = _known_info[k].data_type;
736                         memcpy(&info->uref, &uref, sizeof(uref));
737 
738                         Dmsg(200, "Got READ ci=%d, usage=0x%x, rpt=%d\n",
739                            ci, _known_info[k].usage_code, uref.report_id);
740                      }
741 
742                      // If this is a FEATURE report and we haven't set the
743                      // write uref yet, place it in the write uref (possibly in
744                      // addition to placing it in the read uref above).
745                      if (rinfo.report_type == HID_REPORT_TYPE_FEATURE &&
746                          info->wuref.report_id == 0) {
747                         memcpy(&info->wuref, &uref, sizeof(uref));
748 
749                         Dmsg(200, "Got WRITE ci=%d, usage=0x%x, rpt=%d\n",
750                            ci, _known_info[k].usage_code, uref.report_id);
751                      }
752 
753                      break;
754                   }
755                }
756             }
757          }
758          rinfo.report_id |= HID_REPORT_ID_NEXT;
759       }
760    }
761 
762    _ups->UPS_Cap[CI_STATUS] = true; /* we have status flag */
763    write_unlock(_ups);
764    return 1;
765 }
766 
767 
read_int_from_ups(int ci,int * value)768 int LinuxUsbUpsDriver::read_int_from_ups(int ci, int *value)
769 {
770    USB_VALUE val;
771 
772    if (!pusb_get_value(ci, &val))
773       return false;
774 
775    *value = val.iValue;
776    return true;
777 }
778 
write_int_to_ups(int ci,int value,const char * name)779 int LinuxUsbUpsDriver::write_int_to_ups(int ci, int value, const char *name)
780 {
781    struct hiddev_report_info rinfo;
782    USB_INFO *info;
783    int old_value, new_value;
784 
785    // Make sure we have a writable uref for this CI
786    if (_ups->UPS_Cap[ci] && _info[ci] &&
787       _info[ci]->wuref.report_id) {
788       info = _info[ci];    /* point to our info structure */
789       rinfo.report_type = info->uref.report_type;
790       rinfo.report_id = info->uref.report_id;
791 
792       /* Get report */
793       if (ioctl(_fd, HIDIOCGREPORT, &rinfo) < 0) {
794          Dmsg(000, "HIDIOCGREPORT for function %s failed. ERR=%s\n",
795             name, strerror(errno));
796          return false;
797       }
798 
799       /* Get UPS value */
800       if (ioctl(_fd, HIDIOCGUSAGE, &info->wuref) < 0) {
801          Dmsg(000, "HIDIOCGUSAGE for function %s failed. ERR=%s\n",
802             name, strerror(errno));
803          return false;
804       }
805       old_value = info->uref.value;
806 
807       info->wuref.value = value;
808       rinfo.report_type = info->wuref.report_type;
809       rinfo.report_id = info->wuref.report_id;
810       Dmsg(100, "SUSAGE type=%d id=%d index=%d\n", info->wuref.report_type,
811          info->wuref.report_id, info->wuref.field_index);
812 
813       /* Update UPS value */
814       if (ioctl(_fd, HIDIOCSUSAGE, &info->wuref) < 0) {
815          Dmsg(000, "HIDIOCSUSAGE for function %s failed. ERR=%s\n",
816             name, strerror(errno));
817          return false;
818       }
819 
820       /* Update Report */
821       if (ioctl(_fd, HIDIOCSREPORT, &rinfo) < 0) {
822          Dmsg(000, "HIDIOCSREPORT for function %s failed. ERR=%s\n",
823             name, strerror(errno));
824          return false;
825       }
826 
827       /*
828        * This readback of the report is NOT just for debugging. It
829        * has the effect of flushing the above SET_REPORT to the
830        * device, which is important since we need to make sure it
831        * happens before subsequent reports are sent.
832        */
833 
834       rinfo.report_type = info->uref.report_type;
835       rinfo.report_id = info->uref.report_id;
836 
837       /* Get report */
838       if (ioctl(_fd, HIDIOCGREPORT, &rinfo) < 0) {
839          Dmsg(000, "HIDIOCGREPORT for function %s failed. ERR=%s\n",
840             name, strerror(errno));
841          return false;
842       }
843 
844       /* Get UPS value */
845       if (ioctl(_fd, HIDIOCGUSAGE, &info->uref) < 0) {
846          Dmsg(000, "HIDIOCGUSAGE for function %s failed. ERR=%s\n",
847             name, strerror(errno));
848          return false;
849       }
850 
851       new_value = info->uref.value;
852       Dmsg(100, "function %s ci=%d value=%d OK.\n", name, ci, value);
853       Dmsg(100, "%s before=%d set=%d after=%d\n", name, old_value, value,
854          new_value);
855 
856       return true;
857    }
858 
859    Dmsg(000, "function %s ci=%d not available in this UPS.\n", name, ci);
860    return false;
861 }
862