Filter:   InfoImg
download nut_usb.c
Language: C
License: GPL
Copyright: (C) 2003 Russell Kroll (C) 2005 Wolfgang Ocker
LOC: 149
Project Info
nut
Server: Debian-SVN
Type: svn
...an‑SVN\n\nut\trunk\drivers\
   al175.c
   al175.h
   apc-hid.c
   apc-hid.h
   apccmib.h
   apcsmart.c
   apcsmart.h
   bcmxcp.c
   bcmxcp.h
   bcmxcp_io.h
   bcmxcp_ser.c
   bcmxcp_usb.c
   belkin-hid.c
   belkin-hid.h
   belkin.c
   belkin.h
   belkinunv.c
   belkinunv.h
   bestfcom.c
   bestfcom.h
   bestuferrups.c
   bestuferrups.h
   bestups.c
   bestups.h
   cpsups.c
   cpsups.h
   cyberpower.c
   cyberpower.h
   dstate-hal.c
   dstate-hal.h
   dstate.c
   dstate.h
   dummy-ups.c
   dummy-ups.h
   energizerups.c
   etapro.c
   etapro.h
   everups.c
   everups.h
   explore-hid.c
   explore-hid.h
   gamatronic.c
   gamatronic.h
   genericups.c
   genericups.h
   hidparser.c
   hidparser.h
   hidtypes.h
   ietfmib.h
   isbmex.c
   isbmex.h
   libhid.c
   libhid.h
   libshut.c
   libshut.h
   libusb.c
   libusb.h
   liebert.c
   liebert.h
   main-hal.c
   main-hal.h
   main.c
   main.h
   Makefile.am
   masterguard.c
   masterguard.h
   megatec.c
   megatec.h
   megatec_usb.c
   metasys.c
   metasys.h
   mge-hid.c
   mge-hid.h
   mge-shut.c
   mge-shut.h
   mge-utalk.c
   mge-utalk.h
   mgemib.h
   netvisionmib.h
   nitram.c
   nitram.h
   nut_usb.c
   nut_usb.h
   oneac.c
   oneac.h
   optiups.c
   optiups.h
   powercom.c
   powercom.h
   powerpanel.c
   powerpanel.h
   pwmib.h
   rhino.c
   safenet.c
   safenet.h
   serial.c
   serial.h
   skel.c
   snmp-ups.c
   snmp-ups.h
   solis.c
   solis.h
   tripplite-hid.c
   tripplite-hid.h
   tripplite.c
   tripplite.h
   tripplite_usb.c
   tripplitesu.c
   tripplitesu.h
   upscode2.c
   upscode2.h
   upsdrvctl.c
   usbhid-ups.c
   usbhid-ups.h
   victronups.c
   victronups.h

/* nut_usb.c - common usb functions for Network UPS Tools drivers

   Copyright (C) 2005 Wolfgang Ocker <weo@weo1.de>
   Based upon serial.c: Copyright (C) 2003  Russell Kroll <rkroll@exploits.org>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include "common.h"
#include "timehead.h"

#include <ctype.h>
#include <sys/file.h>
#include <sys/types.h>
#include <unistd.h>
#include <usb.h>

#include "nut_usb.h"

extern	int		exit_flag;
static	unsigned int	comm_failures = 0;

static void nutusb_open_error(const char *port)
{
	printf("Unable to find POWERWARE UPS device on USB bus \n\n");

	printf("Things to try:\n\n");
	printf(" - Connect UPS device to USB bus\n\n");
	printf(" - Run this driver as another user (upsdrvctl -u or 'user=...' in ups.conf).\n");
	printf("   See upsdrvctl(8) and ups.conf(5).\n\n");

	fatalx("Fatal error: unusable configuration");
}

static usb_dev_handle *open_powerware_usb()
{
	struct usb_bus *busses = usb_get_busses();  
	struct usb_bus *bus;
    
	for (bus = busses; bus; bus = bus->next)
	{
		struct usb_device *dev;
    
		for (dev = bus->devices; dev; dev = dev->next)
		{
			/* XXX Check for POWERWARE 3105 or 3110 ... other models??? */
			if (dev->descriptor.bDeviceClass == USB_CLASS_PER_INTERFACE &&
			    (dev->descriptor.idVendor == 0x0592 ||
			     dev->descriptor.idVendor == 0x06da) &&
			    dev->descriptor.idProduct == 0x0002)
				return usb_open(dev);
		}
	}

	return 0;
}

usb_dev_handle *nutusb_open(const char *port)
{
	static int     libusb_init = 0;
	int            dev_claimed = 0;
	usb_dev_handle *dev_h = NULL;
	int            retry;
	
	if (!libusb_init)
	{
		/* Initialize Libusb */
		usb_init();
		libusb_init = 1;
	}

	for (retry = 0; dev_h == NULL && retry < 32; retry++)
	{
		struct timespec t = {5, 0};
		usb_find_busses();
		usb_find_devices();

		dev_h = open_powerware_usb();
		if (!dev_h) {
			upslogx(LOG_WARNING, "Can't open POWERWARE USB device, retrying ...");
			if (nanosleep(&t, NULL) < 0 && errno == EINTR)
				break;
		}
	}
	
	if (!dev_h)
	{
		upslogx(LOG_ERR, "Can't open POWERWARE USB device");
		goto errout;
	}

	if (usb_set_configuration(dev_h, 1) < 0)
	{
		upslogx(LOG_ERR, "Can't set POWERWARE USB configuration");
		goto errout;
	}

	if (usb_claim_interface(dev_h, 0) < 0)
	{
		upslogx(LOG_ERR, "Can't claim POWERWARE USB interface");
  	        goto errout;
	}
	else
		dev_claimed = 1;

	if (usb_set_altinterface(dev_h, 0) < 0)
	{
		upslogx(LOG_ERR, "Can't set POWERWARE USB alternate interface");
  	        goto errout;
	}

	if (usb_clear_halt(dev_h, 0x81) < 0)
	{
		upslogx(LOG_ERR, "Can't reset POWERWARE USB endpoint");
		goto errout;
	}
    
	return dev_h;

errout:
	if (dev_h && dev_claimed)
		usb_release_interface(dev_h, 0);
	if (dev_h)
		usb_close(dev_h);

	nutusb_open_error(port);
	return 0;
}

int nutusb_close(usb_dev_handle *dev_h, const char *port)
{
	if (dev_h)
	{
		usb_release_interface(dev_h, 0);
		return usb_close(dev_h);
	}
	
	return 0;
}

void nutusb_comm_fail(const char *fmt, ...)
{
	int	ret;
	char	why[SMALLBUF];
	va_list	ap;

	/* this means we're probably here because select was interrupted */
	if (exit_flag != 0)
		return;		/* ignored, since we're about to exit anyway */

	comm_failures++;

	if ((comm_failures == USB_ERR_LIMIT) ||
		((comm_failures % USB_ERR_RATE) == 0))
	{
		upslogx(LOG_WARNING, "Warning: excessive comm failures, "
			"limiting error reporting");
	}

	/* once it's past the limit, only log once every USB_ERR_LIMIT calls */
	if ((comm_failures > USB_ERR_LIMIT) &&
		((comm_failures % USB_ERR_LIMIT) != 0))
		return;

	/* generic message if the caller hasn't elaborated */
	if (!fmt)
	{
		upslogx(LOG_WARNING, "Communications with UPS lost"
			" - check cabling");
		return;
	}

	va_start(ap, fmt);
	ret = vsnprintf(why, sizeof(why), fmt, ap);
	va_end(ap);

	if ((ret < 1) || (ret >= (int) sizeof(why)))
		upslogx(LOG_WARNING, "usb_comm_fail: vsnprintf needed "
			"more than %d bytes", sizeof(why));

	upslogx(LOG_WARNING, "Communications with UPS lost: %s", why);
}

void nutusb_comm_good(void)
{
	if (comm_failures == 0)
		return;

	upslogx(LOG_NOTICE, "Communications with UPS re-established");
	comm_failures = 0;
}

int usb_set_descriptor(usb_dev_handle *udev, unsigned char type,
		       unsigned char index, void *buf, int size)
{
	return usb_control_msg(udev, USB_ENDPOINT_OUT, USB_REQ_SET_DESCRIPTOR,
				(type << 8) + index, 0, buf, size, 1000);
}