/* scan_usb.c: detect NUT supported USB devices * * Copyright (C) 2011 - Frederic Bohe * * 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 "nut-scan.h" #ifdef WITH_USB #include "upsclient.h" #include "nutscan-usb.h" #include #include #include /* dynamic link library stuff */ static char * libname = "libusb"; static lt_dlhandle dl_handle = NULL; static const char *dl_error = NULL; static int (*nut_usb_close)(usb_dev_handle *dev); static int (*nut_usb_find_busses)(void); static char * (*nut_usb_strerror)(void); static void (*nut_usb_init)(void); static int (*nut_usb_get_string_simple)(usb_dev_handle *dev, int index, char *buf, size_t buflen); static struct usb_bus * (*nut_usb_busses); static usb_dev_handle * (*nut_usb_open)(struct usb_device *dev); static int (*nut_usb_find_devices)(void); /* return 0 on error */ int nutscan_load_usb_library() { if( dl_handle != NULL ) { /* if previous init failed */ if( dl_handle == (void *)1 ) { return 0; } /* init has already been done */ return 1; } if( lt_dlinit() != 0 ) { fprintf(stderr, "Error initializing lt_init\n"); return 0; } dl_handle = lt_dlopenext(libname); if (!dl_handle) { dl_error = lt_dlerror(); goto err; } lt_dlerror(); /* Clear any existing error */ *(void **) (&nut_usb_close) = lt_dlsym(dl_handle, "usb_close"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_usb_find_busses) = lt_dlsym(dl_handle, "usb_find_busses"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_usb_strerror) = lt_dlsym(dl_handle, "usb_strerror"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_usb_init) = lt_dlsym(dl_handle, "usb_init"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_usb_get_string_simple) = lt_dlsym(dl_handle, "usb_get_string_simple"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_usb_busses) = lt_dlsym(dl_handle, "usb_busses"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **) (&nut_usb_open) = lt_dlsym(dl_handle, "usb_open"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } *(void **)(&nut_usb_find_devices) = lt_dlsym(dl_handle,"usb_find_devices"); if ((dl_error = lt_dlerror()) != NULL) { goto err; } return 1; err: fprintf(stderr, "Cannot load USB library (%s) : %s. USB search disabled.\n", libname, dl_error); dl_handle = (void *)1; lt_dlexit(); return 0; } /* end of dynamic link library stuff */ static char* is_usb_device_supported(usb_device_id_t *usb_device_id_list, int dev_VendorID, int dev_ProductID) { usb_device_id_t *usbdev; for (usbdev=usb_device_id_list; usbdev->driver_name != NULL; usbdev++) { if ( (usbdev->vendorID == dev_VendorID) && (usbdev->productID == dev_ProductID) ) { return usbdev->driver_name; } } return NULL; } /* return NULL if error */ nutscan_device_t * nutscan_scan_usb() { int ret; char string[256]; char *driver_name = NULL; char *serialnumber = NULL; char *device_name = NULL; char *vendor_name = NULL; struct usb_device *dev; struct usb_bus *bus; usb_dev_handle *udev; nutscan_device_t * nut_dev = NULL; nutscan_device_t * current_nut_dev = NULL; if( !nutscan_avail_usb ) { return NULL; } /* libusb base init */ (*nut_usb_init)(); (*nut_usb_find_busses)(); (*nut_usb_find_devices)(); for (bus = (*nut_usb_busses); bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { if ((driver_name = is_usb_device_supported(usb_device_table, dev->descriptor.idVendor, dev->descriptor.idProduct)) != NULL) { /* open the device */ udev = (*nut_usb_open)(dev); if (!udev) { fprintf(stderr,"Failed to open device, \ skipping. (%s)\n", (*nut_usb_strerror)()); continue; } /* get serial number */ if (dev->descriptor.iSerialNumber) { ret = (*nut_usb_get_string_simple)(udev, dev->descriptor.iSerialNumber, string, sizeof(string)); if (ret > 0) { serialnumber = strdup(string); } } /* get product name */ if (dev->descriptor.iProduct) { ret = (*nut_usb_get_string_simple)(udev, dev->descriptor.iProduct, string, sizeof(string)); if (ret > 0) { device_name = strdup(string); } } /* get vendor name */ if (dev->descriptor.iManufacturer) { ret = (*nut_usb_get_string_simple)(udev, dev->descriptor.iManufacturer, string, sizeof(string)); if (ret > 0) { vendor_name = strdup(string); } } nut_dev = nutscan_new_device(); if(nut_dev == NULL) { fprintf(stderr,"Memory allocation \ error\n"); nutscan_free_device(current_nut_dev); free(serialnumber); free(device_name); free(vendor_name); return NULL; } nut_dev->type = TYPE_USB; if(driver_name) { nut_dev->driver = strdup(driver_name); } nut_dev->port = strdup("auto"); sprintf(string,"%04X",dev->descriptor.idVendor); nutscan_add_option_to_device(nut_dev,"vendorid", string); sprintf(string,"%04X", dev->descriptor.idProduct); nutscan_add_option_to_device(nut_dev,"productid", string); if(device_name) { nutscan_add_option_to_device(nut_dev, "product", device_name); free(device_name); } if(serialnumber) { nutscan_add_option_to_device(nut_dev, "serial", serialnumber); free(serialnumber); } if(vendor_name) { nutscan_add_option_to_device(nut_dev, "vendor", vendor_name); free(vendor_name); } nutscan_add_option_to_device(nut_dev,"bus", bus->dirname); current_nut_dev = nutscan_add_device_to_device( current_nut_dev, nut_dev); memset (string, 0, sizeof(string)); (*nut_usb_close)(udev); } } } return current_nut_dev; } #else /* WITH_USB */ nutscan_device_t * nutscan_scan_usb() { return NULL; } #endif /* WITH_USB */