Exemple #1
0
static int
gp_libusb1_find_first_altsetting(struct libusb_device *dev, int *config, int *interface, int *altsetting)
{
	int i, i1, i2;
	struct libusb_device_descriptor desc;

	if (LOG_ON_LIBUSB_E (libusb_get_device_descriptor (dev, &desc)))
		return -1;

	for (i = 0; i < desc.bNumConfigurations; i++) {
		struct libusb_config_descriptor *confdesc;

		if (LOG_ON_LIBUSB_E (libusb_get_config_descriptor (dev, i, &confdesc)))
			return -1;

		for (i1 = 0; i1 < confdesc->bNumInterfaces; i1++)
			for (i2 = 0; i2 < confdesc->interface[i1].num_altsetting; i2++)
				if (confdesc->interface[i1].altsetting[i2].bNumEndpoints) {
					*config = i;
					*interface = i1;
					*altsetting = i2;
					libusb_free_config_descriptor (confdesc);

					return 0;
				}
		libusb_free_config_descriptor (confdesc);
	}
	return -1;
}
Exemple #2
0
static int
gp_libusb1_check_int (GPPort *port, char *bytes, int size, int timeout)
{
	int 		ret;
	struct timeval	tv;

	C_PARAMS (port && port->pl->dh && timeout >= 0);

	if (port->pl->nrofirqs)
		goto handleirq;

	tv.tv_sec = timeout/1000;
	tv.tv_usec = (timeout%1000)*1000;

	ret = LOG_ON_LIBUSB_E (libusb_handle_events_timeout(port->pl->ctx, &tv));

	if (port->pl->nrofirqs)
		goto handleirq;

	if (ret < LIBUSB_SUCCESS)
		return translate_libusb_error(ret, GP_ERROR_IO_READ);

	return GP_ERROR_TIMEOUT;

handleirq:
	if (size > port->pl->irqlens[0])
		size = port->pl->irqlens[0];
	memcpy(bytes, port->pl->irqs[0], size);

	memmove(port->pl->irqs,port->pl->irqs+1,sizeof(port->pl->irqs[0])*(port->pl->nrofirqs-1));
	memmove(port->pl->irqlens,port->pl->irqlens+1,sizeof(port->pl->irqlens[0])*(port->pl->nrofirqs-1));
	port->pl->nrofirqs--;
        return size;
}
Exemple #3
0
static int
_close_async_interrupts(GPPort *port)
{
	int i, haveone;
	struct timeval tv;

	C_PARAMS (port);

	if (port->pl->dh == NULL)
		return GP_OK;

	/* Catch up on pending ones */
	tv.tv_sec = 0;
	tv.tv_usec = 1000;
	LOG_ON_LIBUSB_E (libusb_handle_events_timeout(port->pl->ctx, &tv));
	/* Now cancel and free the async transfers */
	for (i = 0; i < sizeof(port->pl->transfers)/sizeof(port->pl->transfers[0]); i++) {
		if (port->pl->transfers[i]) {
			GP_LOG_D("canceling transfer %d:%p (status %d)",i, port->pl->transfers[i], port->pl->transfers[i]->status);
			/* this happens if the transfer is completed for instance, but not reaped. we cannot cancel it. */
			if (LOG_ON_LIBUSB_E(libusb_cancel_transfer(port->pl->transfers[i])) < 0) {
				libusb_free_transfer (port->pl->transfers[i]);
				port->pl->transfers[i] = NULL;
			}
		}
	}
	tv.tv_sec = 0;
	tv.tv_usec = 0;
	LOG_ON_LIBUSB_E (libusb_handle_events_timeout(port->pl->ctx, &tv));
	/* Do just one round ... this should be sufficient and avoids endless loops. */
	haveone = 0;
	for (i = 0; i < sizeof(port->pl->transfers)/sizeof(port->pl->transfers[0]); i++) {
		if (port->pl->transfers[i]) {
			GP_LOG_D("checking: transfer %d:%p status %d",i, port->pl->transfers[i], port->pl->transfers[i]->status);
			haveone = 1;
		}
	}
	if (haveone)
		LOG_ON_LIBUSB_E (libusb_handle_events(port->pl->ctx));
	return GP_OK;
}
Exemple #4
0
static int
gp_libusb1_close (GPPort *port)
{
	C_PARAMS (port);

	if (port->pl->dh == NULL)
		return GP_OK;

	_close_async_interrupts(port);

	if (libusb_release_interface (port->pl->dh,
				   port->settings.usb.interface) < 0) {
		int saved_errno = errno;
		gp_port_set_error (port, _("Could not release interface %d (%s)."),
				   port->settings.usb.interface,
				   strerror(saved_errno));
		return GP_ERROR_IO;
	}

#if 0
	/* This confuses the EOS 5d camera and possible other EOSs. *sigh* */
	/* This is only for our very special Canon cameras which need a good
	 * whack after close, otherwise they get timeouts on reconnect.
	 */
	if (port->pl->d->descriptor.idVendor == 0x04a9) {
		if (usb_reset (port->pl->dh) < 0) {
			int saved_errno = errno;
			gp_port_set_error (port, _("Could not reset "
						   "USB port (%s)."),
					   strerror(saved_errno));
			return (GP_ERROR_IO);
		}
	}
#endif
	if (port->pl->detached) {
		if (LOG_ON_LIBUSB_E (libusb_attach_kernel_driver (port->pl->dh, port->settings.usb.interface)))
			gp_port_set_error (port, _("Could not reattach kernel driver of camera device."));
	}

	libusb_close (port->pl->dh);

	free (port->pl->irqs);
	port->pl->irqs = NULL;
	free (port->pl->irqlens);
	port->pl->irqlens = NULL;
	port->pl->nrofirqs = 0;
	port->pl->dh = NULL;
	return GP_OK;
}
Exemple #5
0
static int gp_libusb1_init (GPPort *port)
{
	C_MEM (port->pl = malloc (sizeof (GPPortPrivateLibrary)));
	memset (port->pl, 0, sizeof (GPPortPrivateLibrary));

	port->pl->config = port->pl->interface = port->pl->altsetting = -1;

	if (LOG_ON_LIBUSB_E (libusb_init (&port->pl->ctx))) {
		free (port->pl);
		port->pl = NULL;
		return GP_ERROR_IO;
	}
#if 0
	libusb_set_debug (port->pl->ctx, 255);
#endif
	return GP_OK;
}
Exemple #6
0
static int
gp_libusb1_queue_interrupt_urbs (GPPort *port)
{
	unsigned int i;

	for (i = 0; i < sizeof(port->pl->transfers)/sizeof(port->pl->transfers[0]); i++) {
		unsigned char *buf;
		port->pl->transfers[i] = libusb_alloc_transfer(0);

		buf = malloc(256); /* FIXME: safe size? */
		libusb_fill_interrupt_transfer(port->pl->transfers[i], port->pl->dh, port->settings.usb.intep,
			buf, 256, _cb_irq, port->pl, 0
		);
		port->pl->transfers[i]->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
		LOG_ON_LIBUSB_E(libusb_submit_transfer (port->pl->transfers[i]));
		
	}
	return GP_OK;
}
Exemple #7
0
static void LIBUSB_CALL
_cb_irq(struct libusb_transfer *transfer)
{
	struct _GPPortPrivateLibrary *pl = transfer->user_data;
	int i;

	GP_LOG_D("%p with status %d", transfer, transfer->status);

	if (	(transfer->status == LIBUSB_TRANSFER_CANCELLED) ||
		(transfer->status == LIBUSB_TRANSFER_TIMED_OUT) || /* on close */
		(transfer->status == LIBUSB_TRANSFER_NO_DEVICE) /* on removing camera */
	) {
		/* Only requeue the global transfers, not temporary ones */
		for (i = 0; i < sizeof(pl->transfers)/sizeof(pl->transfers[0]); i++) {
			if (pl->transfers[i] == transfer) {
				libusb_free_transfer (transfer);
				pl->transfers[i] = NULL;
				return;
			}
		}
		return;
	}

	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
		GP_LOG_D("transfer %p should be in LIBUSB_TRANSFER_COMPLETED, but is %d!", transfer, transfer->status);
		return;
	}
	if (transfer->actual_length) {
		GP_LOG_DATA ((char*)transfer->buffer, transfer->actual_length, "interrupt");

		pl->irqs 	= realloc(pl->irqs, sizeof(pl->irqs[0])*(pl->nrofirqs+1));
		pl->irqlens	= realloc(pl->irqlens, sizeof(pl->irqlens[0])*(pl->nrofirqs+1));

		pl->irqlens[pl->nrofirqs] = transfer->actual_length;
		pl->irqs[pl->nrofirqs] = malloc(transfer->actual_length);
		memcpy(pl->irqs[pl->nrofirqs],transfer->buffer,transfer->actual_length);
		pl->nrofirqs++;
	}

	GP_LOG_D("requeuing complete transfer %p", transfer);
	LOG_ON_LIBUSB_E(libusb_submit_transfer(transfer));
	return;
}
Exemple #8
0
static int gp_libusb1_init (GPPort *port)
{
	C_MEM (port->pl = malloc (sizeof (GPPortPrivateLibrary)));
	memset (port->pl, 0, sizeof (GPPortPrivateLibrary));

	port->pl->config = port->pl->interface = port->pl->altsetting = -1;

	if (LOG_ON_LIBUSB_E (libusb_init (&port->pl->ctx))) {
		free (port->pl);
		port->pl = NULL;
		return GP_ERROR_IO;
	}
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
	unlink("usblog.raw");
	port->pl->logfd = open("usblog.raw",O_CREAT|O_WRONLY,0644);
#endif
#if 0
	libusb_set_debug (port->pl->ctx, 255);
#endif
	return GP_OK;
}
Exemple #9
0
static int
gp_libusb1_find_ep(libusb_device *dev, int config, int interface, int altsetting, int direction, int type)
{
	const struct libusb_interface_descriptor *intf;
	struct libusb_config_descriptor *confdesc;
	int i;

	if (LOG_ON_LIBUSB_E (libusb_get_config_descriptor (dev, config, &confdesc)))
		return -1;

	intf = &confdesc->interface[interface].altsetting[altsetting];
	for (i = 0; i < intf->bNumEndpoints; i++) {
		if (((intf->endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == direction) &&
		    ((intf->endpoint[i].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == type)) {
			unsigned char ret;
			ret = intf->endpoint[i].bEndpointAddress; /* intf is cleared after next line, copy epaddr! */
			libusb_free_config_descriptor (confdesc);
			return ret;
		}
	}
	libusb_free_config_descriptor (confdesc);
	return -1;
}
Exemple #10
0
static ssize_t
load_devicelist (GPPortPrivateLibrary *pl) {
	time_t	xtime;

	time(&xtime);
	if (xtime != pl->devslastchecked) {
		if (pl->nrofdevs)
			libusb_free_device_list (pl->devs, 1);
		free (pl->descs);
		pl->nrofdevs = 0;
		pl->devs = NULL;
		pl->descs = NULL;
	}
	if (!pl->nrofdevs) {
		int 	i;

		pl->nrofdevs = libusb_get_device_list (pl->ctx, &pl->devs);
		C_MEM (pl->descs = calloc (pl->nrofdevs, sizeof(pl->descs[0])));
		for (i=0;i<pl->nrofdevs;i++)
			LOG_ON_LIBUSB_E (libusb_get_device_descriptor(pl->devs[i], &pl->descs[i]));
	}
	time (&pl->devslastchecked);
	return pl->nrofdevs;
}
Exemple #11
0
static int
gp_libusb1_find_path_lib(GPPort *port)
{
	char *s;
	int d, busnr = 0, devnr = 0;
	GPPortPrivateLibrary *pl;

	C_PARAMS (port);

	pl = port->pl;

	s = strchr (port->settings.usb.port,':');
	C_PARAMS (s && (s[1] != '\0'));
	C_PARAMS (sscanf (s+1, "%d,%d", &busnr, &devnr) == 2); /* usb:%d,%d */

	pl->nrofdevs = load_devicelist (port->pl);

	for (d = 0; d < pl->nrofdevs; d++) {
		struct libusb_config_descriptor *confdesc;
		int config = -1, interface = -1, altsetting = -1;

		if (busnr != libusb_get_bus_number (pl->devs[d]))
			continue;
		if (devnr != libusb_get_device_address (pl->devs[d]))
			continue;

		port->pl->d = pl->devs[d];

		GP_LOG_D ("Found path %s", port->settings.usb.port);

		/* Use the first config, interface and altsetting we find */
		gp_libusb1_find_first_altsetting(pl->devs[d], &config, &interface, &altsetting);

		if (LOG_ON_LIBUSB_E (libusb_get_config_descriptor (pl->devs[d], config, &confdesc)))
			continue;

		/* Set the defaults */
		port->settings.usb.config = confdesc->bConfigurationValue;
		port->settings.usb.interface = confdesc->interface[interface].altsetting[altsetting].bInterfaceNumber;
		port->settings.usb.altsetting = confdesc->interface[interface].altsetting[altsetting].bAlternateSetting;

		port->settings.usb.inep  = gp_libusb1_find_ep(pl->devs[d], config, interface, altsetting, LIBUSB_ENDPOINT_IN, LIBUSB_TRANSFER_TYPE_BULK);
		port->settings.usb.outep = gp_libusb1_find_ep(pl->devs[d], config, interface, altsetting, LIBUSB_ENDPOINT_OUT, LIBUSB_TRANSFER_TYPE_BULK);
		port->settings.usb.intep = gp_libusb1_find_ep(pl->devs[d], config, interface, altsetting, LIBUSB_ENDPOINT_IN, LIBUSB_TRANSFER_TYPE_INTERRUPT);

		port->settings.usb.maxpacketsize = libusb_get_max_packet_size (pl->devs[d], port->settings.usb.inep);
		GP_LOG_D ("Detected defaults: config %d, interface %d, altsetting %d, "
			"inep %02x, outep %02x, intep %02x, class %02x, subclass %02x",
			port->settings.usb.config,
			port->settings.usb.interface,
			port->settings.usb.altsetting,
			port->settings.usb.inep,
			port->settings.usb.outep,
			port->settings.usb.intep,
			confdesc->interface[interface].altsetting[altsetting].bInterfaceClass,
			confdesc->interface[interface].altsetting[altsetting].bInterfaceSubClass
			);
		libusb_free_config_descriptor (confdesc);
		return GP_OK;
	}
#if 0
	gp_port_set_error (port, _("Could not find USB device "
		"(vendor 0x%x, product 0x%x). Make sure this device "
		"is connected to the computer."), idvendor, idproduct);
#endif
	return GP_ERROR_IO_USB_FIND;
}
Exemple #12
0
/*
 * This function applys changes to the device.
 *
 * New settings are in port->settings_pending and the old ones
 * are in port->settings. Compare them first and only call
 * usb_set_configuration() and usb_set_altinterface() if needed
 * since some USB devices does not like it if this is done
 * more than necessary (Canon Digital IXUS 300 for one).
 *
 */
static int
gp_libusb1_update (GPPort *port)
{
	int ifacereleased = FALSE, changedone = FALSE;

	C_PARAMS (port && port->pl && port->pl->ctx);

	GP_LOG_D ("(old int=%d, conf=%d, alt=%d) port %s, (new int=%d, conf=%d, alt=%d) port %s",
		port->settings.usb.interface,
		port->settings.usb.config,
		port->settings.usb.altsetting,
		port->settings.usb.port,
		port->settings_pending.usb.interface,
		port->settings_pending.usb.config,
		port->settings_pending.usb.altsetting,
		port->settings_pending.usb.port
	);

/* do not overwrite it ... we need to set it.
	if (port->pl->interface == -1) port->pl->interface = port->settings.usb.interface;
	if (port->pl->config == -1) port->pl->config = port->settings.usb.config;
	if (port->pl->altsetting == -1) port->pl->altsetting = port->settings.usb.altsetting;
*/

	/* The portname can also be changed with the device still fully closed. */
	memcpy(&port->settings.usb.port, &port->settings_pending.usb.port,
		sizeof(port->settings.usb.port));

	if (!port->pl->dh) {
		GP_LOG_D("lowlevel libusb1 port not yet opened, no need for libusb changes");
		return GP_OK; /* the port might not be opened, yet. that is ok */
	}

	memcpy(&port->settings.usb, &port->settings_pending.usb,
		sizeof(port->settings.usb));

	/* The interface changed. release the old, claim the new ... */
	if (port->settings.usb.interface != port->pl->interface) {
		GP_LOG_D ("changing interface %d -> %d", port->pl->interface, port->settings.usb.interface);
		if (LOG_ON_LIBUSB_E (libusb_release_interface (port->pl->dh, port->pl->interface))) {
			/* Not a hard error for now. -Marcus */
		} else {
			GP_LOG_D ("claiming interface %d", port->settings.usb.interface);
			C_LIBUSB (libusb_claim_interface (port->pl->dh, port->settings.usb.interface),
				  GP_ERROR_IO_USB_CLAIM);
			port->pl->interface = port->settings.usb.interface;
		}
		changedone = TRUE;
	}
	if (port->settings.usb.config != port->pl->config) {
		GP_LOG_D ("changing config %d -> %d", port->pl->config, port->settings.usb.config);
		/* This can only be changed with the interface released. 
		 * This is a hard requirement since 2.6.12.
		 */
		if (LOG_ON_LIBUSB_E (libusb_release_interface (port->pl->dh, port->settings.usb.interface))) {
			ifacereleased = FALSE;
		} else {
			ifacereleased = TRUE;
		}
		if (LOG_ON_LIBUSB_E (libusb_set_configuration(port->pl->dh, port->settings.usb.config))) {
#if 0 /* setting the configuration failure is not fatal */
			int saved_errno = errno;
			gp_port_set_error (port,
					   _("Could not set config %d/%d (%s)"),
					   port->settings.usb.interface,
					   port->settings.usb.config,
					   strerror(saved_errno));
			return GP_ERROR_IO_UPDATE;	
#endif
			GP_LOG_E ("setting configuration from %d to %d failed, but continuing...", port->pl->config, port->settings.usb.config);
		}

		GP_LOG_D ("Changed usb.config from %d to %d", port->pl->config, port->settings.usb.config);

		if (ifacereleased) {
			GP_LOG_D ("claiming interface %d", port->settings.usb.interface);
			LOG_ON_LIBUSB_E (libusb_claim_interface (port->pl->dh, port->settings.usb.interface));
		}
		/*
		 * Copy at once if something else fails so that this
		 * does not get re-applied
		 */
		port->pl->config = port->settings.usb.config;
		changedone = TRUE;
	}

	/* This can be changed with interface claimed. (And I think it must be claimed.) */
	if (port->settings.usb.altsetting != port->pl->altsetting) {
		if (LOG_ON_LIBUSB_E (libusb_set_interface_alt_setting (port->pl->dh,
					port->settings.usb.interface, port->settings.usb.altsetting))) {
			int saved_errno = errno;
			gp_port_set_error (port,
					   _("Could not set altsetting from %d "
					     "to %d (%s)"),
					   port->pl->altsetting,
					   port->settings.usb.altsetting,
					   strerror(saved_errno));
			return GP_ERROR_IO_UPDATE;
		}

		GP_LOG_D ("Changed usb.altsetting from %d to %d", port->pl->altsetting, port->settings.usb.altsetting);
		port->pl->altsetting = port->settings.usb.altsetting;
		changedone = TRUE;
	}

	/* requeue the interrupts */
	if (changedone)
		gp_libusb1_queue_interrupt_urbs (port);
	return GP_OK;
}
Exemple #13
0
static int
gp_libusb1_open (GPPort *port)
{
	int ret;

	GP_LOG_D ("()");
	C_PARAMS (port);

	if (!port->pl->d) {
		gp_libusb1_find_path_lib(port);
		C_PARAMS (port->pl->d);
	}

	C_LIBUSB (libusb_open (port->pl->d, &port->pl->dh), GP_ERROR_IO);
	if (!port->pl->dh) {
		int saved_errno = errno;
		gp_port_set_error (port, _("Could not open USB device (%s)."),
				   strerror(saved_errno));
		return GP_ERROR_IO;
	}
	ret = libusb_kernel_driver_active (port->pl->dh, port->settings.usb.interface);

#if 0
	if (strstr(name,"usbfs") || strstr(name,"storage")) {
		/* other gphoto instance most likely */
		gp_port_set_error (port, _("Camera is already in use."));
		return GP_ERROR_IO_LOCK;
	}
#endif

	switch (ret) {
	case 1: GP_LOG_D ("Device has a kernel driver attached (%d), detaching it now.", ret);
		ret = libusb_detach_kernel_driver (port->pl->dh, port->settings.usb.interface);
		if (ret < 0)
			gp_port_set_error (port, _("Could not detach kernel driver of camera device."));
		else
			port->pl->detached = 1;
	case 0:	/* not detached */
		break;
	default:
		gp_port_set_error (port, _("Could not query kernel driver of device."));
		break;
	}

	GP_LOG_D ("claiming interface %d", port->settings.usb.interface);
	if (LOG_ON_LIBUSB_E (libusb_claim_interface (port->pl->dh, port->settings.usb.interface))) {
		int saved_errno = errno;
		gp_port_set_error (port, _("Could not claim interface %d (%s). "
					   "Make sure no other program (%s) "
					   "or kernel module (such as %s) "
					   "is using the device and you have "
					   "read/write access to the device."),
				   port->settings.usb.interface,
				   strerror(saved_errno),
#ifdef __linux__
				   "gvfs-gphoto2-volume-monitor",
#else
#if defined(__APPLE__)
				   _("MacOS PTPCamera service"),
#else
				   _("unknown libgphoto2 using program"),
#endif
#endif
				   "sdc2xx, stv680, spca50x");
		return GP_ERROR_IO_USB_CLAIM;
	}

	gp_libusb1_queue_interrupt_urbs (port);

	return GP_OK;
}
Exemple #14
0
int
gp_port_library_list (GPPortInfoList *list)
{
	GPPortInfo	info;
	int		nrofdevices = 0;
	int		d, i, i1, i2, unknownint;
	libusb_context	*ctx;
	libusb_device	**devs = NULL;
	int		nrofdevs = 0;
	struct libusb_device_descriptor	*descs;

	C_LIBUSB (libusb_init (&ctx), GP_ERROR_IO);

	/* TODO: make sure libusb_exit gets called in all error paths inside this function */

	/* generic matcher. This will catch passed XXX,YYY entries for instance. */
	C_GP (gp_port_info_new (&info));
	gp_port_info_set_type (info, GP_PORT_USB);
	gp_port_info_set_name (info, "");
	gp_port_info_set_path (info, "^usb:");
	C_GP (gp_port_info_list_append (list, info));

	nrofdevs = libusb_get_device_list (ctx, &devs);
	C_MEM (descs = calloc (nrofdevs, sizeof(descs[0])));
	for (i=0;i<nrofdevs;i++)
		LOG_ON_LIBUSB_E (libusb_get_device_descriptor(devs[i], &descs[i]));

	for (d = 0; d < nrofdevs; d++) {
		/* Devices which are definitely not cameras. */
		if (	(descs[d].bDeviceClass == LIBUSB_CLASS_HUB)		||
			(descs[d].bDeviceClass == LIBUSB_CLASS_HID)		||
			(descs[d].bDeviceClass == LIBUSB_CLASS_PRINTER)	||
			(descs[d].bDeviceClass == LIBUSB_CLASS_COMM)	||
			(descs[d].bDeviceClass == 0xe0)	/* wireless / bluetooth */
		)
			continue;
		/* excepts HUBs, usually the interfaces have the classes, not
		 * the device */
		unknownint = 0;
		for (i = 0; i < descs[d].bNumConfigurations; i++) {
			struct libusb_config_descriptor *config;

			if (LOG_ON_LIBUSB_E (libusb_get_config_descriptor (devs[d], i, &config))) {
				unknownint++;
				continue;
			}
			for (i1 = 0; i1 < config->bNumInterfaces; i1++)
				for (i2 = 0; i2 < config->interface[i1].num_altsetting; i2++) {
					const struct libusb_interface_descriptor *intf = &config->interface[i1].altsetting[i2]; 
					if (	(intf->bInterfaceClass == LIBUSB_CLASS_HID)	||
						(intf->bInterfaceClass == LIBUSB_CLASS_PRINTER)	||
						(intf->bInterfaceClass == LIBUSB_CLASS_COMM)	||
						(intf->bInterfaceClass == 0xe0)	/* wireless/bluetooth*/
					)
						continue;
					unknownint++;
				}
			libusb_free_config_descriptor (config);
		}
		/* when we find only hids, printer or comm ifaces  ... skip this */
		if (!unknownint)
			continue;
		/* Note: We do not skip USB storage. Some devices can support both,
		 * and the Ricoh erronously reports it.
		 */ 
		nrofdevices++;
	}

#if 0
	/* If we already added usb:, and have 0 or 1 devices we have nothing to do.
	 * This should be the standard use case.
	 */
	/* We never want to return just "usb:" ... also return "usb:XXX,YYY", and
	 * let upper layers filter out the usb: */
	if (nrofdevices <= 1) 
		return (GP_OK);
#endif

	/* Redo the same bus/device walk, but now add the ports with usb:x,y notation,
	 * so we can address all USB devices.
	 */
	for (d = 0; d < nrofdevs; d++) {
		char path[200];

		/* Devices which are definitely not cameras. */
		if (	(descs[d].bDeviceClass == LIBUSB_CLASS_HUB)		||
			(descs[d].bDeviceClass == LIBUSB_CLASS_HID)		||
			(descs[d].bDeviceClass == LIBUSB_CLASS_PRINTER)	||
			(descs[d].bDeviceClass == LIBUSB_CLASS_COMM)
		)
			continue;
		/* excepts HUBs, usually the interfaces have the classes, not
		 * the device */
		unknownint = 0;
		for (i = 0; i < descs[d].bNumConfigurations; i++) {
			struct libusb_config_descriptor *config;

			if (LOG_ON_LIBUSB_E (libusb_get_config_descriptor (devs[d], i, &config))) {
				unknownint++;
				continue;
			}
			for (i1 = 0; i1 < config->bNumInterfaces; i1++)
				for (i2 = 0; i2 < config->interface[i1].num_altsetting; i2++) {
					const struct libusb_interface_descriptor *intf = &config->interface[i1].altsetting[i2]; 
					if (	(intf->bInterfaceClass == LIBUSB_CLASS_HID)	||
						(intf->bInterfaceClass == LIBUSB_CLASS_PRINTER)	||
						(intf->bInterfaceClass == LIBUSB_CLASS_COMM))
						continue;
					unknownint++;
				}
			libusb_free_config_descriptor (config);
		}
		/* when we find only hids, printer or comm ifaces  ... skip this */
		if (!unknownint)
			continue;
		/* Note: We do not skip USB storage. Some devices can support both,
		 * and the Ricoh erronously reports it.
		 */ 
		C_GP (gp_port_info_new (&info));
		gp_port_info_set_type (info, GP_PORT_USB);
		gp_port_info_set_name (info, "Universal Serial Bus");
		snprintf (path,sizeof(path), "usb:%03d,%03d",
			libusb_get_bus_number (devs[d]),
			libusb_get_device_address (devs[d])
		);
		gp_port_info_set_path (info, path);
		C_GP (gp_port_info_list_append (list, info));
	}
	/* This will only be added if no other device was ever added.
	 * Users doing "usb:" usage will enter the regular expression matcher case. */
	if (nrofdevices == 0) {
		C_GP (gp_port_info_new (&info));
		gp_port_info_set_type (info, GP_PORT_USB);
		gp_port_info_set_name (info, "Universal Serial Bus");
		gp_port_info_set_path (info, "usb:");
		C_GP (gp_port_info_list_append (list, info));
	}
	libusb_free_device_list (devs, 1);
	libusb_exit (ctx); /* should free all stuff above */
	free (descs);
	return (GP_OK);
}
Exemple #15
0
static int
gp_libusb1_find_device_lib(GPPort *port, int idvendor, int idproduct)
{
	char *s;
	int d, busnr = 0, devnr = 0;
	GPPortPrivateLibrary *pl;

	C_PARAMS (port);

	pl = port->pl;

	s = strchr (port->settings.usb.port,':');
	if (s && (s[1] != '\0')) { /* usb:%d,%d */
		if (sscanf (s+1, "%d,%d", &busnr, &devnr) != 2) {
			devnr = 0;
			sscanf (s+1, "%d", &busnr);
		}
	}
	/*
	 * 0x0000 idvendor is not valid.
	 * 0x0000 idproduct is ok.
	 * Should the USB layer report that ? I don't know.
	 * Better to check here.
	 */
	if (!idvendor) {
		gp_port_set_error (port, _("The supplied vendor or product "
			"id (0x%x,0x%x) is not valid."), idvendor, idproduct);
		return GP_ERROR_BAD_PARAMETERS;
	}

	pl->nrofdevs = load_devicelist (port->pl);

	for (d = 0; d < pl->nrofdevs; d++) {
		struct libusb_config_descriptor *confdesc;
		int config = -1, interface = -1, altsetting = -1;

		if ((pl->descs[d].idVendor != idvendor) ||
		    (pl->descs[d].idProduct != idproduct))
			continue;

		if (busnr && (busnr != libusb_get_bus_number (pl->devs[d])))
			continue;
		if (devnr && (devnr != libusb_get_device_address (pl->devs[d])))
			continue;

		port->pl->d = pl->devs[d];

		GP_LOG_D ("Looking for USB device (vendor 0x%x, product 0x%x)... found.", idvendor, idproduct);

		/* Use the first config, interface and altsetting we find */
		gp_libusb1_find_first_altsetting(pl->devs[d], &config, &interface, &altsetting);

		if (LOG_ON_LIBUSB_E (libusb_get_config_descriptor (pl->devs[d], config, &confdesc)))
			continue;

		/* Set the defaults */
		if (confdesc->interface[interface].altsetting[altsetting].bInterfaceClass
		    == LIBUSB_CLASS_MASS_STORAGE) {
			GP_LOG_D ("USB device (vendor 0x%x, product 0x%x) is a mass"
				  " storage device, and might not function with gphoto2."
				  " Reference: %s", idvendor, idproduct, URL_USB_MASSSTORAGE);
		}
		port->settings.usb.config = confdesc->bConfigurationValue;
		port->settings.usb.interface = confdesc->interface[interface].altsetting[altsetting].bInterfaceNumber;
		port->settings.usb.altsetting = confdesc->interface[interface].altsetting[altsetting].bAlternateSetting;

		port->settings.usb.inep  = gp_libusb1_find_ep(pl->devs[d], config, interface, altsetting, LIBUSB_ENDPOINT_IN, LIBUSB_TRANSFER_TYPE_BULK);
		port->settings.usb.outep = gp_libusb1_find_ep(pl->devs[d], config, interface, altsetting, LIBUSB_ENDPOINT_OUT, LIBUSB_TRANSFER_TYPE_BULK);
		port->settings.usb.intep = gp_libusb1_find_ep(pl->devs[d], config, interface, altsetting, LIBUSB_ENDPOINT_IN, LIBUSB_TRANSFER_TYPE_INTERRUPT);

		port->settings.usb.maxpacketsize = libusb_get_max_packet_size (pl->devs[d], port->settings.usb.inep);
		GP_LOG_D ("Detected defaults: config %d, interface %d, altsetting %d, "
			  "inep %02x, outep %02x, intep %02x, class %02x, subclass %02x",
			port->settings.usb.config,
			port->settings.usb.interface,
			port->settings.usb.altsetting,
			port->settings.usb.inep,
			port->settings.usb.outep,
			port->settings.usb.intep,
			confdesc->interface[interface].altsetting[altsetting].bInterfaceClass,
			confdesc->interface[interface].altsetting[altsetting].bInterfaceSubClass
			);
		libusb_free_config_descriptor (confdesc);
		return GP_OK;
	}
#if 0
	gp_port_set_error (port, _("Could not find USB device "
		"(vendor 0x%x, product 0x%x). Make sure this device "
		"is connected to the computer."), idvendor, idproduct);
#endif
	return GP_ERROR_IO_USB_FIND;
}