/** * \brief Lookup a specific path in the list * * \param list a #GPPortInfoList * \param path a path * * Looks for an entry in the list with the supplied path. If no exact match * can be found, a regex search will be performed in the hope some driver * claimed ports like "serial:*". * * \return The index of the entry or a gphoto2 error code **/ int gp_port_info_list_lookup_path (GPPortInfoList *list, const char *path) { int i, result, generic; regex_t pattern; #ifdef HAVE_GNU_REGEX const char *rv; #else regmatch_t match; #endif CHECK_NULL (list && path); gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", ngettext( "Looking for path '%s' (%i entry available)...", "Looking for path '%s' (%i entries available)...", list->count ), path, list->count); /* Exact match? */ for (generic = i = 0; i < list->count; i++) if (!strlen (list->info[i].name)) generic++; else if (!strcmp (list->info[i].path, path)) return (i - generic); /* Regex match? */ gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Starting regex search for '%s'..."), path); for (i = 0; i < list->count; i++) { GPPortInfo newinfo; if (strlen (list->info[i].name)) continue; gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Trying '%s'..."), list->info[i].path); /* Compile the pattern */ #ifdef HAVE_GNU_REGEX memset (&pattern, 0, sizeof (pattern)); rv = re_compile_pattern (list->info[i].path, strlen (list->info[i].path), &pattern); if (rv) { gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", "%s", rv); continue; } #else result = regcomp (&pattern, list->info[i].path, REG_ICASE); if (result) { char buf[1024]; if (regerror (result, &pattern, buf, sizeof (buf))) gp_log (GP_LOG_ERROR, "gphoto2-port-info-list", "%s", buf); else gp_log (GP_LOG_ERROR, "gphoto2-port-info-list", _("regcomp failed")); return (GP_ERROR_UNKNOWN_PORT); } #endif /* Try to match */ #ifdef HAVE_GNU_REGEX result = re_match (&pattern, path, strlen (path), 0, NULL); regfree (&pattern); if (result < 0) { gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("re_match failed (%i)"), result); continue; } #else result = regexec (&pattern, path, 1, &match, 0); regfree (&pattern); if (result) { gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("regexec failed")); continue; } #endif memcpy (&newinfo, &list->info[i], sizeof(newinfo)); strncpy (newinfo.path, path, sizeof (newinfo.path)); strncpy (newinfo.name, _("Generic Port"), sizeof (newinfo.name)); CR (result = gp_port_info_list_append (list, newinfo)); return result; } return (GP_ERROR_UNKNOWN_PORT); }
static int put_file_func (CameraFilesystem *fs, const char *folder, const char *filename, CameraFile *file, void *data, GPContext *context) { Camera *camera = data; /* * Upload the file to the camera. Use gp_file_get_data_and_size etc. */ int result = -EPROTO; time_t startTime = time(NULL); enum { START, DATA, END, FINISHED } state; int src = -1; int r; int update = 0; struct stat srcStat; __u64 fileSize; __u64 byteCount = 0; const char *filename; char *path; struct tf_packet reply; if(0 != fstat(src, &srcStat)) { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Can not examine source file: %s\n", strerror(errno)); result = errno; goto out; } fileSize = srcStat.st_size; if(fileSize == 0) { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Source file is empty - not transfering.\n"); result = -ENODATA; goto out; } path = get_path (camera, folder, filename); r = send_cmd_hdd_file_send(camera, PUT, path, context); if(r < 0) goto out; state = START; while(0 < get_tf_packet(camera, &reply, context)) { update = (update + 1) % 16; switch (get_u32(&reply.cmd)) { case SUCCESS: switch (state) { case START: { /* Send start */ struct typefile *tf = (struct typefile *) packet.data; put_u16(&packet.length, PACKET_HEAD_SIZE + 114); put_u32(&packet.cmd, DATA_HDD_FILE_START); time_to_tfdt(srcStat.st_mtime, &tf->stamp); tf->filetype = 2; put_u64(&tf->size, srcStat.st_size); strncpy((char *) tf->name, path, 94); tf->name[94] = '\0'; tf->unused = 0; tf->attrib = 0; gp_log (GP_LOG_DEBUG, "topfield", "%s: DATA_HDD_FILE_START\n", __func__); r = send_tf_packet(camera, &packet, context); if(r < 0) { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Incomplete send.\n"); goto out; } state = DATA; break; } case DATA: { int payloadSize = sizeof(packet.data) - 9; ssize_t w = read(src, &packet.data[8], payloadSize); /* Detect a Topfield protcol bug and prevent the sending of packets that are a multiple of 512 bytes. */ if((w > 4) && (((((PACKET_HEAD_SIZE + 8 + w) + 1) & ~1) % 0x200) == 0)) { lseek(src, -4, SEEK_CUR); w -= 4; payloadSize -= 4; } put_u16(&packet.length, PACKET_HEAD_SIZE + 8 + w); put_u32(&packet.cmd, DATA_HDD_FILE_DATA); put_u64(packet.data, byteCount); byteCount += w; /* Detect EOF and transition to END */ if((w < 0) || (byteCount >= fileSize)) { state = END; } if(w > 0) { gp_log (GP_LOG_DEBUG, "topfield", "%s: DATA_HDD_FILE_DATA\n", __func__); r = send_tf_packet(camera, &packet, context); if(r < w) { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Incomplete send.\n"); goto out; } } if(!update && !quiet) { progressStats(fileSize, byteCount, startTime); } break; } case END: /* Send end */ put_u16(&packet.length, PACKET_HEAD_SIZE); put_u32(&packet.cmd, DATA_HDD_FILE_END); gp_log (GP_LOG_DEBUG, "topfield", "%s: DATA_HDD_FILE_END\n", __func__); r = send_tf_packet(camera, &packet, context); if(r < 0) { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Incomplete send.\n"); goto out; } state = FINISHED; break; case FINISHED: result = 0; goto out; break; } break; case FAIL: gp_log (GP_LOG_ERROR, "topfield", "ERROR: Device reports %s\n", decode_error(&reply)); goto out; break; default: gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unhandled packet (%d)\n", get_u32(&reply.cmd)); break; } } finalStats(byteCount, startTime); out: close(src); return result; }
static int foreach_func (const char *filename, lt_ptr data) { GPPortInfoList *list = data; lt_dlhandle lh; GPPortLibraryType lib_type; GPPortLibraryList lib_list; GPPortType type; unsigned int j, old_size = list->count; int result; gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Called for filename '%s'."), filename ); lh = lt_dlopenext (filename); if (!lh) { gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Could not load '%s': '%s'."), filename, lt_dlerror ()); return (0); } lib_type = lt_dlsym (lh, "gp_port_library_type"); lib_list = lt_dlsym (lh, "gp_port_library_list"); if (!lib_type || !lib_list) { gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Could not find some functions in '%s': '%s'."), filename, lt_dlerror ()); lt_dlclose (lh); return (0); } type = lib_type (); for (j = 0; j < list->count; j++) if (list->info[j].type == type) break; if (j != list->count) { gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("'%s' already loaded"), filename); lt_dlclose (lh); return (0); } result = lib_list (list); lt_dlclose (lh); if (result < 0) { gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Could not load port driver list: '%s'."), gp_port_result_as_string (result)); return (0); } for (j = old_size; j < list->count; j++){ gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Loaded '%s' ('%s') from '%s'."), list->info[j].name, list->info[j].path, filename); strcpy (list->info[j].library_filename, filename); } return (0); }
static int gp_port_serial_check_speed (GPPort *dev) { speed_t speed; #ifdef OS2 ULONG rc; ULONG ulParmLen = 2; /* Maximum size of the parameter packet */ #else #ifdef HAVE_TERMIOS_H struct termios tio; #else struct sgttyb ttyb; #endif #endif /* * We need an open device in order to set the speed. If there is no * open device, postpone setting of speed. */ if (!dev->pl->fd) return (GP_OK); /* If baudrate is up to date, do nothing */ if (dev->pl->baudrate == dev->settings.serial.speed) return (GP_OK); gp_log (GP_LOG_DEBUG, "gphoto2-port-serial", "Setting baudrate to %d...", dev->settings.serial.speed); speed = gp_port_serial_baudconv (dev->settings.serial.speed); #ifdef OS2 rc = DosDevIOCtl (dev->pl->fd, /* Device handle */ 0x0001, /* Serial-device control */ 0x0043, /* Sets bit rate */ (PULONG) &(dev->settings.serial.speed), sizeof(baudrate), /* Max. size of parameter list */ &ulParmLen, /* Size of parameter packet */ NULL, /* No data packet */ 0, /* Maximum size of data packet */ NULL); /* Size of data packet */ if(rc != 0) printf("DosDevIOCtl baudrate error:%d\n",rc); #else /* !OS2 */ #ifdef HAVE_TERMIOS_H if (tcgetattr(dev->pl->fd, &tio) < 0) { gp_port_set_error (dev, _("Could not set the baudrate to %d"), dev->settings.serial.speed); return GP_ERROR_IO_SERIAL_SPEED; } tio.c_cflag = (tio.c_cflag & ~CSIZE) | CS8; /* Set into raw, no echo mode */ tio.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | IXANY | IXON | IXOFF | INPCK | ISTRIP); #ifdef IUCLC tio.c_iflag &= ~IUCLC; #endif tio.c_iflag |= (BRKINT | IGNPAR); tio.c_oflag &= ~OPOST; tio.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | ECHOE | ECHOK | IEXTEN); tio.c_cflag &= ~(CRTSCTS | PARENB | PARODD); tio.c_cflag |= CLOCAL | CREAD; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; if (dev->settings.serial.parity != GP_PORT_SERIAL_PARITY_OFF) { tio.c_iflag &= ~IGNPAR; tio.c_iflag |= INPCK | PARMRK ; tio.c_cflag |= PARENB; if (dev->settings.serial.parity == GP_PORT_SERIAL_PARITY_ODD) tio.c_cflag |= PARODD; } /* Set the new speed. */ cfsetispeed (&tio, speed); cfsetospeed (&tio, speed); if (tcsetattr (dev->pl->fd, TCSANOW, &tio) < 0) { GP_DEBUG ("Error on 'tcsetattr'."); return GP_ERROR_IO_SERIAL_SPEED; } /* Clear O_NONBLOCK. */ if (fcntl (dev->pl->fd, F_SETFL, 0) < 0) { GP_DEBUG ("Error on 'fcntl'."); return GP_ERROR_IO_SERIAL_SPEED; } /* * Verify if the speed change has been successful. * This is needed because some Solaris systems just ignore unsupported * speeds (like 115200) instead of complaining. * * Only perform the check if we really changed to some speed. */ if (speed != B0) { if (tcgetattr (dev->pl->fd, &tio)) { GP_DEBUG ("Error on 'tcgetattr'."); return (GP_ERROR_IO_SERIAL_SPEED); } if ((cfgetispeed (&tio) != speed) || (cfgetospeed (&tio) != speed)) { GP_DEBUG ("Cannot set baudrate to %d...", dev->settings.serial.speed); return (GP_ERROR_NOT_SUPPORTED); } } #else /* !HAVE_TERMIOS_H */ if (ioctl (dev->pl->fd, TIOCGETP, &ttyb) < 0) { perror("ioctl(TIOCGETP)"); return GP_ERROR_IO_SERIAL_SPEED; } ttyb.sg_ispeed = dev->settings.serial.speed; ttyb.sg_ospeed = dev->settings.serial.speed; ttyb.sg_flags = 0; if (ioctl (dev->pl->fd, TIOCSETP, &ttyb) < 0) { perror("ioctl(TIOCSETP)"); return GP_ERROR_IO_SERIAL_SPEED; } #endif #endif dev->pl->baudrate = dev->settings.serial.speed; return GP_OK; }
static int get_file_func (CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, void *data, GPContext *context) { Camera *camera = data; int result = GP_ERROR_IO; enum { START, DATA, ABORT } state; int r, pid = 0, update = 0; uint64_t byteCount = 0; struct utimbuf mod_utime_buf = { 0, 0 }; char *path; struct tf_packet reply; if (type != GP_FILE_TYPE_NORMAL) return GP_ERROR_NOT_SUPPORTED; do_cmd_turbo (camera, "ON", context); path = get_path(camera, folder, filename); r = send_cmd_hdd_file_send(camera, GET, path, context); free (path); if(r < 0) goto out; state = START; while(0 < (r = get_tf_packet(camera, &reply, context))) { update = (update + 1) % 4; switch (get_u32(&reply.cmd)) { case DATA_HDD_FILE_START: if(state == START) { struct typefile *tf = (struct typefile *) reply.data; byteCount = get_u64(&tf->size); pid = gp_context_progress_start (context, byteCount, _("Downloading %s..."), filename); mod_utime_buf.actime = mod_utime_buf.modtime = tfdt_to_time(&tf->stamp); send_success(camera,context); state = DATA; } else { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unexpected DATA_HDD_FILE_START packet in state %d\n", state); send_cancel(camera,context); state = ABORT; } break; case DATA_HDD_FILE_DATA: if(state == DATA) { uint64_t offset = get_u64(reply.data); uint16_t dataLen = get_u16(&reply.length) - (PACKET_HEAD_SIZE + 8); int w; if (!update) { /* avoid doing it too often */ gp_context_progress_update (context, pid, offset + dataLen); if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) { send_cancel(camera,context); state = ABORT; } } if(r < get_u16(&reply.length)) { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Short packet %d instead of %d\n", r, get_u16(&reply.length)); /* TODO: Fetch the rest of the packet */ } w = gp_file_append (file, (char*)&reply.data[8], dataLen); if(w < GP_OK) { /* Can't write data - abort transfer */ gp_log (GP_LOG_ERROR, "topfield", "ERROR: Can not write data: %d\n", w); send_cancel(camera,context); state = ABORT; } } else { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unexpected DATA_HDD_FILE_DATA packet in state %d\n", state); send_cancel(camera,context); state = ABORT; } break; case DATA_HDD_FILE_END: send_success(camera,context); result = GP_OK; goto out; break; case FAIL: gp_log (GP_LOG_ERROR, "topfield", "ERROR: Device reports %s\n", decode_error(&reply)); send_cancel(camera,context); state = ABORT; break; case SUCCESS: goto out; break; default: gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unhandled packet (cmd 0x%x)\n", get_u32(&reply.cmd)); break; } } if (pid) gp_context_progress_stop (context, pid); out: do_cmd_turbo (camera, "OFF", context); return result; }
int gp_port_library_list (GPPortInfoList *list) { GPPortInfo info; int nrofdevices = 0; int d, i, i1, i2, unknownint; /* generic matcher. This will catch passed XXX,YYY entries for instance. */ info.type = GP_PORT_USB; strcpy (info.name, ""); strcpy (info.path, "^usb:"); CHECK (gp_port_info_list_append (list, info)); libusb_init (NULL); gp_nrofdevs = load_devicelist (NULL); for (d = 0; d < gp_nrofdevs; d++) { /* Devices which are definitely not cameras. */ if ( (gp_descs[d].bDeviceClass == LIBUSB_CLASS_HUB) || (gp_descs[d].bDeviceClass == LIBUSB_CLASS_HID) || (gp_descs[d].bDeviceClass == LIBUSB_CLASS_PRINTER) || (gp_descs[d].bDeviceClass == LIBUSB_CLASS_COMM) || (gp_descs[d].bDeviceClass == 0xe0) /* wireless / bluetooth */ ) continue; /* excepts HUBs, usually the interfaces have the classes, not * the device */ unknownint = 0; for (i = 0; i < gp_descs[d].bNumConfigurations; i++) { struct libusb_config_descriptor *config; int ret; ret = libusb_get_config_descriptor (gp_devs[d], i, &config); if (ret) { 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 < gp_nrofdevs; d++) { /* Devices which are definitely not cameras. */ if ( (gp_descs[d].bDeviceClass == LIBUSB_CLASS_HUB) || (gp_descs[d].bDeviceClass == LIBUSB_CLASS_HID) || (gp_descs[d].bDeviceClass == LIBUSB_CLASS_PRINTER) || (gp_descs[d].bDeviceClass == LIBUSB_CLASS_COMM) ) continue; /* excepts HUBs, usually the interfaces have the classes, not * the device */ unknownint = 0; for (i = 0; i < gp_descs[d].bNumConfigurations; i++) { struct libusb_config_descriptor *config; int ret; ret = libusb_get_config_descriptor (gp_devs[d], i, &config); if (ret) { gp_log (GP_LOG_ERROR, "libusb1", "libusb_get_config_descriptor(%d) returned %d", d, ret); 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. */ info.type = GP_PORT_USB; strcpy (info.name, "Universal Serial Bus"); snprintf (info.path,sizeof(info.path), "usb:%03d,%03d", libusb_get_bus_number (gp_devs[d]), libusb_get_device_address (gp_devs[d]) ); CHECK (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) { info.type = GP_PORT_USB; strcpy (info.name, "Universal Serial Bus"); strcpy (info.path, "usb:"); CHECK (gp_port_info_list_append (list, info)); } libusb_exit (NULL); return (GP_OK); }
static int gp_port_usb_find_device_lib(GPPort *port, int idvendor, int idproduct) { char *s; int d, busnr = 0, devnr = 0; GPPortPrivateLibrary *pl; if (!port) return (GP_ERROR_BAD_PARAMETERS); 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 ret; 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 (GP_LOG_VERBOSE, "libusb1", "Looking for USB device " "(vendor 0x%x, product 0x%x)... found.", idvendor, idproduct); /* Use the first config, interface and altsetting we find */ gp_port_usb_find_first_altsetting(pl->devs[d], &config, &interface, &altsetting); ret = libusb_get_config_descriptor (pl->devs[d], config, &confdesc); if (ret) continue; /* Set the defaults */ if (confdesc->interface[interface].altsetting[altsetting].bInterfaceClass == LIBUSB_CLASS_MASS_STORAGE) { gp_log (GP_LOG_VERBOSE, "libusb1", _("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_port_usb_find_ep(pl->devs[d], config, interface, altsetting, LIBUSB_ENDPOINT_IN, LIBUSB_TRANSFER_TYPE_BULK); port->settings.usb.outep = gp_port_usb_find_ep(pl->devs[d], config, interface, altsetting, LIBUSB_ENDPOINT_OUT, LIBUSB_TRANSFER_TYPE_BULK); port->settings.usb.intep = gp_port_usb_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 (GP_LOG_VERBOSE, "libusb1", "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 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_port_usb_match_mtp_device(struct usb_device *dev,int *configno, int *interfaceno, int *altsettingno) { 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 ((dev->descriptor.bDeviceClass!=0xff) && (dev->descriptor.bDeviceClass!=0)) return 0; #endif if (dev->config) { xifaces = xnocamifaces = 0; for (i = 0; i < dev->descriptor.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 == USB_CLASS_HID) || (intf->bInterfaceClass == USB_CLASS_PRINTER) || (intf->bInterfaceClass == USB_CLASS_AUDIO) || (intf->bInterfaceClass == USB_CLASS_HUB) || (intf->bInterfaceClass == USB_CLASS_COMM) || (intf->bInterfaceClass == 0xe0) /* wireless/bluetooth*/ ) xnocamifaces++; } } } } if (xifaces == xnocamifaces) /* only non-camera ifaces */ return 0; /* Marcus: Avoid this probing altogether, its too unstable on some devices */ return 0; #if 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). */ for (i = 0; i < dev->descriptor.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 (GP_LOG_DEBUG, "mtp matcher", "Configuration %d, interface %d, altsetting %d:\n", i, j, k); gp_log (GP_LOG_DEBUG, "mtp matcher", " Interface description contains the string \"MTP\"\n"); gp_log (GP_LOG_DEBUG, "mtp matcher", " 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("get_MS_OSD",buf, ret); 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|USB_TYPE_VENDOR, cmd, 0, 4, buf, sizeof(buf), 1000); if (ret == -1) { gp_log (GP_LOG_ERROR, "mtp matcher", "control message says %d\n", ret); goto errout; } if (buf[0] != 0x28) { gp_log (GP_LOG_ERROR, "mtp matcher", "ret is %d, buf[0] is %x\n", ret, buf[0]); goto errout; } if (ret > 0) gp_log_data("get_MS_ExtDesc",buf, ret); if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) { gp_log (GP_LOG_ERROR, "mtp matcher", "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|USB_TYPE_VENDOR, cmd, 0, 5, buf, sizeof(buf), 1000); if (ret == -1) goto errout; if (buf[0] != 0x28) { gp_log (GP_LOG_ERROR, "mtp matcher", "ret is %d, buf[0] is %x\n", ret, buf[0]); goto errout; } if (ret > 0) gp_log_data("get_MS_ExtProp",buf, ret); if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) { gp_log (GP_LOG_ERROR, "mtp matcher", "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 (dev->descriptor.bNumConfigurations > 1) gp_log (GP_LOG_ERROR, "mtp matcher", "The device has %d configurations!\n", dev->descriptor.bNumConfigurations); for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { struct usb_config_descriptor *config = &dev->config[i]; if (config->bNumInterfaces > 1) gp_log (GP_LOG_ERROR, "mtp matcher", "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 (GP_LOG_ERROR, "mtp matcher", "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 }
/** * \brief Send a SCSI command to a port (for usb scsi ports) * * \param port a #GPPort * \param to_dev data direction, set to 1 for a scsi cmd which sends * data to the device, set to 0 for cmds which read data from the dev. * \param cmd buffer holding the command to send * \param cmd_size sizeof cmd buffer * \param sense buffer for returning scsi sense information * \param sense_size sizeof sense buffer * \param data buffer containing informatino to write to the device * (to_dev is 1), or to store data read from the device (to_dev 0). * * Send a SCSI command to a usb scsi port attached device. * * \return a gphoto2 error code **/ int gp_port_send_scsi_cmd (GPPort *port, int to_dev, char *cmd, int cmd_size, char *sense, int sense_size, char *data, int data_size) { int retval; gp_log (GP_LOG_DEBUG, "gphoto2-port", "Sending scsi cmd:"); gp_log_data ("gphoto2-port", cmd, cmd_size); if (to_dev && data_size) { gp_log (GP_LOG_DEBUG, "gphoto2-port", "scsi cmd data:"); gp_log_data ("gphoto2-port", data, data_size); } CHECK_NULL (port); CHECK_INIT (port); memset (sense, 0, sense_size); CHECK_SUPP (port, "send_scsi_cmd", port->pc->ops->send_scsi_cmd); retval = port->pc->ops->send_scsi_cmd (port, to_dev, cmd, cmd_size, sense, sense_size, data, data_size); gp_log (GP_LOG_DEBUG, "gphoto2-port", "scsi cmd result: %d", retval); if (sense[0] != 0) { gp_log (GP_LOG_DEBUG, "gphoto2-port", "sense data:"); gp_log_data ("gphoto2-port", sense, sense_size); /* https://secure.wikimedia.org/wikipedia/en/wiki/Key_Code_Qualifier */ gp_log(GP_LOG_DEBUG, "gphoto2-port","sense decided:"); if ((sense[0]&0x7f)!=0x70) { gp_log(GP_LOG_DEBUG, "gphoto2-port","\tInvalid header."); } gp_log(GP_LOG_DEBUG, "gphoto2-port", "\tCurrent command read filemark: %s",(sense[2]&0x80)?"yes":"no"); gp_log(GP_LOG_DEBUG, "gphoto2-port", "\tEarly warning passed: %s",(sense[2]&0x40)?"yes":"no"); gp_log(GP_LOG_DEBUG, "gphoto2-port", "\tIncorrect blocklengt: %s",(sense[2]&0x20)?"yes":"no"); gp_log(GP_LOG_DEBUG, "gphoto2-port", "\tSense Key: %d",sense[2]&0xf); if (sense[0]&0x80) gp_log(GP_LOG_DEBUG, "gphoto2-port", "\tResidual Length: %d",sense[3]*0x1000000+sense[4]*0x10000+sense[5]*0x100+sense[6]); gp_log(GP_LOG_DEBUG, "gphoto2-port", "\tAdditional Sense Length: %d",sense[7]); gp_log(GP_LOG_DEBUG, "gphoto2-port", "\tAdditional Sense Code: %d",sense[12]); gp_log(GP_LOG_DEBUG, "gphoto2-port", "\tAdditional Sense Code Qualifier: %d",sense[13]); if (sense[15]&0x80) { gp_log(GP_LOG_DEBUG, "gphoto2-port", "\tIllegal Param is in %s",(sense[15]&0x40)?"the CDB":"the Data Out Phase"); if (sense[15]&0x8) { gp_log(GP_LOG_DEBUG, "gphoto2-port", "Pointer at %d, bit %d",sense[16]*256+sense[17],sense[15]&0x7); } } } if (!to_dev && data_size) { gp_log (GP_LOG_DEBUG, "gphoto2-port", "scsi cmd data:"); gp_log_data ("gphoto2-port", data, data_size); } return retval; }
/* * 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_port_usb_update (GPPort *port) { int ret, ifacereleased = FALSE; gp_log (GP_LOG_DEBUG, "libusb", "gp_port_usb_update(old int=%d, conf=%d, alt=%d), (new int=%d, conf=%d, alt=%d)", port->settings.usb.interface, port->settings.usb.config, port->settings.usb.altsetting, port->settings_pending.usb.interface, port->settings_pending.usb.config, port->settings_pending.usb.altsetting ); if (!port) return GP_ERROR_BAD_PARAMETERS; #if 0 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; #endif /* 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) return GP_ERROR_BAD_PARAMETERS; 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 (GP_LOG_DEBUG, "libusb", "changing interface %d -> %d", port->pl->interface, port->settings.usb.interface ); if (usb_release_interface (port->pl->dh, port->pl->interface) < 0) { gp_log (GP_LOG_DEBUG, "gphoto2-port-usb","releasing the iface for config failed."); /* Not a hard error for now. -Marcus */ } else { gp_log (GP_LOG_DEBUG,"libusb","claiming interface %d", port->settings.usb.interface); ret = usb_claim_interface (port->pl->dh, port->settings.usb.interface); if (ret < 0) { gp_log (GP_LOG_DEBUG, "gphoto2-port-usb","reclaiming the iface for config failed."); return GP_ERROR_IO_UPDATE; } port->pl->interface = port->settings.usb.interface; } } if (port->settings.usb.config != port->pl->config) { gp_log (GP_LOG_DEBUG, "libusb", "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 (usb_release_interface (port->pl->dh, port->settings.usb.interface) < 0) { gp_log (GP_LOG_DEBUG, "gphoto2-port-usb","releasing the iface for config failed."); ifacereleased = FALSE; } else { ifacereleased = TRUE; } ret = usb_set_configuration(port->pl->dh, port->settings.usb.config); if (ret < 0) { #if 0 /* setting the configuration failure is not fatal */ gp_port_set_error (port, _("Could not set config %d/%d (%m)"), port->settings.usb.interface, port->settings.usb.config); return GP_ERROR_IO_UPDATE; #endif gp_log (GP_LOG_ERROR, "gphoto2-port-usb","setting configuration from %d to %d failed with ret = %d, but continue...", port->pl->config, port->settings.usb.config, ret); } gp_log (GP_LOG_DEBUG, "gphoto2-port-usb", "Changed usb.config from %d to %d", port->pl->config, port->settings.usb.config); if (ifacereleased) { gp_log (GP_LOG_DEBUG,"libusb","claiming interface %d", port->settings.usb.interface); ret = usb_claim_interface (port->pl->dh, port->settings.usb.interface); if (ret < 0) { gp_log (GP_LOG_DEBUG, "gphoto2-port-usb","reclaiming the iface for config failed."); } } /* * Copy at once if something else fails so that this * does not get re-applied */ port->pl->config = port->settings.usb.config; } /* This can be changed with interface claimed. (And I think it must be claimed.) */ if (port->settings.usb.altsetting != port->pl->altsetting) { ret = usb_set_altinterface(port->pl->dh, port->settings.usb.altsetting); if (ret < 0) { gp_port_set_error (port, _("Could not set altsetting from %d " "to %d (%m)"), port->pl->altsetting, port->settings.usb.altsetting); return GP_ERROR_IO_UPDATE; } gp_log (GP_LOG_DEBUG, "gphoto2-port-usb", "Changed usb.altsetting from %d to %d", port->pl->altsetting, port->settings.usb.altsetting); port->pl->altsetting = port->settings.usb.altsetting; } return GP_OK; }
static int gp_port_usb_find_device_lib(GPPort *port, int idvendor, int idproduct) { struct usb_bus *bus; struct usb_device *dev; char *s; char busname[64], devname[64]; if (!port) return (GP_ERROR_BAD_PARAMETERS); s = strchr (port->settings.usb.port,':'); busname[0] = devname[0] = '\0'; if (s && (s[1] != '\0')) { /* usb:%d,%d */ strncpy(busname,s+1,sizeof(busname)); busname[sizeof(busname)-1] = '\0'; s = strchr(busname,','); if (s) { strncpy(devname, s+1,sizeof(devname)); devname[sizeof(devname)-1] = '\0'; *s = '\0'; } else { busname[0] = '\0'; } } /* * NULL idvendor is not valid. * NULL 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; } for (bus = usb_busses; bus; bus = bus->next) { if ((busname[0] != '\0') && strcmp(busname, bus->dirname)) continue; for (dev = bus->devices; dev; dev = dev->next) { if ( (devname[0] != '\0') && (dev->filename != strstr(dev->filename, devname)) ) continue; if ((dev->descriptor.idVendor == idvendor) && (dev->descriptor.idProduct == idproduct)) { int config = -1, interface = -1, altsetting = -1; port->pl->d = dev; gp_log (GP_LOG_VERBOSE, "gphoto2-port-usb", "Looking for USB device " "(vendor 0x%x, product 0x%x)... found.", idvendor, idproduct); /* Use the first config, interface and altsetting we find */ gp_port_usb_find_first_altsetting(dev, &config, &interface, &altsetting); /* Set the defaults */ if (dev->config) { int i; if (dev->config[config].interface[interface].altsetting[altsetting].bInterfaceClass == USB_CLASS_MASS_STORAGE) { gp_log (GP_LOG_VERBOSE, "gphoto2-port-usb", _("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 = dev->config[config].bConfigurationValue; port->settings.usb.interface = dev->config[config].interface[interface].altsetting[altsetting].bInterfaceNumber; port->settings.usb.altsetting = dev->config[config].interface[interface].altsetting[altsetting].bAlternateSetting; port->settings.usb.inep = gp_port_usb_find_ep(dev, config, interface, altsetting, USB_ENDPOINT_IN, USB_ENDPOINT_TYPE_BULK); port->settings.usb.outep = gp_port_usb_find_ep(dev, config, interface, altsetting, USB_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK); port->settings.usb.intep = gp_port_usb_find_ep(dev, config, interface, altsetting, USB_ENDPOINT_IN, USB_ENDPOINT_TYPE_INTERRUPT); port->settings.usb.maxpacketsize = 0; gp_log (GP_LOG_DEBUG, "gphoto2-port-usb", "inep to look for is %02x", port->settings.usb.inep); for (i=0;i<dev->config[config].interface[interface].altsetting[altsetting].bNumEndpoints;i++) { if (port->settings.usb.inep == dev->config[config].interface[interface].altsetting[altsetting].endpoint[i].bEndpointAddress) { port->settings.usb.maxpacketsize = dev->config[config].interface[interface].altsetting[altsetting].endpoint[i].wMaxPacketSize; break; } } gp_log (GP_LOG_VERBOSE, "gphoto2-port-usb", "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, dev->config[config].interface[interface].altsetting[altsetting].bInterfaceClass, dev->config[config].interface[interface].altsetting[altsetting].bInterfaceSubClass ); } 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; }
GPPortType gp_port_library_type (void) { gp_log(GP_LOG_DEBUG,__FUNCTION__,"()"); return GP_PORT_USB; }
static int gp_port_vusb_update (GPPort *port) { gp_log(GP_LOG_DEBUG,__FUNCTION__,"()"); return GP_OK; }
static int gp_port_vusb_read(GPPort *port, char *bytes, int size) { gp_log(GP_LOG_DEBUG,__FUNCTION__,"()"); return port->pl->vcamera->read(port->pl->vcamera, 0x81, (unsigned char*)bytes, size); }
/** * Get list of supported cameras, walk through it and create some output. */ int main (int argc, char *argv[]) { CameraAbilitiesList *al; int i; int count; const char *fmt_str = NULL; parse_command_line (argc, argv); if (do_debug) { gettimeofday (&glob_tv_zero, NULL); CHECK (gp_log_add_func (GP_LOG_ALL, debug_func, NULL)); gp_log (GP_LOG_DEBUG, "main", "test-camera-list start"); } CHECK (gp_abilities_list_new (&al)); CHECK (gp_abilities_list_load (al, NULL)); count = gp_abilities_list_count (al); if (count < 0) { printf("gp_abilities_list_count error: %d\n", count); return(1); } else if (count == 0) { /* Copied from gphoto2-abilities-list.c gp_abilities_list_load() */ const char *camlib_env = getenv(CAMLIBDIR_ENV); const char *camlibs = (camlib_env != NULL)?camlib_env:CAMLIBS; printf("no camera drivers (camlibs) found in camlib dir:\n" " CAMLIBS='%s', default='%s', used=%s\n", camlib_env?camlib_env:"(null)", CAMLIBS, (camlib_env!=NULL)?"CAMLIBS":"default"); return(1); } /* Set output format for file body, * and print opening part of output file. */ switch (format) { case FMT_CSV: fmt_str = "%d,%s,%s,%s\n"; break; case FMT_FLAT_TEXT: fmt_str = "%3d|%-20s|%-20s|%s\n"; break; case FMT_HEADED_TEXT: fmt_str = "%3d|%-20s|%-20s|%s\n"; break; case FMT_XML: fmt_str = " <camera name=\"%4$s\" entry_number=\"%1$d\">\n" " <camlib-name value=\"%2$s\"/>\n" " <driver-name value=\"%3$s\"/>\n" " </camera>\n"; printf("<?xml version=\"%s\" encoding=\"%s\"?>\n" "<camera-list camera-count=\"%d\">\n", "1.0", "us-ascii", count); break; case FMT_FLAT_CAMLIBS: fmt_str = "%2$-28s %3$s\n"; break; case FMT_COUNT: printf("%d\n", count); return(0); break; } /* For each camera in the list, add a text snippet to the * output file. */ for (i = 0; i < count; i++) { CameraAbilities abilities; const char *camlib_basename; CHECK (gp_abilities_list_get_abilities (al, i, &abilities)); camlib_basename = path_basename(abilities.library); switch (format) { case FMT_HEADED_TEXT: if ( ((i%25)== 0) && ( (i==0) || ((count-i) > 5) ) ) { print_hline(); print_headline(); print_hline(); } break; case FMT_FLAT_CAMLIBS: break; case FMT_XML: break; case FMT_CSV: break; case FMT_FLAT_TEXT: break; case FMT_COUNT: break; } printf(fmt_str, i+1, camlib_basename, abilities.id, abilities.model); } /* Print closing part of output file. */ switch (format) { case FMT_HEADED_TEXT: print_hline(); print_headline(); print_hline(); break; case FMT_FLAT_CAMLIBS: break; case FMT_XML: printf("</camera-list>\n"); break; case FMT_CSV: break; case FMT_FLAT_TEXT: break; case FMT_COUNT: break; } CHECK (gp_abilities_list_free (al)); return (0); }
/** * \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) { GPPortLibraryOperations ops_func; CHECK_NULL (port); if (port->pc->info.name) free (port->pc->info.name); port->pc->info.name = strdup (info->name); if (port->pc->info.path) free (port->pc->info.path); port->pc->info.path = strdup (info->path); port->pc->info.type = info->type; if (port->pc->info.library_filename) free (port->pc->info.library_filename); 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) { lt_dlclose (port->pc->lh); lt_dlexit (); } lt_dlinit (); port->pc->lh = lt_dlopenext (info->library_filename); if (!port->pc->lh) { gp_log (GP_LOG_ERROR, "gphoto2-port", _("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 (GP_LOG_ERROR, "gphoto2-port", _("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: 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; } gp_port_set_settings (port, port->settings); return (GP_OK); }
/* * Function that downloads image * * Camera camera : camera structure * int index : image index ( in gphoto point of view) -1 for real index * char* toc : pointer to toc * char** img_buf : returned image data * int* img_size : returned image data size * */ static int enigma13_download_img(Camera *camera, char *toc, int index, char **img_data, int *img_size) { uint8_t *p; uint32_t file_size = 0, aligned_size = 0; char* buf=NULL; int align=0; char retbuf[2]; gp_log(GP_LOG_DEBUG, "enigma13","DOWNLOADING IMAGE NO %d",index); /* Offset for image informations . Each image has 16 bytes for name and 16 for size, and others*/ p = toc + (index*2)*32; /* real size from toc*/ aligned_size = file_size = (p[0x1c] & 0xff) + (p[0x1d] & 0xff) * 0x100 + (p[0x1e] & 0xff) * 0x10000; CHECK (gp_port_usb_msg_read (camera->port, 0x23, 0x0000, 0x64, retbuf, 0x01)); if (retbuf[0]==0x20){ align=ENIGMA13_BLK_CARD_ALIGN; gp_log(GP_LOG_DEBUG, "enigma13"," Image from card, alignement is set to %d bytes ",align); } else if (retbuf[0]==0x10){ align=ENIGMA13_BLK_FLASH_ALIGN; gp_log(GP_LOG_DEBUG, "enigma13"," Image from flash, alignement is set to %d bytes",align); } else { return GP_ERROR; } if (file_size % align != 0) aligned_size = ((file_size / align) + 1) * align; buf = (char*) malloc (aligned_size); if (!buf) return GP_ERROR_NO_MEMORY; CHECK_AND_FREE (gp_port_usb_msg_write (camera->port, 0x54, index+1, 2, NULL, 0x00), buf); GP_SYSTEM_SLEEP(ENIGMA13_WAIT_IMAGE_READY_MS); CHECK_AND_FREE (gp_port_usb_msg_read (camera->port, 0x21, 0x0000, 0x0000, buf, 0x01), buf); if (buf[0]!=0x41) { free (buf); return GP_ERROR; } CHECK_AND_FREE (gp_port_usb_msg_read (camera->port, 0x21, 0x0000, 0x0002, buf, 0x01), buf); if (buf[0]!=0x01) { free (buf); return GP_ERROR; } CHECK_AND_FREE (gp_port_usb_msg_read (camera->port, 0x21, 0x0000, 0x0002, buf, 0x01), buf); if (buf[0]!=0x01) { free (buf); return GP_ERROR; } gp_log(GP_LOG_DEBUG, "enigma13","READY FOR TRANSFER"); CHECK_AND_FREE (gp_port_read (camera->port, buf, aligned_size), buf); *img_data=buf; *img_size=file_size; return GP_OK; }
/** * \brief Log data * \brief domain the domain * \brief data the data to be logged * \brief size the size of the data * * Takes the data and creates a formatted hexdump string. If you would like * to log text messages, use #gp_log instead. **/ void gp_log_data (const char *domain, const char *data, unsigned int size) { static const char hexchars[16] = "0123456789abcdef"; char *curline, *result; int x = HEXDUMP_INIT_X; int y = HEXDUMP_INIT_Y; unsigned int index; unsigned char value; if (!data) { gp_log (GP_LOG_DATA, domain, _("No hexdump (NULL buffer)")); return; } if (!size) { gp_log (GP_LOG_DATA, domain, _("Empty hexdump of empty buffer")); return; } if (size > 1024*1024) { /* Does not make sense for 200 MB movies */ gp_log (GP_LOG_DATA, domain, _("Truncating dump from %d bytes to 1MB"), size); size = 1024*1024; } curline = result = malloc ((HEXDUMP_LINE_WIDTH+1)*(((size-1)/16)+1)+1); if (!result) { gp_log (GP_LOG_ERROR, "gphoto2-log", _("Malloc for %i bytes " "failed"), (HEXDUMP_LINE_WIDTH+1)*(((size-1)/16)+1)+1); return; } for (index = 0; index < size; ++index) { value = (unsigned char)data[index]; curline[x] = hexchars[value >> 4]; curline[x+1] = hexchars[value & 0xf]; curline[x+2] = ' '; curline[y++] = ((value>=32)&&(value<127))?value:'.'; x += 3; if ((index & 0xf) == 0xf) { /* end of line */ x = HEXDUMP_INIT_X; y = HEXDUMP_INIT_Y; HEXDUMP_COMPLETE_LINE; } } if ((index & 0xf) != 0) { /* not at end of line yet? */ /* if so, complete this line */ while (y < HEXDUMP_INIT_Y + 16) { curline[x+0] = ' '; curline[x+1] = ' '; curline[x+2] = ' '; curline[y++] = ' '; x += 3; } HEXDUMP_COMPLETE_LINE; } curline[0] = '\0'; gp_log (GP_LOG_DATA, domain, _("Hexdump of %i = 0x%x bytes follows:\n%s"), size, size, result); free (result); }
static int gp_port_usb_open (GPPort *port) { int ret; gp_log (GP_LOG_DEBUG,"libusb1","gp_port_usb_open()"); if (!port || !port->pl->d) return GP_ERROR_BAD_PARAMETERS; ret = libusb_open (port->pl->d, &port->pl->dh); if (ret) { gp_log (GP_LOG_ERROR, "libusb1", "libusb_open returned %d", ret); return 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 (GP_LOG_DEBUG,"libusb1",_("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: if (errno != ENODATA) /* ENODATA - just no driver there */ gp_port_set_error (port, _("Could not query kernel driver of device.")); } gp_log (GP_LOG_DEBUG,"libusb1","claiming interface %d", port->settings.usb.interface); ret = libusb_claim_interface (port->pl->dh, port->settings.usb.interface); if (ret < 0) { int saved_errno = errno; gp_port_set_error (port, _("Could not claim interface %d (%s). " "Make sure no other program " "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), "sdc2xx, stv680, spca50x"); return GP_ERROR_IO_USB_CLAIM; } return GP_OK; }
static int gp_port_usb_find_path_lib(GPPort *port) { char *s; int d, busnr = 0, devnr = 0; GPPortPrivateLibrary *pl; if (!port) return (GP_ERROR_BAD_PARAMETERS); 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) return GP_ERROR_BAD_PARAMETERS; } else { return GP_ERROR_BAD_PARAMETERS; } pl->nrofdevs = load_devicelist (port->pl); for (d = 0; d < pl->nrofdevs; d++) { struct libusb_config_descriptor *confdesc; int ret; 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 (GP_LOG_VERBOSE, "libusb1", "Found path %s", port->settings.usb.port); /* Use the first config, interface and altsetting we find */ gp_port_usb_find_first_altsetting(pl->devs[d], &config, &interface, &altsetting); ret = libusb_get_config_descriptor (pl->devs[d], config, &confdesc); if (ret) 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_port_usb_find_ep(pl->devs[d], config, interface, altsetting, LIBUSB_ENDPOINT_IN, LIBUSB_TRANSFER_TYPE_BULK); port->settings.usb.outep = gp_port_usb_find_ep(pl->devs[d], config, interface, altsetting, LIBUSB_ENDPOINT_OUT, LIBUSB_TRANSFER_TYPE_BULK); port->settings.usb.intep = gp_port_usb_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 (GP_LOG_VERBOSE, "libusb1", "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; }