mirror of
https://git.planet-casio.com/Lephenixnoir/fxsdk.git
synced 2024-12-28 20:43:37 +01:00
159 lines
3.5 KiB
C
159 lines
3.5 KiB
C
#include "usb.h"
|
|
#include "fxlink.h"
|
|
#include "util.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
char const *usb_id(libusb_device *dev)
|
|
{
|
|
static char id[32];
|
|
sprintf(id, "%d:%d",
|
|
libusb_get_bus_number(dev),
|
|
libusb_get_device_address(dev));
|
|
return id;
|
|
}
|
|
|
|
char *usb_serial_number(libusb_device_handle *dh)
|
|
{
|
|
struct libusb_device_descriptor dc;
|
|
libusb_device *dev = libusb_get_device(dh);
|
|
|
|
if(libusb_get_device_descriptor(dev, &dc))
|
|
return NULL;
|
|
if(!dc.iSerialNumber)
|
|
return NULL;
|
|
|
|
char serial[256];
|
|
int length = libusb_get_string_descriptor_ascii(dh, dc.iSerialNumber,
|
|
(unsigned char *)serial, 256);
|
|
if(length < 0)
|
|
return NULL;
|
|
|
|
/* LINK sends a 12-byte serial number with four leading 0. Remove them */
|
|
int start = (length == 12 && !strncmp(serial, "0000", 4)) ? 4 : 0;
|
|
return strndup(serial + start, length - start);
|
|
}
|
|
|
|
properties_t usb_properties(struct libusb_device_descriptor *dc,
|
|
libusb_device_handle *dh)
|
|
{
|
|
properties_t props = { 0 };
|
|
|
|
/* Type of calculator based on USB behavior, detected by idProduct */
|
|
if(dc->idProduct == 0x6101)
|
|
props.p7 = true;
|
|
if(dc->idProduct == 0x6102)
|
|
props.mass_storage = true;
|
|
if(dh)
|
|
props.serial_number = usb_serial_number(dh);
|
|
|
|
return props;
|
|
}
|
|
|
|
int usb_unique_matching(filter_t const *filter, libusb_context *context,
|
|
libusb_device **dev)
|
|
{
|
|
libusb_device *unique = NULL;
|
|
int status = FILTER_NONE;
|
|
bool error;
|
|
|
|
for_libusb_devices(it, context, &error) {
|
|
if(!filter_match(&it.props, filter)) continue;
|
|
|
|
/* Already found a device before */
|
|
if(unique) {
|
|
status = FILTER_MULTIPLE;
|
|
libusb_unref_device(unique);
|
|
unique = NULL;
|
|
break;
|
|
}
|
|
|
|
/* First device: record it */
|
|
unique = libusb_ref_device(it.dev);
|
|
status = FILTER_UNIQUE;
|
|
}
|
|
if(error)
|
|
return FILTER_ERROR;
|
|
|
|
/* Don't keep the reference to the device if we're not returning it */
|
|
if(unique && !dev)
|
|
libusb_unref_device(unique);
|
|
if(unique && dev)
|
|
*dev = unique;
|
|
|
|
return status;
|
|
}
|
|
|
|
int usb_unique_wait(filter_t const *filter, delay_t *delay,
|
|
libusb_context *context, libusb_device **dev)
|
|
{
|
|
while(true) {
|
|
int rc = usb_unique_matching(filter, context, dev);
|
|
|
|
/* If a device is found, multiple devices are found, or an error
|
|
occurs, forward the result; wait only if nothing was found */
|
|
if(rc != FILTER_NONE) return rc;
|
|
if(delay_cycle(delay)) return FILTER_NONE;
|
|
}
|
|
}
|
|
|
|
//---
|
|
// Iteration on libusb devices
|
|
//---
|
|
|
|
usb_iterator_t usb_iter_start(libusb_context *context, bool *error)
|
|
{
|
|
usb_iterator_t it = { 0 };
|
|
|
|
it.device_count = libusb_get_device_list(context, &it.devices);
|
|
if(it.device_count < 0) {
|
|
libusb_err(it.device_count, "cannot get libusb device list");
|
|
it.done = true;
|
|
if(error) *error = true;
|
|
return it;
|
|
}
|
|
|
|
it.index = -1;
|
|
usb_iter_next(&it);
|
|
if(error) *error = false;
|
|
return it;
|
|
}
|
|
|
|
void usb_iter_next(usb_iterator_t *it)
|
|
{
|
|
if(it->done == true) return;
|
|
int rc;
|
|
|
|
/* Free the resources from the previous iteration */
|
|
if(it->dh)
|
|
libusb_close(it->dh);
|
|
it->dev = NULL;
|
|
it->dh = NULL;
|
|
|
|
/* Load the next device */
|
|
if(++it->index >= it->device_count) {
|
|
it->done = true;
|
|
}
|
|
else {
|
|
it->dev = it->devices[it->index];
|
|
|
|
if((rc = libusb_get_device_descriptor(it->dev, &it->dc))) {
|
|
libusb_err(rc, "cannot get descriptor for device %s",
|
|
usb_id(it->dev));
|
|
return usb_iter_next(it);
|
|
}
|
|
|
|
/* Ignore non-CASIO devices */
|
|
if(it->dc.idVendor != 0x07cf)
|
|
return usb_iter_next(it);
|
|
|
|
if((rc = libusb_open(it->dev, &it->dh)))
|
|
libusb_wrn(rc, "cannot open device %s", usb_id(it->dev));
|
|
|
|
it->props = usb_properties(&it->dc, it->dh);
|
|
}
|
|
|
|
if(it->done)
|
|
libusb_free_device_list(it->devices, true);
|
|
}
|