Rev 10 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "ArcusPerformaxDriver.h"
#ifdef DEBUGARCUS
#include <stdio.h>
#endif // DEBUGARCUS
//
// I'm not thrilled with the use of these globals, but it seems required to support
// the existing fnPerformax function prototypes...
//
struct libusb_context * usb_context = 0;
AR_DWORD libusb_ReadTimeout = 0;
AR_DWORD libusb_WriteTimeout = 0;
#define AR_FALSE 0
#define AR_TRUE 1
// Internal function to allow us to keep a single list of
// vendor/product codes that are compatible with this driver
int _is_performax_device_by_vendor_product(int vendor, int product) {
if ((vendor == 0x1589) && (product == 0xa101) ) {
return AR_TRUE;
}
return AR_FALSE;
}
// Internal function to figure out if the libusb_device_descriptor is a performax device
int _is_performax_device(struct libusb_device_descriptor *descriptor) {
return _is_performax_device_by_vendor_product(descriptor->idVendor, descriptor->idProduct);
}
// Iterate through the list of usb devices present and count the number of
// devices that we could use (based on returning true to _is_performax_device)
AR_BOOL fnPerformaxComGetNumDevices(AR_DWORD *numDevices) {
ssize_t device_count, i;
libusb_device **list;
struct libusb_device_descriptor descriptor;
if (!InitializePerformaxLibrary()) {
return AR_FALSE;
}
*numDevices = 0;
device_count = libusb_get_device_list(usb_context, &list);
for (i = 0; i < device_count; i++) {
if (0 == libusb_get_device_descriptor(list[i], &descriptor)) {
if ( _is_performax_device(&descriptor) ) {
(*numDevices) ++ ;
}
}
}
libusb_free_device_list(list, 1); // Unreference and remove items from the list
return AR_TRUE;
}
// Internal function
// Return a libusb_device_descriptor for the device given by the dwNumDevice offset.
// On success, the offset number in the libusb_device list is returned.
// On error, -1 is returned.
int _get_libusb_device_offset_from_arcos_offset(libusb_device **list, ssize_t list_count,
struct libusb_device_descriptor *descriptor, AR_DWORD dwNumDevice) {
int i;
for (i = 0; i < list_count; i++) {
// iterate through each device and find a perfmax device:
if (0 == libusb_get_device_descriptor(list[i], descriptor)) {
if ( _is_performax_device(descriptor) ) {
if (dwNumDevice) {
// skip to the perfmax device offset in dwNumDevice
dwNumDevice--;
} else { // This is the one we're interested in...
return i;
}
}
}
}
return -1; // Couldn't find the offset requested...
}
AR_BOOL fnPerformaxComGetProductString(AR_DWORD dwNumDevice, AR_VOID *lpDeviceString, AR_DWORD dwOptions) {
ssize_t device_count, i;
libusb_device **list;
struct libusb_device_descriptor descriptor;
AR_BOOL result;
libusb_device_handle *device_handle;
if (!InitializePerformaxLibrary()) {
return AR_FALSE;
}
result = AR_TRUE; // no error yet...
// Get the list of all devices:
device_count = libusb_get_device_list(usb_context, &list);
i = _get_libusb_device_offset_from_arcos_offset(list, device_count, &descriptor, dwNumDevice);
if (i<0) {
result = AR_FALSE; // invlaid dwNumDevice id; we should have found the offset above...
} else {
if (libusb_open(list[i], &device_handle) != 0 ) {
result = AR_FALSE; // libusb_open error
} else {
if (dwOptions == PERFORMAX_RETURN_SERIAL_NUMBER) {
if (0 > libusb_get_string_descriptor_ascii(
device_handle, descriptor.iSerialNumber, lpDeviceString, PERFORMAX_MAX_DEVICE_STRLEN)) {
result = AR_FALSE; // invalid descriptor
}
} else if (dwOptions == PERFORMAX_RETURN_DESCRIPTION) {
if (0 > libusb_get_string_descriptor_ascii(
device_handle, descriptor.iProduct, lpDeviceString, PERFORMAX_MAX_DEVICE_STRLEN)) {
result = AR_FALSE; // invalid descriptor
}
} else {
result = AR_FALSE; // invlaid dwOption
}
libusb_close(device_handle);
}
}
libusb_free_device_list(list, 1); // Unreference and remove items from the list
return result;
}
int _send_urb_control(AR_HANDLE device_handle, int id) {
return libusb_control_transfer(device_handle,
0x40, // bmRequestType
0x02, // bRequest,
id, // wValue,
0x00, // wIndex,
NULL, // data,
0, // wLength,
libusb_WriteTimeout);
}
AR_BOOL fnPerformaxComOpen(AR_DWORD dwDeviceNum, AR_HANDLE *device_handle) {
ssize_t device_count, i;
libusb_device **list;
struct libusb_device_descriptor descriptor;
AR_BOOL result;
if (!InitializePerformaxLibrary()) {
return AR_FALSE;
}
result = AR_TRUE; // no error yet...
// Get the list of all devices:
device_count = libusb_get_device_list(usb_context, &list);
i = _get_libusb_device_offset_from_arcos_offset(list, device_count, &descriptor, dwDeviceNum);
if (i<0) {
result = AR_FALSE; // invlaid dwNumDevice id; we should have found the offset above...
} else {
if (0 != libusb_open(list[i], device_handle) ) {
result = AR_FALSE; // libusb_open error
}
if (0 != libusb_claim_interface(*device_handle, 0) ) {
result = AR_FALSE; // libusb_open error
}
}
libusb_free_device_list(list, 1); // Unreference and remove items from the list
_send_urb_control(*device_handle, 0x02); // Should document this better; it's some open command
return result;
}
AR_BOOL fnPerformaxComClose(AR_HANDLE device_handle) {
AR_BOOL result;
if (!InitializePerformaxLibrary()) {
return AR_FALSE;
}
_send_urb_control(device_handle, 0x04); // Should document this better; it's some close command
result = AR_TRUE; // no error yet...
if (0 != libusb_release_interface(device_handle, 0) ) {
result = AR_FALSE; // libusb_open error
}
libusb_close(device_handle);
return result;
}
AR_BOOL fnPerformaxComSetTimeouts(AR_DWORD dwReadTimeout, AR_DWORD dwWriteTimeout) {
if (!InitializePerformaxLibrary()) {
return AR_FALSE;
}
libusb_ReadTimeout = dwReadTimeout;
libusb_WriteTimeout = dwWriteTimeout;
return AR_TRUE; // TODO: errors for wacky times?
}
AR_BOOL fnPerformaxComSendRecv(AR_HANDLE device_handle, AR_VOID *wBuffer, AR_DWORD dwNumBytesToWrite, AR_DWORD dwNumBytesToRead, AR_VOID *rBuffer) {
if (!InitializePerformaxLibrary()) {
return AR_FALSE;
}
int transferred;
int result;
unsigned char buffer[4096];
// clear any outstanding reads:
result = libusb_bulk_transfer(device_handle, 0x82, buffer, sizeof(buffer), &transferred, libusb_ReadTimeout);
// if the above fails, it's probably ok. We probably don't care.
result = libusb_bulk_transfer(device_handle, 0x02, wBuffer, dwNumBytesToWrite, &transferred, libusb_WriteTimeout);
#ifdef DEBUGARCUS
printf("sent: %d (%d) result %d '%s'\n", transferred, (int)dwNumBytesToWrite, result, (char *)wBuffer);
#endif // DEBUGARCUS
if (0 != result) {
return AR_FALSE;
}
result = libusb_bulk_transfer(device_handle, 0x82, rBuffer, dwNumBytesToRead, &transferred, libusb_ReadTimeout);
#ifdef DEBUGARCUS
printf("received: %d (%d) result %d - %s\n", transferred, (int)dwNumBytesToRead, result, (char *)rBuffer);
#endif // DEBUGARCUS
if (0 != result) {
return AR_FALSE;
}
return AR_TRUE;
}
AR_BOOL fnPerformaxComFlush(AR_HANDLE device_handle) {
if (!InitializePerformaxLibrary()) {
return AR_FALSE;
}
if (_send_urb_control(device_handle, 0x01) == 0) { // Should document this better; it's some flush command
return AR_TRUE;
}
return AR_FALSE;
}
//the following does _not_ need to be called before using the other functions. It is safe to ignore its existence
// Since the original interface contained the above line, all functions call the initialization function
// below. Since we have no context being passed inthe fnPerformax functions, we don't get the opportunity
// anywhere to properly close the libusb library with libusb_exit...
AR_BOOL InitializePerformaxLibrary() {
if (usb_context) {
return AR_TRUE;
}
if (!libusb_init(&usb_context)) {
return AR_TRUE;
}
return AR_FALSE;
}