/** * Allocates the memory for a #Camera. * * @param camera the #Camera object to initialize. * @return a gphoto2 error code * */ int gp_camera_new (Camera **camera) { int result; C_PARAMS (camera); C_MEM (*camera = calloc (1, sizeof (Camera))); (*camera)->functions = calloc (1, sizeof (CameraFunctions)); (*camera)->pc = calloc (1, sizeof (CameraPrivateCore)); if (!(*camera)->functions || !(*camera)->pc) { result = GP_ERROR_NO_MEMORY; goto error; } (*camera)->pc->ref_count = 1; /* Create the filesystem */ result = gp_filesystem_new (&(*camera)->fs); if (result < GP_OK) goto error; /* Create the port */ result = gp_port_new (&(*camera)->port); if (result < GP_OK) goto error; return(GP_OK); error: gp_camera_free (*camera); return result; }
/** * @param camera a #Camera * @param timeout number of seconds that should pass between each call to * \c func * @param func the function that should be called each \c timeout seconds * @return The id of the background process or a gphoto2 error code * * This function should be called by the camera driver during camera_init() * if the camera needs to be sent messages periodically in order to prevent * it from shutting down. * */ int gp_camera_start_timeout (Camera *camera, unsigned int timeout, CameraTimeoutFunc func) { int id; C_PARAMS (camera && camera->pc); if (!camera->pc->timeout_start_func) return (GP_ERROR_NOT_SUPPORTED); /* * We remember the id here in order to automatically remove * the timeout on gp_camera_exit. */ C_MEM (camera->pc->timeout_ids = realloc (camera->pc->timeout_ids, sizeof (int) * (camera->pc->timeout_ids_len + 1))); id = camera->pc->timeout_start_func (camera, timeout, func, camera->pc->timeout_data); if (id < 0) return (id); camera->pc->timeout_ids[camera->pc->timeout_ids_len] = id; camera->pc->timeout_ids_len++; return (id); }
static int gp_port_usbscsi_init (GPPort *port) { C_MEM (port->pl = calloc (1, sizeof (GPPortPrivateLibrary))); port->pl->fd = -1; return GP_OK; }
static int gp_port_vusb_init (GPPort *dev) { gp_log(GP_LOG_DEBUG,__FUNCTION__,"()"); C_MEM (dev->pl = calloc (1, sizeof (GPPortPrivateLibrary))); dev->pl->vcamera = vcamera_new(NIKON_D750); dev->pl->vcamera->init(dev->pl->vcamera); return GP_OK; }
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; }
/** * \brief Create new GPPort * * Allocate and initialize the memory for a new #GPPort. * * After you called this function, * you probably want to call #gp_port_set_info in order to make the newly * created port functional. * * \param port Pointer the #GPPort* pointer * \return a gphoto2 error code **/ int gp_port_new (GPPort **port) { C_PARAMS (port); GP_LOG_D ("Creating new device..."); C_MEM (*port = calloc (1, sizeof (GPPort))); (*port)->pc = calloc (1, sizeof (GPPortPrivateCore)); if (!(*port)->pc) { gp_port_free (*port); return (GP_ERROR_NO_MEMORY); } return (GP_OK); }
/** * \brief Allocate the memory for a new abilities list. * * Function to allocate the memory for a new abilities list. * \param list CameraAbilitiesList object to initialize * \return gphoto2 error code * * You would then call gp_abilities_list_load() in order to * populate it. */ int gp_abilities_list_new (CameraAbilitiesList **list) { C_PARAMS (list); /* * We do this here because everybody needs to call this function * first before accessing a camera. Pretty ugly, but I don't know * an other way without introducing a global initialization * function... */ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); C_MEM (*list = calloc (1, sizeof (CameraAbilitiesList))); return (GP_OK); }
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; }
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; }
/** * \brief Append the abilities to the list. * \param list CameraAbilitiesList * \param abilities CameraAbilities * \return a gphoto2 error code * * This function is called by a camera library on camera_abilities() * in order to inform libgphoto2 about a supported camera model. * */ int gp_abilities_list_append (CameraAbilitiesList *list, CameraAbilities abilities) { C_PARAMS (list); if (list->count == list->maxcount) { C_MEM (list->abilities = realloc (list->abilities, sizeof (CameraAbilities) * (list->maxcount + 100))); list->maxcount += 100; } memcpy (&(list->abilities [list->count]), &abilities, sizeof (CameraAbilities)); /* FIXME: We replace the colon by a space in the model string * This keeps backward compatibility until we have * thought of and implemented something better. */ remove_colon_from_string(list->abilities[list->count].model); list->count++; 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); }
static int gp_port_disk_init (GPPort *dev) { C_MEM (dev->pl = calloc (1, sizeof (GPPortPrivateLibrary))); return GP_OK; }
/** * \brief Configure a port * * Makes a port functional by passing in the necessary path * information (from the serial:/dev/ttyS0 or similar variables). * After calling this function, you can access the port using for * example gp_port_open(). * * \param port a GPPort * \param info the GPPortInfo to set * * \return a gphoto2 error code **/ int gp_port_set_info (GPPort *port, GPPortInfo info) { int ret; GPPortLibraryOperations ops_func; C_PARAMS (port); free (port->pc->info.name); C_MEM (port->pc->info.name = strdup (info->name)); free (port->pc->info.path); C_MEM (port->pc->info.path = strdup (info->path)); port->pc->info.type = info->type; free (port->pc->info.library_filename); C_MEM (port->pc->info.library_filename = strdup (info->library_filename)); port->type = info->type; /* Clean up */ if (port->pc->ops) { gp_port_exit (port); free (port->pc->ops); port->pc->ops = NULL; } if (port->pc->lh) { #if !defined(VALGRIND) lt_dlclose (port->pc->lh); lt_dlexit (); #endif } lt_dlinit (); port->pc->lh = lt_dlopenext (info->library_filename); if (!port->pc->lh) { GP_LOG_E ("Could not load '%s' ('%s').", info->library_filename, lt_dlerror ()); lt_dlexit (); return (GP_ERROR_LIBRARY); } /* Load the operations */ ops_func = lt_dlsym (port->pc->lh, "gp_port_library_operations"); if (!ops_func) { GP_LOG_E ("Could not find 'gp_port_library_operations' in '%s' ('%s')", info->library_filename, lt_dlerror ()); lt_dlclose (port->pc->lh); lt_dlexit (); port->pc->lh = NULL; return (GP_ERROR_LIBRARY); } port->pc->ops = ops_func (); gp_port_init (port); /* Initialize the settings to some default ones */ switch (info->type) { case GP_PORT_SERIAL: port->settings.serial.speed = 0; port->settings.serial.bits = 8; port->settings.serial.parity = 0; port->settings.serial.stopbits = 1; gp_port_set_timeout (port, 500); break; case GP_PORT_USB: if (sizeof (port->settings.usb.port) <= strlen(info->path)) { GP_LOG_E ("Path is too long for static buffer '%s'.", info->path); return GP_ERROR_LIBRARY; } strncpy (port->settings.usb.port, info->path, sizeof (port->settings.usb.port)); port->settings.usb.inep = -1; port->settings.usb.outep = -1; port->settings.usb.config = -1; port->settings.usb.interface = 0; port->settings.usb.altsetting = -1; gp_port_set_timeout (port, 5000); break; case GP_PORT_USB_DISK_DIRECT: snprintf(port->settings.usbdiskdirect.path, sizeof(port->settings.usbdiskdirect.path), "%s", strchr(info->path, ':') + 1); break; case GP_PORT_USB_SCSI: snprintf(port->settings.usbscsi.path, sizeof(port->settings.usbscsi.path), "%s", strchr(info->path, ':') + 1); break; default: /* Nothing in here */ break; } ret = gp_port_set_settings (port, port->settings); if (ret != GP_ERROR_NOT_SUPPORTED) CHECK_RESULT (ret); return GP_OK; }