/** * Retrieves information about a file. * * @param camera a #Camera * @param folder a folder * @param file the name of the file * @param info * @param context a #GPContext * @return a gphoto2 error code * **/ int gp_camera_file_get_info (Camera *camera, const char *folder, const char *file, CameraFileInfo *info, GPContext *context) { int result = GP_OK; const char *mime_type; const char *data; /* long int size; */ CameraFile *cfile; GP_LOG_D ("Getting file info for '%s' in '%s'...", file, folder); C_PARAMS (camera && folder && file && info); CHECK_INIT (camera, context); memset (info, 0, sizeof (CameraFileInfo)); /* Check first if the camera driver supports the filesystem */ CHECK_OPEN (camera, context); result = gp_filesystem_get_info (camera->fs, folder, file, info, context); CHECK_CLOSE (camera, context); if (result != GP_ERROR_NOT_SUPPORTED) { CAMERA_UNUSED (camera, context); return (result); } /* * The CameraFilesystem doesn't support file info. We simply get * the preview and the file and look for ourselves... */ /* It takes too long to get the file */ info->file.fields = GP_FILE_INFO_NONE; /* Get the preview */ info->preview.fields = GP_FILE_INFO_NONE; CRS (camera, gp_file_new (&cfile), context); if (gp_camera_file_get (camera, folder, file, GP_FILE_TYPE_PREVIEW, cfile, context) == GP_OK) { unsigned long size; info->preview.fields |= GP_FILE_INFO_SIZE | GP_FILE_INFO_TYPE; gp_file_get_data_and_size (cfile, &data, &size); info->preview.size = size; gp_file_get_mime_type (cfile, &mime_type); strncpy (info->preview.type, mime_type, sizeof (info->preview.type)); } gp_file_unref (cfile); CAMERA_UNUSED (camera, context); return (GP_OK); }
uint16_t ptp_usb_control_device_reset_request (PTPParams *params) { Camera *camera = ((PTPData *)params->data)->camera; int ret; GP_LOG_D ("Sending usb device reset request."); ret = gp_port_usb_msg_class_write (camera->port, 0x66, 0x0000, 0x0000, NULL, 0); if (ret < GP_OK) return PTP_ERROR_IO; return PTP_RC_OK; }
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; }
uint16_t ptp_usb_control_get_extended_event_data (PTPParams *params, char *buffer, int *size) { Camera *camera = ((PTPData *)params->data)->camera; int ret; GP_LOG_D ("Getting extended event data."); ret = gp_port_usb_msg_class_read (camera->port, 0x65, 0x0000, 0x0000, buffer, *size); if (ret < GP_OK) return PTP_ERROR_IO; *size = ret; return PTP_RC_OK; }
/** * \brief Flush data on serial port * * \param port a GPPort * \param direction the direction of the flush * * Flushes the serial output or input (depending on direction) * of the serial port. * * \return a gphoto2 error code */ int gp_port_flush (GPPort *port, int direction) { GP_LOG_D ("Flushing port..."); C_PARAMS (port); CHECK_SUPP (port, "flush", port->pc->ops->flush); CHECK_RESULT (port->pc->ops->flush (port, direction)); return (GP_OK); }
/** * \brief Close a port. * \param port a #GPPort * * Closes a port temporarily. It can afterwards be reopened using * #gp_port_open. * * \return a gphoto2 error code **/ int gp_port_close (GPPort *port) { GP_LOG_D ("Closing port..."); C_PARAMS (port); CHECK_INIT (port); CHECK_SUPP (port, "close", port->pc->ops->close); CHECK_RESULT (port->pc->ops->close(port)); return (GP_OK); }
/** * \brief Send a break over a serial port * * \param port a GPPort * \param duration duration of break in milliseconds * * Sends a break with the specified duration in milliseconds. * * \return a gphoto2 error code */ int gp_port_send_break (GPPort *port, int duration) { GP_LOG_D ("Sending break (%i milliseconds)...", duration); C_PARAMS (port); CHECK_INIT (port); CHECK_SUPP (port, "send_break", port->pc->ops->send_break); CHECK_RESULT (port->pc->ops->send_break (port, duration)); return (GP_OK); }
/** * \brief Clear USB endpoint HALT condition * * \param port a GPPort * \param ep endpoint to clear HALT * * Clears the HALT (stall?) endpoint condition of the specified endpoint. * * \return a gphoto2 error code */ int gp_port_usb_clear_halt (GPPort *port, int ep) { GP_LOG_D ("Clear USB halt..."); C_PARAMS (port); CHECK_INIT (port); CHECK_SUPP (port, "clear_halt", port->pc->ops->clear_halt); CHECK_RESULT (port->pc->ops->clear_halt (port, ep)); return (GP_OK); }
uint16_t ptp_usb_sendreq (PTPParams* params, PTPContainer* req) { int res, towrite, do_retry = TRUE; PTPUSBBulkContainer usbreq; Camera *camera = ((PTPData *)params->data)->camera; GP_LOG_D ("Sending PTP_OC 0x%0x (%s) request...", req->Code, ptp_get_opcode_name(params, req->Code)); /* build appropriate USB container */ usbreq.length=htod32(PTP_USB_BULK_REQ_LEN- (sizeof(uint32_t)*(5-req->Nparam))); usbreq.type=htod16(PTP_USB_CONTAINER_COMMAND); usbreq.code=htod16(req->Code); usbreq.trans_id=htod32(req->Transaction_ID); usbreq.payload.params.param1=htod32(req->Param1); usbreq.payload.params.param2=htod32(req->Param2); usbreq.payload.params.param3=htod32(req->Param3); usbreq.payload.params.param4=htod32(req->Param4); usbreq.payload.params.param5=htod32(req->Param5); /* send it to responder */ towrite = PTP_USB_BULK_REQ_LEN-(sizeof(uint32_t)*(5-req->Nparam)); retry: res = gp_port_write (camera->port, (char*)&usbreq, towrite); if (res != towrite) { if (res < 0) { GP_LOG_E ("PTP_OC 0x%04x sending req failed: %s (%d)", req->Code, gp_port_result_as_string(res), res); if (res == GP_ERROR_IO_WRITE && do_retry) { GP_LOG_D ("Clearing halt on OUT EP and retrying once."); gp_port_usb_clear_halt (camera->port, GP_PORT_USB_ENDPOINT_OUT); do_retry = FALSE; goto retry; } } else GP_LOG_E ("PTP_OC 0x%04x sending req failed: wrote only %d of %d bytes", req->Code, res, towrite); return PTP_ERROR_IO; } return PTP_RC_OK; }
/** * \brief Reset a port. * \param port a #GPPort * * Resets a port. Device will likely reconnect and appear under a new id. * * \return a gphoto2 error code **/ int gp_port_reset (GPPort *port) { GP_LOG_D ("Resetting port..."); C_PARAMS (port); CHECK_INIT (port); CHECK_SUPP (port, "reset", port->pc->ops->reset); CHECK_RESULT (port->pc->ops->reset(port)); return (GP_OK); }
/** * \brief Open a port. * \param port a #GPPort * * Opens a port which should have been created with #gp_port_new and * configured with #gp_port_set_info and #gp_port_set_settings * * \return a gphoto2 error code **/ int gp_port_open (GPPort *port) { C_PARAMS (port); CHECK_INIT (port); GP_LOG_D ("Opening %s port...", port->type == GP_PORT_SERIAL ? "SERIAL" : (port->type == GP_PORT_USB ? "USB" : "")); CHECK_SUPP (port, "open", port->pc->ops->open); CHECK_RESULT (port->pc->ops->open (port)); return GP_OK; }
static uint16_t ptp_usb_getpacket(PTPParams *params, PTPUSBBulkContainer *packet, uint32_t *rlen) { int tries = 0, result; Camera *camera = ((PTPData *)params->data)->camera; /* read the header and potentially the first data */ if (params->response_packet_size > 0) { GP_LOG_D ("Returning previously buffered response packet."); /* If there is a buffered packet, just use it. */ memcpy(packet, params->response_packet, params->response_packet_size); *rlen = params->response_packet_size; free(params->response_packet); params->response_packet = NULL; params->response_packet_size = 0; /* Here this signifies a "virtual read" */ return PTP_RC_OK; } retry: /* A packet should come in a single read always. */ result = gp_port_read (camera->port, (char*)packet, sizeof(*packet)); /* This might be a left over zero-write of the device at the end of the previous transmission */ if (result == 0) result = gp_port_read (camera->port, (char*)packet, sizeof(*packet)); if (result > 0) { *rlen = result; return PTP_RC_OK; } if (result == GP_ERROR_IO_READ) { GP_LOG_D ("Clearing halt on IN EP and retrying once."); gp_port_usb_clear_halt (camera->port, GP_PORT_USB_ENDPOINT_IN); /* retrying only makes sense if we did not read anything yet */ if (tries++ < 1) goto retry; } return PTP_ERROR_IO; }
/** * Deletes the file from \c folder. * * \param camera a #Camera * \param folder a folder * \param file the name of a file * \param context a #GPContext * \return a gphoto2 error code * **/ int gp_camera_file_delete (Camera *camera, const char *folder, const char *file, GPContext *context) { GP_LOG_D ("Deleting file '%s' in folder '%s'...", file, folder); C_PARAMS (camera && folder && file); CHECK_INIT (camera, context); CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_delete_file ( camera->fs, folder, file, context), context); CAMERA_UNUSED (camera, context); return (GP_OK); }
/** * Deletes all files in a given \c folder. * * @param camera a #Camera * @param folder a folder * @param context a #GPContext * @return a gphoto2 error code * **/ int gp_camera_folder_delete_all (Camera *camera, const char *folder, GPContext *context) { GP_LOG_D ("Deleting all files in '%s'...", folder); C_PARAMS (camera && folder); CHECK_INIT (camera, context); CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_delete_all (camera->fs, folder, context), context); CAMERA_UNUSED (camera, context); 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); }
/** * Lists the folders in supplied \c folder. * * @param camera a #Camera * @param folder a folder * @param list a #CameraList * @param context a #GPContext * @return a gphoto2 error code * **/ int gp_camera_folder_list_folders (Camera *camera, const char* folder, CameraList *list, GPContext *context) { GP_LOG_D ("Listing folders in '%s'...", folder); C_PARAMS (camera && folder && list); CHECK_INIT (camera, context); CR (camera, gp_list_reset (list), context); CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_list_folders ( camera->fs, folder, list, context), context); CR (camera, gp_list_sort (list), context); CAMERA_UNUSED (camera, context); return (GP_OK); }
/** * Uploads a file into given \c folder. * * @param camera a #Camera * @param folder a folder * @param file a #CameraFile * @param context a #GPContext * @return a gphoto2 error code * **/ int gp_camera_folder_put_file (Camera *camera, const char *folder, const char *filename, CameraFileType type, CameraFile *file, GPContext *context) { GP_LOG_D ("Uploading file into '%s'...", folder); C_PARAMS (camera && folder && file); CHECK_INIT (camera, context); CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_put_file (camera->fs, folder, filename, type, file, context), context); CAMERA_UNUSED (camera, context); return (GP_OK); }
/** * \brief Sets the camera abilities. * * @param camera a #Camera * @param abilities the #CameraAbilities to be set * @return a gphoto2 error code * * You need to call this function before calling #gp_camera_init the * first time unless you want gphoto2 to autodetect cameras and choose * the first detected one. By setting the \c abilities, you * tell gphoto2 what model the \c camera is and what camera driver should * be used for accessing the \c camera. You can get \c abilities by calling * #gp_abilities_list_get_abilities. * */ int gp_camera_set_abilities (Camera *camera, CameraAbilities abilities) { GP_LOG_D ("Setting abilities ('%s')...", abilities.model); C_PARAMS (camera); /* * If the camera is currently initialized, terminate that connection. * We don't care if we are successful or not. */ if (camera->pc->lh) gp_camera_exit (camera, NULL); memcpy (&camera->pc->a, &abilities, sizeof (CameraAbilities)); return (GP_OK); }
/** * Close connection to camera. * * @param camera a #Camera object * @param context a #GPContext object * @return a gphoto2 error code. * * Closes a connection to the camera and therefore gives other application * the possibility to access the camera, too. * * It is recommended that you * call this function when you currently don't need the camera. The camera * will get reinitialized by gp_camera_init() automatically if you try to * access the camera again. * */ int gp_camera_exit (Camera *camera, GPContext *context) { C_PARAMS (camera); GP_LOG_D ("Exiting camera ('%s')...", camera->pc->a.model); /* * We have to postpone this operation if the camera is currently * in use. gp_camera_exit will be called again if the * camera->pc->used will drop to zero. */ if (camera->pc->used) { camera->pc->exit_requested = 1; return (GP_OK); } /* Remove every timeout that is still pending */ while (camera->pc->timeout_ids_len) gp_camera_stop_timeout (camera, camera->pc->timeout_ids[0]); free (camera->pc->timeout_ids); camera->pc->timeout_ids = NULL; if (camera->functions->exit) { #ifdef HAVE_MULTI gp_port_open (camera->port); #endif camera->functions->exit (camera, context); } gp_port_close (camera->port); memset (camera->functions, 0, sizeof (CameraFunctions)); if (camera->pc->lh) { #if !defined(VALGRIND) lt_dlclose (camera->pc->lh); lt_dlexit (); #endif camera->pc->lh = NULL; } gp_filesystem_reset (camera->fs); return (GP_OK); }
static int gp_port_usbscsi_send_scsi_cmd (GPPort *port, int to_dev, char *cmd, int cmd_size, char *sense, int sense_size, char *data, int data_size) { #ifdef HAVE_SCSI_SG_H sg_io_hdr_t io_hdr; C_PARAMS (port); /* The device needs to be opened for that operation */ if (port->pl->fd == -1) CHECK (gp_port_usbscsi_open (port)) memset(sense, 0, sense_size); memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); if (to_dev) { io_hdr.dxfer_direction = SG_DXFER_TO_DEV; } else { memset (data, 0, data_size); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; } io_hdr.interface_id = 'S'; io_hdr.cmdp = (unsigned char *)cmd; io_hdr.cmd_len = cmd_size; io_hdr.sbp = (unsigned char *)sense; io_hdr.mx_sb_len = sense_size; io_hdr.dxferp = (unsigned char *)data; io_hdr.dxfer_len = data_size; /*io_hdr.timeout = 1500;*/ io_hdr.timeout = port->timeout; GP_LOG_D ("setting scsi command timeout to %d", port->timeout); if (io_hdr.timeout < 1500) io_hdr.timeout = 1500; if (ioctl (port->pl->fd, SG_IO, &io_hdr) < 0) { gp_port_set_error (port, _("Could not send scsi command to: " "'%s' (%m)."), port->settings.usbscsi.path); return GP_ERROR_IO; } return GP_OK; #else return GP_ERROR_NOT_SUPPORTED; #endif }
/** * \brief Set port settings * \param port a #GPPort * \param settings the #GPPortSettings to be set * * Adjusts the settings of a port. You should always call * #gp_port_get_settings, adjust the values depending on the type of the port, * and then call #gp_port_set_settings. * * \return a gphoto2 error code **/ int gp_port_set_settings (GPPort *port, GPPortSettings settings) { GP_LOG_D ("Setting settings..."); C_PARAMS (port); CHECK_INIT (port); /* * We copy the settings to settings_pending and call update on the * port. */ memcpy (&port->settings_pending, &settings, sizeof (port->settings_pending)); CHECK_SUPP (port, "update", port->pc->ops->update); CHECK_RESULT (port->pc->ops->update (port)); return (GP_OK); }
/** * \brief Print a message to the context * * This sends a message to the passed context, to be printed by * it in some kind of way, but do no other action. * * To be used by camera drivers. * * \param context A GPContext * \param format A sprintf style format string * \param ... variable argument list depending on format string */ void gp_context_message (GPContext *context, const char *format, ...) { va_list args; char *str; va_start (args, format); str = gpi_vsnprintf(format, args); va_end (args); if (!str) return; /* Log the message */ GP_LOG_D ("%s", str); if (context && context->message_func) context->message_func (context, str, context->message_func_data); free (str); }
int gp_camera_set_port_info (Camera *camera, GPPortInfo info) { char *name, *path; C_PARAMS (camera); /* * If the camera is currently initialized, terminate that connection. * We don't care if we are successful or not. */ if (camera->pc->lh) gp_camera_exit (camera, NULL); gp_port_info_get_name (info, &name); gp_port_info_get_path (info, &path); GP_LOG_D ("Setting port info for port '%s' at '%s'...", name, path); CR (camera, gp_port_set_info (camera->port, info), NULL); return (GP_OK); }
/** * Free the \c camera. * * @param camera a #Camera * @return a gphoto2 error code * * \deprecated * This function should never be used. Please use #gp_camera_unref instead. * */ int gp_camera_free (Camera *camera) { C_PARAMS (camera); GP_LOG_D ("Freeing camera..."); /* * If the camera is currently initialized, close the connection. * We don't care if we are successful or not. */ if (camera->port && camera->pc && camera->pc->lh) gp_camera_exit (camera, NULL); /* We don't care if anything goes wrong */ if (camera->port) { gp_port_free (camera->port); camera->port = NULL; } if (camera->pc) { free (camera->pc->timeout_ids); free (camera->pc); camera->pc = NULL; } if (camera->fs) { gp_filesystem_free (camera->fs); camera->fs = NULL; } if (camera->functions) { free (camera->functions); camera->functions = NULL; } free (camera); return (GP_OK); }
/** * \brief Free the port structure * \param port a #GPPort * * Closes the port and frees the memory. * * \return a gphoto2 error code **/ int gp_port_free (GPPort *port) { GP_LOG_D ("Freeing port..."); C_PARAMS (port); if (port->pc) { if (port->pc->ops) { /* We don't care for return values */ gp_port_close (port); 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 port->pc->lh = NULL; } free (port->pc->info.name); free (port->pc->info.path); free (port->pc->info.library_filename); free (port->pc); port->pc = NULL; } free (port); return GP_OK; }
/** * \brief Set specified serial PIN to value * * \param port a GPPort * \param pin the serial pin to be retrieved * \param level the setting of the pin * * Pulls the specified pin of a serial port to the specified level. * * \return a gphoto2 error code */ int gp_port_set_pin (GPPort *port, GPPin pin, GPLevel level) { unsigned int i, j; for (i = 0; PinTable[i].description_short; i++) if (PinTable[i].pin == pin) break; for (j = 0; LevelTable[j].description; j++) if (LevelTable[j].level == level) break; GP_LOG_D ("Setting pin %i (%s: '%s') to '%s'...", PinTable[i].number, PinTable[i].description_short, PinTable[i].description_long, _(LevelTable[j].description)); C_PARAMS (port); CHECK_INIT (port); CHECK_SUPP (port, "set_pin", port->pc->ops->set_pin); CHECK_RESULT (port->pc->ops->set_pin (port, pin, level)); return (GP_OK); }
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; }
/* * 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; }
/* This function reads the Microsoft OS Descriptor and looks inside to * find if it is a MTP device. This is the similar to the way that * Windows Media Player 10 uses. * It is documented to some degree on various internet pages. */ static int gp_libusb1_match_mtp_device(struct libusb_device *dev,int *configno, int *interfaceno, int *altsettingno) { /* Marcus: Avoid this probing altogether, its too unstable on some devices */ return 0; #if 0 char buf[1000], cmd; int ret,i,i1,i2, xifaces,xnocamifaces; usb_dev_handle *devh; /* All of them are "vendor specific" device class */ #if 0 if ((desc.bDeviceClass!=0xff) && (desc.bDeviceClass!=0)) return 0; #endif if (dev->config) { xifaces = xnocamifaces = 0; for (i = 0; i < desc.bNumConfigurations; i++) { unsigned int j; for (j = 0; j < dev->config[i].bNumInterfaces; j++) { int k; xifaces++; for (k = 0; k < dev->config[i].interface[j].num_altsetting; k++) { struct usb_interface_descriptor *intf = &dev->config[i].interface[j].altsetting[k]; if ( (intf->bInterfaceClass == LIBUSB_CLASS_HID) || (intf->bInterfaceClass == LIBUSB_CLASS_PRINTER) || (intf->bInterfaceClass == LIBUSB_CLASS_AUDIO) || (intf->bInterfaceClass == LIBUSB_CLASS_HUB) || (intf->bInterfaceClass == LIBUSB_CLASS_COMM) || (intf->bInterfaceClass == 0xe0) /* wireless/bluetooth*/ ) xnocamifaces++; } } } } if (xifaces == xnocamifaces) /* only non-camera ifaces */ return 0; devh = usb_open (dev); if (!devh) return 0; /* * Loop over the device configurations and interfaces. Nokia MTP-capable * handsets (possibly others) typically have the string "MTP" in their * MTP interface descriptions, that's how they can be detected, before * we try the more esoteric "OS descriptors" (below). */ if (dev->config) { for (i = 0; i < desc.bNumConfigurations; i++) { unsigned int j; for (j = 0; j < dev->config[i].bNumInterfaces; j++) { int k; for (k = 0; k < dev->config[i].interface[j].num_altsetting; k++) { buf[0] = '\0'; ret = usb_get_string_simple(devh, dev->config[i].interface[j].altsetting[k].iInterface, (char *) buf, 1024); if (ret < 3) continue; if (strcmp((char *) buf, "MTP") == 0) { GP_LOG_D ("Configuration %d, interface %d, altsetting %d:\n", i, j, k); GP_LOG_D (" Interface description contains the string \"MTP\"\n"); GP_LOG_D (" Device recognized as MTP, no further probing.\n"); goto found; } } } } } /* get string descriptor at 0xEE */ ret = usb_get_descriptor (devh, 0x03, 0xee, buf, sizeof(buf)); if (ret > 0) GP_LOG_DATA (buf, ret, "get_MS_OSD"); if (ret < 10) goto errout; if (!((buf[2] == 'M') && (buf[4]=='S') && (buf[6]=='F') && (buf[8]=='T'))) goto errout; cmd = buf[16]; ret = usb_control_msg (devh, USB_ENDPOINT_IN|USB_RECIP_DEVICE|LIBUSB_REQUEST_TYPE_VENDOR, cmd, 0, 4, buf, sizeof(buf), 1000); if (ret == -1) { GP_LOG_E ("control message says %d\n", ret); goto errout; } if (buf[0] != 0x28) { GP_LOG_E ("ret is %d, buf[0] is %x\n", ret, buf[0]); goto errout; } if (ret > 0) GP_LOG_DATA (buf, ret, "get_MS_ExtDesc"); if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) { GP_LOG_E ("buf at 0x12 is %02x%02x%02x\n", buf[0x12], buf[0x13], buf[0x14]); goto errout; } ret = usb_control_msg (devh, USB_ENDPOINT_IN|USB_RECIP_DEVICE|LIBUSB_REQUEST_TYPE_VENDOR, cmd, 0, 5, buf, sizeof(buf), 1000); if (ret == -1) goto errout; if (buf[0] != 0x28) { GP_LOG_E ("ret is %d, buf[0] is %x\n", ret, buf[0]); goto errout; } if (ret > 0) GP_LOG_DATA (buf, ret, "get_MS_ExtProp"); if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) { GP_LOG_E ("buf at 0x12 is %02x%02x%02x\n", buf[0x12], buf[0x13], buf[0x14]); goto errout; } found: usb_close (devh); /* Now chose a nice interface for us to use ... Just take the first. */ if (desc.bNumConfigurations > 1) GP_LOG_E ("The device has %d configurations!\n", desc.bNumConfigurations); for (i = 0; i < desc.bNumConfigurations; i++) { struct usb_config_descriptor *config = &dev->config[i]; if (config->bNumInterfaces > 1) GP_LOG_E ("The configuration has %d interfaces!\n", config->bNumInterfaces); for (i1 = 0; i1 < config->bNumInterfaces; i1++) { struct usb_interface *interface = &config->interface[i1]; if (interface->num_altsetting > 1) GP_LOG_E ("The interface has %d altsettings!\n", interface->num_altsetting); for (i2 = 0; i2 < interface->num_altsetting; i2++) { *configno = i; *interfaceno = i1; *altsettingno = i2; return 1; } } } return 1; errout: usb_close (devh); return 0; #endif }