~ubuntu-branches/ubuntu/saucy/nut/saucy

« back to all changes in this revision

Viewing changes to drivers/bcmxcp_usb.c

  • Committer: Chuck Short
  • Date: 2013-05-13 12:57:25 UTC
  • Revision ID: zulcss@ubuntu.com-20130513125725-llq8wsohyhq9idsy
* Merge from Debian.  Remaining changes:
  - debian/control:
    + remove Build-Depends on libpowerman0-dev
    + remove nut-powerman-pdu
  - debian/nut-powerman-pdu.{install,manpages}: dropped for now
  - debian/{nut-cgi,nut-server}.postinst: add nut to the dialout and nut
    groups unconditonally to handle the upgrade from hardy release.
  - debian/source_nut.py, debian/{nut,nut-server,nut-client}.install,
    debian/rules: Install apport hooks for all top-level nut packages.
  - debian/rules: Use udev version for Ubuntu
  - debian/series, debian/patches/backport-fix-lp753661.patch: re-enabled
* Non-maintainer upload with fixes for wheezy.
* debian/nut-client.preinst: also revert /etc/nut/nut.conf mangling done
  by postinst during upgrade from lenny to squeeze (Really closes: #677054)
  Thanks to Andreas Beckmann for the review.
* Merge from Debian.  Remaining changes:
  - debian/control:
    + remove Build-Depends on libpowerman0-dev
    + remove nut-powerman-pdu
  - debian/nut-powerman-pdu.{install,manpages}: dropped for now
  - debian/{nut-cgi,nut-server}.postinst: add nut to the dialout and nut
    groups unconditonally to handle the upgrade from hardy release.
  - debian/source_nut.py, debian/{nut,nut-server,nut-client}.install,
    debian/rules: Install apport hooks for all top-level nut packages.
  - debian/rules: Use udev version for Ubuntu
  - debian/series, debian/patches/backport-fix-lp753661.patch: re-enabled
* Dropped the following patches, no longer required:
  - debian/patches/CVE-2012-2944.patch (included upstream)
* Non-maintainer upload with fixes for wheezy.
* Only remove /etc/init.d/nut from previous versions of nut in nut-server
  postinst if there are no local changes.
* Also remove /etc/init.d/nut in nut-client postinst. Thanks to 
  Laurent Bigonville for the hint.
* Only fix permissions of configfiles on first install.
* debian/control: Fix typo in package description. Thanks to Julien Cristau
  for spotting this.
* Non-maintainer upload.
* debian/nut-client.preinst: revert /etc/nut/nut.conf mangling done by older
  versions of the postinst (Closes: #677054)
* debian/rules: Stop the nut-client before nut-server on systems using
  static
  boot ordering (Closes: #679451)
* debian/nut-server.postinst: Remove /etc/init.d/nut on upgrade
  (Closes: #677822)
* Rename nut-server.lintian-overrides to nut-client.lintian-overrides and
  adjust overrides now that ups-monitor is shipped in nut-client package
  (Closes: #677947)
* Add debian/patches/0001-fix-upsmon-regression.patch: Fix upsmon/upssched
  regression (Taken from upstream) (Closes: #679513)
* Move nut metapackage to Section: metapackages
* Also create nut user when installing nut-client package and do not delete
  it on purge anymore (Closes: #682000)
* Drop /etc/default/nut → /etc/nut/nut.conf migration code, migration
  happends before squeeze release and this was against policy to have a
  maintainer script modifying a conffile in the first place (Closes: #684392)
* Add dependency against adduser and lsb-base on nut-client package
* Be sure that client is stopped before the server also when using
  dependencies based boot
* Fix package descriptions (Closes: #678068)
* Also install /bin/upssched-cmd in nut-client package as this script is
  referenced in default upssched.conf config file
* debian/watch: Update watch file
* Be sure that all maintainer scripts are returning 0 at their end
* New upstream release (Closes: #671444)
* acknowledges NMU (Closes: #613643)
* debian/nut-client.init: fix action "start" and use of log_*_*msg
  LSB log functions (Closes: #675619)
* debian/nut-server.preinst: remove obsolete file(s) left in
  /etc/udev/rules.d and related processing: udev files are now located
  in /lib/udev/rules, and there is no reason to modify the dedicated
  USB UPS rules (52-nut-usbups.rules) (Closes: #660072)
* debian/nut-server.init: rewrite to match upsd / drivers startup scope
* debian/nut-client.init: created to match upsmon startup scope
  (Closes: #634858)
* debian/nut.TODO.Debian, debian/Makefile.am: updated to reflect the above
* debian/rules: install nut-client.init, and update to reflect the above
* debian/control, debian/Makefile.am: updated to reflect the above
* debian/control:
  - add Breaks on nut-server (<< 2.6.3-1~)
  - bump Standards-Version to 3.9.3
* debian/nut-client.links: renamed from debian/nut-server.links, since
  ups-monitor is now provided by nut-client initscript
* debian/nut.README.Debian: renamed from nut-server.README.Debian,
  to provide it with both client and server packages
* debian/nut-server.install: add missing drivers (clone-outlet,
  liebert-esp2 and microdowell)
* debian/nut-server.manpages: add missing manual pages (apcsmart-old,
  ivtscd, liebert-esp2 and microdowell)
* SECURITY UPDATE: remote denial of service
 - debian/CVE-2012-2944.patch: limit the set of parsed characters to ' '
   through '~'
 - CVE-2012-2944
* Merge from Debian testing.  Remaining changes:
  - debian/control: Drop Build-Depends on libpowerman0-dev (currently in 
    universe)
  - debian/{nut-cgi,nut-server}.postinst: add nut to the dialout and nut 
    groups unconditonally to handle the upgrade from hardy release.
  - debian/nut-powerman-pdu.{install,manpages}: dropped for now.
  - debian/source_nut.py, debian/{nut,nut-server,nut-client}.install, 
    debian/rules: Install apport hooks for all top-level nut packages.
  - debian/rules: Use udev version for Ubuntu.
  - debian/series, debian/patches/backport-fix-lp753661.patch: re-enabled.
* New upstream release (Closes: #635186, #598741, #633756, #638221)
* debian/nut-server.{install,manpages}: add richcomm_usb
* debian/nut-server.install, debian/rules: install Avahi service file
* debian/rules, nut-client.install: install Augeas lenses
* debian/nut-server.README.Debian: clarify udev explanation (Closes: #529664)
* debian/patches/0001-fix_spelling_and_typo.patch,
  debian/patches/0003-libupsclient-version.patch: removed since these are now
  fixed upstream
* debian/patches/series: updated
* Merge from debian unstable.  Remaining changes:
  - debian/control: Drop Build-Depends on libpowerman0-dev (currently in 
    universe)
  - debian/{nut-cgi,nut-server}.postinst: add nut to the dialout and nut 
    groups unconditonally to handle the upgrade from hardy release.
  - debian/nut-powerman-pdu.{install,manpages}: dropped for now.
  - debian/source_nut.py, debian/{nut,nut-server,nut-client}.install, 
    debian/rules: Install apport hooks for all top-level nut packages.
  - debian/rules: Use udev version for Ubuntu.
  - debian/series, debian/patches/backport-fix-lp753661.patch: re-enabled.
* New upstream release (Closes: #594989)
* debian/control:
  - remove legacy Build-Depends for nut-hal-drivers on libdbus and libglib
  - Build-Depends-Indep on docbook-xsl for offline document
    generation (Closes: #635347)
* debian/nut-server.install: add apcsmart-old
* debian/nut-server.init:
  - add udev as Required-Start/Stop (Closes: #642412)
  - remove legacy support for /etc/default/nut (Closes: #638021)
* debian/patches/0003-libupsclient-version.patch: added to fix the missing
  libupsclient version info bump
* debian/libupsclient1-dev.links: update link name
* debian/libupsclient1.symbols: add with upscli_tryconnect
* debian/nut.TODO.Debian: update and complete the TODO list
* Fix FTBFS for Ubuntu (LP: #815760):
  - debian/control: Build-Depends-Indep on docbook-xsl for offline 
    document generation.
* Merge from Debian unstable (LP: #811976). Remaining changes:
  - debian/control: Drop Build-Depends on libpowerman0-dev (currently in 
    universe)
  - debian/{nut-cgi,nut-server}.postinst: add nut to the dialout and nut 
    groups unconditonally to handle the upgrade from hardy release.
  - debian/nut-powerman-pdu.{install,manpages}: dropped for now.
  - debian/source_nut.py, debian/{nut,nut-server,nut-client}.install, 
    debian/rules: Install apport hooks for all top-level nut packages.
  - debian/rules: Use udev version for Ubuntu.
  - debian/series, debian/patches/backport-fix-lp753661.patch: re-enabled.
* debian/nut.README.Debian: Adjust udev rules naming for permissions override
  (Closes: #529664)
* Re-add and refresh debian/patches/0001-fix_spelling_and_typo.patch:
  Some typos and spelling errors remain.
* Split nut package into nut-client and nut-server, keep nut package as
  metapackage
* Generate PDF and html doc and install it in nut-doc package
* debian/rules:
  - List non-installed files
  - Includes python-module.mk
  - Add flags to build documentation and install it
* debian/control:
  - Add python-nut package and add python build-dependency
  - Set nut-powerman-pdu priority to extras
  - Add nut-monitor package
  - Add nut-doc package and add required C/R/P
  - Add libups-nut-perl package
* debian/nut-server.prerm: Remove /var/run/nut during removal
* Merge from debian unstable.  Remaining changes:
  - debian/control:
    + Drop Build-Depends on libpowerman0-dev (currently in universe)
  - debian/{nut-cgi,nut}.postinst: add nut to the dialout and nut groups
    unconditonally to handle the upgrade from hardy release.
  - debian/nut-powerman-pdu.{install,manpages}: dropped for now.
  - debian/source_nut.py, debian/nut.install, debian/rules: Install apport hook.
  - debian/rules: Use udev version for Ubuntu.
* debian/patches/backport-fix-lp753661.patch: Refreshed.
* Drop changes due to .pc being not clean.
* New upstream release (Closes: #595953, #614842, #595773)
* debian/patches/*.patch: removed since these are now fixed upstream
* Drop HAL package and build-dependencies (Closes: #613197)
* debian/control:
  - Bump Standards-Version to 3.9.2 (no further changes)
  - Drop autotools build-dependencies (not needed anymore)
  - Drop non-existing build-dependencies
* debian/rules:
  - Correctly pass flags to configure
* Merge from debian unstable (LP: #789323).  Remaining changes:
  + debian/control:
    - Update maintainer as per spec.
    - Add Breaks on nut-hal-drivers to ensure we have correct udev version.
    - Drop libpowerman0-dev from the Build-Depends (currently in universe)
  + debian/{nut-cgi,nut}.postinst: add nut to the dialout and nut groups
    unconditonally to handle the upgrade from hardy release.
  + debian/nut-powerman-pdu.install, debian/nut-powerman-pdu.manpages: dropped for now.
  + debian/nul-hal-drivers.{docs,install,postinst,preinst}: Dropped since hal is in universe now
  + debian/nut.links: must create the init script link, used if the upse needs to be powered down
    (LP: #357583)
  + debian/source_nut.py, debian/nut.install, debian/rules: Install apport hook.
  + debian/patches/backport-fix-lp753661.patch
  + Dropped:
    - debian/patches/fix_pc_file.patch: replaced by debian's 0002-fix_libupsclient_pc.patch
* debian/patches/fix_pc_file.patch: add DEP3 patch header
* debian/patches/debian-changes-2.6.0-1: remove that accidental file
* debian/nut-snmp.docs: Distribute snmp.txt doc file (Closes: #548295)
* d/p/0001-fix_spelling_and_typo.patch: Update and refresh
* debian/nut.lintian-overrides: Fix typo
* debian/patch/0002-fix_libupsclient_pc.patch: Fix libupsclient.pc (Closes:
  #624255)
* debian/rules:
  - Switch to cdbs
  - Remove not existing configure options (Closes: #611813)
  - Drop Phony rules (Closes: #613699)
* debian/control:
  - Add cdbs build-dependency
* debian/patches/backport-fix-lp753661.patch: Backport fix 
  to trim extraneous end-of-line, in buggy HID string tables, 
  which results in upsc breaking the communication pipe.
  (LP: #753661)
* fix_pc_file.patch: fix .pc source files by using LIBSSL_LIBS instead of
  LIBSSL_LDFLAGS to avoid a FTBFS in packages that uses libupsclient.pc
  (LP: #743484)
* Merge from Debian unstable, remaining changes:
  + debian/control:
    - Update maintainer as per spec.
    - Add Breaks on nut-hal-drivers to ensure we have correct udev version.
    - Drop libpowerman0-dev from the Build-Depends (currently in universe)
  + debian/{nut-cgi,nut}.postinst: add nut to the dialout and nut groups
    unconditonally to hanle the upgrade from hardy release.
  + debian/nut-powerman-pdu.install, debian/nut-powerman-pdu.manpages: dropped for now.
  + debian/nul-hal-drivers.{docs,install,postinst,preinst}: Dropped since hal is in universe now
  + debian/nut.links: must create the init script link, used if the upse needs to be powered down
    (LP: #357583)
  + debian/source_nut.py, debian/nut.install, debian/rules: Install apport hook.
  + Dropped:
    - debian/patches/0002-fix_udev_action.patch: Accepted upstream.
    - debian/patches/0004-netvision-improvements-lp-600950: no longer needed.
    - debian/patches/0005-fix-nut-m4.patch: no longer needed.
    - debian/patches/9999-autoconf.patch: no longer needed.
* New upstream release (Closes: #575176, #588648, #609597, #687985)
* debian/patches/*.patch: removed since these are now fixed upstream
* debian/patches/0001-fix_spelling_and_typo.patch,
  debian/patches/series: reworked to match the new upstream release
* debian/nut.install, debian/nut.manpages: remove obsolete reference to
  megatec and megatec_usb, now respectively replaced by blazer_ser and
  blazer_usb
* debian/nut.docs: limit distributed documentation
* debian/control:
  - Wrap build-dependencies
  - Change nut-cgi Recommends to apache2 | httpd-cgi
* debian/nut.postinst: Only trigger USB subsystem, should Closes: #574769
* debian/patches/0002-fix_udev_action.patch: Use SUBSYSTEM instead of BUS
* debian/control, debian/rules, 
  debian/nut-hal-drivers.{docs,install,postinst,preinst}: Drop
  nut-hal-drivers since Nut doesnt go into universe.
* Split patches/debian-changes-2.4.3-2ubuntu1 into
  patches/0005-fix-nut-m4.patch and patches/9999-autoconf.patch
* Readd lost debian/patches0004-netvision-improvements-lp-600950.patch patch
  (LP: #707050)
* debian/patches/0002-fix_udev_action.patch:
  Change BUS to SUBSYSTEMS, since the former is deprecated. (LP: #692171)
* debian/nut.postinst: Uncomment missing call to adduser
* debian/control: Drop hal build dependency, we don't need the daemon to
  build the package. Add a hal dependency to nut-hal-drivers, which is the
  only thing that actually needs it.
* Merge from debian unstable.  Remaining changes:
  + debian/control:
    - Update maintainer as per spec.
    - Add Breaks on nut-hal-drivers to ensure we have correct udev version.
    - Drop libpowerman0-dev from the Build-Depends (currently in universe)
  + debian/{nut-cgi,nut}.postinst: add nut to the dialout and nut groups
    unconditonally to hanle the upgrade from hardy release.
  + debian/nut-powerman-pdu.install, debian/nut-powerman-pdu.manpages: dropped for now.
  + debian/nut.links: must create the init script link, used if the upse needs to be powered down
    (LP: #357583)
  + debian/nut.postinst: Update udevadm trigger.
    "libusb_get_report: error sending control message: 
     Operation not permitted" error on some UPS devices. (LP: #572262)
  + debian/source_nut.py, debian/nut.install, debian/rules: Install apport hook.
  + debian/patches/netvision-improvements-lp-600950.patch: Add improvements
    for netvision UPSes
  + Fix FTBFS with ld --as-needed.
  + Dropped:
    - debian/patches/03_udev_rules_change.dpatch: Use debian's instead.
    - debian/patches/04_nut_small-buffers.dpatch: Use debian's instead.
* debian/control:
  - Bump Standards-Version to 3.9.1
  - Update Vcs-* fields to new GIT repository
  - Add myself as Uploaders
* Switch to dpkg-source 3.0 (quilt) format (Closes: #573601)
* debian/patches/0001-low_speed_usb_ups.patch: Use patch system for changes
  that were applied directly in the source
* Add debian/gbp.conf file
* debian/watch: Bump version to 3
* Add debian/patches/0002-fix_udev_action.patch: Also set permission for
  "change" udev ACTION (Closes: #557178)
* debian/nut.postrm: Do not try to remove nut user is deluser is not
  installed anymore
* debian/nut.manpages: Install manpage nut.conf.5 (Closes: #528222)
* debian/copyright: Fix copyright-with-old-dh-make-debian-copyright
* Remove nut-snmp.lintian-overrides, not needed anymore
* debian/patches/0003-fix_spelling_and_typo.patch: Fix some spelling errors
* Add debian/libupsclient1.symbols file
* Add debian/nut.links: Re-add /etc/init.d/ups-monitor that was lost for
  some reasons (Closes: #592351)
* debian/nut.lintian-overrides: Add override for
  init.d-script-does-not-provide-itself /etc/init.d/ups-monitor
* Drop libupsclient1.post{inst,rm}: ldconfig call is added automatically by
  debhelper
* debian/libupsclient1-dev.install: Do not ship /lib/libupsclient.la anymore
* debian/rules: Remove dpatch logic as we are using package source version
  '3.0 (quilt)'
* debian/compat: Bump debhelper compatibility to 8
* Non-maintainer upload.
* drivers/libhid.c: Apply r2407 from upstream to fix bug with some
  low speed UPS devices. (Closes: #583371)
* Fix FTBFS with ld --as-needed.
* debian/patches/netvision-improvements-lp-600950.patch: Add improvements for netvision UPSes 
  (LP: #600950) 
* debian/source_nut.py, debian/nut.install, debian/rules: Install apport hook. 
* debian/patches/04_nut-small-buffers.dpatch: Fix "libusb_get_report: error sending control message: 
  Operation not permitted" error on some UPS devices. (LP: #572262)
* debian/nut.postinst: Revert dropping of --action=change. "add" events must
  not ever be triggered automatically.
* Add 03_udev_rules_change.dpatch: Run udev rules on change events, too.
* debian/control: grr...fix ftbfs. 
* Merge from debian testing.  Remaining changes (LP: #535152):
  + debian/control:
    - Update maintainer as per spec.
    - Add Breaks on nut-hal-drivers to ensure we have correct udev version.
    - Drop libpowerman0-dev from the Build-Depends (currently in universe)
  + debian/{nut-cgi,nut}.postinst: add nut to the dialout and nut groups
    unconditonally to hanle the upgrade from hardy release.
  + debian/nut-powerman-pdu.install, debian/nut-powerman-pdu.manpages: dropped for now.
  + debian/nut.links: must create the init script link, used if the upse needs to be powered down
    (LP: #357583)
  + debian/nut.postinst: Update udevadm trigger.
  + Dropped:
    - debian/patches/02-fix-trust-pw4130m.dpatch: No longer needed.
* New upstream release (Closes: #544390, #528222, #539747, #526811,
  #562064)
* debian/nut.install, debian/nut.manpages:
  - remove cyberpower driver and manpage
  - add bestfortress, clone and ivtscd drivers and manpages
* debian/rules:
  - change udev dir to /lib/udev (Closes: #522327)
  - replace deprecated calls to 'dh_clean -k' by dh_prep (Closes: #536599)
* debian/rules, debian/nut.install, debian/nut.install,
  debian/nut.README.Debian: install configuration files, without the
  sample suffix (Closes: #528641)
* debian/nut.links: restored (Closes: #522506)
* debian/nut.init:
  - source nut.conf instead of default/nut for POWEROFF_WAIT(Closes:
    #538173)
  - fix status checking (Closes: #538785)
  - improve detection of non configured system and beautify related
    output (Closes: #563112)
  - use 'invoke-rc.d' instead of calling the reboot script directly
  - add $remote_fs to Required-Start and Required-Stop
* debian/nut.postrm: remove udev files and simplify cleanup (Closes:
  #541629)
* debian/control:
  - remove Luca Filipozzi from the Uploaders list (Closes: #568987)
  - update Standards-Version to 3.8.4
  - remove the debconf dependency
  - bump debhelper version to (>= 7) in Build-Depends, for dh_prep
  - add Breaks on nut-hal-drivers to ensure we have correct udev version
* Remove debconf support since it was related to really old nut
  version (Closes: #518056):
  - remove nut-cgi.config, nut.config, nut-cgi.templates, nut.templates,
    and po/ directory
  - update nut-cgi.postinst
* debian/nut.dirs: remove /var/run/nut to conform to Debian Policy
* debian/nut.postint:
  - create /var/run/nut if needed
  - improve security checks
* debian/nut.README.Debian: add a security note for ups.conf
* debian/watch: URL update
* debian/patches/02-fix-trust-pw4130m.dpatch: Fix issues with Trust
  PW-4130M UPS. (LP: #447586) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#include "main.h"
2
2
#include "bcmxcp.h"
3
3
#include "bcmxcp_io.h"
4
 
#include "nut_usb.h"
5
 
 
6
 
usb_dev_handle *upsdev = NULL;
 
4
#include "common.h"
 
5
#include "usb-common.h"
 
6
#include "timehead.h"
 
7
#include "nut_stdint.h" /* for uint16_t */
 
8
#include <ctype.h>
 
9
#include <sys/file.h>
 
10
#include <sys/types.h>
 
11
#include <unistd.h>
 
12
#include <usb.h>
7
13
 
8
14
#define SUBDRIVER_NAME  "USB communication subdriver"
9
 
#define SUBDRIVER_VERSION       "0.17"
 
15
#define SUBDRIVER_VERSION       "0.21"
10
16
 
11
17
/* communication driver description structure */
12
18
upsdrv_info_t comm_upsdrv_info = {
17
23
        { NULL }
18
24
};
19
25
 
 
26
#define MAX_TRY 4
 
27
 
 
28
/* Powerware */
 
29
#define POWERWARE       0x0592
 
30
 
 
31
/* Phoenixtec Power Co., Ltd */
 
32
#define PHOENIXTEC      0x06da
 
33
 
 
34
/* Hewlett Packard */
 
35
#define HP_VENDORID     0x03f0
 
36
 
 
37
/* USB functions */
 
38
usb_dev_handle *nutusb_open(const char *port);
 
39
int nutusb_close(usb_dev_handle *dev_h, const char *port);
 
40
/* unified failure reporting: call these often */
 
41
void nutusb_comm_fail(const char *fmt, ...)
 
42
        __attribute__ ((__format__ (__printf__, 1, 2)));
 
43
void nutusb_comm_good(void);
 
44
/* function pointer, set depending on which device is used */
 
45
int (*usb_set_descriptor)(usb_dev_handle *udev, unsigned char type,
 
46
        unsigned char index, void *buf, int size);
 
47
 
 
48
/* usb_set_descriptor() for Powerware devices */
 
49
static int usb_set_powerware(usb_dev_handle *udev, unsigned char type, unsigned char index, void *buf, int size)
 
50
{
 
51
        return usb_control_msg(udev, USB_ENDPOINT_OUT, USB_REQ_SET_DESCRIPTOR, (type << 8) + index, 0, buf, size, 1000);
 
52
}
 
53
 
 
54
static void *powerware_ups(void) {
 
55
        usb_set_descriptor = &usb_set_powerware;
 
56
        return NULL;
 
57
}
 
58
 
 
59
/* usb_set_descriptor() for Phoenixtec devices */
 
60
static int usb_set_phoenixtec(usb_dev_handle *udev, unsigned char type, unsigned char index, void *buf, int size)
 
61
{
 
62
        return usb_control_msg(udev, 0x42, 0x0d, (0x00 << 8) + 0x0, 0, buf, size, 1000);
 
63
}
 
64
 
 
65
static void *phoenixtec_ups(void) {
 
66
        usb_set_descriptor = &usb_set_phoenixtec;
 
67
        return NULL;
 
68
}
 
69
 
 
70
/* USB IDs device table */
 
71
static usb_device_id_t pw_usb_device_table[] = {
 
72
        /* various models */
 
73
        { USB_DEVICE(POWERWARE, 0x0002), &powerware_ups },
 
74
 
 
75
        /* various models */
 
76
        { USB_DEVICE(PHOENIXTEC, 0x0002), &phoenixtec_ups },
 
77
 
 
78
        /* T500 */
 
79
        { USB_DEVICE(HP_VENDORID, 0x1f01), &phoenixtec_ups },
 
80
        /* T750 */
 
81
        { USB_DEVICE(HP_VENDORID, 0x1f02), &phoenixtec_ups },
 
82
        
 
83
        /* Terminating entry */
 
84
        { -1, -1, NULL }
 
85
};
 
86
 
 
87
/* limit the amount of spew that goes in the syslog when we lose the UPS */
 
88
#define USB_ERR_LIMIT 10        /* start limiting after 10 in a row  */
 
89
#define USB_ERR_RATE 10         /* then only print every 10th error */
 
90
#define XCP_USB_TIMEOUT 5000
 
91
 
 
92
/* global variables */
 
93
usb_dev_handle *upsdev = NULL;
 
94
extern  int             exit_flag;
 
95
static  unsigned int    comm_failures = 0;
 
96
 
 
97
/* Functions implementations */
20
98
void send_read_command(unsigned char command)
21
99
{
22
 
        unsigned char buf[4];
 
100
        unsigned char buf[4];
23
101
 
24
 
        buf[0]=PW_COMMAND_START_BYTE;
25
 
        buf[1]=0x01;                    /* data length */
26
 
        buf[2]=command;                 /* command to send */
27
 
        buf[3]=calc_checksum(buf);      /* checksum */
28
 
        usb_set_descriptor(upsdev, USB_DT_STRING, 4, buf, 4); /* Ignore error */
 
102
        if (upsdev) {
 
103
                buf[0] = PW_COMMAND_START_BYTE;
 
104
                buf[1] = 0x01;                    /* data length */
 
105
                buf[2] = command;                 /* command to send */
 
106
                buf[3] = calc_checksum(buf);      /* checksum */
 
107
                upsdebug_hex (3, "send_read_command", buf, 4);
 
108
                usb_set_descriptor(upsdev, USB_DT_STRING, 4, buf, 4); /* FIXME: Ignore error */
 
109
        }
29
110
}
30
111
 
31
112
void send_write_command(unsigned char *command, int command_length)
32
113
{
33
114
        unsigned char sbuf[128];
34
115
 
35
 
        /* Prepare the send buffer */
36
 
        sbuf[0] = PW_COMMAND_START_BYTE;
37
 
        sbuf[1] = (unsigned char)(command_length);
38
 
        memcpy(sbuf+2, command, command_length);
39
 
        command_length += 2;
 
116
        if (upsdev) {
 
117
                /* Prepare the send buffer */
 
118
                sbuf[0] = PW_COMMAND_START_BYTE;
 
119
                sbuf[1] = (unsigned char)(command_length);
 
120
                memcpy(sbuf+2, command, command_length);
 
121
                command_length += 2;
40
122
 
41
 
        /* Add checksum */
42
 
        sbuf[command_length] = calc_checksum(sbuf);
43
 
        command_length += 1;
44
 
        usb_set_descriptor(upsdev, USB_DT_STRING, 4, sbuf, command_length);  /* Ignore error */
 
123
                /* Add checksum */
 
124
                sbuf[command_length] = calc_checksum(sbuf);
 
125
                command_length += 1;
 
126
                upsdebug_hex (3, "send_write_command", sbuf, command_length);
 
127
                usb_set_descriptor(upsdev, USB_DT_STRING, 4, sbuf, command_length);  /* FIXME: Ignore error */
 
128
        }
45
129
}
46
130
 
47
131
/* get the answer of a command from the ups. And check that the answer is for this command */
48
132
int get_answer(unsigned char *data, unsigned char command)
49
133
{
50
134
        unsigned char buf[1024], *my_buf = buf;
51
 
        int length, end_length, res, endblock, start;
52
 
        unsigned char block_number, sequence, pre_sequence;
53
 
 
54
 
        end_length = 0;
55
 
        endblock = 0;
56
 
        pre_sequence = 0;
57
 
        start = 0;
58
 
 
59
 
        res = usb_interrupt_read(upsdev, 1, (char *)buf, sizeof(buf), 1000);
60
 
        if (res < 0) {
61
 
                nutusb_comm_fail("Receive error (Request command): COMMAND: %x\n", command);
62
 
                upsdrv_reconnect();
 
135
        int length, end_length, res, endblock, bytes_read, ellapsed_time;
 
136
        unsigned char block_number, sequence, seq_num;
 
137
        struct timeval start_time, now;
 
138
 
 
139
        if (upsdev == NULL)
63
140
                return -1;
64
 
        }
65
 
 
66
 
        
67
 
        while (endblock != 1 && my_buf < buf+sizeof(buf) && res > 0){
 
141
 
 
142
        length = 1;                     /* non zero to enter the read loop */
 
143
        end_length = 0;         /* total length of sequence(s), not counting header(s) */
 
144
        endblock = 0;           /* signal the last sequence in the block */
 
145
        bytes_read = 0;         /* total length of data read, including XCP header */
 
146
        res = 0;
 
147
        ellapsed_time = 0;
 
148
        seq_num = 1;            /* current theoric sequence */
 
149
 
 
150
        upsdebugx(1, "entering get_answer(%x)", command);
 
151
 
 
152
        /* Store current time */
 
153
        gettimeofday(&start_time, NULL);
 
154
 
 
155
        while ( (!endblock) && ((XCP_USB_TIMEOUT - ellapsed_time)  > 0) ) {
 
156
 
 
157
                /* Get (more) data if needed */
 
158
                if ((length - bytes_read) > 0) {
 
159
                        res = usb_interrupt_read(upsdev, 0x81,
 
160
                                (char *)&buf[bytes_read],
 
161
                                (PW_ANSWER_MAX_SIZE - bytes_read),
 
162
                                (XCP_USB_TIMEOUT - ellapsed_time));
 
163
 
 
164
                        /* Update time */
 
165
                        gettimeofday(&now, NULL);
 
166
                        ellapsed_time = (now.tv_sec - start_time.tv_sec)*1000 +
 
167
                                        (now.tv_usec - start_time.tv_usec)/1000;
 
168
 
 
169
                        /* Check libusb return value */
 
170
                        if (res < 0)
 
171
                        {
 
172
                                /* Clear any possible endpoint stalls */
 
173
                                usb_clear_halt(upsdev, 0x81);
 
174
                                /* continue; */ /* FIXME: seems a break would be better! */
 
175
                                break;
 
176
                        }
 
177
 
 
178
                        /* this seems to occur on XSlot USB card */
 
179
                        if (res == 0)
 
180
                        {
 
181
                                /* FIXME: */
 
182
                                continue;
 
183
                        }
 
184
                        
 
185
                        /* Else, we got some input bytes */ 
 
186
                        bytes_read += res;
 
187
                        upsdebug_hex(1, "get_answer", buf, bytes_read);
 
188
                }
 
189
 
 
190
                /* Now validate XCP frame */
 
191
                /* Check header */
 
192
                if ( my_buf[0] != 0xAB ) {
 
193
                        upsdebugx(2, "get_answer: wrong header");
 
194
                        return -1;
 
195
                }
 
196
 
 
197
                /* These validations seem not needed! */
68
198
                /* Read block number byte */
69
 
                block_number = (unsigned char)my_buf[1];
70
 
 
 
199
                block_number = my_buf[1];
 
200
                upsdebugx(1, "get_answer: block_number = %x", block_number);
 
201
#if 0
71
202
                if (command <= 0x43) {
72
203
                        if ((command - 0x30) != block_number){
73
 
                                nutusb_comm_fail("Receive error (Request command): BLOCK: %x, COMMAND: %x!\n", block_number, command);
 
204
                                nutusb_comm_fail("Receive error (Request command): BLOCK: %x (instead of %x), COMMAND: %x!\n",
 
205
                                        block_number, (command - 0x30), command);
74
206
                                return -1;
75
207
                        }
76
208
                }
77
209
 
78
210
                if (command >= 0x89) {
79
211
                        if ((command == 0xA0) && (block_number != 0x01)){
80
 
                                nutusb_comm_fail("Receive error (Request command): BLOCK: %x, COMMAND: %x!\n", block_number, command);
 
212
                                nutusb_comm_fail("Receive error (Request command): BLOCK: %x (instead of 0x01), COMMAND: %x!\n", block_number, command);
81
213
                                return -1;
82
214
                        }
83
215
                        else if ((command != 0xA0) && (block_number != 0x09)){
84
 
                                nutusb_comm_fail("Receive error (Request command): BLOCK: %x, COMMAND: %x!\n", block_number, command);
 
216
                                nutusb_comm_fail("Receive error (Request command): BLOCK: %x (instead of 0x09), COMMAND: %x!\n", block_number, command);
85
217
                                return -1;
86
218
                        }
87
219
                }
88
 
 
89
 
                /* Read data length byte */
90
 
                length = (unsigned char)my_buf[2];
91
 
 
92
 
                if (length < 1) {
93
 
                        nutusb_comm_fail("Receive error (length): packet length %x!!!\n", length);
94
 
                        return -1;
95
 
                }
96
 
 
97
 
                /* Read sequence byte */
98
 
                sequence = (unsigned char)my_buf[3];
99
 
                if ((sequence & 0x80) == 0x80) {
 
220
#endif /* if 0 */
 
221
 
 
222
                /* Check data length byte (remove the header length) */
 
223
                length = my_buf[2];
 
224
                upsdebugx(3, "get_answer: data length = %d", length);
 
225
                if ((bytes_read - 5) < length) {
 
226
                        upsdebugx(2, "get_answer: need to read %d more data", length - (bytes_read - 5));
 
227
                        continue;
 
228
                }
 
229
                /* Check if Length conforms to XCP (121 for normal, 140 for Test mode) */
 
230
                /* Use the more generous length for testing */
 
231
                if (length > 140 ) {
 
232
                        upsdebugx(2, "get_answer: bad length");
 
233
                        return -1;
 
234
                }
 
235
 
 
236
                /* Test the Sequence # */
 
237
                sequence = my_buf[3];
 
238
                if ((sequence & PW_SEQ_MASK) != seq_num) {
 
239
                        nutusb_comm_fail("get_answer: not the right sequence received %x!!!\n", (sequence & PW_SEQ_MASK));
 
240
                        return -1;
 
241
                }
 
242
                else {
 
243
                        upsdebugx(2, "get_answer: sequence number (%x) is ok", (sequence & PW_SEQ_MASK));
 
244
                }
 
245
 
 
246
                /* Validate checksum */
 
247
                if (!checksum_test(my_buf)) {
 
248
                        nutusb_comm_fail("get_answer: checksum error! ");
 
249
                        return -1;
 
250
                }
 
251
                else {
 
252
                        upsdebugx(2, "get_answer: checksum is ok");
 
253
                }
 
254
 
 
255
                /* Check if it's the last sequence */
 
256
                if (sequence & PW_LAST_SEQ) {
 
257
                        /* we're done receiving data */
 
258
                        upsdebugx(2, "get_answer: all data received");
100
259
                        endblock = 1;
101
260
                }
102
 
 
103
 
                if ((sequence & 0x07) != (pre_sequence + 1)) {
104
 
                        nutusb_comm_fail("Not the right sequence received %x!!!\n", sequence);
105
 
                        return -1;
106
 
                }
107
 
 
108
 
                pre_sequence = sequence;
109
 
 
110
 
                /* Try to read all the remainig bytes */
111
 
                if (res-5 < length) {
112
 
                        nutusb_comm_fail("Receive error (data): got %d bytes instead of %d!!!\n", res-5, length);
113
 
                        return -1;
114
 
                }
115
 
 
116
 
                /* now we have the whole answer from the ups, we can checksum it */
117
 
                if (!checksum_test(my_buf)) {
118
 
                        nutusb_comm_fail("checksum error! ");
119
 
                        return -1;
120
 
                }
121
 
 
 
261
                else {
 
262
                        seq_num++;
 
263
                }
 
264
 
 
265
                /* copy the current valid XCP frame back */
122
266
                memcpy(data+end_length, my_buf+4, length);
 
267
                /* increment pointers to process the next sequence */
123
268
                end_length += length;
124
 
 
125
269
                my_buf += length + 5;
126
 
                res -= length - 5;
127
270
        }
 
271
 
 
272
        upsdebug_hex (5, "get_answer", data, end_length);
128
273
        return end_length;
129
274
}
130
275
 
154
299
{
155
300
        int bytes_read = 0;
156
301
        int retry = 0;
157
 
        
 
302
 
158
303
        while ((bytes_read < 1) && (retry < 5)) {
159
304
                send_write_command(command, command_length);
160
 
                bytes_read = get_answer(answer, command[0]);            
 
305
                sleep(PW_SLEEP);
 
306
                bytes_read = get_answer(answer, command[0]);
161
307
                retry ++;
162
308
        }
163
309
 
171
317
}
172
318
 
173
319
 
174
 
void upsdrv_comm_good()
 
320
void upsdrv_comm_good(void)
175
321
{
176
322
        nutusb_comm_good();
177
323
}
189
335
 
190
336
void upsdrv_reconnect(void)
191
337
{
192
 
        
193
338
        upslogx(LOG_WARNING, "RECONNECT USB DEVICE\n");
194
339
        nutusb_close(upsdev, "USB");
195
340
        upsdev = NULL;
196
 
        sleep(3);
197
 
        upsdrv_initups();       
 
341
        upsdrv_initups();
 
342
}
 
343
 
 
344
/* USB functions */
 
345
static void nutusb_open_error(const char *port)
 
346
{
 
347
        printf("Unable to find POWERWARE UPS device on USB bus (%s)\n\n", port);
 
348
 
 
349
        printf("Things to try:\n\n");
 
350
        printf(" - Connect UPS device to USB bus\n\n");
 
351
        printf(" - Run this driver as another user (upsdrvctl -u or 'user=...' in ups.conf).\n");
 
352
        printf("   See upsdrvctl(8) and ups.conf(5).\n\n");
 
353
 
 
354
        fatalx(EXIT_FAILURE, "Fatal error: unusable configuration");
 
355
}
 
356
 
 
357
/* FIXME: this part of the opening can go into common... */
 
358
static usb_dev_handle *open_powerware_usb(void)
 
359
{
 
360
        struct usb_bus *busses = usb_get_busses();  
 
361
        struct usb_bus *bus;
 
362
    
 
363
        for (bus = busses; bus; bus = bus->next)
 
364
        {
 
365
                struct usb_device *dev;
 
366
    
 
367
                for (dev = bus->devices; dev; dev = dev->next)
 
368
                {
 
369
                        if (dev->descriptor.bDeviceClass != USB_CLASS_PER_INTERFACE) {
 
370
                                continue;
 
371
                        }
 
372
 
 
373
                        if (is_usb_device_supported(pw_usb_device_table,
 
374
                                dev->descriptor.idVendor, dev->descriptor.idProduct) == SUPPORTED) {
 
375
                                return usb_open(dev);
 
376
                        }
 
377
                }
 
378
        }
 
379
        return 0;
 
380
}
 
381
 
 
382
usb_dev_handle *nutusb_open(const char *port)
 
383
{
 
384
        int            dev_claimed = 0;
 
385
        usb_dev_handle *dev_h = NULL;
 
386
        int            retry, errout = 0;
 
387
 
 
388
        upsdebugx(1, "entering nutusb_open()");
 
389
 
 
390
        /* Initialize Libusb */
 
391
        usb_init();
 
392
        usb_find_busses();
 
393
        usb_find_devices();
 
394
 
 
395
        for (retry = 0; retry < MAX_TRY ; retry++)
 
396
        {
 
397
                dev_h = open_powerware_usb();
 
398
                if (!dev_h) {
 
399
                        upsdebugx(1, "Can't open POWERWARE USB device");
 
400
                        errout = 1;
 
401
                }
 
402
                else {
 
403
                        upsdebugx(1, "device %s opened successfully", usb_device(dev_h)->filename);
 
404
                        errout = 0;
 
405
 
 
406
                        if (usb_claim_interface(dev_h, 0) < 0)
 
407
                        {
 
408
                                upsdebugx(1, "Can't claim POWERWARE USB interface: %s", usb_strerror());
 
409
                                errout = 1;
 
410
                        }
 
411
                        else {
 
412
                                dev_claimed = 1;
 
413
                                errout = 0;
 
414
                        }
 
415
/* FIXME: the above part of the opening can go into common... up to here at least */
 
416
 
 
417
                        if (usb_clear_halt(dev_h, 0x81) < 0)
 
418
                        {
 
419
                                upsdebugx(1, "Can't reset POWERWARE USB endpoint: %s", usb_strerror());
 
420
                                errout = 1;
 
421
                        }
 
422
                        else
 
423
                                errout = 0;
 
424
                }
 
425
 
 
426
                /* Test if we succeeded */
 
427
                if ( (dev_h != NULL) && dev_claimed && (errout == 0) )
 
428
                        break;
 
429
                else {
 
430
                        /* Clear errors, and try again */
 
431
                        errout = 0;
 
432
                }
 
433
        }
 
434
 
 
435
        if (!dev_h && !dev_claimed && retry == MAX_TRY)
 
436
                errout = 1;
 
437
        else
 
438
                return dev_h;
 
439
 
 
440
        if (dev_h && dev_claimed)
 
441
                usb_release_interface(dev_h, 0);
 
442
 
 
443
        if (dev_h)
 
444
                usb_close(dev_h);
 
445
 
 
446
        if (errout == 1)
 
447
                nutusb_open_error(port);
 
448
 
 
449
        return NULL;
 
450
}
 
451
 
 
452
/* FIXME: this part can go into common... */
 
453
int nutusb_close(usb_dev_handle *dev_h, const char *port)
 
454
{
 
455
        if (dev_h)
 
456
        {
 
457
                usb_release_interface(dev_h, 0);
 
458
                return usb_close(dev_h);
 
459
        }
 
460
        
 
461
        return 0;
 
462
}
 
463
 
 
464
void nutusb_comm_fail(const char *fmt, ...)
 
465
{
 
466
        int     ret;
 
467
        char    why[SMALLBUF];
 
468
        va_list ap;
 
469
 
 
470
        /* this means we're probably here because select was interrupted */
 
471
        if (exit_flag != 0)
 
472
                return;         /* ignored, since we're about to exit anyway */
 
473
 
 
474
        comm_failures++;
 
475
 
 
476
        if ((comm_failures == USB_ERR_LIMIT) ||
 
477
                ((comm_failures % USB_ERR_RATE) == 0))
 
478
        {
 
479
                upslogx(LOG_WARNING, "Warning: excessive comm failures, "
 
480
                        "limiting error reporting");
 
481
        }
 
482
 
 
483
        /* once it's past the limit, only log once every USB_ERR_LIMIT calls */
 
484
        if ((comm_failures > USB_ERR_LIMIT) &&
 
485
                ((comm_failures % USB_ERR_LIMIT) != 0)) {
 
486
                /* Try reconnection */
 
487
                upsdrv_reconnect();
 
488
                return;
 
489
        }
 
490
 
 
491
        /* generic message if the caller hasn't elaborated */
 
492
        if (!fmt)
 
493
        {
 
494
                upslogx(LOG_WARNING, "Communications with UPS lost - check cabling");
 
495
                return;
 
496
        }
 
497
 
 
498
        va_start(ap, fmt);
 
499
        ret = vsnprintf(why, sizeof(why), fmt, ap);
 
500
        va_end(ap);
 
501
 
 
502
        if ((ret < 1) || (ret >= (int) sizeof(why)))
 
503
                upslogx(LOG_WARNING, "usb_comm_fail: vsnprintf needed "
 
504
                        "more than %d bytes", (int)sizeof(why));
 
505
 
 
506
        upslogx(LOG_WARNING, "Communications with UPS lost: %s", why);
 
507
}
 
508
 
 
509
void nutusb_comm_good(void)
 
510
{
 
511
        if (comm_failures == 0)
 
512
                return;
 
513
 
 
514
        upslogx(LOG_NOTICE, "Communications with UPS re-established");
 
515
        comm_failures = 0;
198
516
}