From 3ce3bcd6e5f63e681cbcc4a570c26af84ab0268a Mon Sep 17 00:00:00 2001 From: "Stephen J. Butler" Date: Fri, 18 Apr 2014 03:22:32 -0500 Subject: [PATCH 1/4] Be more conservative about claim/release USB interface --- drivers/libshut.c | 13 +++++- drivers/libshut.h | 2 + drivers/libusb.c | 103 +++++++++++++++++++++++++++---------------- drivers/libusb.h | 2 + drivers/usbhid-ups.c | 69 ++++++++++++++++++++--------- 5 files changed, 129 insertions(+), 60 deletions(-) diff --git a/drivers/libshut.c b/drivers/libshut.c index 1e2cd8d8cc..66bf88f569 100644 --- a/drivers/libshut.c +++ b/drivers/libshut.c @@ -281,6 +281,15 @@ static void align_request(struct shut_ctrltransfer_s *ctrl ) #endif } +int libshut_claim_interface(int upsfd, int interface) { + return 0; +} + +int libshut_release_interface(int upsfd, int interface) { + return 0; +} + + /* On success, fill in the curDevice structure and return the report * descriptor length. On failure, return -1. * Note: When callback is not NULL, the report descriptor will be @@ -569,7 +578,9 @@ shut_communication_subdriver_t shut_subdriver = { libshut_get_report, libshut_set_report, libshut_get_string, - libshut_get_interrupt + libshut_get_interrupt, + libshut_claim_interface, + libshut_release_interface }; /***********************************************************************/ diff --git a/drivers/libshut.h b/drivers/libshut.h index 48f48bbca9..0dab2ee63e 100644 --- a/drivers/libshut.h +++ b/drivers/libshut.h @@ -69,6 +69,8 @@ typedef struct shut_communication_subdriver_s { int StringIdx, char *buf, size_t buflen); int (*get_interrupt)(int upsfd, unsigned char *buf, int bufsize, int timeout); + int (*claim_interface)(int upsfd, int interface); + int (*release_interface)(int upsfd, int interface); } shut_communication_subdriver_t; extern shut_communication_subdriver_t shut_subdriver; diff --git a/drivers/libusb.c b/drivers/libusb.c index fd8f5b9487..a874e729e3 100644 --- a/drivers/libusb.c +++ b/drivers/libusb.c @@ -70,6 +70,45 @@ static inline int matches(USBDeviceMatcher_t *matcher, USBDevice_t *device) { return matcher->match_function(device, matcher->privdata); } +static int libusb_claim_interface(usb_dev_handle *udev, int interface) { + int retries, res = -1; + + for (retries = 3; retries > 0; --retries) { + res = usb_claim_interface(udev, interface); + if (res == 0) { + upsdebugx(2, "Claimed USB interface"); + break; + } else { + upsdebugx(2, "failed to claim USB device: %s", usb_strerror()); + /* don't run the rest of this scope if + * we're not going to loop again */ + if (retries <= 0) + break; + } + +#ifdef HAVE_USB_DETACH_KERNEL_DRIVER_NP + /* this method requires at least libusb 0.1.8: + * it force device claiming by unbinding + * attached driver... From libhid */ + if (usb_detach_kernel_driver_np(udev, interface) < 0) { + upsdebugx(2, "failed to detach kernel driver from USB device: %s", usb_strerror()); + } else { + upsdebugx(2, "detached kernel driver from USB device..."); + } +#endif + + /* wait before trying again */ + sleep( 5 ); + } + + if (res == 0) { + /* set default interface */ + usb_set_altinterface(udev, interface); + } + + return res; +} + #define usb_control_msg typesafe_control_msg /* On success, fill in the curDevice structure and return the report @@ -83,9 +122,7 @@ static inline int matches(USBDeviceMatcher_t *matcher, USBDevice_t *device) { static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDeviceMatcher_t *matcher, int (*callback)(usb_dev_handle *udev, USBDevice_t *hd, unsigned char *rdbuf, int rdlen)) { -#ifdef HAVE_USB_DETACH_KERNEL_DRIVER_NP - int retries; -#endif + static int done_init = 0; /* only call usb_init() once */ int rdlen1, rdlen2; /* report descriptor length, method 1+2 */ USBDeviceMatcher_t *m; struct usb_device *dev; @@ -93,7 +130,7 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice usb_dev_handle *udev; struct usb_interface_descriptor *iface; - int ret, res; + int ret, res, claimed; unsigned char buf[20]; unsigned char *p; char string[256]; @@ -104,7 +141,10 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice int rdlen; /* libusb base init */ - usb_init(); + if (!done_init) { + usb_init(); + done_init = 1; + } usb_find_busses(); usb_find_devices(); @@ -122,6 +162,7 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice supplied matcher */ /* open the device */ + claimed = 0; *udevp = udev = usb_open(dev); if (!udev) { upsdebugx(2, "Failed to open device, skipping. (%s)", usb_strerror()); @@ -191,42 +232,19 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice } upsdebugx(2, "Device matches"); - /* Now we have matched the device we wanted. Claim it. */ - -#ifdef HAVE_USB_DETACH_KERNEL_DRIVER_NP - /* this method requires at least libusb 0.1.8: - * it force device claiming by unbinding - * attached driver... From libhid */ - retries = 3; - while (usb_claim_interface(udev, 0) < 0) { - - upsdebugx(2, "failed to claim USB device: %s", usb_strerror()); - - if (usb_detach_kernel_driver_np(udev, 0) < 0) { - upsdebugx(2, "failed to detach kernel driver from USB device: %s", usb_strerror()); - } else { - upsdebugx(2, "detached kernel driver from USB device..."); - } - - if (retries-- > 0) { - continue; - } - - fatalx(EXIT_FAILURE, "Can't claim USB device [%04x:%04x]: %s", curDevice->VendorID, curDevice->ProductID, usb_strerror()); - } -#else - if (usb_claim_interface(udev, 0) < 0) { - fatalx(EXIT_FAILURE, "Can't claim USB device [%04x:%04x]: %s", curDevice->VendorID, curDevice->ProductID, usb_strerror()); - } -#endif - - /* set default interface */ - usb_set_altinterface(udev, 0); - if (!callback) { return 1; } + /* Now we have matched the device we wanted. Claim it. */ + claimed = (libusb_claim_interface(udev, 0) == 0); + + if (!claimed) { + upsdebugx(2, "Can't claim USB device [%04x:%04x]: %s", curDevice->VendorID, curDevice->ProductID, usb_strerror()); + goto next_device; + } + + if (!dev->config) { /* ?? this should never happen */ upsdebugx(2, " Couldn't retrieve descriptors"); goto next_device; @@ -329,9 +347,16 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice upsdebugx(2, "Found HID device"); fflush(stdout); + usb_release_interface(udev, 0); + claimed = 0; + return rdlen; next_device: + if (claimed) { + usb_release_interface(udev, 0); + claimed = 0; + } usb_close(udev); } } @@ -486,5 +511,7 @@ usb_communication_subdriver_t usb_subdriver = { libusb_get_report, libusb_set_report, libusb_get_string, - libusb_get_interrupt + libusb_get_interrupt, + libusb_claim_interface, + usb_release_interface }; diff --git a/drivers/libusb.h b/drivers/libusb.h index 66d2633553..6e51dfa9e6 100644 --- a/drivers/libusb.h +++ b/drivers/libusb.h @@ -58,6 +58,8 @@ typedef struct usb_communication_subdriver_s { int StringIdx, char *buf, size_t buflen); int (*get_interrupt)(usb_dev_handle *sdev, unsigned char *buf, int bufsize, int timeout); + int (*claim_interface)(usb_dev_handle *sdev, int interface); + int (*release_interface)(usb_dev_handle *sdev, int interface); } usb_communication_subdriver_t; extern usb_communication_subdriver_t usb_subdriver; diff --git a/drivers/usbhid-ups.c b/drivers/usbhid-ups.c index cdfbad7a71..6a42988b2f 100644 --- a/drivers/usbhid-ups.c +++ b/drivers/usbhid-ups.c @@ -618,14 +618,20 @@ int instcmd(const char *cmdname, const char *extradata) value = atol(val); } + if (comm_driver->claim_interface(udev, 0) != 0) { + return STAT_INSTCMD_FAILED; + } + /* Actual variable setting */ if (HIDSetDataValue(udev, hidups_item->hiddata, value) == 1) { upsdebugx(5, "instcmd: SUCCEED\n"); /* Set the status so that SEMI_STATIC vars are polled */ data_has_changed = TRUE; + comm_driver->release_interface(udev, 0); return STAT_INSTCMD_HANDLED; } + comm_driver->release_interface(udev, 0); upsdebugx(3, "instcmd: FAILED\n"); /* TODO: HANDLED but FAILED, not UNKNOWN! */ return STAT_INSTCMD_FAILED; } @@ -672,14 +678,20 @@ int setvar(const char *varname, const char *val) value = atol(val); } + if (comm_driver->claim_interface(udev, 0) != 0) { + return STAT_SET_UNKNOWN; + } + /* Actual variable setting */ if (HIDSetDataValue(udev, hidups_item->hiddata, value) == 1) { upsdebugx(5, "setvar: SUCCEED\n"); /* Set the status so that SEMI_STATIC vars are polled */ data_has_changed = TRUE; + comm_driver->release_interface(udev, 0); return STAT_SET_HANDLED; } + comm_driver->release_interface(udev, 0); upsdebugx(3, "setvar: FAILED\n"); /* FIXME: HANDLED but FAILED, not UNKNOWN! */ return STAT_SET_UNKNOWN; } @@ -791,35 +803,42 @@ void upsdrv_updateinfo(void) #endif /* Get HID notifications on Interrupt pipe first */ if (use_interrupt_pipe == TRUE) { + if (comm_driver->claim_interface(udev, 0) != 0) { + return; + } + evtCount = HIDGetEvents(udev, event, MAX_EVENT_NUM); upsdebugx(1, "Got %i HID objects...", (evtCount >= 0) ? evtCount : 0); - } else { - evtCount = 0; - upsdebugx(1, "Not using interrupt pipe..."); - } - /* Process pending events (HID notifications on Interrupt pipe) */ - for (i = 0; i < evtCount; i++) { + /* Process pending events (HID notifications on Interrupt pipe) */ + for (i = 0; i < evtCount; i++) { - if (HIDGetDataValue(udev, event[i], &value, poll_interval) != 1) - continue; + if (HIDGetDataValue(udev, event[i], &value, poll_interval) != 1) + continue; - if (nut_debug_level >= 2) { - upsdebugx(2, "Path: %s, Type: %s, ReportID: 0x%02x, Offset: %i, Size: %i, Value: %g", - HIDGetDataItem(event[i], subdriver->utab), - HIDDataType(event[i]), event[i]->ReportID, - event[i]->Offset, event[i]->Size, value); - } + if (nut_debug_level >= 2) { + upsdebugx(2, "Path: %s, Type: %s, ReportID: 0x%02x, Offset: %i, Size: %i, Value: %g", + HIDGetDataItem(event[i], subdriver->utab), + HIDDataType(event[i]), event[i]->ReportID, + event[i]->Offset, event[i]->Size, value); + } - /* Skip Input reports, if we don't use the Feature report */ - item = find_hid_info(FindObject_with_Path(pDesc, &(event[i]->Path), ITEM_FEATURE)); - if (!item) { - upsdebugx(3, "NUT doesn't use this HID object"); - continue; + /* Skip Input reports, if we don't use the Feature report */ + item = find_hid_info(FindObject_with_Path(pDesc, &(event[i]->Path), ITEM_FEATURE)); + if (!item) { + upsdebugx(3, "NUT doesn't use this HID object"); + continue; + } + + ups_infoval_set(item, value); } - ups_infoval_set(item, value); + comm_driver->release_interface(udev, 0); + } else { + evtCount = 0; + upsdebugx(1, "Not using interrupt pipe..."); } + #ifdef DEBUG upsdebugx(1, "took %.3f seconds handling interrupt reports...\n", interval()); #endif @@ -1165,6 +1184,10 @@ static bool_t hid_ups_walk(walkmode_t mode) double value; int retcode; + if (comm_driver->claim_interface(udev, 0) != 0) { + return FALSE; + } + /* 3 modes: HU_WALKMODE_INIT, HU_WALKMODE_QUICK_UPDATE and HU_WALKMODE_FULL_UPDATE */ /* Device data walk ----------------------------- */ @@ -1174,8 +1197,10 @@ static bool_t hid_ups_walk(walkmode_t mode) /* Check if we are asked to stop (reactivity++) in SHUT mode. * In USB mode, looping through this takes well under a second, * so any effort to improve reactivity here is wasted. */ - if (exit_flag != 0) + if (exit_flag != 0) { + comm_driver->release_interface(udev, 0); return TRUE; + } #endif /* filter data according to mode */ switch (mode) @@ -1258,6 +1283,7 @@ static bool_t hid_ups_walk(walkmode_t mode) case -ENXIO: /* No such device or address */ case -ENOENT: /* No such file or directory */ /* Uh oh, got to reconnect! */ + comm_driver->release_interface(udev, 0); hd = NULL; return FALSE; @@ -1318,6 +1344,7 @@ static bool_t hid_ups_walk(walkmode_t mode) } } + comm_driver->release_interface(udev, 0); return TRUE; } From 09df42c202850c25baf5e38311f9230af8353f7d Mon Sep 17 00:00:00 2001 From: "Stephen J. Butler" Date: Fri, 18 Apr 2014 19:14:46 -0500 Subject: [PATCH 2/4] Add compat mode for dvrs that expect udev to be claimed after return from open() --- drivers/blazer_usb.c | 4 ++-- drivers/libshut.c | 2 +- drivers/libshut.h | 2 +- drivers/libusb.c | 8 +++++--- drivers/libusb.h | 2 +- drivers/nutdrv_qx.c | 4 ++-- drivers/riello_usb.c | 4 ++-- drivers/tripplite_usb.c | 4 ++-- drivers/usbhid-ups.c | 4 ++-- 9 files changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/blazer_usb.c b/drivers/blazer_usb.c index 7ba4df289c..5cd40b58ca 100644 --- a/drivers/blazer_usb.c +++ b/drivers/blazer_usb.c @@ -409,7 +409,7 @@ int blazer_command(const char *cmd, char *buf, size_t buflen) int ret; if (udev == NULL) { - ret = usb->open(&udev, &usbdevice, reopen_matcher, NULL); + ret = usb->open(&udev, &usbdevice, reopen_matcher, NULL, 1); if (ret < 1) { return ret; @@ -589,7 +589,7 @@ void upsdrv_initups(void) /* link the matchers */ regex_matcher->next = &device_matcher; - ret = usb->open(&udev, &usbdevice, regex_matcher, NULL); + ret = usb->open(&udev, &usbdevice, regex_matcher, NULL, 1); if (ret < 0) { fatalx(EXIT_FAILURE, "No supported devices found. Please check your device availability with 'lsusb'\n" diff --git a/drivers/libshut.c b/drivers/libshut.c index 66bf88f569..04abd20d87 100644 --- a/drivers/libshut.c +++ b/drivers/libshut.c @@ -298,7 +298,7 @@ int libshut_release_interface(int upsfd, int interface) { * is accepted, or < 1 if not. */ int libshut_open(int *upsfd, SHUTDevice_t *curDevice, char *device_path, - int (*callback)(int upsfd, SHUTDevice_t *hd, unsigned char *rdbuf, int rdlen)) + int (*callback)(int upsfd, SHUTDevice_t *hd, unsigned char *rdbuf, int rdlen), int claim) { int ret, res; unsigned char buf[20]; diff --git a/drivers/libshut.h b/drivers/libshut.h index 0dab2ee63e..306c0c963f 100644 --- a/drivers/libshut.h +++ b/drivers/libshut.h @@ -59,7 +59,7 @@ typedef struct shut_communication_subdriver_s { int (*open)(int *upsfd, /* try to open the next available */ SHUTDevice_t *curDevice, /* device matching USBDeviceMatcher_t */ char *device_path, - int (*callback)(int upsfd, SHUTDevice_t *hd, unsigned char *rdbuf, int rdlen)); + int (*callback)(int upsfd, SHUTDevice_t *hd, unsigned char *rdbuf, int rdlen), int claim); void (*close)(int upsfd); int (*get_report)(int upsfd, int ReportId, unsigned char *raw_buf, int ReportSize ); diff --git a/drivers/libusb.c b/drivers/libusb.c index a874e729e3..955c366997 100644 --- a/drivers/libusb.c +++ b/drivers/libusb.c @@ -120,7 +120,7 @@ static int libusb_claim_interface(usb_dev_handle *udev, int interface) { * (if any) will be tried, until there are no more devices left. */ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDeviceMatcher_t *matcher, - int (*callback)(usb_dev_handle *udev, USBDevice_t *hd, unsigned char *rdbuf, int rdlen)) + int (*callback)(usb_dev_handle *udev, USBDevice_t *hd, unsigned char *rdbuf, int rdlen), int claim) { static int done_init = 0; /* only call usb_init() once */ int rdlen1, rdlen2; /* report descriptor length, method 1+2 */ @@ -347,8 +347,10 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice upsdebugx(2, "Found HID device"); fflush(stdout); - usb_release_interface(udev, 0); - claimed = 0; + if (!claim) { + usb_release_interface(udev, 0); + claimed = 0; + } return rdlen; diff --git a/drivers/libusb.h b/drivers/libusb.h index 6e51dfa9e6..2d193edf82 100644 --- a/drivers/libusb.h +++ b/drivers/libusb.h @@ -48,7 +48,7 @@ typedef struct usb_communication_subdriver_s { int (*open)(usb_dev_handle **sdevp, /* try to open the next available */ USBDevice_t *curDevice, /* device matching USBDeviceMatcher_t */ USBDeviceMatcher_t *matcher, - int (*callback)(usb_dev_handle *udev, USBDevice_t *hd, unsigned char *rdbuf, int rdlen)); + int (*callback)(usb_dev_handle *udev, USBDevice_t *hd, unsigned char *rdbuf, int rdlen), int claim); void (*close)(usb_dev_handle *sdev); int (*get_report)(usb_dev_handle *sdev, int ReportId, unsigned char *raw_buf, int ReportSize ); diff --git a/drivers/nutdrv_qx.c b/drivers/nutdrv_qx.c index f27e89b333..c119ce72c0 100644 --- a/drivers/nutdrv_qx.c +++ b/drivers/nutdrv_qx.c @@ -1610,7 +1610,7 @@ void upsdrv_initups(void) /* Link the matchers */ regex_matcher->next = &device_matcher; - ret = usb->open(&udev, &usbdevice, regex_matcher, NULL); + ret = usb->open(&udev, &usbdevice, regex_matcher, NULL, TRUE); if (ret < 0) { fatalx(EXIT_FAILURE, "No supported devices found. Please check your device availability with 'lsusb'\n" @@ -1729,7 +1729,7 @@ static int qx_command(const char *cmd, char *buf, size_t buflen) #endif /* QX_SERIAL */ if (udev == NULL) { - ret = usb->open(&udev, &usbdevice, reopen_matcher, NULL); + ret = usb->open(&udev, &usbdevice, reopen_matcher, NULL, TRUE); if (ret < 1) { return ret; diff --git a/drivers/riello_usb.c b/drivers/riello_usb.c index 89909da5f8..445bdbe8de 100644 --- a/drivers/riello_usb.c +++ b/drivers/riello_usb.c @@ -312,7 +312,7 @@ int riello_command(uint8_t *cmd, uint8_t *buf, uint16_t length, uint16_t buflen) int ret; if (udev == NULL) { - ret = usb->open(&udev, &usbdevice, reopen_matcher, NULL); + ret = usb->open(&udev, &usbdevice, reopen_matcher, NULL, 1); if (ret < 1) { return ret; @@ -759,7 +759,7 @@ void upsdrv_initups(void) /* link the matchers */ regex_matcher->next = &device_matcher; - ret = usb->open(&udev, &usbdevice, regex_matcher, NULL); + ret = usb->open(&udev, &usbdevice, regex_matcher, NULL, 1); if (ret < 0) { fatalx(EXIT_FAILURE, "No supported devices found. Please check your device availability with 'lsusb'\n" diff --git a/drivers/tripplite_usb.c b/drivers/tripplite_usb.c index e907c124df..8fa0ef3f8b 100644 --- a/drivers/tripplite_usb.c +++ b/drivers/tripplite_usb.c @@ -258,7 +258,7 @@ static int reconnect_ups(void) upsdebugx(2, "= device has been disconnected, try to reconnect ="); upsdebugx(2, "=================================================="); - ret = comm_driver->open(&udev, &curDevice, reopen_matcher, NULL); + ret = comm_driver->open(&udev, &curDevice, reopen_matcher, NULL, 1); if (ret < 1) { upslogx(LOG_INFO, "Reconnecting to UPS failed; will retry later..."); dstate_datastale(); @@ -1323,7 +1323,7 @@ void upsdrv_initups(void) /* Search for the first supported UPS matching the regular * expression */ - r = comm_driver->open(&udev, &curDevice, regex_matcher, NULL); + r = comm_driver->open(&udev, &curDevice, regex_matcher, NULL, 1); if (r < 1) { fatalx(EXIT_FAILURE, "No matching USB/HID UPS found"); } diff --git a/drivers/usbhid-ups.c b/drivers/usbhid-ups.c index 6a42988b2f..1de26b42f6 100644 --- a/drivers/usbhid-ups.c +++ b/drivers/usbhid-ups.c @@ -958,7 +958,7 @@ void upsdrv_initups(void) /* Search for the first supported UPS matching the regular expression (USB) or device_path (SHUT) */ - ret = comm_driver->open(&udev, &curDevice, subdriver_matcher, &callback); + ret = comm_driver->open(&udev, &curDevice, subdriver_matcher, &callback, FALSE); if (ret < 1) fatalx(EXIT_FAILURE, "No matching HID UPS found"); @@ -1356,7 +1356,7 @@ static int reconnect_ups(void) upsdebugx(4, "= device has been disconnected, try to reconnect ="); upsdebugx(4, "=================================================="); - ret = comm_driver->open(&udev, &curDevice, subdriver_matcher, NULL); + ret = comm_driver->open(&udev, &curDevice, subdriver_matcher, NULL, FALSE); if (ret > 0) { return 1; From b09d81538b2efaf5e974866e89c0abe471620d78 Mon Sep 17 00:00:00 2001 From: "Stephen J. Butler" Date: Sat, 19 Apr 2014 00:00:09 -0500 Subject: [PATCH 3/4] Make usbhid-ups more resillient in case of disconnects --- drivers/al175.c | 4 +- drivers/apcsmart-old.c | 4 +- drivers/apcsmart.c | 4 +- drivers/apcupsd-ups.c | 4 +- drivers/bcmxcp_io.h | 2 +- drivers/bcmxcp_ser.c | 4 +- drivers/bcmxcp_usb.c | 4 +- drivers/belkin.c | 4 +- drivers/belkinunv.c | 4 +- drivers/bestfcom.c | 4 +- drivers/bestfortress.c | 4 +- drivers/bestuferrups.c | 4 +- drivers/bestups.c | 4 +- drivers/blazer_ser.c | 4 +- drivers/blazer_usb.c | 4 +- drivers/clone-outlet.c | 4 +- drivers/clone.c | 4 +- drivers/dummy-ups.c | 4 +- drivers/etapro.c | 4 +- drivers/everups.c | 4 +- drivers/gamatronic.c | 3 +- drivers/genericups.c | 4 +- drivers/isbmex.c | 4 +- drivers/ivtscd.c | 4 +- drivers/liebert-esp2.c | 4 +- drivers/liebert.c | 4 +- drivers/macosx-ups.c | 4 +- drivers/main.c | 10 +++- drivers/main.h | 2 +- drivers/masterguard.c | 4 +- drivers/metasys.c | 4 +- drivers/mge-shut.c | 4 +- drivers/mge-utalk.c | 4 +- drivers/microdowell.c | 4 +- drivers/netxml-ups.c | 4 +- drivers/nut-ipmipsu.c | 4 +- drivers/nutdrv_atcl_usb.c | 3 +- drivers/nutdrv_qx.c | 4 +- drivers/oneac.c | 4 +- drivers/optiups.c | 4 +- drivers/powercom.c | 7 ++- drivers/powerman-pdu.c | 4 +- drivers/powerpanel.c | 5 +- drivers/rhino.c | 3 +- drivers/richcomm_usb.c | 4 +- drivers/riello_ser.c | 4 +- drivers/riello_usb.c | 4 +- drivers/safenet.c | 4 +- drivers/skel.c | 4 +- drivers/snmp-ups.c | 4 +- drivers/solis.c | 4 +- drivers/tripplite.c | 4 +- drivers/tripplite_usb.c | 4 +- drivers/tripplitesu.c | 4 +- drivers/upscode2.c | 4 +- drivers/usbhid-ups.c | 113 ++++++++++++++++++++++---------------- drivers/victronups.c | 4 +- 57 files changed, 233 insertions(+), 107 deletions(-) diff --git a/drivers/al175.c b/drivers/al175.c index 7d0b02e57e..1003b1e7f6 100644 --- a/drivers/al175.c +++ b/drivers/al175.c @@ -1261,12 +1261,14 @@ void upsdrv_makevartable(void) { } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); ser_disable_flow_control(); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/apcsmart-old.c b/drivers/apcsmart-old.c index 5c06372ee5..1ccd86cfcd 100644 --- a/drivers/apcsmart-old.c +++ b/drivers/apcsmart-old.c @@ -1414,7 +1414,7 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "advorder", "Enable advanced shutdown control"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { char *cable; @@ -1428,6 +1428,8 @@ void upsdrv_initups(void) /* make sure we wake up if the UPS sends alert chars to us */ extrafd = upsfd; + + return 1; } void upsdrv_help(void) diff --git a/drivers/apcsmart.c b/drivers/apcsmart.c index 018b29dd63..849e79c893 100644 --- a/drivers/apcsmart.c +++ b/drivers/apcsmart.c @@ -2004,7 +2004,7 @@ void upsdrv_help(void) ); } -void upsdrv_initups(void) +int upsdrv_initups(void) { char *val; apc_vartab_t *ptr; @@ -2030,6 +2030,8 @@ void upsdrv_initups(void) /* fill length values */ for (ptr = apc_vartab; ptr->name; ptr++) ptr->nlen0 = strlen(ptr->name) + 1; + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/apcupsd-ups.c b/drivers/apcupsd-ups.c index 1cfc39b32b..125600cd00 100644 --- a/drivers/apcupsd-ups.c +++ b/drivers/apcupsd-ups.c @@ -260,7 +260,7 @@ void upsdrv_makevartable(void) { } -void upsdrv_initups(void) +int upsdrv_initups(void) { char *p; struct hostent *h; @@ -283,6 +283,8 @@ void upsdrv_initups(void) /* TODO: add IPv6 support */ host.sin_family=AF_INET; host.sin_port=htons(port); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/bcmxcp_io.h b/drivers/bcmxcp_io.h index b785a371a5..3d4770cd0f 100644 --- a/drivers/bcmxcp_io.h +++ b/drivers/bcmxcp_io.h @@ -12,7 +12,7 @@ void send_write_command(unsigned char *command, int command_length); int get_answer(unsigned char *data, unsigned char command); int command_read_sequence(unsigned char command, unsigned char *data); int command_write_sequence(unsigned char *command, int command_length, unsigned char *answer); -void upsdrv_initups(void); +int upsdrv_initups(void); void upsdrv_cleanup(void); void upsdrv_reconnect(void); void upsdrv_comm_good(void); diff --git a/drivers/bcmxcp_ser.c b/drivers/bcmxcp_ser.c index 74cecf9c8e..bcdb1d6985 100644 --- a/drivers/bcmxcp_ser.c +++ b/drivers/bcmxcp_ser.c @@ -322,10 +322,12 @@ void pw_comm_setup(const char *port) fatalx(EXIT_FAILURE, "Can't connect to the UPS on port %s!\n", port); } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); pw_comm_setup(device_path); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/bcmxcp_usb.c b/drivers/bcmxcp_usb.c index 2788029676..ee48bdd7e3 100644 --- a/drivers/bcmxcp_usb.c +++ b/drivers/bcmxcp_usb.c @@ -322,9 +322,11 @@ void upsdrv_comm_good(void) nutusb_comm_good(); } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsdev = nutusb_open("USB"); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/belkin.c b/drivers/belkin.c index ad5a658493..aff226a925 100644 --- a/drivers/belkin.c +++ b/drivers/belkin.c @@ -466,7 +466,7 @@ void upsdrv_makevartable(void) } /* prep the serial port */ -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); @@ -478,6 +478,8 @@ void upsdrv_initups(void) sleep(1); ser_flush_io(upsfd); + + return 1; } void upsdrv_initinfo(void) diff --git a/drivers/belkinunv.c b/drivers/belkinunv.c index c5abda2fe7..9e73d43657 100644 --- a/drivers/belkinunv.c +++ b/drivers/belkinunv.c @@ -1307,7 +1307,7 @@ void upsdrv_makevartable(void) } /* prep the serial port */ -void upsdrv_initups(void) +int upsdrv_initups(void) { /* If '-x wait' or '-x wait=' option given, branch into standalone behavior. */ @@ -1316,6 +1316,8 @@ void upsdrv_initups(void) } belkin_nut_open_tty(); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/bestfcom.c b/drivers/bestfcom.c index 54ea93ec2f..8deb58ca88 100644 --- a/drivers/bestfcom.c +++ b/drivers/bestfcom.c @@ -731,7 +731,7 @@ void upsdrv_init_fc(const char *fcstring) fc.valid = 1; } -void upsdrv_initups(void) +int upsdrv_initups(void) { char rstring[256]; @@ -754,7 +754,7 @@ void upsdrv_initups(void) upsdrv_init_fc(rstring); } - return; + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/bestfortress.c b/drivers/bestfortress.c index b12dd15975..45a94cb6eb 100644 --- a/drivers/bestfortress.c +++ b/drivers/bestfortress.c @@ -422,7 +422,7 @@ struct { {NULL, B1200}, }; -void upsdrv_initups(void) +int upsdrv_initups(void) { speed_t speed = B1200; @@ -447,6 +447,8 @@ void upsdrv_initups(void) /* the upsh handlers can't be done here, as they get initialized * shortly after upsdrv_initups returns to main. */ + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/bestuferrups.c b/drivers/bestuferrups.c index d60cb027d6..20965388f2 100644 --- a/drivers/bestuferrups.c +++ b/drivers/bestuferrups.c @@ -397,7 +397,7 @@ static void setup_serial(void) } -void upsdrv_initups () +int upsdrv_initups () { char temp[256], fcstring[512]; @@ -488,7 +488,7 @@ void upsdrv_initups () } fc.valid = 1; - return; + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/bestups.c b/drivers/bestups.c index 854bddf440..92f10d6cf6 100644 --- a/drivers/bestups.c +++ b/drivers/bestups.c @@ -426,10 +426,12 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "ID", "Force UPS ID response string"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/blazer_ser.c b/drivers/blazer_ser.c index 7fa72806be..c90f0de623 100644 --- a/drivers/blazer_ser.c +++ b/drivers/blazer_ser.c @@ -112,7 +112,7 @@ void upsdrv_makevartable(void) } -void upsdrv_initups(void) +int upsdrv_initups(void) { #ifndef TESTING const struct { @@ -183,6 +183,8 @@ void upsdrv_initups(void) usleep(100000); #endif blazer_initups(); + + return 1; } diff --git a/drivers/blazer_usb.c b/drivers/blazer_usb.c index 5cd40b58ca..f5abc7c0a6 100644 --- a/drivers/blazer_usb.c +++ b/drivers/blazer_usb.c @@ -513,7 +513,7 @@ void upsdrv_makevartable(void) } -void upsdrv_initups(void) +int upsdrv_initups(void) { #ifndef TESTING const struct { @@ -633,6 +633,8 @@ void upsdrv_initups(void) } #endif blazer_initups(); + + return 1; } diff --git a/drivers/clone-outlet.c b/drivers/clone-outlet.c index 99d150cf12..d7b277eaff 100644 --- a/drivers/clone-outlet.c +++ b/drivers/clone-outlet.c @@ -385,7 +385,7 @@ void upsdrv_makevartable(void) } -void upsdrv_initups(void) +int upsdrv_initups(void) { char buf[SMALLBUF]; const char *val; @@ -405,6 +405,8 @@ void upsdrv_initups(void) prefix.status = xstrdup(buf); extrafd = upsfd = sstate_connect(); + + return 1; } diff --git a/drivers/clone.c b/drivers/clone.c index c8beb830dc..a594c636ec 100644 --- a/drivers/clone.c +++ b/drivers/clone.c @@ -545,9 +545,11 @@ void upsdrv_makevartable(void) } -void upsdrv_initups(void) +int upsdrv_initups(void) { extrafd = upsfd = sstate_connect(); + + return 1; } diff --git a/drivers/dummy-ups.c b/drivers/dummy-ups.c index 7dbb9910d2..36d9cf1424 100644 --- a/drivers/dummy-ups.c +++ b/drivers/dummy-ups.c @@ -218,7 +218,7 @@ void upsdrv_makevartable(void) { } -void upsdrv_initups(void) +int upsdrv_initups(void) { /* check the running mode... */ if (strchr(device_path, '@')) @@ -234,6 +234,8 @@ void upsdrv_initups(void) mode = MODE_DUMMY; dstate_setinfo("driver.parameter.mode", "dummy"); } + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/etapro.c b/drivers/etapro.c index 6690348600..1742a0b69c 100644 --- a/drivers/etapro.c +++ b/drivers/etapro.c @@ -350,7 +350,7 @@ upsdrv_makevartable(void) { } -void +int upsdrv_initups(void) { upsfd = ser_open(device_path); @@ -358,6 +358,8 @@ upsdrv_initups(void) ser_set_dtr(upsfd, 0); ser_set_rts(upsfd, 1); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/everups.c b/drivers/everups.c index 7cd9328743..bf70812eb6 100644 --- a/drivers/everups.c +++ b/drivers/everups.c @@ -186,13 +186,15 @@ void upsdrv_makevartable(void) { } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B300); init_serial(); InitUpsType(); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/gamatronic.c b/drivers/gamatronic.c index acc56a3929..dfc0edf297 100644 --- a/drivers/gamatronic.c +++ b/drivers/gamatronic.c @@ -365,7 +365,7 @@ void setup_serial(const char *port) printf("Connected to UPS on %s baudrate: %d\n",port, baud_rates[i].name); } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); setup_serial(device_path); @@ -401,6 +401,7 @@ void upsdrv_initups(void) */ + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/genericups.c b/drivers/genericups.c index bc8ddc43d6..45e424ab65 100644 --- a/drivers/genericups.c +++ b/drivers/genericups.c @@ -290,7 +290,7 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "sdtime", "Hold time for shutdown value (seconds)"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { struct termios tio; char *v; @@ -329,6 +329,8 @@ void upsdrv_initups(void) if (ioctl(upsfd, TIOCMSET, &upstab[upstype].line_norm)) { fatal_with_errno(EXIT_FAILURE, "ioctl TIOCMSET"); } + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/isbmex.c b/drivers/isbmex.c index 17328b2abe..5ac9125687 100644 --- a/drivers/isbmex.c +++ b/drivers/isbmex.c @@ -341,10 +341,12 @@ void upsdrv_makevartable(void) { } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/ivtscd.c b/drivers/ivtscd.c index d8ae507dfe..d3e5c4f942 100644 --- a/drivers/ivtscd.c +++ b/drivers/ivtscd.c @@ -201,7 +201,7 @@ void upsdrv_makevartable(void) { } -void upsdrv_initups(void) +int upsdrv_initups(void) { struct termios tio; const char *val; @@ -250,6 +250,8 @@ void upsdrv_initups(void) if (battery.voltage.nom <= battery.voltage.low) { fatalx(EXIT_FAILURE, "Nominal battery voltage must be higher than low battery voltage!"); } + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/liebert-esp2.c b/drivers/liebert-esp2.c index fca7c5e14d..91ded24d1a 100644 --- a/drivers/liebert-esp2.c +++ b/drivers/liebert-esp2.c @@ -519,7 +519,7 @@ void upsdrv_makevartable(void) addvar (VAR_VALUE, "baudrate", "serial line speed"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { const char *val = getval("baudrate"); speed_t baudrate = B2400; @@ -549,6 +549,8 @@ void upsdrv_initups(void) upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, baudrate); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/liebert.c b/drivers/liebert.c index b2faa29d4a..459afe268d 100644 --- a/drivers/liebert.c +++ b/drivers/liebert.c @@ -172,7 +172,7 @@ void upsdrv_help(void) { } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); @@ -183,6 +183,8 @@ void upsdrv_initups(void) /* raise RTS */ ser_set_rts(upsfd, 1); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/macosx-ups.c b/drivers/macosx-ups.c index 11ed475699..bb6204550d 100644 --- a/drivers/macosx-ups.c +++ b/drivers/macosx-ups.c @@ -307,7 +307,7 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "model", "Regular Expression to match power source model name"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { CFArrayRef power_source_key_list; CFIndex num_keys, index; @@ -428,6 +428,8 @@ void upsdrv_initups(void) /* do stuff */ CFRelease(power_dictionary); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/main.c b/drivers/main.c index 7c2fc55f17..674d22c15a 100644 --- a/drivers/main.c +++ b/drivers/main.c @@ -606,7 +606,15 @@ int main(int argc, char **argv) /* clear out callback handler data */ memset(&upsh, '\0', sizeof(upsh)); - upsdrv_initups(); + /* loop looking for the UPS. Driver is allowed to not see it + * immediately. */ + while (!exit_flag) { + if (upsdrv_initups()) + break; + + upslogx(LOG_WARNING, "UPS initialization failed. Retrying after sleep..."); + sleep(poll_interval); + } /* UPS is detected now, cleanup upon exit */ atexit(upsdrv_cleanup); diff --git a/drivers/main.h b/drivers/main.h index 3e3e84eb6e..00fde9f386 100644 --- a/drivers/main.h +++ b/drivers/main.h @@ -13,7 +13,7 @@ extern int upsfd, extrafd, broken_driver, experimental_driver, do_lock_port, ex extern unsigned int poll_interval; /* functions & variables required in each driver */ -void upsdrv_initups(void); /* open connection to UPS, fail if not found */ +int upsdrv_initups(void); /* open connection to UPS, retry if not found */ void upsdrv_initinfo(void); /* prep data, settings for UPS monitoring */ void upsdrv_updateinfo(void); /* update state data if possible */ void upsdrv_shutdown(void); /* make the UPS power off the load */ diff --git a/drivers/masterguard.c b/drivers/masterguard.c index 7edc899968..1c97481878 100644 --- a/drivers/masterguard.c +++ b/drivers/masterguard.c @@ -567,7 +567,7 @@ void upsdrv_makevartable(void) * Detects the UPS and handles the command line args. * ********************************************************************/ -void upsdrv_initups(void) +int upsdrv_initups(void) { int count = 0; int fail = 0; @@ -608,6 +608,8 @@ void upsdrv_initups(void) ser_send_pace(upsfd, UPS_PACE, "%s", "C\x0D" ); fatalx(EXIT_FAILURE, "Shutdown cancelled"); } + + return 1; } /******************************************************************** diff --git a/drivers/metasys.c b/drivers/metasys.c index 647de3c3ce..57e754c865 100644 --- a/drivers/metasys.c +++ b/drivers/metasys.c @@ -1036,11 +1036,13 @@ void upsdrv_makevartable(void) } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); send_zeros(); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/mge-shut.c b/drivers/mge-shut.c index 06398edf0e..ff18eb97e1 100644 --- a/drivers/mge-shut.c +++ b/drivers/mge-shut.c @@ -290,7 +290,7 @@ void upsdrv_makevartable (void) /* --------------------------------------------------------------- */ -void upsdrv_initups (void) +int upsdrv_initups (void) { upsdebugx(2, "entering upsdrv_initups()"); @@ -324,6 +324,8 @@ void upsdrv_initups (void) /* initialise HID communication */ if(hid_init_device() != 0) fatalx(EXIT_FAILURE, "Can't initialise HID device"); + + return 1; } /* --------------------------------------------------------------- */ diff --git a/drivers/mge-utalk.c b/drivers/mge-utalk.c index 2935e91d68..94821dcc12 100644 --- a/drivers/mge-utalk.c +++ b/drivers/mge-utalk.c @@ -159,7 +159,7 @@ void upsdrv_makevartable(void) /* --------------------------------------------------------------- */ -void upsdrv_initups(void) +int upsdrv_initups(void) { char buf[BUFFLEN]; int RTS = TIOCM_RTS; @@ -210,6 +210,8 @@ void upsdrv_initups(void) else upsdebugx(1, "initups: OffDelay unavailable"); } + + return 1; } /* --------------------------------------------------------------- */ diff --git a/drivers/microdowell.c b/drivers/microdowell.c index a1d6605312..06a1508563 100644 --- a/drivers/microdowell.c +++ b/drivers/microdowell.c @@ -958,7 +958,7 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "ups.delay.start", "Override restart delay (10s)"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path) ; @@ -970,6 +970,8 @@ void upsdrv_initups(void) ser_set_rts(upsfd, 0); usleep(10000) ; /* small delay (1/100 s)) */ + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/netxml-ups.c b/drivers/netxml-ups.c index 2568ff06f8..4daad2fab1 100644 --- a/drivers/netxml-ups.c +++ b/drivers/netxml-ups.c @@ -515,7 +515,7 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "shutdown_timer", buf); } -void upsdrv_initups(void) +int upsdrv_initups(void) { int ret; char *val; @@ -629,6 +629,8 @@ void upsdrv_initups(void) } upslogx(LOG_INFO, "Connectivity test: %s", ne_get_error(session)); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/nut-ipmipsu.c b/drivers/nut-ipmipsu.c index 2991cfc3c8..e6b486b4af 100644 --- a/drivers/nut-ipmipsu.c +++ b/drivers/nut-ipmipsu.c @@ -186,7 +186,7 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "fruid", "FRU identifier to match a specific device"); */ } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsdebugx(1, "upsdrv_initups..."); @@ -232,6 +232,8 @@ void upsdrv_initups(void) */ /* don't try to detect the UPS here */ + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/nutdrv_atcl_usb.c b/drivers/nutdrv_atcl_usb.c index 74244935a3..3e11f57c03 100644 --- a/drivers/nutdrv_atcl_usb.c +++ b/drivers/nutdrv_atcl_usb.c @@ -359,7 +359,7 @@ static int usb_device_open(usb_dev_handle **handlep, USBDevice_t *device, USBDev /* * Initialise the UPS */ -void upsdrv_initups(void) +int upsdrv_initups(void) { int i; @@ -383,6 +383,7 @@ void upsdrv_initups(void) "Fatal error: unusable configuration"); } + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/nutdrv_qx.c b/drivers/nutdrv_qx.c index c119ce72c0..0676bd17e5 100644 --- a/drivers/nutdrv_qx.c +++ b/drivers/nutdrv_qx.c @@ -1429,7 +1429,7 @@ void upsdrv_initinfo(void) } /* Open the port and the like and choose the subdriver */ -void upsdrv_initups(void) +int upsdrv_initups(void) { upsdebugx(1, "%s...", __func__); @@ -1666,6 +1666,8 @@ void upsdrv_initups(void) /* Subdriver initups */ if (subdriver->initups != NULL) subdriver->initups(); + + return 1; } /* Close the ports and the like */ diff --git a/drivers/oneac.c b/drivers/oneac.c index 55035f7bbd..510ffac06a 100644 --- a/drivers/oneac.c +++ b/drivers/oneac.c @@ -189,7 +189,7 @@ void EliminateLeadingZeroes (const char* buff1, int StringSize, char* buff2, * Below are the commands that are called by main * ***************************************************************/ -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); @@ -198,6 +198,8 @@ void upsdrv_initups(void) ser_send_pace(upsfd, 100, "%s", COMMAND_END); ser_send_pace(upsfd, 100, "%s", COMMAND_END); sleep (1); + + return 1; } void upsdrv_initinfo(void) diff --git a/drivers/optiups.c b/drivers/optiups.c index 26b7f47797..b5776641dc 100644 --- a/drivers/optiups.c +++ b/drivers/optiups.c @@ -540,12 +540,14 @@ void upsdrv_makevartable(void) addvar(VAR_FLAG, OPTI_POWERUP, "(Zinto D) Power-up UPS at start (cannot identify a powered-down Zinto D)"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); /* NO PARSED COMMAND LINE VARIABLES */ + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/powercom.c b/drivers/powercom.c index 62d8683f5d..08dbfc2aea 100644 --- a/drivers/powercom.c +++ b/drivers/powercom.c @@ -761,7 +761,7 @@ void upsdrv_shutdown(void) } /* initialize UPS */ -void upsdrv_initups(void) +int upsdrv_initups(void) { int tmp,model = 0; unsigned int i; @@ -905,7 +905,7 @@ void upsdrv_initups(void) /* Setup Model and LineVoltage */ if (!strncmp(types[type].name, "BNT",3) || !strcmp(types[type].name, "KIN") || !strcmp(types[type].name, "IMP") || !strcmp(types[type].name, "OPTI")) { - if (!ups_getinfo()) return; + if (!ups_getinfo()) return 1; /* Give "BNT-other" a chance! */ if (raw_data[MODELNAME]==0x42 || raw_data[MODELNAME]==0x4B || raw_data[MODELNAME]==0x4F){ model=BNTmodels[raw_data[MODELNUMBER]/16]; @@ -937,7 +937,7 @@ void upsdrv_initups(void) if (ser_send_char (upsfd, BATTERY_TEST) != 1) { upslogx(LOG_NOTICE, "writing error"); dstate_datastale(); - return; + return 1; } } @@ -978,6 +978,7 @@ void upsdrv_initups(void) types[type].voltage[2], types[type].voltage[3]); } + return 1; } /* display help */ diff --git a/drivers/powerman-pdu.c b/drivers/powerman-pdu.c index b7bcf3dab2..a9923a670a 100644 --- a/drivers/powerman-pdu.c +++ b/drivers/powerman-pdu.c @@ -165,7 +165,7 @@ void upsdrv_makevartable(void) /* FIXME: anything useful to be put here? */ } -void upsdrv_initups(void) +int upsdrv_initups(void) { pm_err_t rv = PM_ESUCCESS; @@ -177,6 +177,8 @@ void upsdrv_initups(void) /* FIXME: suitable? * poll_interval = 30; */ + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/powerpanel.c b/drivers/powerpanel.c index c683c3fab0..79506548b1 100644 --- a/drivers/powerpanel.c +++ b/drivers/powerpanel.c @@ -147,7 +147,7 @@ void upsdrv_shutdown(void) upslogx(LOG_ERR, "Shutdown command failed!"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { char *version; @@ -170,7 +170,7 @@ void upsdrv_initups(void) if (subdriver[mode]->initups() > 0) { upslogx(LOG_INFO, "CyberPower UPS with %s protocol on %s detected", subdriver[mode]->version, device_path); - return; + return 1; } ser_set_dtr(upsfd, 0); @@ -178,6 +178,7 @@ void upsdrv_initups(void) } fatalx(EXIT_FAILURE, "CyberPower UPS not found on %s", device_path); + return 0; } void upsdrv_help(void) diff --git a/drivers/rhino.c b/drivers/rhino.c index c43c411b1c..dd2e83792e 100644 --- a/drivers/rhino.c +++ b/drivers/rhino.c @@ -775,7 +775,7 @@ void upsdrv_makevartable(void) } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B19200); @@ -784,6 +784,7 @@ void upsdrv_initups(void) ser_set_dtr(upsfd, 1); ser_set_rts(upsfd, 0); + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/richcomm_usb.c b/drivers/richcomm_usb.c index 0b9b8f2742..d4947e230d 100644 --- a/drivers/richcomm_usb.c +++ b/drivers/richcomm_usb.c @@ -351,7 +351,7 @@ static int usb_device_open(usb_dev_handle **handlep, USBDevice_t *device, USBDev /* * Initialise the UPS */ -void upsdrv_initups(void) +int upsdrv_initups(void) { char reply[REPLY_PACKETSIZE]; int i; @@ -382,6 +382,8 @@ void upsdrv_initups(void) query_ups(reply); sleep(1); } + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/riello_ser.c b/drivers/riello_ser.c index b76be96345..3db2dc674a 100644 --- a/drivers/riello_ser.c +++ b/drivers/riello_ser.c @@ -939,7 +939,7 @@ void upsdrv_makevartable(void) /* addvar(VAR_VALUE, "foo", "Override foo setting"); */ } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsdebugx(2, "entering upsdrv_initups()"); @@ -978,6 +978,8 @@ void upsdrv_initups(void) /* don't try to detect the UPS here */ /* initialise communication */ + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/riello_usb.c b/drivers/riello_usb.c index 445bdbe8de..27181bda04 100644 --- a/drivers/riello_usb.c +++ b/drivers/riello_usb.c @@ -698,7 +698,7 @@ void upsdrv_makevartable(void) } -void upsdrv_initups(void) +int upsdrv_initups(void) { const struct { const char *name; @@ -784,6 +784,8 @@ void upsdrv_initups(void) dstate_setinfo("ups.vendorid", "%04x", usbdevice.VendorID); dstate_setinfo("ups.productid", "%04x", usbdevice.ProductID); + + return 1; } void upsdrv_initinfo(void) diff --git a/drivers/safenet.c b/drivers/safenet.c index 77170fb32d..90fbd9e71f 100644 --- a/drivers/safenet.c +++ b/drivers/safenet.c @@ -462,7 +462,7 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "offdelay", "Delay before UPS shutdown (seconds)"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { struct termios tio; const char *val; @@ -519,6 +519,8 @@ void upsdrv_initups(void) if ((offdelay < 0) || (offdelay > 999)) { fatalx(EXIT_FAILURE, "Shutdown delay '%d' out of range [0..999]", offdelay); } + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/skel.c b/drivers/skel.c index 5d4b93060e..5b435511fd 100644 --- a/drivers/skel.c +++ b/drivers/skel.c @@ -150,7 +150,7 @@ void upsdrv_makevartable(void) /* addvar(VAR_VALUE, "foo", "Override foo setting"); */ } -void upsdrv_initups(void) +int upsdrv_initups(void) { /* upsfd = ser_open(device_path); */ /* ser_set_speed(upsfd, device_path, B1200); */ @@ -184,6 +184,8 @@ void upsdrv_initups(void) */ /* don't try to detect the UPS here */ + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/snmp-ups.c b/drivers/snmp-ups.c index e99615d9a0..389c8ce3db 100644 --- a/drivers/snmp-ups.c +++ b/drivers/snmp-ups.c @@ -256,7 +256,7 @@ void upsdrv_makevartable(void) "Set the privacy protocol (DES or AES) used for encrypted SNMPv3 messages (default=DES)"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { snmp_info_t *su_info_p; char model[SU_INFOSIZE]; @@ -308,6 +308,8 @@ void upsdrv_initups(void) dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); } + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/solis.c b/drivers/solis.c index 78e83e00a8..3f9a4ac2eb 100644 --- a/drivers/solis.c +++ b/drivers/solis.c @@ -1113,13 +1113,15 @@ void upsdrv_makevartable(void) } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); ser_set_dtr(upsfd, 1); ser_set_rts(upsfd, 0); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/tripplite.c b/drivers/tripplite.c index 78ef2539e2..1c7d918cb2 100644 --- a/drivers/tripplite.c +++ b/drivers/tripplite.c @@ -568,7 +568,7 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "rebootdelay", msg); } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); @@ -579,6 +579,8 @@ void upsdrv_initups(void) startdelay = atoi(getval("startdelay")); if (getval("rebootdelay")) bootdelay = atoi(getval("rebootdelay")); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/tripplite_usb.c b/drivers/tripplite_usb.c index 8fa0ef3f8b..6101ed95c7 100644 --- a/drivers/tripplite_usb.c +++ b/drivers/tripplite_usb.c @@ -1298,7 +1298,7 @@ void upsdrv_makevartable(void) * @todo Allow binding based on firmware version (which seems to vary wildly * from unit to unit) */ -void upsdrv_initups(void) +int upsdrv_initups(void) { char *regex_array[6]; int r; @@ -1351,6 +1351,8 @@ void upsdrv_initups(void) if (getval("rebootdelay")) bootdelay = atoi(getval("rebootdelay")); #endif + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/tripplitesu.c b/drivers/tripplitesu.c index d0d0563760..4c81625ddd 100644 --- a/drivers/tripplitesu.c +++ b/drivers/tripplitesu.c @@ -845,10 +845,12 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "lowbatt", "Set low battery level, in percent"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); + + return 1; } void upsdrv_cleanup(void) diff --git a/drivers/upscode2.c b/drivers/upscode2.c index 1a5a6a25fb..3687f454a9 100644 --- a/drivers/upscode2.c +++ b/drivers/upscode2.c @@ -460,7 +460,7 @@ void upsdrv_help(void) } -void upsdrv_initups(void) +int upsdrv_initups(void) { struct termios tio; int baud = B1200; @@ -529,6 +529,8 @@ void upsdrv_initups(void) upsdebugx(1, "use_crlf = %d", use_crlf); use_pre_lf = testvar("use_pre_lf"); upsdebugx(1, "use_pre_lf = %d", use_pre_lf); + + return 1; } diff --git a/drivers/usbhid-ups.c b/drivers/usbhid-ups.c index 1de26b42f6..fe1870b312 100644 --- a/drivers/usbhid-ups.c +++ b/drivers/usbhid-ups.c @@ -804,6 +804,8 @@ void upsdrv_updateinfo(void) /* Get HID notifications on Interrupt pipe first */ if (use_interrupt_pipe == TRUE) { if (comm_driver->claim_interface(udev, 0) != 0) { + /* flag for reconnect */ + hd = NULL; return; } @@ -904,71 +906,86 @@ void upsdrv_initinfo(void) upsh.instcmd = instcmd; } -void upsdrv_initups(void) +int upsdrv_initups(void) { + static int initups_stage = 0; + int ret; char *val; + + if (initups_stage == 0) { #ifdef SHUT_MODE - /*! - * SHUT is a serial protocol, so it needs - * only the device path - */ - upsdebugx(1, "upsdrv_initups..."); + /*! + * SHUT is a serial protocol, so it needs + * only the device path + */ + upsdebugx(1, "upsdrv_initups..."); - subdriver_matcher = device_path; + subdriver_matcher = device_path; #else - char *regex_array[6]; + char *regex_array[6]; - upsdebugx(1, "upsdrv_initups..."); + upsdebugx(1, "upsdrv_initups..."); - subdriver_matcher = &subdriver_matcher_struct; + subdriver_matcher = &subdriver_matcher_struct; - /* enforce use of the "vendorid" option if "explore" is given */ - if (testvar("explore") && getval("vendorid")==NULL) { - fatalx(EXIT_FAILURE, "must specify \"vendorid\" when using \"explore\""); - } + /* enforce use of the "vendorid" option if "explore" is given */ + if (testvar("explore") && getval("vendorid")==NULL) { + fatalx(EXIT_FAILURE, "must specify \"vendorid\" when using \"explore\""); + } - /* Activate maxreport tweak */ - if (testvar("maxreport")) { - max_report_size = 1; - } + /* Activate maxreport tweak */ + if (testvar("maxreport")) { + max_report_size = 1; + } - /* process the UPS selection options */ - regex_array[0] = getval("vendorid"); - regex_array[1] = getval("productid"); - regex_array[2] = getval("vendor"); - regex_array[3] = getval("product"); - regex_array[4] = getval("serial"); - regex_array[5] = getval("bus"); + /* process the UPS selection options */ + regex_array[0] = getval("vendorid"); + regex_array[1] = getval("productid"); + regex_array[2] = getval("vendor"); + regex_array[3] = getval("product"); + regex_array[4] = getval("serial"); + regex_array[5] = getval("bus"); - ret = USBNewRegexMatcher(®ex_matcher, regex_array, REG_ICASE | REG_EXTENDED); - switch(ret) - { - case 0: - break; - case -1: - fatal_with_errno(EXIT_FAILURE, "HIDNewRegexMatcher()"); - default: - fatalx(EXIT_FAILURE, "invalid regular expression: %s", regex_array[ret]); - } + ret = USBNewRegexMatcher(®ex_matcher, regex_array, REG_ICASE | REG_EXTENDED); + switch(ret) + { + case 0: + break; + case -1: + fatal_with_errno(EXIT_FAILURE, "HIDNewRegexMatcher()"); + default: + fatalx(EXIT_FAILURE, "invalid regular expression: %s", regex_array[ret]); + } - /* link the matchers */ - subdriver_matcher->next = regex_matcher; + /* link the matchers */ + subdriver_matcher->next = regex_matcher; #endif /* SHUT_MODE */ + initups_stage = 1; + } - /* Search for the first supported UPS matching the - regular expression (USB) or device_path (SHUT) */ - ret = comm_driver->open(&udev, &curDevice, subdriver_matcher, &callback, FALSE); - if (ret < 1) - fatalx(EXIT_FAILURE, "No matching HID UPS found"); + if (initups_stage == 1) { + /* Search for the first supported UPS matching the + regular expression (USB) or device_path (SHUT) */ + ret = comm_driver->open(&udev, &curDevice, subdriver_matcher, &callback, FALSE); + if (ret < 1) { + upslogx(LOG_ERR, "No matching HID UPS found"); + return 0; + } - hd = &curDevice; + hd = &curDevice; - upsdebugx(1, "Detected a UPS: %s/%s", hd->Vendor ? hd->Vendor : "unknown", - hd->Product ? hd->Product : "unknown"); + upsdebugx(1, "Detected a UPS: %s/%s", hd->Vendor ? hd->Vendor : "unknown", + hd->Product ? hd->Product : "unknown"); + initups_stage = 2; + } + + // after this part there aren't any more things to retry, so stop + // tracking the stage if (hid_ups_walk(HU_WALKMODE_INIT) == FALSE) { - fatalx(EXIT_FAILURE, "Can't initialize data from HID UPS"); + upslogx(LOG_ERR, "Can't initialize data from HID UPS"); + return 0; } if (dstate_getinfo("battery.charge.low")) { @@ -1010,6 +1027,8 @@ void upsdrv_initups(void) dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); } + + return 1; } void upsdrv_cleanup(void) @@ -1185,6 +1204,8 @@ static bool_t hid_ups_walk(walkmode_t mode) int retcode; if (comm_driver->claim_interface(udev, 0) != 0) { + /* Uh oh, got to reconnect! */ + hd = NULL; return FALSE; } diff --git a/drivers/victronups.c b/drivers/victronups.c index 5b6cf6d406..833b80a461 100644 --- a/drivers/victronups.c +++ b/drivers/victronups.c @@ -514,7 +514,7 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "modelname", "Seting model name"); } -void upsdrv_initups(void) +int upsdrv_initups(void) { char temp[ LENGTH_TEMP ], *usd = NULL; /* = NULL je dulezite jen pro prekladac */ @@ -551,6 +551,8 @@ void upsdrv_initups(void) /* the upsh handlers can't be done here, as they get initialized * shortly after upsdrv_initups returns to main. */ + + return 1; } void upsdrv_cleanup(void) From d6af1ea05fcfd4383c5c8522edb24fd51e9138d0 Mon Sep 17 00:00:00 2001 From: "Stephen J. Butler" Date: Sat, 19 Apr 2014 15:42:10 -0500 Subject: [PATCH 4/4] Fix linux double-free with usb_close(). Prob caused by temporarily assigning *udevp handles to devices we skip and then usb_close(). Don't assign *udevp till we're sure we're going to return it. --- drivers/libusb.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/libusb.c b/drivers/libusb.c index 955c366997..7f74142b39 100644 --- a/drivers/libusb.c +++ b/drivers/libusb.c @@ -148,10 +148,8 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice usb_find_busses(); usb_find_devices(); -#ifndef __linux__ /* SUN_LIBUSB (confirmed to work on Solaris and FreeBSD) */ - /* Causes a double free corruption in linux if device is detached! */ libusb_close(*udevp); -#endif + *udevp = NULL; for (bus = usb_busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { @@ -163,7 +161,7 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice /* open the device */ claimed = 0; - *udevp = udev = usb_open(dev); + udev = usb_open(dev); if (!udev) { upsdebugx(2, "Failed to open device, skipping. (%s)", usb_strerror()); continue; @@ -233,6 +231,7 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice upsdebugx(2, "Device matches"); if (!callback) { + *udevp = udev; return 1; } @@ -352,6 +351,7 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice claimed = 0; } + *udevp = udev; return rdlen; next_device: @@ -363,7 +363,6 @@ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDevice } } - *udevp = NULL; upsdebugx(2, "No appropriate HID device found"); fflush(stdout);