sent two 0 byte packets to the driver, then it sent 'URB_FUNCTION_SYNC_REST_PIPE_AND_CLEAR_STALL' down the pipe which seems to come back up as well, and then the UPS turned off. I'll play around later with what happens in that regard, although it may be a bit tricky to figure out when the battery is low without having it plugged in ;-) Also, about nut-usbups.rules.in... The previously discussed Kebo is in there with the same vendorid/productid. May be useful to add a comment there as well (in fact, anywhere Kebo is mentioned), I have a feeling the Kebo may just work with this driver. Here are the diffs for nut_usb.c (svn diff): Index: nut_usb.c ==================================================================--- nut_usb.c (revision 911) +++ nut_usb.c (working copy) @@ -56,11 +56,13 @@ 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); + if ((dev->descriptor.bDeviceClass =USB_CLASS_PER_INTERFACE && + (dev->descriptor.idVendor == 0x0592 || + dev->descriptor.idVendor == 0x06da) && + dev->descriptor.idProduct == 0x0002) || + (dev->descriptor.idVendor == 0x0925 && + dev->descriptor.idProduct == 0x1234)) + return usb_open(dev); } } @@ -101,11 +103,33 @@ goto errout; } +#if LIBUSB_HAS_DETACH_KRNL_DRV + /* this method requires at least libusb 0.1.8: + * it force device claiming by unbinding + * attached driver... From libhid */ + retry = 3; + while (usb_set_configuration(dev_h, 1) != 0 && retry-- > 0) { +// while ((dev_claimed = usb_claim_interface(dev_h, 0)) != 0 && retry-- > 0) { + + upsdebugx(2, "failed to claim USB device, trying %d more time(s)...", retry); + + upsdebugx(2, "detaching kernel driver from USB device..."); + if (usb_detach_kernel_driver_np(dev_h, 0) < 0) { + upsdebugx(2, "failed to detach kernel driver from USB device..."); + } + + upsdebugx(2, "trying again to claim USB device..."); + } + + if (dev_claimed == 0) + dev_claimed = 1; +#else if (usb_set_configuration(dev_h, 1) < 0) { upslogx(LOG_ERR, "Can't set POWERWARE USB configuration"); goto errout; } +#endif if (usb_claim_interface(dev_h, 0) < 0) { ==================================================================sweex_usb.c: ==================================================================/* sweex_usb.h - driver for newer Sweex models, such as 'Sweex Manageable UPS 1000VA' (ca. 2006) May also work on 'Kebo UPS-650D', not tested as of 05/23/2007 Copyright (C) 2007 Peter van Valderen <p.v.valderen at probu.nl> Dirk Teurlings <dirk at upexia.nl> 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 "main.h" #include "nut_usb.h" #include "sweex_usb.h" usb_dev_handle *upsdev = NULL; int query_ups (unsigned char *reply) { unsigned char buf[4]; int ret; /* * This packet is a status request to the UPS */ buf[0]=0x01; buf[1]=0x00; buf[2]=0x00; buf[3]=0x30; return execute_and_retrieve_query(buf, reply); } int execute_and_retrieve_query(unsigned char *query, unsigned char *reply) { int ret; ret = usb_control_msg(upsdev, STATUS_REQUESTTYPE, REQUEST_VALUE, MESSAGE_VALUE, INDEX_VALUE, query, sizeof(query), 1000); if (ret < 0) { return ret; } ret = usb_interrupt_read(upsdev, REPLY_REQUESTTYPE, reply, sizeof(REPLY_PACKETSIZE), 1000); return ret; } void claim_device () { int ret; ret = usb_claim_interface(upsdev, 0); if (ret < 0) { upslogx(LOG_ERR, "Can't claim USB interface"); } return ret; } void upsdrv_comm_good() { nutusb_comm_good(); } /* * Initialise the UPS */ void upsdrv_initups(void) { unsigned char reply[REPLY_PACKETSIZE]; int i; upsdev = nutusb_open("USB"); /* * Claim the device */ claim_device(); /* * Read rubbish data a few times; the UPS doesn't seem to respond properly * the first few times after connecting */ for (i=0;i<5;i++) { query_ups(reply); sleep(1); } } void upsdrv_cleanup(void) { upslogx(LOG_ERR, "CLOSING\n"); nutusb_close(upsdev, "USB"); } void upsdrv_reconnect(void) { upslogx(LOG_WARNING, "RECONNECT USB DEVICE\n"); nutusb_close(upsdev, "USB"); upsdev = NULL; sleep(3); upsdrv_initups(); } void upsdrv_initinfo(void) { dstate_setinfo("driver.version.internal", "%s", DRV_VERSION); dstate_setinfo("ups.mfr", "Sweex"); dstate_setinfo("ups.model","Unknown"); } void upsdrv_updateinfo(void) { unsigned char reply[REPLY_PACKETSIZE]; int ret, online, battery_normal; unsigned char test; ret = query_ups(reply); if (ret < 0) { upslog_with_errno(LOG_INFO, "Query to UPS failed"); dstate_datastale(); return; } /* * 3rd bit of 4th byte indicates whether the UPS is on line (1) * or on battery (0) */ online = (reply[3]&4)>>2; /* * 2nd bit of 4th byte indicates battery status; normal (1) * or low (0) */ battery_normal = (reply[3]&2)>>1; status_init(); if (online) { status_set("OL"); } else { status_set("OB"); } if (!battery_normal) { status_set("LB"); } status_commit(); dstate_dataok(); } /* * The shutdown feature is a bit strange on this UPS IMHO, it * switches the polarity of the 'Shutdown UPS' signal, at which * point it will automatically power down once it loses power. * * It will still, however, be possible to poll the UPS and * reverse the polarity _again_, at which point it will * start back up once power comes back. * * Maybe this is the normal way, it just seems a bit strange. * * Please note, this function doesn't power the UPS off if * line power is connected. */ void upsdrv_shutdown(void) { unsigned char reply[REPLY_PACKETSIZE]; unsigned char buf[4]; int ret; /* * This packet shuts down the UPS, that is, if it is * not currently on line power */ buf[0]=0x02; buf[1]=0x00; buf[2]=0x00; buf[3]=0x00; execute_and_retrieve_query(buf, reply); sleep(1); /* have to, the previous command seems to be * ignored if the second command comes right * behind it */ /* * This should make the UPS turn itself back on once the * power comes back on; which is probably what we want */ buf[0]=0x02; buf[1]=0x01; buf[2]=0x00; buf[3]=0x00; execute_and_retrieve_query(buf, reply); } void upsdrv_help(void) { } void upsdrv_makevartable(void) { } void upsdrv_banner(void) { printf("Network UPS Tools - Sweex USB UPS driver %s (%s)\n\n", DRV_VERSION, UPS_VERSION); }