static int gp_libusb1_clear_halt_lib(GPPort *port, int ep) { unsigned char internal_ep; C_PARAMS (port && port->pl->dh); switch (ep) { case GP_PORT_USB_ENDPOINT_IN : internal_ep = port->settings.usb.inep; break; case GP_PORT_USB_ENDPOINT_OUT : internal_ep = port->settings.usb.outep; break; case GP_PORT_USB_ENDPOINT_INT : internal_ep = port->settings.usb.intep; break; default: gp_port_set_error (port, "bad EndPoint argument 0x%x", ep); return GP_ERROR_BAD_PARAMETERS; } C_LIBUSB (libusb_clear_halt(port->pl->dh, internal_ep), GP_ERROR_IO_USB_CLEAR_HALT); return GP_OK; }
static int gp_libusb1_msg(GPPort *port, int request, int value, int index, char *bytes, int size, int flags, int default_error) { int handled = 0; C_PARAMS (port && port->pl->dh); C_LIBUSB (handled = libusb_control_transfer (port->pl->dh, flags, request, value, index, (unsigned char*)bytes, size, port->timeout), default_error); return handled; }
static int gp_libusb1_reset(GPPort *port) { C_PARAMS (port && port->pl->dh); /* earlier libusb 1 versions get crashes otherwise */ _close_async_interrupts(port); C_LIBUSB (libusb_reset_device (port->pl->dh), GP_ERROR_IO); return GP_OK; }
static int gp_libusb1_read(GPPort *port, char *bytes, int size) { int curread; C_PARAMS (port && port->pl->dh); C_LIBUSB (libusb_bulk_transfer (port->pl->dh, port->settings.usb.inep, (unsigned char*)bytes, size, &curread, port->timeout), GP_ERROR_IO_READ ); return curread; }
static int gp_libusb1_write (GPPort *port, const char *bytes, int size) { int curwritten; C_PARAMS (port && port->pl->dh); C_LIBUSB (libusb_bulk_transfer (port->pl->dh, port->settings.usb.outep, (unsigned char*)bytes, size, &curwritten, port->timeout), GP_ERROR_IO_WRITE); return curwritten; }
static int gp_libusb1_read(GPPort *port, char *bytes, int size) { int curread; C_PARAMS (port && port->pl->dh); C_LIBUSB (libusb_bulk_transfer (port->pl->dh, port->settings.usb.inep, (unsigned char*)bytes, size, &curread, port->timeout), GP_ERROR_IO_READ ); #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION write(port->pl->logfd, bytes, curread); #endif return curread; }
/* * 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; }
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; }
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); }