// libusbi.h: libusb wrapper // This file is part of scanbuttond. // Copyleft )c( 2004-2006 by Bernhard Stiftner // // 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., 675 Mass Ave, Cambridge, MA 02139, USA. #include #include #include #include #include #include #include #include "scanbuttond/libusbi.h" #define TIMEOUT 10 * 1000 /* 10 seconds */ int invocation_count = 0; libusb_handle_t* libusb_init(void) { libusb_handle_t* handle; invocation_count++; if (invocation_count == 1) { syslog(LOG_INFO, "libusbi: initializing..."); usb_init(); } handle = (libusb_handle_t*)malloc(sizeof(libusb_handle_t)); handle->devices = NULL; libusb_rescan(handle); return handle; } int libusb_search_interface(struct usb_device* device) { int found = 0; int interface; for (interface = 0; interface < device->config[0].bNumInterfaces && !found; interface++) { switch (device->descriptor.bDeviceClass) { case USB_CLASS_VENDOR_SPEC: found = 1; break; case USB_CLASS_PER_INTERFACE: switch (device->config[0].interface[interface].altsetting[0].bInterfaceClass) { case USB_CLASS_VENDOR_SPEC: case USB_CLASS_PER_INTERFACE: case 16: /* data? */ found = 1; break; } break; } } interface--; if (!found) return -1; return interface; } int libusb_search_in_endpoint(struct usb_device* device) { int usb_in_ep = 0; int usb_out_ep = 0; struct usb_interface_descriptor *interface; interface = &device->config[0].interface->altsetting[0]; int num; for (num = 0; num < interface->bNumEndpoints; num++) { struct usb_endpoint_descriptor *endpoint; int address, direction, transfer_type; endpoint = &interface->endpoint[num]; address = endpoint->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK; direction = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK; transfer_type = endpoint->bmAttributes & USB_ENDPOINT_TYPE_MASK; if (transfer_type == USB_ENDPOINT_TYPE_BULK) { if (direction) { /* in */ if (!usb_in_ep) usb_in_ep = endpoint->bEndpointAddress; } else { /* out */ if (!usb_out_ep) usb_out_ep = endpoint->bEndpointAddress; } } } return usb_in_ep; } int libusb_search_out_endpoint(struct usb_device* device) { int usb_in_ep = 0; int usb_out_ep = 0; struct usb_interface_descriptor *interface; interface = &device->config[0].interface->altsetting[0]; int num; for (num = 0; num < interface->bNumEndpoints; num++) { struct usb_endpoint_descriptor *endpoint; int address, direction, transfer_type; endpoint = &interface->endpoint[num]; address = endpoint->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK; direction = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK; transfer_type = endpoint->bmAttributes & USB_ENDPOINT_TYPE_MASK; if (transfer_type == USB_ENDPOINT_TYPE_BULK) { if (direction) { /* in */ if (!usb_in_ep) usb_in_ep = endpoint->bEndpointAddress; } else { /* out */ if (!usb_out_ep) usb_out_ep = endpoint->bEndpointAddress; } } } return usb_out_ep; } void libusb_attach_device(struct usb_device* device, libusb_handle_t* handle) { libusb_device_t* libusb_device = (libusb_device_t*)malloc(sizeof(libusb_device_t)); libusb_device->vendorID = device->descriptor.idVendor; libusb_device->productID = device->descriptor.idProduct; // the location string consists of bus number, followed by a colon (":"), and the device number libusb_device->location = (char*)malloc(strlen(device->bus->dirname) + strlen(device->filename) + 2); strcpy(libusb_device->location, device->bus->dirname); strcat(libusb_device->location, ":"); strcat(libusb_device->location, device->filename); libusb_device->device = device; libusb_device->handle = NULL; libusb_device->interface = libusb_search_interface(device); if (libusb_device->interface < 0) { free(libusb_device->location); free(libusb_device); return; } libusb_device->out_endpoint = libusb_search_out_endpoint(device); if (libusb_device->out_endpoint < 0) { free(libusb_device->location); free(libusb_device); return; } libusb_device->in_endpoint = libusb_search_in_endpoint(device); if (libusb_device->in_endpoint < 0) { free(libusb_device->location); free(libusb_device); return; } libusb_device->next = handle->devices; handle->devices = libusb_device; } void libusb_detach_devices(libusb_handle_t* handle) { libusb_device_t* next; while (handle->devices != NULL) { next = handle->devices->next; free(handle->devices->location); free(handle->devices); handle->devices = next; } } void libusb_rescan(libusb_handle_t* handle) { struct usb_bus *bus; struct usb_device *device; libusb_detach_devices(handle); usb_find_busses(); usb_find_devices(); handle->devices = NULL; bus = usb_busses; while (bus != NULL) { device = bus->devices; while (device != NULL) { libusb_attach_device(device, handle); device = device->next; } bus = bus->next; } } int libusb_get_changed_device_count(void) { usb_find_busses(); return usb_find_devices(); } libusb_device_t* libusb_get_devices(libusb_handle_t* handle) { return handle->devices; } int libusb_open(libusb_device_t* device) { int result; if (!device || !device->device) return -ENODEV; device->handle = usb_open(device->device); if (device->handle == NULL) { syslog(LOG_ERR, "libusbi: could not open device %s", device->location); return -ENODEV; } // Calling usb_set_configuration should not be necessary. // It is even considered harmful, since it may disturb other processes // which are currently communicating with the scanner! // // usb_set_configuration(device->handle, // usb_device(device->handle)->config[0].bConfigurationValue); result = usb_claim_interface(device->handle, device->interface); switch (result) { case 0: return 0; case -ENOMEM: syslog(LOG_ERR, "libusbi: could not claim interface for device %s. (ENOMEM)", device->location); usb_close(device->handle); return -ENODEV; case -EBUSY: syslog(LOG_ERR, "libusbi: could not claim interface for device %s. (EBUSY)", device->location); usb_close(device->handle); return -EBUSY; default: syslog(LOG_ERR, "libusbi: could not claim interface for device %s. (code=%d)", device->location, result); usb_close(device->handle); return -ENODEV; } } int libusb_close(libusb_device_t* device) { int result; result = usb_release_interface(device->handle, device->interface); if (result < 0) { syslog(LOG_ERR, "libusbi: could not release interface, error code=%d, device=%s", result, device->location); return result; } result = usb_close(device->handle); if (result < 0) { syslog(LOG_ERR, "libusbi: could not close usb device, error code=%d, device=%s", result, device->location); return result; } return 0; } int libusb_read(libusb_device_t* device, void* buffer, int bytecount) { int num_bytes = usb_bulk_read(device->handle, device->in_endpoint, buffer, bytecount, TIMEOUT); if (num_bytes<0) { usb_clear_halt(device->handle, device->in_endpoint); return 0; } return num_bytes; } int libusb_write(libusb_device_t* device, void* buffer, int bytecount) { int num_bytes = usb_bulk_write(device->handle, device->out_endpoint, buffer, bytecount, TIMEOUT); if (num_bytes<0) { usb_clear_halt(device->handle, device->in_endpoint); return 0; } return num_bytes; } void libusb_flush(libusb_device_t* device) { char buffer[16]; while (usb_bulk_read(device->handle, device->in_endpoint, buffer, 16, 500) > 0) {}; } int libusb_control_msg(libusb_device_t* device, int requesttype, int request, int value, int index, void* bytes, int size) { int num_bytes = usb_control_msg(device->handle, requesttype, request, value, index, bytes, size, TIMEOUT); if (num_bytes<0) { // Doesn't seem to be needed... (bs, Jun 07 2005) // usb_clear_halt(device->handle, device->in_endpoint); return 0; } return num_bytes; } void libusb_exit(libusb_handle_t* handle) { invocation_count--; if (invocation_count == 0) syslog(LOG_INFO, "libusbi: shutting down..."); libusb_detach_devices(handle); free(handle); }