#include "mini_libusb.h" #define SYSFS_MOUNT_PATH "/sys" #define SYSFS_DEVICE_PATH SYSFS_MOUNT_PATH "/bus/usb/devices" struct setup_data { uint8_t bRequestType; uint8_t bRequest; uint16_t wValue; uint16_t wIndex; uint16_t wLength; uint8_t data[]; }; int usb_get_att(uint16_t *val, char *d_name, char *attr, int base) { int ret = -1; char filepath[256]; char attr_buf[20]; int attr_fd; snprintf(filepath, sizeof(filepath), SYSFS_DEVICE_PATH "/%s/%s", d_name, attr); attr_fd = open(filepath, O_RDONLY); if (attr_fd < 0) { DEBUG_MSG( "Usb %s: %s attribute not found.\n", d_name, attr ); goto exit; } if ( !read(attr_fd, attr_buf, sizeof(attr_buf)) ) { DEBUG_MSG( "Usb %s: couldn't read %s.\n", d_name, attr ); goto exit; } *val = (uint16_t) strtol(attr_buf, NULL, base); ret = 0; exit: close(attr_fd); return ret; } int usb_find_path_by_vid_pid( char *path, uint16_t vid, uint16_t pid ) { int ret = -1; uint16_t d_vid, d_pid, d_bus, d_num; DIR *devices = opendir( SYSFS_DEVICE_PATH ); struct dirent *entry; if ( !devices ) { fprintf( stderr, "Critical Error: Sysfs not avaiable." ); return 1; } while ( ( entry = readdir( devices ) ) ) { if ( !isdigit( entry->d_name[0] ) || strchr( entry->d_name, ':' ) ) continue; if ( !usb_get_att( &d_vid, entry->d_name, "idVendor", 16 ) && ( vid == d_vid ) && !usb_get_att( &d_pid, entry->d_name, "idProduct", 16 ) && ( pid == d_pid ) && !usb_get_att( &d_bus, entry->d_name, "busnum", 10 ) && !usb_get_att( &d_num, entry->d_name, "devnum", 10 ) ) { sprintf( path, "/dev/bus/usb/%03d/%03d", d_bus, d_num ); ret = 0; break; } } closedir( devices ); return ret; } int usb_open_by_vid_pid( uint16_t vid, uint16_t pid, uint8_t wait ) { int ret; char path[256]; do { ret = usb_find_path_by_vid_pid( path, vid, pid ); usleep( 500 ); } while ( wait && ( ret < 0 ) ); DEBUG_MSG( "USB Path: %s\n", path ); if (ret) { return -1; } return open( path, O_RDWR ); } int usb_close( int usb ) { return usb; } int usb_send_control_txn( int usb, uint8_t bRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t len, uint8_t *data, int32_t timeout ) { int ret = -1; size_t setup_len = sizeof ( struct setup_data ) + len; struct setup_data *setup_data_buf; setup_data_buf = malloc( setup_len ); memset( setup_data_buf, 0, setup_len ); setup_data_buf->bRequestType = bRequestType; setup_data_buf->bRequest = bRequest; setup_data_buf->wValue = wValue; setup_data_buf->wIndex = wIndex; setup_data_buf->wLength = len; struct usbdevfs_urb usb_control_urb; memset(&usb_control_urb, 0, sizeof (usb_control_urb)); usb_control_urb.type = USBDEVFS_URB_TYPE_CONTROL; usb_control_urb.endpoint = 0x0; usb_control_urb.buffer = setup_data_buf; usb_control_urb.buffer_length = setup_len; ioctl( usb, USBDEVFS_SUBMITURB, &usb_control_urb ); struct usbdevfs_urb *urb_reaped = NULL; if ( timeout ) { while ( timeout > 0 ) { int _ret = ioctl( usb, USBDEVFS_REAPURBNDELAY, &urb_reaped ); if ( _ret == 0 ) { break; } usleep(200000); timeout -= 200; } } else { ioctl( usb, USBDEVFS_REAPURB, &urb_reaped ); } if ( urb_reaped && urb_reaped->status == 0 ) { ret = 0; memcpy( data, setup_data_buf->data, len ); } if ( setup_data_buf ) free( setup_data_buf ); return ret; } int usb_send_bulk_txn( int usb, uint32_t ep, uint32_t len, void *data ) { struct usbdevfs_bulktransfer bulk_txn; memset( &bulk_txn, 0, sizeof ( bulk_txn ) ); bulk_txn.ep = ep; bulk_txn.len = len; bulk_txn.timeout = USB_BULK_TIMEOUT; bulk_txn.data = data; if ( ioctl( usb, USBDEVFS_BULK, &bulk_txn ) == len ) return 0; return -1; }