/** * \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_DATA (cmd, cmd_size, "Sending scsi cmd:"); if (to_dev && data_size) GP_LOG_DATA (data, data_size, "with scsi cmd data:"); C_PARAMS (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_D ("scsi cmd result: %d", retval); if (sense[0] != 0) { GP_LOG_DATA (sense, sense_size, "sense data:"); /* https://secure.wikimedia.org/wikipedia/en/wiki/Key_Code_Qualifier */ GP_LOG_D ("sense decided:"); if ((sense[0]&0x7f)!=0x70) { GP_LOG_D ("\tInvalid header."); } GP_LOG_D ("\tCurrent command read filemark: %s",(sense[2]&0x80)?"yes":"no"); GP_LOG_D ("\tEarly warning passed: %s",(sense[2]&0x40)?"yes":"no"); GP_LOG_D ("\tIncorrect blocklengt: %s",(sense[2]&0x20)?"yes":"no"); GP_LOG_D ("\tSense Key: %d",sense[2]&0xf); if (sense[0]&0x80) GP_LOG_D ("\tResidual Length: %d",sense[3]*0x1000000+sense[4]*0x10000+sense[5]*0x100+sense[6]); GP_LOG_D ("\tAdditional Sense Length: %d",sense[7]); GP_LOG_D ("\tAdditional Sense Code: %d",sense[12]); GP_LOG_D ("\tAdditional Sense Code Qualifier: %d",sense[13]); if (sense[15]&0x80) { GP_LOG_D ("\tIllegal Param is in %s",(sense[15]&0x40)?"the CDB":"the Data Out Phase"); if (sense[15]&0x8) { GP_LOG_D ("Pointer at %d, bit %d",sense[16]*256+sense[17],sense[15]&0x7); } } } if (!to_dev && data_size) GP_LOG_DATA (data, data_size, "scsi cmd data:"); return retval; }
/** * \brief Send a USB control message with output data * * \param port a GPPort * \param request control request code * \param value control value * \param index control index * \param bytes pointer to data * \param size size of the data * * Sends a specific USB control command and write associated data. * * \return a gphoto2 error code */ int gp_port_usb_msg_write (GPPort *port, int request, int value, int index, char *bytes, int size) { int retval; GP_LOG_DATA (bytes, size, "Writing message (request=0x%x value=0x%x index=0x%x size=%i=0x%x):", request, value, index, size, size); C_PARAMS (port); CHECK_INIT (port); CHECK_SUPP (port, "msg_write", port->pc->ops->msg_write); retval = port->pc->ops->msg_write(port, request, value, index, bytes, size); CHECK_RESULT (retval); return (retval); }
static void LIBUSB_CALL _cb_irq(struct libusb_transfer *transfer) { struct _GPPortPrivateLibrary *pl = transfer->user_data; int i; GP_LOG_D("%p with status %d", transfer, transfer->status); if ( (transfer->status == LIBUSB_TRANSFER_CANCELLED) || (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) || /* on close */ (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) /* on removing camera */ ) { /* Only requeue the global transfers, not temporary ones */ for (i = 0; i < sizeof(pl->transfers)/sizeof(pl->transfers[0]); i++) { if (pl->transfers[i] == transfer) { libusb_free_transfer (transfer); pl->transfers[i] = NULL; return; } } return; } if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { GP_LOG_D("transfer %p should be in LIBUSB_TRANSFER_COMPLETED, but is %d!", transfer, transfer->status); return; } if (transfer->actual_length) { GP_LOG_DATA ((char*)transfer->buffer, transfer->actual_length, "interrupt"); pl->irqs = realloc(pl->irqs, sizeof(pl->irqs[0])*(pl->nrofirqs+1)); pl->irqlens = realloc(pl->irqlens, sizeof(pl->irqlens[0])*(pl->nrofirqs+1)); pl->irqlens[pl->nrofirqs] = transfer->actual_length; pl->irqs[pl->nrofirqs] = malloc(transfer->actual_length); memcpy(pl->irqs[pl->nrofirqs],transfer->buffer,transfer->actual_length); pl->nrofirqs++; } GP_LOG_D("requeuing complete transfer %p", transfer); LOG_ON_LIBUSB_E(libusb_submit_transfer(transfer)); return; }
/* 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 }