diff --git a/gphoto2/gphoto2-abilities-list.h b/gphoto2/gphoto2-abilities-list.h index 1c7db131f..ac17dd386 100644 --- a/gphoto2/gphoto2-abilities-list.h +++ b/gphoto2/gphoto2-abilities-list.h @@ -198,6 +198,7 @@ int gp_init_localedir (const char *localedir); */ #ifdef _GPHOTO2_INTERNAL_CODE #define CAMLIBDIR_ENV "CAMLIBS" +#define CAMLIBDIR_PREFIX_ENV "CAMLIBS_PREFIX" #endif /* _GPHOTO2_INTERNAL_CODE */ diff --git a/libgphoto2/gphoto2-abilities-list.c b/libgphoto2/gphoto2-abilities-list.c index 7db617aed..1ed196d87 100644 --- a/libgphoto2/gphoto2-abilities-list.c +++ b/libgphoto2/gphoto2-abilities-list.c @@ -179,8 +179,13 @@ foreach_func (const char *filename, lt_ptr data) { foreach_data_t *fd = data; CameraList *list = fd->list; + char *prefix = getenv(CAMLIBDIR_PREFIX_ENV); GP_LOG_D ("Found '%s'.", filename); + if(prefix && !strstr(filename,prefix)) { + GP_LOG_D("Skipping camlib filename '%s' not matching %s.",filename,prefix); + return (0); + } fd->result = gp_list_append (list, filename, NULL); return ((fd->result == GP_OK)?0:1); @@ -312,6 +317,7 @@ unlocked_gp_abilities_list_load_dir (CameraAbilitiesList *list, const char *dir, return GP_ERROR_CANCEL; } } + gp_context_progress_stop (context, p); lt_dlexit (); gp_list_free (flist); diff --git a/libgphoto2_port/configure.ac b/libgphoto2_port/configure.ac index 2b52a093d..ef57b2795 100644 --- a/libgphoto2_port/configure.ac +++ b/libgphoto2_port/configure.ac @@ -384,6 +384,10 @@ GP_CHECK_LIBRARY([LIBUSB1],[libusb-1.0],[>= 1.0.0], AC_DEFINE([HAVE_LIBUSB_STRERROR], [1], [Define if libusb-1.0 has libusb_strerror]) ]) + AC_CHECK_FUNC([libusb_wrap_sys_device], [dnl + AC_DEFINE([HAVE_LIBUSB_WRAP_SYS_DEVICE], [1], + [Define if libusb-1.0 has libusb_wrap_sys_device]) + ]) LIBS="$save_LIBS" ], [], [default-on], diff --git a/libgphoto2_port/gphoto2/gphoto2-port-info-list.h b/libgphoto2_port/gphoto2/gphoto2-port-info-list.h index 53f9ef39d..77ebd29fe 100644 --- a/libgphoto2_port/gphoto2/gphoto2-port-info-list.h +++ b/libgphoto2_port/gphoto2/gphoto2-port-info-list.h @@ -106,6 +106,7 @@ int gp_port_init_localedir (const char *localedir); */ #ifdef _GPHOTO2_INTERNAL_CODE #define IOLIBDIR_ENV "IOLIBS" +#define IOLIBDIR_PREFIX_ENV "IOLIBS_PREFIX" #endif /* _GPHOTO2_INTERNAL_CODE */ diff --git a/libgphoto2_port/gphoto2/gphoto2-port.h b/libgphoto2_port/gphoto2/gphoto2-port.h index 6e734ea33..d23a1fc4f 100644 --- a/libgphoto2_port/gphoto2/gphoto2-port.h +++ b/libgphoto2_port/gphoto2/gphoto2-port.h @@ -202,6 +202,21 @@ int gp_port_set_pin (GPPort *port, GPPin pin, GPLevel level); int gp_port_send_break (GPPort *port, int duration); int gp_port_flush (GPPort *port, int direction); +/** + * \brief Allow using file descriptor of USB device without auto-discovery + * + * This is required for access of USB on android since applications don't have direct + * access to USB device + * + * It must be called prior to library initialization + */ +int gp_port_usb_set_sys_device(int fd); + +/** + * \brief Get externally set file descriptor of USB device, return -1 if not set + */ +int gp_port_usb_get_sys_device(void); + int gp_port_usb_find_device (GPPort *port, int idvendor, int idproduct); int gp_port_usb_find_device_by_class (GPPort *port, int mainclass, int subclass, int protocol); int gp_port_usb_clear_halt (GPPort *port, int ep); diff --git a/libgphoto2_port/libgphoto2_port/gphoto2-port-info-list.c b/libgphoto2_port/libgphoto2_port/gphoto2-port-info-list.c index 4f547770e..da418f509 100644 --- a/libgphoto2_port/libgphoto2_port/gphoto2-port-info-list.c +++ b/libgphoto2_port/libgphoto2_port/gphoto2-port-info-list.c @@ -238,8 +238,13 @@ foreach_func (const char *filename, lt_ptr data) GPPortType type; unsigned int j, old_size = list->count; int result; + char *prefix = getenv(IOLIBDIR_PREFIX_ENV); GP_LOG_D ("Called for filename '%s'.", filename ); + if(prefix && !strstr(filename,prefix)) { + GP_LOG_D("Skipping filename '%s' not matching %s.",filename,prefix); + return (0); + } lh = lt_dlopenext (filename); if (!lh) { diff --git a/libgphoto2_port/libgphoto2_port/gphoto2-port.c b/libgphoto2_port/libgphoto2_port/gphoto2-port.c index dc8871b58..84a4a543b 100644 --- a/libgphoto2_port/libgphoto2_port/gphoto2-port.c +++ b/libgphoto2_port/libgphoto2_port/gphoto2-port.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "libgphoto2_port/gphoto2-port-info.h" @@ -1214,3 +1215,37 @@ gp_port_get_error (GPPort *port) return _("No error description available"); } + + +#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE + +static int gp_port_usb_fd = -1; + +int +gp_port_usb_set_sys_device(int fd) +{ + gp_port_usb_fd = fd; + return (GP_OK); +} + +int +gp_port_usb_get_sys_device(void) +{ + return gp_port_usb_fd; +} +#else +int gp_port_usb_set_sys_device(int fd) +{ + return GP_ERROR_NOT_SUPPORTED; +} + +int gp_port_usb_get_sys_device() +{ + return -1; +} +#endif + + + + + diff --git a/libgphoto2_port/libgphoto2_port/libgphoto2_port.ver b/libgphoto2_port/libgphoto2_port/libgphoto2_port.ver index 651c7609a..afceca453 100644 --- a/libgphoto2_port/libgphoto2_port/libgphoto2_port.ver +++ b/libgphoto2_port/libgphoto2_port/libgphoto2_port.ver @@ -48,6 +48,8 @@ LIBGPHOTO2_5_0 { gp_port_timeout_get; gp_port_timeout_set; gp_port_usb_clear_halt; + gp_port_usb_set_sys_device; + gp_port_usb_get_sys_device; gp_port_usb_find_device; gp_port_usb_find_device_by_class; gp_port_usb_msg_class_read; diff --git a/libgphoto2_port/libusb1/libusb1.c b/libgphoto2_port/libusb1/libusb1.c index c3a5fe5cb..5d19d5add 100644 --- a/libgphoto2_port/libusb1/libusb1.c +++ b/libgphoto2_port/libusb1/libusb1.c @@ -116,6 +116,33 @@ struct _PrivateIrqCompleted { /* FIXME: safe size? */ #define INTERRUPT_BUFFER_SIZE 256 +#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE +static struct _GPPortExternalSysDevice { + /* some more may be used in future */ + libusb_device_handle *h; + libusb_device *d; + libusb_context *ctx; + libusb_device *dl[1]; +} external_sys_device = { NULL, NULL, NULL, { NULL } }; + +static int has_external_fd() +{ + if(gp_port_usb_get_sys_device() == -1) + return 0; + if(external_sys_device.h) + return 1; + libusb_set_option(NULL,LIBUSB_OPTION_NO_DEVICE_DISCOVERY,NULL); + C_LIBUSB (libusb_init (&external_sys_device.ctx), GP_ERROR_IO); + LOG_ON_LIBUSB_E(libusb_wrap_sys_device(external_sys_device.ctx,gp_port_usb_get_sys_device(),&external_sys_device.h)); + external_sys_device.d = libusb_get_device(external_sys_device.h); + external_sys_device.dl[0] = external_sys_device.d; + return 1; +} + + +#endif + + struct _GPPortPrivateLibrary { libusb_context *ctx; libusb_device *d; @@ -155,6 +182,10 @@ load_devicelist (GPPortPrivateLibrary *pl) { time_t xtime; time(&xtime); +#if HAVE_LIBUSB_WRAP_SYS_DEVICE + if(!has_external_fd()) /* when external device present no need to research for Android */ +#endif + { if (xtime != pl->devslastchecked) { if (pl->nrofdevs) libusb_free_device_list (pl->devs, 1); @@ -163,6 +194,16 @@ load_devicelist (GPPortPrivateLibrary *pl) { pl->devs = NULL; pl->descs = NULL; } + } + + #ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE + if(has_external_fd()) { + pl->nrofdevs = 1; + pl->devs = external_sys_device.dl; + C_MEM (pl->descs = calloc (1, sizeof(pl->descs[0]))); + LOG_ON_LIBUSB_E (libusb_get_device_descriptor(pl->devs[0], &pl->descs[0])); + } + #endif if (!pl->nrofdevs) { int i; @@ -186,7 +227,16 @@ gp_port_library_list (GPPortInfoList *list) int nrofdevs = 0; struct libusb_device_descriptor *descs; +#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE + if(has_external_fd()) { + ctx = external_sys_device.ctx; + } + else { C_LIBUSB (libusb_init (&ctx), GP_ERROR_IO); + } +#else + C_LIBUSB (libusb_init (&ctx), GP_ERROR_IO); +#endif /* TODO: make sure libusb_exit gets called in all error paths inside this function */ @@ -197,11 +247,20 @@ gp_port_library_list (GPPortInfoList *list) gp_port_info_set_path (info, "^usb:"); gp_port_info_list_append (list, info); /* do not check return value, it might be -1 */ +#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE + if(has_external_fd()) { + nrofdevs = 1; + devs = external_sys_device.dl; + } + else +#endif + { nrofdevs = libusb_get_device_list (ctx, &devs); if (!nrofdevs) { libusb_exit (ctx); /* should free all stuff above */ goto nodevices; } + } C_MEM (descs = calloc (nrofdevs, sizeof(descs[0]))); for (i=0;ipl->config = port->pl->interface = port->pl->altsetting = -1; +#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE + if(has_external_fd()) { + port->pl->ctx = external_sys_device.ctx; + } + else +#endif + { 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); @@ -356,9 +428,20 @@ gp_libusb1_exit (GPPort *port) #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (port->pl->logfd >=0 ) close (port->pl->logfd); #endif - if (port->pl->nrofdevs) + if (port->pl->nrofdevs) { +#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE + if(!has_external_fd()) +#endif + { libusb_free_device_list (port->pl->devs, 1); + } + } +#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE + if(!has_external_fd()) +#endif + { libusb_exit (port->pl->ctx); + } free (port->pl); port->pl = NULL; } @@ -380,13 +463,27 @@ gp_libusb1_open (GPPort *port) C_PARAMS (port->pl->d); } +#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE + if(gp_port_usb_get_sys_device() != -1) { + if(!external_sys_device.h) { + LOG_ON_LIBUSB_E(libusb_wrap_sys_device(port->pl->ctx,gp_port_usb_get_sys_device(),&external_sys_device.h)); + libusb_ref_device(libusb_get_device(external_sys_device.h)); + } + port->pl->dh = external_sys_device.h; + port->pl->d = libusb_get_device(external_sys_device.h); + } + else +#endif + { 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 @@ -493,6 +590,9 @@ gp_libusb1_close (GPPort *port) _close_async_interrupts(port); +#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE + if(gp_port_usb_get_sys_device() == -1) { +#endif if (libusb_release_interface (port->pl->dh, port->settings.usb.interface) < 0) { int saved_errno = errno; @@ -523,6 +623,9 @@ gp_libusb1_close (GPPort *port) } libusb_close (port->pl->dh); +#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE + } +#endif struct _PrivateIrqCompleted *irq_iter; struct _PrivateIrqCompleted *irq_next;