13aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* 23aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * \file libusb-glue.c 33aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Low-level USB interface glue towards libusb. 43aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 53aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Copyright (C) 2005-2007 Richard A. Low <richard@wentnet.com> 63aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Copyright (C) 2005-2008 Linus Walleij <triad@df.lth.se> 73aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Copyright (C) 2006-2007 Marcus Meissner 83aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Copyright (C) 2007 Ted Bullock 93aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Copyright (C) 2008 Chris Bagwell <chris@cnpbagwell.com> 103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This library is free software; you can redistribute it and/or 123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * modify it under the terms of the GNU Lesser General Public 133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * License as published by the Free Software Foundation; either 143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * version 2 of the License, or (at your option) any later version. 153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This library is distributed in the hope that it will be useful, 173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * but WITHOUT ANY WARRANTY; without even the implied warranty of 183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Lesser General Public License for more details. 203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * You should have received a copy of the GNU Lesser General Public 223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * License along with this library; if not, write to the 233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Boston, MA 02111-1307, USA. 253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Created by Richard Low on 24/12/2005. (as mtp-utils.c) 273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Modified by Linus Walleij 2006-03-06 283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * (Notice that Anglo-Saxons use little-endian dates and Swedes 293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * use big-endian dates.) 303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include "config.h" 333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include "libmtp.h" 343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include "libusb-glue.h" 353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include "device-flags.h" 363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include "util.h" 373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include "ptp.h" 383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include <errno.h> 403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include <stdio.h> 413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include <stdlib.h> 423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include <string.h> 433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include <usb.h> 443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include "ptp-pack.c" 463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* Aha, older libusb does not have USB_CLASS_PTP */ 483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifndef USB_CLASS_PTP 493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define USB_CLASS_PTP 6 503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 52cf0434d3f7db5068cb85ffa96e403518198bf8a5Yavor Goulishev/* libusb dosn't have misc class defined */ 53cf0434d3f7db5068cb85ffa96e403518198bf8a5Yavor Goulishev#ifndef USB_CLASS_MISC 54cf0434d3f7db5068cb85ffa96e403518198bf8a5Yavor Goulishev#define USB_CLASS_MISC 0xEF 55cf0434d3f7db5068cb85ffa96e403518198bf8a5Yavor Goulishev#endif 56cf0434d3f7db5068cb85ffa96e403518198bf8a5Yavor Goulishev 57c1de2578a686fc1a0c2795f6a45159a4e20a4824Yavor Goulishev#define APPLE_VID 0x05ac 58c1de2578a686fc1a0c2795f6a45159a4e20a4824Yavor Goulishev 593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* To enable debug prints for USB stuff, switch on this */ 603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev//#define ENABLE_USB_BULK_DEBUG 613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* Default USB timeout length. This can be overridden as needed 633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * but should start with a reasonable value so most common 643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * requests can be completed. The original value of 4000 was 653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * not long enough for large file transfer. Also, players can 663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * spend a bit of time collecting data. Higher values also 673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * make connecting/disconnecting more reliable. 683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define USB_TIMEOUT_DEFAULT 10000 703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* USB control message data phase direction */ 723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifndef USB_DP_HTD 733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define USB_DP_HTD (0x00 << 7) /* host to device */ 743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifndef USB_DP_DTH 763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define USB_DP_DTH (0x01 << 7) /* device to host */ 773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* USB Feature selector HALT */ 803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifndef USB_FEATURE_HALT 813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define USB_FEATURE_HALT 0x00 823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* Internal data types */ 853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstruct mtpdevice_list_struct { 863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_device *libusb_device; 873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPParams *params; 883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTP_USB *ptp_usb; 893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint32_t bus_location; 903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct mtpdevice_list_struct *next; 913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev}; 923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevtypedef struct mtpdevice_list_struct mtpdevice_list_t; 933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic const LIBMTP_device_entry_t mtp_device_table[] = { 953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* We include an .h file which is shared between us and libgphoto2 */ 963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#include "music-players.h" 973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev}; 983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic const int mtp_device_table_size = sizeof(mtp_device_table) / sizeof(LIBMTP_device_entry_t); 993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev// Local functions 1013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic struct usb_bus* init_usb(); 1023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic void close_usb(PTP_USB* ptp_usb); 1033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic void find_interface_and_endpoints(struct usb_device *dev, 1043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint8_t *interface, 1053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int* inep, 1063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int* inep_maxpacket, 1073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int* outep, 1083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int* outep_maxpacket, 1093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int* intep); 1103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic void clear_stall(PTP_USB* ptp_usb); 1113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic int init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev); 1123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic short ptp_write_func (unsigned long,PTPDataHandler*,void *data,unsigned long*); 1133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic short ptp_read_func (unsigned long,PTPDataHandler*,void *data,unsigned long*,int); 1143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep); 1153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status); 1163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 1183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Get a list of the supported USB devices. 1193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 1203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * The developers depend on users of this library to constantly 1213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * add in to the list of supported devices. What we need is the 1223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * device name, USB Vendor ID (VID) and USB Product ID (PID). 1233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * put this into a bug ticket at the project homepage, please. 1243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * The VID/PID is used to let e.g. udev lift the device to 1253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * console userspace access when it's plugged in. 1263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 1273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param devices a pointer to a pointer that will hold a device 1283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * list after the call to this function, if it was 1293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * successful. 1303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param numdevs a pointer to an integer that will hold the number 1313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * of devices in the device list if the call was successful. 1323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @return 0 if the list was successfull retrieved, any other 1333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * value means failure. 1343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 1353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevint LIBMTP_Get_Supported_Devices_List(LIBMTP_device_entry_t ** const devices, int * const numdevs) 1363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 1373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *devices = (LIBMTP_device_entry_t *) &mtp_device_table; 1383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *numdevs = mtp_device_table_size; 1393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 1403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 1413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic struct usb_bus* init_usb() 1443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 1453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_init(); 1463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_find_busses(); 1473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_find_devices(); 1483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return (usb_get_busses()); 1493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 1503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 1523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Small recursive function to append a new usb_device to the linked list of 1533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * USB MTP devices 1543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param devlist dynamic linked list of pointers to usb devices with MTP 1553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * properties, to be extended with new device. 1563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param newdevice the new device to add. 1573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param bus_location bus for this device. 1583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @return an extended array or NULL on failure. 1593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 1603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic mtpdevice_list_t *append_to_mtpdevice_list(mtpdevice_list_t *devlist, 1613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_device *newdevice, 1623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint32_t bus_location) 1633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 1643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev mtpdevice_list_t *new_list_entry; 1653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev new_list_entry = (mtpdevice_list_t *) malloc(sizeof(mtpdevice_list_t)); 1673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (new_list_entry == NULL) { 1683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return NULL; 1693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 1703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Fill in USB device, if we *HAVE* to make a copy of the device do it here. 1713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev new_list_entry->libusb_device = newdevice; 1723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev new_list_entry->bus_location = bus_location; 1733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev new_list_entry->next = NULL; 1743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (devlist == NULL) { 1763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return new_list_entry; 1773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else { 1783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev mtpdevice_list_t *tmp = devlist; 1793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev while (tmp->next != NULL) { 1803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev tmp = tmp->next; 1813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 1823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev tmp->next = new_list_entry; 1833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 1843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return devlist; 1853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 1863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 1883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Small recursive function to free dynamic memory allocated to the linked list 1893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * of USB MTP devices 1903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param devlist dynamic linked list of pointers to usb devices with MTP 1913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * properties. 1923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @return nothing 1933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 1943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic void free_mtpdevice_list(mtpdevice_list_t *devlist) 1953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 1963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev mtpdevice_list_t *tmplist = devlist; 1973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (devlist == NULL) 1993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return; 2003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev while (tmplist != NULL) { 2013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev mtpdevice_list_t *tmp = tmplist; 2023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev tmplist = tmplist->next; 2033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Do not free() the fields (ptp_usb, params)! These are used elsewhere. 2043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev free(tmp); 2053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 2063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return; 2073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 2083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 2093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* Comment out this define to enable the original, more aggressive probing. */ 2103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define MILD_MTP_PROBING 2113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 2123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef MILD_MTP_PROBING 2133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 2143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This checks if a device has an interface with MTP description. 2153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 2163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param dev a device struct from libusb. 2173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param dumpfile set to non-NULL to make the descriptors dump out 2183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * to this file in human-readable hex so we can scruitinze them. 2193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @return 1 if the device is MTP compliant, 0 if not. 2203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 2213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic int probe_device_descriptor(struct usb_device *dev, FILE *dumpfile) 2223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 2233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_dev_handle *devh; 2243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned char buf[1024]; 2253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int i; 2263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int ret; 2273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 2283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 2293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Don't examine devices that are not likely to 2303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * contain any MTP interface, update this the day 2313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * you find some weird combination... 2323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 2333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (!(dev->descriptor.bDeviceClass == USB_CLASS_PER_INTERFACE || 234c1de2578a686fc1a0c2795f6a45159a4e20a4824Yavor Goulishev dev->descriptor.bDeviceClass == USB_CLASS_PTP || 235c1de2578a686fc1a0c2795f6a45159a4e20a4824Yavor Goulishev dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC) || 236c1de2578a686fc1a0c2795f6a45159a4e20a4824Yavor Goulishev /* Apple devices sometimes freeze when probed by libusb */ 237c1de2578a686fc1a0c2795f6a45159a4e20a4824Yavor Goulishev dev->descriptor.idVendor == APPLE_VID) { 2383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 2393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 2403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 2413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Attempt to open Device on this port */ 2423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev devh = usb_open(dev); 2433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (devh == NULL) { 2443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Could not open this device */ 2453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 2463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 2473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 2483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 2493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This sometimes crashes on the j for loop below 2503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * I think it is because config is NULL yet 2513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * dev->descriptor.bNumConfigurations > 0 2523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * this check should stop this 2533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 2543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dev->config) { 2553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 2563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Loop over the interfaces, and check for string "MTP" 2573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * in the descriptions. 2583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 2593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 2603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { 2613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint8_t j; 2623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 2633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (j = 0; j < dev->config[i].bNumInterfaces; j++) { 2643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int k; 2653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (k = 0; k < dev->config[i].interface[j].num_altsetting; k++) { 2663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Current interface descriptor */ 2673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_interface_descriptor *intf = 2683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &dev->config[i].interface[j].altsetting[k]; 2693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 2703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev buf[0] = '\0'; 2713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_get_string_simple(devh, 2723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->config[i].interface[j].altsetting[k].iInterface, 2733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (char *) buf, 2743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1024); 2753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 2763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret < 3) 2773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev continue; 2783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (strcmp((char *) buf, "MTP") == 0) { 2793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dumpfile != NULL) { 2803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(dumpfile, "Configuration %d, interface %d, altsetting %d:\n", i, j, k); 2813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(dumpfile, " Interface description contains the string \"MTP\"\n"); 2823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(dumpfile, " Device recognized as MTP, no further probing.\n"); 2833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 2843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_close(devh); 2853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 1; 2863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 2873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 2883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 2893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 2903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 2913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 292afc55a0d0657e4e12b17ea4bac5472c0f17d338aYavor Goulishev usb_close(devh); 2933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 2943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 2953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 2963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#else /* MILD_MTP_PROBING */ 2973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 2983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This checks if a device has an MTP descriptor. The descriptor was 2993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * elaborated about in gPhoto bug 1482084, and some official documentation 3003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * with no strings attached was published by Microsoft at 3013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * http://www.microsoft.com/whdc/system/bus/USB/USBFAQ_intermed.mspx#E3HAC 3023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 3033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param dev a device struct from libusb. 3043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param dumpfile set to non-NULL to make the descriptors dump out 3053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * to this file in human-readable hex so we can scruitinze them. 3063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @return 1 if the device is MTP compliant, 0 if not. 3073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 3083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic int probe_device_descriptor(struct usb_device *dev, FILE *dumpfile) 3093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 3103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_dev_handle *devh; 3113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned char buf[1024], cmd; 3123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int i; 3133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int ret; 3143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 3153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Don't examine hubs (no point in that) */ 3163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dev->descriptor.bDeviceClass == USB_CLASS_HUB) { 3173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 3183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 3193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 3203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Attempt to open Device on this port */ 3213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev devh = usb_open(dev); 3223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (devh == NULL) { 3233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Could not open this device */ 3243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 3253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 3263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 3273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 3283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This sometimes crashes on the j for loop below 3293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * I think it is because config is NULL yet 3303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * dev->descriptor.bNumConfigurations > 0 3313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * this check should stop this 3323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 3333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dev->config) { 3343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 3353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Loop over the device configurations and interfaces. Nokia MTP-capable 3363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * handsets (possibly others) typically have the string "MTP" in their 3373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * MTP interface descriptions, that's how they can be detected, before 3383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * we try the more esoteric "OS descriptors" (below). 3393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 3403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { 3413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint8_t j; 3423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 3433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (j = 0; j < dev->config[i].bNumInterfaces; j++) { 3443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int k; 3453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (k = 0; k < dev->config[i].interface[j].num_altsetting; k++) { 3463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Current interface descriptor */ 3473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_interface_descriptor *intf = 3483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &dev->config[i].interface[j].altsetting[k]; 3493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 3503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 3513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev buf[0] = '\0'; 3523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_get_string_simple(devh, 3533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->config[i].interface[j].altsetting[k].iInterface, 3543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (char *) buf, 3553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 1024); 3563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret < 3) 3573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev continue; 3583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (strcmp((char *) buf, "MTP") == 0) { 3593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dumpfile != NULL) { 3603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(dumpfile, "Configuration %d, interface %d, altsetting %d:\n", i, j, k); 3613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(dumpfile, " Interface description contains the string \"MTP\"\n"); 3623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(dumpfile, " Device recognized as MTP, no further probing.\n"); 3633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 3643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_close(devh); 3653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 1; 3663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 3673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev #ifdef LIBUSB_HAS_GET_DRIVER_NP 3683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev { 3693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 3703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Specifically avoid probing anything else than USB mass storage devices 3713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * and non-associated drivers in Linux. 3723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 3733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev char devname[0x10]; 3743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 3753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev devname[0] = '\0'; 3763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_get_driver_np(devh, 3773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->config[i].interface[j].altsetting[k].iInterface, 3783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev devname, 3793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev sizeof(devname)); 3803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (devname[0] != '\0' && strcmp(devname, "usb-storage")) { 3813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("avoid probing device using kernel interface \"%s\"\n", devname); 3823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 3833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 3843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 3853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev #endif 3863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 3873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 3883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 3893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else { 3903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dev->descriptor.bNumConfigurations) 3913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("dev->config is NULL in probe_device_descriptor yet dev->descriptor.bNumConfigurations > 0\n"); 3923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 3933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 3943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Read the special descriptor */ 3953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_get_descriptor(devh, 0x03, 0xee, buf, sizeof(buf)); 3963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 3973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Dump it, if requested 3983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dumpfile != NULL && ret > 0) { 3993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(dumpfile, "Microsoft device descriptor 0xee:\n"); 4003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev data_dump_ascii(dumpfile, buf, ret, 16); 4013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 4023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Check if descriptor length is at least 10 bytes */ 4043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret < 10) { 4053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_close(devh); 4063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 4073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 4083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Check if this device has a Microsoft Descriptor */ 4103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (!((buf[2] == 'M') && (buf[4] == 'S') && 4113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (buf[6] == 'F') && (buf[8] == 'T'))) { 4123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_close(devh); 4133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 4143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 4153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Check if device responds to control message 1 or if there is an error */ 4173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev cmd = buf[16]; 4183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_control_msg (devh, 4193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev USB_ENDPOINT_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 4203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev cmd, 4213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 0, 4223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4, 4233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (char *) buf, 4243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev sizeof(buf), 4253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev USB_TIMEOUT_DEFAULT); 4263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Dump it, if requested 4283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dumpfile != NULL && ret > 0) { 4293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(dumpfile, "Microsoft device response to control message 1, CMD 0x%02x:\n", cmd); 4303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev data_dump_ascii(dumpfile, buf, ret, 16); 4313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 4323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* If this is true, the device either isn't MTP or there was an error */ 4343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret <= 0x15) { 4353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* TODO: If there was an error, flag it and let the user know somehow */ 4363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* if(ret == -1) {} */ 4373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_close(devh); 4383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 4393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 4403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Check if device is MTP or if it is something like a USB Mass Storage 4423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev device with Janus DRM support */ 4433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) { 4443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_close(devh); 4453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 4463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 4473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* After this point we are probably dealing with an MTP device */ 4493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Check if device responds to control message 2 or if there is an error*/ 4513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_control_msg (devh, 4523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev USB_ENDPOINT_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 4533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev cmd, 4543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 0, 4553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 5, 4563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (char *) buf, 4573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev sizeof(buf), 4583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev USB_TIMEOUT_DEFAULT); 4593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Dump it, if requested 4613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dumpfile != NULL && ret > 0) { 4623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(dumpfile, "Microsoft device response to control message 2, CMD 0x%02x:\n", cmd); 4633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev data_dump_ascii(dumpfile, buf, ret, 16); 4643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 4653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* If this is true, the device errored against control message 2 */ 4673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret == -1) { 4683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* TODO: Implement callback function to let managing program know there 4693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev was a problem, along with description of the problem */ 4703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "Potential MTP Device with VendorID:%04x and " 4713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "ProductID:%04x encountered an error responding to " 4723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "control message 2.\n" 4733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "Problems may arrise but continuing\n", 4743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->descriptor.idVendor, dev->descriptor.idProduct); 4753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else if (ret <= 0x15) { 4763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* TODO: Implement callback function to let managing program know there 4773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev was a problem, along with description of the problem */ 4783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "Potential MTP Device with VendorID:%04x and " 4793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "ProductID:%04x responded to control message 2 with a " 4803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "response that was too short. Problems may arrise but " 4813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "continuing\n", 4823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->descriptor.idVendor, dev->descriptor.idProduct); 4833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) { 4843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* TODO: Implement callback function to let managing program know there 4853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev was a problem, along with description of the problem */ 4863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "Potential MTP Device with VendorID:%04x and " 4873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "ProductID:%04x encountered an error responding to " 4883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "control message 2\n" 4893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "Problems may arrise but continuing\n", 4903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->descriptor.idVendor, dev->descriptor.idProduct); 4913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 4923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Close the USB device handle */ 4943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_close(devh); 4953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 1; 4963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 4973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif /* MILD_MTP_PROBING */ 4983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 4993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 5003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This function scans through the connected usb devices on a machine and 5013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * if they match known Vendor and Product identifiers appends them to the 5023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * dynamic array mtp_device_list. Be sure to call 5033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * <code>free_mtpdevice_list(mtp_device_list)</code> when you are done 5043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * with it, assuming it is not NULL. 5053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param mtp_device_list dynamic array of pointers to usb devices with MTP 5063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * properties (if this list is not empty, new entries will be appended 5073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * to the list). 5083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @return LIBMTP_ERROR_NONE implies that devices have been found, scan the list 5093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * appropriately. LIBMTP_ERROR_NO_DEVICE_ATTACHED implies that no 5103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * devices have been found. 5113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 5123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic LIBMTP_error_number_t get_mtp_usb_device_list(mtpdevice_list_t ** mtp_device_list) 5133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 5143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_bus *bus = init_usb(); 5153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (; bus != NULL; bus = bus->next) { 5163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_device *dev = bus->devices; 5173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (; dev != NULL; dev = dev->next) { 5183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dev->descriptor.bDeviceClass != USB_CLASS_HUB) { 5193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int i; 5203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int found = 0; 5213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 5223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // First check if we know about the device already. 5233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Devices well known to us will not have their descriptors 5243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // probed, it caused problems with some devices. 5253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for(i = 0; i < mtp_device_table_size; i++) { 5263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if(dev->descriptor.idVendor == mtp_device_table[i].vendor_id && 5273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->descriptor.idProduct == mtp_device_table[i].product_id) { 5283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Append this usb device to the MTP device list */ 5293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *mtp_device_list = append_to_mtpdevice_list(*mtp_device_list, 5303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev, 5313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev bus->location); 5323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev found = 1; 5333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 5343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 5353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 5363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // If we didn't know it, try probing the "OS Descriptor". 5373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (!found) { 5383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (probe_device_descriptor(dev, NULL)) { 5393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Append this usb device to the MTP USB Device List */ 5403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *mtp_device_list = append_to_mtpdevice_list(*mtp_device_list, 5413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev, 5423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev bus->location); 5433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 5443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 5453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * By thomas_-_s: Also append devices that are no MTP but PTP devices 5463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * if this is commented out. 5473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 5483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 5493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev else { 5503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Check whether the device is no USB hub but a PTP. 5513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if ( dev->config != NULL &&dev->config->interface->altsetting->bInterfaceClass == USB_CLASS_PTP && dev->descriptor.bDeviceClass != USB_CLASS_HUB ) { 5523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *mtp_device_list = append_to_mtpdevice_list(*mtp_device_list, dev, bus->location); 5533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 5543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 5553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 5563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 5573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 5583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 5593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 5603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 5613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* If nothing was found we end up here. */ 5623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if(*mtp_device_list == NULL) { 5633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_NO_DEVICE_ATTACHED; 5643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 5653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_NONE; 5663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 5673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 5683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 5693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Detect the raw MTP device descriptors and return a list of 5703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * of the devices found. 5713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 5723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param devices a pointer to a variable that will hold 5733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * the list of raw devices found. This may be NULL 5743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * on return if the number of detected devices is zero. 5753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * The user shall simply <code>free()</code> this 5763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * variable when finished with the raw devices, 5773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * in order to release memory. 5783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param numdevs a pointer to an integer that will hold 5793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * the number of devices in the list. This may 5803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * be 0. 5813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @return 0 if successful, any other value means failure. 5823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 5833aa430dc5437a98734b36f996f9b17081a589143Yavor GoulishevLIBMTP_error_number_t LIBMTP_Detect_Raw_Devices(LIBMTP_raw_device_t ** devices, 5843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int * numdevs) 5853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 5863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev mtpdevice_list_t *devlist = NULL; 5873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev mtpdevice_list_t *dev; 5883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev LIBMTP_error_number_t ret; 5893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev LIBMTP_raw_device_t *retdevs; 5903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int devs = 0; 5913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int i, j; 5923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 5933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = get_mtp_usb_device_list(&devlist); 5943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret == LIBMTP_ERROR_NO_DEVICE_ATTACHED) { 5953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *devices = NULL; 5963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *numdevs = 0; 5973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 5983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else if (ret != LIBMTP_ERROR_NONE) { 5993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "LIBMTP PANIC: get_mtp_usb_device_list() " 6003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "error code: %d on line %d\n", ret, __LINE__); 6013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 6023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 6033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 6043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Get list size 6053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev = devlist; 6063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev while (dev != NULL) { 6073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev devs++; 6083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev = dev->next; 6093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 6103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (devs == 0) { 6113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *devices = NULL; 6123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *numdevs = 0; 6133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_NONE; 6143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 6153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Conjure a device list 6163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs = (LIBMTP_raw_device_t *) malloc(sizeof(LIBMTP_raw_device_t) * devs); 6173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (retdevs == NULL) { 6183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Out of memory 6193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *devices = NULL; 6203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *numdevs = 0; 6213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_MEMORY_ALLOCATION; 6223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 6233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev = devlist; 6243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev i = 0; 6253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev while (dev != NULL) { 6263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int device_known = 0; 6273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 6283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Assign default device info 6293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].device_entry.vendor = NULL; 6303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].device_entry.vendor_id = dev->libusb_device->descriptor.idVendor; 6313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].device_entry.product = NULL; 6323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].device_entry.product_id = dev->libusb_device->descriptor.idProduct; 6333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].device_entry.device_flags = 0x00000000U; 6343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // See if we can locate some additional vendor info and device flags 6353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for(j = 0; j < mtp_device_table_size; j++) { 6363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if(dev->libusb_device->descriptor.idVendor == mtp_device_table[j].vendor_id && 6373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->libusb_device->descriptor.idProduct == mtp_device_table[j].product_id) { 6383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev device_known = 1; 6393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].device_entry.vendor = mtp_device_table[j].vendor; 6403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].device_entry.product = mtp_device_table[j].product; 6413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].device_entry.device_flags = mtp_device_table[j].device_flags; 6423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 6433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef _AFT_BUILD 6443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Disable the following features for all devices. 6453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].device_entry.device_flags |= DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST| 6463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev DEVICE_FLAG_BROKEN_SET_OBJECT_PROPLIST| 6473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev DEVICE_FLAG_BROKEN_SEND_OBJECT_PROPLIST; 6483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 6493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 6503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 6513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // This device is known to the developers 6523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "Device %d (VID=%04x and PID=%04x) is a %s %s.\n", 6533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev i, 6543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->libusb_device->descriptor.idVendor, 6553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->libusb_device->descriptor.idProduct, 6563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev mtp_device_table[j].vendor, 6573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev mtp_device_table[j].product); 6583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 6593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 6603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 6613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 6623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (!device_known) { 6633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // This device is unknown to the developers 6643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "Device %d (VID=%04x and PID=%04x) is UNKNOWN.\n", 6653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev i, 6663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->libusb_device->descriptor.idVendor, 6673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->libusb_device->descriptor.idProduct); 6683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "Please report this VID/PID and the device model to the " 6693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "libmtp development team\n"); 6703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 6713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Trying to get iManufacturer or iProduct from the device at this 6723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * point would require opening a device handle, that we don't want 6733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * to do right now. (Takes time for no good enough reason.) 6743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 6753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 6763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Save the location on the bus 6773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].bus_location = dev->bus_location; 6783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev retdevs[i].devnum = dev->libusb_device->devnum; 6793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev i++; 6803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev = dev->next; 6813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 6823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *devices = retdevs; 6833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *numdevs = i; 6843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev free_mtpdevice_list(devlist); 6853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_NONE; 6863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 6873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 6883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 6893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This routine just dumps out low-level 6903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * USB information about the current device. 6913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param ptp_usb the USB device to get information from. 6923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 6933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevvoid dump_usbinfo(PTP_USB *ptp_usb) 6943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 6953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_device *dev; 6963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 6973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef LIBUSB_HAS_GET_DRIVER_NP 6983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev char devname[0x10]; 6993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int res; 7003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 7013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev devname[0] = '\0'; 7023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev res = usb_get_driver_np(ptp_usb->handle, (int) ptp_usb->interface, devname, sizeof(devname)); 7033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (devname[0] != '\0') { 7043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" Using kernel interface \"%s\"\n", devname); 7053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 7063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 7073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev = usb_device(ptp_usb->handle); 7083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" bcdUSB: %d\n", dev->descriptor.bcdUSB); 7093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" bDeviceClass: %d\n", dev->descriptor.bDeviceClass); 7103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" bDeviceSubClass: %d\n", dev->descriptor.bDeviceSubClass); 7113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" bDeviceProtocol: %d\n", dev->descriptor.bDeviceProtocol); 7123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" idVendor: %04x\n", dev->descriptor.idVendor); 7133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" idProduct: %04x\n", dev->descriptor.idProduct); 7143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" IN endpoint maxpacket: %d bytes\n", ptp_usb->inep_maxpacket); 7153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" OUT endpoint maxpacket: %d bytes\n", ptp_usb->outep_maxpacket); 7163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" Raw device info:\n"); 7173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" Bus location: %d\n", ptp_usb->rawdevice.bus_location); 7183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" Device number: %d\n", ptp_usb->rawdevice.devnum); 7193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" Device entry info:\n"); 7203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" Vendor: %s\n", ptp_usb->rawdevice.device_entry.vendor); 7213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" Vendor id: 0x%04x\n", ptp_usb->rawdevice.device_entry.vendor_id); 7223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" Product: %s\n", ptp_usb->rawdevice.device_entry.product); 7233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" Vendor id: 0x%04x\n", ptp_usb->rawdevice.device_entry.product_id); 7243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf(" Device flags: 0x%08x\n", ptp_usb->rawdevice.device_entry.device_flags); 7253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (void) probe_device_descriptor(dev, stdout); 7263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 7273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 7283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 7293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Retrieve the apropriate playlist extension for this 7303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * device. Rather hacky at the moment. This is probably 7313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * desired by the managing software, but when creating 7323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * lists on the device itself you notice certain preferences. 7333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param ptp_usb the USB device to get suggestion for. 7343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @return the suggested playlist extension. 7353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 7363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevconst char *get_playlist_extension(PTP_USB *ptp_usb) 7373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 7383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_device *dev; 7393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev static char creative_pl_extension[] = ".zpl"; 7403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev static char default_pl_extension[] = ".pla"; 7413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 7423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev = usb_device(ptp_usb->handle); 7433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dev->descriptor.idVendor == 0x041e) { 7443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return creative_pl_extension; 7453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 7463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return default_pl_extension; 7473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 7483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 7493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic void 7503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevlibusb_glue_debug (PTPParams *params, const char *format, ...) 7513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 7523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev va_list args; 7533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 7543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev va_start (args, format); 7553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (params->debug_func!=NULL) 7563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->debug_func (params->data, format, args); 7573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev else 7583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev { 7593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev vfprintf (stderr, format, args); 7603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf (stderr,"\n"); 7613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fflush (stderr); 7623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 7633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev va_end (args); 7643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 7653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 7663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic void 7673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevlibusb_glue_error (PTPParams *params, const char *format, ...) 7683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 7693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev va_list args; 7703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 7713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev va_start (args, format); 7723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (params->error_func!=NULL) 7733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->error_func (params->data, format, args); 7743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev else 7753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev { 7763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev vfprintf (stderr, format, args); 7773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf (stderr,"\n"); 7783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fflush (stderr); 7793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 7803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev va_end (args); 7813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 7823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 7833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 7843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* 7853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * ptp_read_func() and ptp_write_func() are 7863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * based on same functions usb.c in libgphoto2. 7873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Much reading packet logs and having fun with trials and errors 7883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * reveals that WMP / Windows is probably using an algorithm like this 7893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * for large transfers: 7903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 7913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 1. Send the command (0x0c bytes) if headers are split, else, send 7923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * command plus sizeof(endpoint) - 0x0c bytes. 7933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 2. Send first packet, max size to be sizeof(endpoint) but only when using 7943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * split headers. Else goto 3. 7953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 3. REPEAT send 0x10000 byte chunks UNTIL remaining bytes < 0x10000 7963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * We call 0x10000 CONTEXT_BLOCK_SIZE. 7973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 4. Send remaining bytes MOD sizeof(endpoint) 7983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 5. Send remaining bytes. If this happens to be exactly sizeof(endpoint) 7993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * then also send a zero-length package. 8003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 8013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Further there is some special quirks to handle zero reads from the 8023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * device, since some devices can't do them at all due to shortcomings 8033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * of the USB slave controller in the device. 8043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 8053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define CONTEXT_BLOCK_SIZE_1 0x3e00 8063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define CONTEXT_BLOCK_SIZE_2 0x200 8073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define CONTEXT_BLOCK_SIZE CONTEXT_BLOCK_SIZE_1+CONTEXT_BLOCK_SIZE_2 8083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic short 8093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_read_func ( 8103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long size, PTPDataHandler *handler,void *data, 8113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long *readbytes, 8123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int readzero 8133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev) { 8143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTP_USB *ptp_usb = (PTP_USB *)data; 8153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long toread = 0; 8163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int result = 0; 8173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long curread = 0; 8183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long written; 8193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned char *bytes; 8203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int expect_terminator_byte = 0; 8213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 8223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // This is the largest block we'll need to read in. 8233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev bytes = malloc(CONTEXT_BLOCK_SIZE); 8243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev while (curread < size) { 8253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 8263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 8273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Remaining size to read: 0x%04lx bytes\n", size - curread); 8283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 8293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // check equal to condition here 8303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (size - curread < CONTEXT_BLOCK_SIZE) 8313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev { 8323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // this is the last packet 8333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev toread = size - curread; 8343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // this is equivalent to zero read for these devices 8353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (readzero && FLAG_NO_ZERO_READS(ptp_usb) && toread % 64 == 0) { 8363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev toread += 1; 8373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev expect_terminator_byte = 1; 8383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 8393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 8403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev else if (curread == 0) 8413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // we are first packet, but not last packet 8423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev toread = CONTEXT_BLOCK_SIZE_1; 8433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev else if (toread == CONTEXT_BLOCK_SIZE_1) 8443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev toread = CONTEXT_BLOCK_SIZE_2; 8453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev else if (toread == CONTEXT_BLOCK_SIZE_2) 8463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev toread = CONTEXT_BLOCK_SIZE_1; 8473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev else 8483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("unexpected toread size 0x%04x, 0x%04x remaining bytes\n", 8493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (unsigned int) toread, (unsigned int) (size-curread)); 8503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 8513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 8523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Reading in 0x%04lx bytes\n", toread); 8533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 8543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev result = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, (char*)bytes, toread, ptp_usb->timeout); 8553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 8563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Result of read: 0x%04x\n", result); 8573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 8583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 8593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result < 0) { 8603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_ERROR_IO; 8613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 8623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 8633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("<==USB IN\n"); 8643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result == 0) 8653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Zero Read\n"); 8663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev else if (result < 0) 8673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "USB_BULK_READ result=%#x\n", result); 8683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev else 8693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev data_dump_ascii (stdout,bytes,result,16); 8703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 8713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 8723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // want to discard extra byte 8733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (expect_terminator_byte && result == toread) 8743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev { 8753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 8763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("<==USB IN\nDiscarding extra byte\n"); 8773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 8783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev result--; 8793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 8803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 8813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int putfunc_ret = handler->putfunc(NULL, handler->priv, result, bytes, &written); 8823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (putfunc_ret != PTP_RC_OK) 8833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return putfunc_ret; 8843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 8853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->current_transfer_complete += result; 8863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev curread += result; 8873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 8883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Increase counters, call callback 8893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ptp_usb->callback_active) { 8903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) { 8913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // send last update and disable callback. 8923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total; 8933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->callback_active = 0; 8943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 8953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ptp_usb->current_transfer_callback != NULL) { 8963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int ret; 8973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete, 8983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->current_transfer_total, 8993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->current_transfer_callback_data); 9003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret != 0) { 9013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_ERROR_CANCEL; 9023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 9063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result < toread) /* short reads are common */ 9073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 9083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (readbytes) *readbytes = curread; 9103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev free (bytes); 9113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 9123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // there might be a zero packet waiting for us... 9133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (readzero && 9143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev !FLAG_NO_ZERO_READS(ptp_usb) && 9153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev curread % ptp_usb->outep_maxpacket == 0) { 9163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev char temp; 9173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int zeroresult = 0; 9183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 9193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 9203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("<==USB IN\n"); 9213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Zero Read\n"); 9223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 9233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev zeroresult = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, &temp, 0, ptp_usb->timeout); 9243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (zeroresult != 0) 9253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("LIBMTP panic: unable to read in zero packet, response 0x%04x", zeroresult); 9263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 9283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 9293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 9303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 9313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic short 9323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_write_func ( 9333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long size, 9343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPDataHandler *handler, 9353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev void *data, 9363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long *written 9373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev) { 9383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTP_USB *ptp_usb = (PTP_USB *)data; 9393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long towrite = 0; 9403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int result = 0; 9413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long curwrite = 0; 9423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned char *bytes; 9433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 9443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // This is the largest block we'll need to read in. 9453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev bytes = malloc(CONTEXT_BLOCK_SIZE); 9463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (!bytes) { 9473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_ERROR_IO; 9483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev while (curwrite < size) { 9503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long usbwritten = 0; 9513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev towrite = size-curwrite; 9523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (towrite > CONTEXT_BLOCK_SIZE) { 9533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev towrite = CONTEXT_BLOCK_SIZE; 9543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else { 9553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // This magic makes packets the same size that WMP send them. 9563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (towrite > ptp_usb->outep_maxpacket && towrite % ptp_usb->outep_maxpacket != 0) { 9573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev towrite -= towrite % ptp_usb->outep_maxpacket; 9583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int getfunc_ret = handler->getfunc(NULL, handler->priv,towrite,bytes,&towrite); 9613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (getfunc_ret != PTP_RC_OK) 9623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return getfunc_ret; 9633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev while (usbwritten < towrite) { 9643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev result = USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,((char*)bytes+usbwritten),towrite-usbwritten,ptp_usb->timeout); 9653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 9663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("USB OUT==>\n"); 9673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result > 0) { 9683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev data_dump_ascii (stdout,bytes+usbwritten,result,16); 9693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else { 9703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "USB_BULK_WRITE: result=%#x\n", result); 9713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 9733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result < 0) { 9743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_ERROR_IO; 9753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // check for result == 0 perhaps too. 9773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Increase counters 9783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->current_transfer_complete += result; 9793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev curwrite += result; 9803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbwritten += result; 9813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // call callback 9833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ptp_usb->callback_active) { 9843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) { 9853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // send last update and disable callback. 9863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total; 9873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->callback_active = 0; 9883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ptp_usb->current_transfer_callback != NULL) { 9903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int ret; 9913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete, 9923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->current_transfer_total, 9933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->current_transfer_callback_data); 9943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret != 0) { 9953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_ERROR_CANCEL; 9963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 9993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result < towrite) /* short writes happen */ 10003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 10013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 10023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev free (bytes); 10033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (written) { 10043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *written = curwrite; 10053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 10063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // If this is the last transfer send a zero write if required 10093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) { 10103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if ((towrite % ptp_usb->outep_maxpacket) == 0) { 10113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 10123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("USB OUT==>\n"); 10133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Zero Write\n"); 10143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 10153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)"x",0,ptp_usb->timeout); 10163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 10173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 10183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result < 0) 10203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_ERROR_IO; 10213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 10223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 10233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* memory data get/put handler */ 10253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevtypedef struct { 10263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned char *data; 10273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long size, curoff; 10283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} PTPMemHandlerPrivate; 10293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic uint16_t 10313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevmemory_getfunc(PTPParams* params, void* private, 10323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long wantlen, unsigned char *data, 10333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long *gotlen 10343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev) { 10353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)private; 10363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long tocopy = wantlen; 10373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (priv->curoff + tocopy > priv->size) 10393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev tocopy = priv->size - priv->curoff; 10403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev memcpy (data, priv->data + priv->curoff, tocopy); 10413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv->curoff += tocopy; 10423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *gotlen = tocopy; 10433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 10443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 10453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic uint16_t 10473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevmemory_putfunc(PTPParams* params, void* private, 10483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long sendlen, unsigned char *data, 10493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long *putlen 10503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev) { 10513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)private; 10523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (priv->curoff + sendlen > priv->size) { 10543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv->data = realloc (priv->data, priv->curoff+sendlen); 10553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv->size = priv->curoff + sendlen; 10563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 10573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev memcpy (priv->data + priv->curoff, data, sendlen); 10583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv->curoff += sendlen; 10593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *putlen = sendlen; 10603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 10613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 10623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* init private struct for receiving data. */ 10643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic uint16_t 10653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_init_recv_memory_handler(PTPDataHandler *handler) { 10663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPMemHandlerPrivate* priv; 10673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv = malloc (sizeof(PTPMemHandlerPrivate)); 10683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev handler->priv = priv; 10693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev handler->getfunc = memory_getfunc; 10703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev handler->putfunc = memory_putfunc; 10713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv->data = NULL; 10723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv->size = 0; 10733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv->curoff = 0; 10743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 10753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 10763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* init private struct and put data in for sending data. 10783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * data is still owned by caller. 10793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 10803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic uint16_t 10813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_init_send_memory_handler(PTPDataHandler *handler, 10823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned char *data, unsigned long len 10833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev) { 10843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPMemHandlerPrivate* priv; 10853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv = malloc (sizeof(PTPMemHandlerPrivate)); 10863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (!priv) 10873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_GeneralError; 10883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev handler->priv = priv; 10893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev handler->getfunc = memory_getfunc; 10903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev handler->putfunc = memory_putfunc; 10913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv->data = data; 10923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv->size = len; 10933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev priv->curoff = 0; 10943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 10953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 10963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 10973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* free private struct + data */ 10983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic uint16_t 10993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_exit_send_memory_handler (PTPDataHandler *handler) { 11003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)handler->priv; 11013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* data is owned by caller */ 11023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev free (priv); 11033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 11043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 11053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 11063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* hand over our internal data to caller */ 11073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic uint16_t 11083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_exit_recv_memory_handler (PTPDataHandler *handler, 11093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned char **data, unsigned long *size 11103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev) { 11113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)handler->priv; 11123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *data = priv->data; 11133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *size = priv->size; 11143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev free (priv); 11153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 11163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 11173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 11183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* send / receive functions */ 11193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 11203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevuint16_t 11213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_usb_sendreq (PTPParams* params, PTPContainer* req) 11223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 11233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint16_t ret; 11243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPUSBBulkContainer usbreq; 11253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPDataHandler memhandler; 11263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long written = 0; 11273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long towrite; 11283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 11293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev char txt[256]; 11303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 11313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (void) ptp_render_opcode (params, req->Code, sizeof(txt), txt); 11323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("REQUEST: 0x%04x, %s\n", req->Code, txt); 11333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 11343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* build appropriate USB container */ 11353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbreq.length=htod32(PTP_USB_BULK_REQ_LEN- 11363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (sizeof(uint32_t)*(5-req->Nparam))); 11373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbreq.type=htod16(PTP_USB_CONTAINER_COMMAND); 11383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbreq.code=htod16(req->Code); 11393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbreq.trans_id=htod32(req->Transaction_ID); 11403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbreq.payload.params.param1=htod32(req->Param1); 11413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbreq.payload.params.param2=htod32(req->Param2); 11423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbreq.payload.params.param3=htod32(req->Param3); 11433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbreq.payload.params.param4=htod32(req->Param4); 11443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbreq.payload.params.param5=htod32(req->Param5); 11453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* send it to responder */ 11463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev towrite = PTP_USB_BULK_REQ_LEN-(sizeof(uint32_t)*(5-req->Nparam)); 11473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_init_send_memory_handler (&memhandler, (unsigned char*)&usbreq, towrite); 11483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret=ptp_write_func( 11493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev towrite, 11503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &memhandler, 11513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->data, 11523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &written 11533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ); 11543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_exit_send_memory_handler (&memhandler); 11553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret!=PTP_RC_OK && ret!=PTP_ERROR_CANCEL) { 11563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_ERROR_IO; 11573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 11583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (written != towrite && ret != PTP_ERROR_CANCEL && ret != PTP_ERROR_IO) { 11593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev libusb_glue_error (params, 11603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "PTP: request code 0x%04x sending req wrote only %ld bytes instead of %d", 11613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev req->Code, written, towrite 11623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ); 11633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_ERROR_IO; 11643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 11653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 11663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 11673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 11683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevuint16_t 11693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_usb_senddata (PTPParams* params, PTPContainer* ptp, 11703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long size, PTPDataHandler *handler 11713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev) { 11723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint16_t ret; 11733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int wlen, datawlen; 11743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long written; 11753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPUSBBulkContainer usbdata; 11763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint32_t bytes_left_to_transfer; 11773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPDataHandler memhandler; 11783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 11793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 11803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("SEND DATA PHASE\n"); 11813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 11823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* build appropriate USB container */ 11833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbdata.length = htod32(PTP_USB_BULK_HDR_LEN+size); 11843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbdata.type = htod16(PTP_USB_CONTAINER_DATA); 11853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbdata.code = htod16(ptp->Code); 11863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbdata.trans_id= htod32(ptp->Transaction_ID); 11873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 11883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ((PTP_USB*)params->data)->current_transfer_complete = 0; 11893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ((PTP_USB*)params->data)->current_transfer_total = size+PTP_USB_BULK_HDR_LEN; 11903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 11913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (params->split_header_data) { 11923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev datawlen = 0; 11933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev wlen = PTP_USB_BULK_HDR_LEN; 11943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else { 11953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long gotlen; 11963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* For all camera devices. */ 11973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev datawlen = (size<PTP_USB_BULK_PAYLOAD_LEN_WRITE)?size:PTP_USB_BULK_PAYLOAD_LEN_WRITE; 11983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev wlen = PTP_USB_BULK_HDR_LEN + datawlen; 11993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 12003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = handler->getfunc(params, handler->priv, datawlen, usbdata.payload.data, &gotlen); 12013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret != PTP_RC_OK) 12023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 12033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (gotlen != datawlen) 12043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_GeneralError; 12053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 12063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_init_send_memory_handler (&memhandler, (unsigned char *)&usbdata, wlen); 12073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* send first part of data */ 12083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_write_func(wlen, &memhandler, params->data, &written); 12093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_exit_send_memory_handler (&memhandler); 12103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret!=PTP_RC_OK) { 12113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 12123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 12133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (size <= datawlen) return ret; 12143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* if everything OK send the rest */ 12153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev bytes_left_to_transfer = size-datawlen; 12163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_RC_OK; 12173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev while(bytes_left_to_transfer > 0) { 12183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_write_func (bytes_left_to_transfer, handler, params->data, &written); 12193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret != PTP_RC_OK) 12203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 12213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (written == 0) { 12223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_ERROR_IO; 12233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 12243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 12253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev bytes_left_to_transfer -= written; 12263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 12273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret!=PTP_RC_OK && ret!=PTP_ERROR_CANCEL) 12283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_ERROR_IO; 12293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 12303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 12313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 12323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic uint16_t ptp_usb_getpacket(PTPParams *params, 12333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPUSBBulkContainer *packet, unsigned long *rlen) 12343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 12353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPDataHandler memhandler; 12363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint16_t ret; 12373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned char *x = NULL; 12383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 12393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* read the header and potentially the first data */ 12403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (params->response_packet_size > 0) { 12413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* If there is a buffered packet, just use it. */ 12423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev memcpy(packet, params->response_packet, params->response_packet_size); 12433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *rlen = params->response_packet_size; 12443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev free(params->response_packet); 12453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->response_packet = NULL; 12463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->response_packet_size = 0; 12473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Here this signifies a "virtual read" */ 12483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 12493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 12503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_init_recv_memory_handler (&memhandler); 12513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_read_func(PTP_USB_BULK_HS_MAX_PACKET_LEN_READ, &memhandler, params->data, rlen, 0); 12523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_exit_recv_memory_handler (&memhandler, &x, rlen); 12533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (x) { 12543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev memcpy (packet, x, *rlen); 12553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev free (x); 12563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 12573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 12583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 12593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 12603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevuint16_t 12613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_usb_getdata (PTPParams* params, PTPContainer* ptp, PTPDataHandler *handler) 12623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 12633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint16_t ret; 12643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPUSBBulkContainer usbdata; 12653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long written; 12663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTP_USB *ptp_usb = (PTP_USB *) params->data; 12673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 12683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 12693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("GET DATA PHASE\n"); 12703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 12713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev memset(&usbdata,0,sizeof(usbdata)); 12723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev do { 12733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long len, rlen; 12743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 12753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_usb_getpacket(params, &usbdata, &rlen); 12763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret!=PTP_RC_OK) { 12773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_ERROR_IO; 12783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 12793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 12803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dtoh16(usbdata.type)!=PTP_USB_CONTAINER_DATA) { 12813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_ERROR_DATA_EXPECTED; 12823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 12833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 12843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dtoh16(usbdata.code)!=ptp->Code) { 12853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (FLAG_IGNORE_HEADER_ERRORS(ptp_usb)) { 12863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev libusb_glue_debug (params, "ptp2/ptp_usb_getdata: detected a broken " 12873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "PTP header, code field insane, expect problems! (But continuing)"); 12883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Repair the header, so it won't wreak more havoc, don't just ignore it. 12893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Typically these two fields will be broken. 12903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbdata.code = htod16(ptp->Code); 12913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usbdata.trans_id = htod32(ptp->Transaction_ID); 12923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_RC_OK; 12933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else { 12943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = dtoh16(usbdata.code); 12953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // This filters entirely insane garbage return codes, but still 12963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // makes it possible to return error codes in the code field when 12973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // getting data. It appears Windows ignores the contents of this 12983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // field entirely. 12993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret < PTP_RC_Undefined || ret > PTP_RC_SpecificationOfDestinationUnsupported) { 13003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev libusb_glue_debug (params, "ptp2/ptp_usb_getdata: detected a broken " 13013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "PTP header, code field insane."); 13023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_ERROR_IO; 13033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 13043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 13053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 13063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 13073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (usbdata.length == 0xffffffffU) { 13083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Copy first part of data to 'data' */ 13093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int putfunc_ret = 13103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev handler->putfunc( 13113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params, handler->priv, rlen - PTP_USB_BULK_HDR_LEN, usbdata.payload.data, 13123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &written 13133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ); 13143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (putfunc_ret != PTP_RC_OK) 13153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return putfunc_ret; 13163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* stuff data directly to passed data handler */ 13173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev while (1) { 13183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long readdata; 13193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint16_t xret; 13203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 13213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev xret = ptp_read_func( 13223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTP_USB_BULK_HS_MAX_PACKET_LEN_READ, 13233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev handler, 13243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->data, 13253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &readdata, 13263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 0 13273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ); 13283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (xret != PTP_RC_OK) 13293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return xret; 13303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (readdata < PTP_USB_BULK_HS_MAX_PACKET_LEN_READ) 13313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 13323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 13333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 13343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 13353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (rlen > dtoh32(usbdata.length)) { 13363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 13373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Buffer the surplus response packet if it is >= 13383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * PTP_USB_BULK_HDR_LEN 13393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * (i.e. it is probably an entire package) 13403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * else discard it as erroneous surplus data. 13413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This will even work if more than 2 packets appear 13423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * in the same transaction, they will just be handled 13433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * iteratively. 13443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * 13453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Marcus observed stray bytes on iRiver devices; 13463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * these are still discarded. 13473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 13483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned int packlen = dtoh32(usbdata.length); 13493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned int surplen = rlen - packlen; 13503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 13513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (surplen >= PTP_USB_BULK_HDR_LEN) { 13523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->response_packet = malloc(surplen); 13533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev memcpy(params->response_packet, 13543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (uint8_t *) &usbdata + packlen, surplen); 13553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->response_packet_size = surplen; 13563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Ignore reading one extra byte if device flags have been set */ 13573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else if(!FLAG_NO_ZERO_READS(ptp_usb) && 13583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (rlen - dtoh32(usbdata.length) == 1)) { 13593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev libusb_glue_debug (params, "ptp2/ptp_usb_getdata: read %d bytes " 13603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "too much, expect problems!", 13613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev rlen - dtoh32(usbdata.length)); 13623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 13633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev rlen = packlen; 13643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 13653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 13663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* For most PTP devices rlen is 512 == sizeof(usbdata) 13673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * here. For MTP devices splitting header and data it might 13683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * be 12. 13693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 13703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Evaluate full data length. */ 13713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev len=dtoh32(usbdata.length)-PTP_USB_BULK_HDR_LEN; 13723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 13733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* autodetect split header/data MTP devices */ 13743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dtoh32(usbdata.length) > 12 && (rlen==12)) 13753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->split_header_data = 1; 13763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 13773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Copy first part of data to 'data' */ 13783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int putfunc_ret = 13793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev handler->putfunc( 13803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params, handler->priv, rlen - PTP_USB_BULK_HDR_LEN, usbdata.payload.data, 13813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &written 13823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ); 13833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (putfunc_ret != PTP_RC_OK) 13843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return putfunc_ret; 13853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 13863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (FLAG_NO_ZERO_READS(ptp_usb) && 13873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev len+PTP_USB_BULK_HDR_LEN == PTP_USB_BULK_HS_MAX_PACKET_LEN_READ) { 13883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 13893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Reading in extra terminating byte\n"); 13903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 13913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // need to read in extra byte and discard it 13923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int result = 0; 13933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev char byte = 0; 13943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev result = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, &byte, 1, ptp_usb->timeout); 13953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 13963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result != 1) 13973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Could not read in extra byte for PTP_USB_BULK_HS_MAX_PACKET_LEN_READ long file, return value 0x%04x\n", result); 13983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else if (len+PTP_USB_BULK_HDR_LEN == PTP_USB_BULK_HS_MAX_PACKET_LEN_READ && params->split_header_data == 0) { 13993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int zeroresult = 0; 14003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev char zerobyte = 0; 14013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 14033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Reading in zero packet after header\n"); 14043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 14053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev zeroresult = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, &zerobyte, 0, ptp_usb->timeout); 14063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (zeroresult != 0) 14083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("LIBMTP panic: unable to read in zero packet, response 0x%04x", zeroresult); 14093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 14103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Is that all of data? */ 14123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (len+PTP_USB_BULK_HDR_LEN<=rlen) { 14133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 14143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 14153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_read_func(len - (rlen - PTP_USB_BULK_HDR_LEN), 14173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev handler, 14183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->data, &rlen, 1); 14193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret!=PTP_RC_OK) { 14213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 14223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 14233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } while (0); 14243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 14253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 14263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevuint16_t 14283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_usb_getresp (PTPParams* params, PTPContainer* resp) 14293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 14303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint16_t ret; 14313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long rlen; 14323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPUSBBulkContainer usbresp; 14333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTP_USB *ptp_usb = (PTP_USB *)(params->data); 14343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 14363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("RESPONSE: "); 14373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 14383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev memset(&usbresp,0,sizeof(usbresp)); 14393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* read response, it should never be longer than sizeof(usbresp) */ 14403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_usb_getpacket(params, &usbresp, &rlen); 14413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Fix for bevahiour reported by Scott Snyder on Samsung YP-U3. The player 14433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // sends a packet containing just zeroes of length 2 (up to 4 has been seen too) 14443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // after a NULL packet when it should send the response. This code ignores 14453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // such illegal packets. 14463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev while (ret==PTP_RC_OK && rlen<PTP_USB_BULK_HDR_LEN && usbresp.length==0) { 14473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev libusb_glue_debug (params, "ptp_usb_getresp: detected short response " 14483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "of %d bytes, expect problems! (re-reading " 14493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "response), rlen"); 14503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_usb_getpacket(params, &usbresp, &rlen); 14513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 14523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret!=PTP_RC_OK) { 14543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_ERROR_IO; 14553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else 14563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dtoh16(usbresp.type)!=PTP_USB_CONTAINER_RESPONSE) { 14573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_ERROR_RESP_EXPECTED; 14583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else 14593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dtoh16(usbresp.code)!=resp->Code) { 14603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = dtoh16(usbresp.code); 14613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 14623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef ENABLE_USB_BULK_DEBUG 14633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("%04x\n", ret); 14643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 14653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret!=PTP_RC_OK) { 14663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* libusb_glue_error (params, 14673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "PTP: request code 0x%04x getting resp error 0x%04x", 14683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev resp->Code, ret);*/ 14693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 14703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 14713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* build an appropriate PTPContainer */ 14723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev resp->Code=dtoh16(usbresp.code); 14733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev resp->SessionID=params->session_id; 14743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev resp->Transaction_ID=dtoh32(usbresp.trans_id); 14753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (FLAG_IGNORE_HEADER_ERRORS(ptp_usb)) { 14763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (resp->Transaction_ID != params->transaction_id-1) { 14773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev libusb_glue_debug (params, "ptp_usb_getresp: detected a broken " 14783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "PTP header, transaction ID insane, expect " 14793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "problems! (But continuing)"); 14803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Repair the header, so it won't wreak more havoc. 14813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev resp->Transaction_ID = params->transaction_id-1; 14823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 14833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 14843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev resp->Param1=dtoh32(usbresp.payload.params.param1); 14853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev resp->Param2=dtoh32(usbresp.payload.params.param2); 14863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev resp->Param3=dtoh32(usbresp.payload.params.param3); 14873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev resp->Param4=dtoh32(usbresp.payload.params.param4); 14883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev resp->Param5=dtoh32(usbresp.payload.params.param5); 14893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 14903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 14913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* Event handling functions */ 14933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/* PTP Events wait for or check mode */ 14953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define PTP_EVENT_CHECK 0x0000 /* waits for */ 14963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#define PTP_EVENT_CHECK_FAST 0x0001 /* checks */ 14973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 14983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic inline uint16_t 14993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_usb_event (PTPParams* params, PTPContainer* event, int wait) 15003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 15013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint16_t ret; 15023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int result; 15033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned long rlen; 15043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPUSBEventContainer usbevent; 15053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTP_USB *ptp_usb = (PTP_USB *)(params->data); 15063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev memset(&usbevent,0,sizeof(usbevent)); 15083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if ((params==NULL) || (event==NULL)) 15103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_ERROR_BADPARAM; 15113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = PTP_RC_OK; 15123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev switch(wait) { 15133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev case PTP_EVENT_CHECK: 15143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)&usbevent,sizeof(usbevent),ptp_usb->timeout); 15153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result==0) 15163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev result = USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *) &usbevent, sizeof(usbevent), ptp_usb->timeout); 15173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result < 0) ret = PTP_ERROR_IO; 15183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 15193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev case PTP_EVENT_CHECK_FAST: 15203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)&usbevent,sizeof(usbevent),ptp_usb->timeout); 15213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result==0) 15223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev result = USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *) &usbevent, sizeof(usbevent), ptp_usb->timeout); 15233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (result < 0) ret = PTP_ERROR_IO; 15243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 15253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev default: 15263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret=PTP_ERROR_BADPARAM; 15273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 15283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 15293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret!=PTP_RC_OK) { 15303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev libusb_glue_error (params, 15313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "PTP: reading event an error 0x%04x occurred", ret); 15323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_ERROR_IO; 15333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 15343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev rlen = result; 15353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (rlen < 8) { 15363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev libusb_glue_error (params, 15373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "PTP: reading event an short read of %ld bytes occurred", rlen); 15383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_ERROR_IO; 15393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 15403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* if we read anything over interrupt endpoint it must be an event */ 15413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* build an appropriate PTPContainer */ 15423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev event->Code=dtoh16(usbevent.code); 15433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev event->SessionID=params->session_id; 15443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev event->Transaction_ID=dtoh32(usbevent.trans_id); 15453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev event->Param1=dtoh32(usbevent.param1); 15463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev event->Param2=dtoh32(usbevent.param2); 15473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev event->Param3=dtoh32(usbevent.param3); 15483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ret; 15493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 15503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevuint16_t 15523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_usb_event_check (PTPParams* params, PTPContainer* event) { 15533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ptp_usb_event (params, event, PTP_EVENT_CHECK_FAST); 15553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 15563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevuint16_t 15583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_usb_event_wait (PTPParams* params, PTPContainer* event) { 15593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return ptp_usb_event (params, event, PTP_EVENT_CHECK); 15613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 15623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevuint16_t 15643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevptp_usb_control_cancel_request (PTPParams *params, uint32_t transactionid) { 15653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTP_USB *ptp_usb = (PTP_USB *)(params->data); 15663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int ret; 15673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev unsigned char buffer[6]; 15683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev htod16a(&buffer[0],PTP_EC_CancelTransaction); 15703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev htod32a(&buffer[2],transactionid); 15713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_control_msg(ptp_usb->handle, 15723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev USB_TYPE_CLASS | USB_RECIP_INTERFACE, 15733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 0x64, 0x0000, 0x0000, (char *) buffer, sizeof(buffer), ptp_usb->timeout); 15743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret < sizeof(buffer)) 15753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_ERROR_IO; 15763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return PTP_RC_OK; 15773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 15783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic int init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev) 15803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 15813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_dev_handle *device_handle; 15823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->sendreq_func=ptp_usb_sendreq; 15843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->senddata_func=ptp_usb_senddata; 15853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->getresp_func=ptp_usb_getresp; 15863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->getdata_func=ptp_usb_getdata; 15873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->cancelreq_func=ptp_usb_control_cancel_request; 15883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->data=ptp_usb; 15893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->transaction_id=0; 15903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 15913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This is hardcoded here since we have no devices whatsoever that are BE. 15923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Change this the day we run into our first BE device (if ever). 15933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 15943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->byteorder = PTP_DL_LE; 15953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->timeout = USB_TIMEOUT_DEFAULT; 15973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 15983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev device_handle = usb_open(dev); 15993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (!device_handle) { 16003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev perror("usb_open()"); 16013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return -1; 16023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 16043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->handle = device_handle; 16053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 16063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 16073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * If this device is known to be wrongfully claimed by other kernel 16083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * drivers (such as mass storage), then try to unload it to make it 16093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * accessible from user space. 16103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 16113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (FLAG_UNLOAD_DRIVER(ptp_usb)) { 16123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (usb_detach_kernel_driver_np(device_handle, (int) ptp_usb->interface)) { 16133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Totally ignore this error! 16143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // perror("usb_detach_kernel_driver_np()"); 16153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 16183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#ifdef __WIN32__ 16193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Only needed on Windows, and cause problems on other platforms. 16203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (usb_set_configuration(device_handle, dev->config->bConfigurationValue)) { 16213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev perror("usb_set_configuration()"); 16223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return -1; 16233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev#endif 16253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (usb_claim_interface(device_handle, (int) ptp_usb->interface)) { 16263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev perror("usb_claim_interface()"); 16273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return -1; 16283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 16303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return 0; 16313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 16323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 16333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic void clear_stall(PTP_USB* ptp_usb) 16343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 16353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint16_t status; 16363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int ret; 16373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 16383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* check the inep status */ 16393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev status = 0; 16403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status); 16413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret<0) { 16423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev perror ("inep: usb_get_endpoint_status()"); 16433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else if (status) { 16443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Clearing stall on IN endpoint\n"); 16453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_clear_stall_feature(ptp_usb,ptp_usb->inep); 16463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret<0) { 16473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev perror ("usb_clear_stall_feature()"); 16483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 16513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* check the outep status */ 16523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev status=0; 16533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status); 16543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret<0) { 16553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev perror("outep: usb_get_endpoint_status()"); 16563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else if (status) { 16573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev printf("Clearing stall on OUT endpoint\n"); 16583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_clear_stall_feature(ptp_usb,ptp_usb->outep); 16593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret<0) { 16603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev perror("usb_clear_stall_feature()"); 16613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 16643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* TODO: do we need this for INTERRUPT (ptp_usb->intep) too? */ 16653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 16663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 16673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic void clear_halt(PTP_USB* ptp_usb) 16683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 16693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int ret; 16703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 16713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_clear_halt(ptp_usb->handle,ptp_usb->inep); 16723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret<0) { 16733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev perror("usb_clear_halt() on IN endpoint"); 16743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_clear_halt(ptp_usb->handle,ptp_usb->outep); 16763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret<0) { 16773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev perror("usb_clear_halt() on OUT endpoint"); 16783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = usb_clear_halt(ptp_usb->handle,ptp_usb->intep); 16803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret<0) { 16813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev perror("usb_clear_halt() on INTERRUPT endpoint"); 16823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 16833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 16843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 16853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic void close_usb(PTP_USB* ptp_usb) 16863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 16873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Commented out since it was confusing some 16883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // devices to do these things. 16893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (!FLAG_NO_RELEASE_INTERFACE(ptp_usb)) { 16903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 16913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 16923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Clear any stalled endpoints 16933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * On misbehaving devices designed for Windows/Mac, quote from: 16943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * http://www2.one-eyed-alien.net/~mdharm/linux-usb/target_offenses.txt 16953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Device does Bad Things(tm) when it gets a GET_STATUS after CLEAR_HALT 16963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * (...) Windows, when clearing a stall, only sends the CLEAR_HALT command, 16973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * and presumes that the stall has cleared. Some devices actually choke 16983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * if the CLEAR_HALT is followed by a GET_STATUS (used to determine if the 16993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * STALL is persistant or not). 17003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 17013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev clear_stall(ptp_usb); 17023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Clear halts on any endpoints 17033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev clear_halt(ptp_usb); 17043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Added to clear some stuff on the OUT endpoint 17053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // TODO: is this good on the Mac too? 17063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // HINT: some devices may need that you comment these two out too. 17073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_resetep(ptp_usb->handle, ptp_usb->outep); 17083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_release_interface(ptp_usb->handle, (int) ptp_usb->interface); 17093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 17103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 17113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_close(ptp_usb->handle); 17123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 17133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 17143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 17153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Self-explanatory? 17163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 17173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic void find_interface_and_endpoints(struct usb_device *dev, 17183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint8_t *interface, 17193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int* inep, 17203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int* inep_maxpacket, 17213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int* outep, 17223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int *outep_maxpacket, 17233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int* intep) 17243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 17253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int i; 17263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 17273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Loop over the device configurations 17283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { 17293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint8_t j; 17303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 17313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (j = 0; j < dev->config[i].bNumInterfaces; j++) { 17323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint8_t k; 17333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint8_t no_ep; 17343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_endpoint_descriptor *ep; 17353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 17363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (dev->descriptor.bNumConfigurations > 1 || dev->config[i].bNumInterfaces > 1) { 17373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // OK This device has more than one interface, so we have to find out 17383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // which one to use! 17393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // FIXME: Probe the interface. 17403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // FIXME: Release modules attached to all other interfaces in Linux...? 17413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 17423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 17433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *interface = dev->config[i].interface[j].altsetting->bInterfaceNumber; 17443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ep = dev->config[i].interface[j].altsetting->endpoint; 17453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev no_ep = dev->config[i].interface[j].altsetting->bNumEndpoints; 17463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 17473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (k = 0; k < no_ep; k++) { 17483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ep[k].bmAttributes==USB_ENDPOINT_TYPE_BULK) { 17493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if ((ep[k].bEndpointAddress&USB_ENDPOINT_DIR_MASK)== 17503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev USB_ENDPOINT_DIR_MASK) 17513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev { 17523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *inep=ep[k].bEndpointAddress; 17533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *inep_maxpacket=ep[k].wMaxPacketSize; 17543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 17553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if ((ep[k].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==0) 17563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev { 17573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *outep=ep[k].bEndpointAddress; 17583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *outep_maxpacket=ep[k].wMaxPacketSize; 17593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 17603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } else if (ep[k].bmAttributes==USB_ENDPOINT_TYPE_INTERRUPT){ 17613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if ((ep[k].bEndpointAddress&USB_ENDPOINT_DIR_MASK)== 17623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev USB_ENDPOINT_DIR_MASK) 17633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev { 17643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *intep=ep[k].bEndpointAddress; 17653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 17663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 17673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 17683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // We assigned the endpoints so return here. 17693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return; 17703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 17713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 17723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 17733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 17743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev/** 17753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This function assigns params and usbinfo given a raw device 17763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * as input. 17773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param device the device to be assigned. 17783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @param usbinfo a pointer to the new usbinfo. 17793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * @return an error code. 17803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 17813aa430dc5437a98734b36f996f9b17081a589143Yavor GoulishevLIBMTP_error_number_t configure_usb_device(LIBMTP_raw_device_t *device, 17823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTPParams *params, 17833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev void **usbinfo) 17843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 17853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev PTP_USB *ptp_usb; 17863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_device *libusb_device; 17873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev uint16_t ret = 0; 17883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_bus *bus; 17893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev int found = 0; 17903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 17913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* See if we can find this raw device again... */ 17923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev bus = init_usb(); 17933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (; bus != NULL; bus = bus->next) { 17943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (bus->location == device->bus_location) { 17953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev struct usb_device *dev = bus->devices; 17963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 17973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev for (; dev != NULL; dev = dev->next) { 17983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if(dev->devnum == device->devnum && 17993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->descriptor.idVendor == device->device_entry.vendor_id && 18003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev dev->descriptor.idProduct == device->device_entry.product_id ) { 18013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev libusb_device = dev; 18023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev found = 1; 18033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 18043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (found) 18073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev break; 18083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Device has gone since detecting raw devices! */ 18113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (!found) { 18123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_NO_DEVICE_ATTACHED; 18133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Allocate structs */ 18163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb = (PTP_USB *) malloc(sizeof(PTP_USB)); 18173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ptp_usb == NULL) { 18183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_MEMORY_ALLOCATION; 18193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Start with a blank slate (includes setting device_flags to 0) */ 18213aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev memset(ptp_usb, 0, sizeof(PTP_USB)); 18223aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18233aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Copy the raw device */ 18243aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev memcpy(&ptp_usb->rawdevice, device, sizeof(LIBMTP_raw_device_t)); 18253aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18263aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 18273aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * Some devices must have their "OS Descriptor" massaged in order 18283aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * to work. 18293aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 18303aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (FLAG_ALWAYS_PROBE_DESCRIPTOR(ptp_usb)) { 18313aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev // Massage the device descriptor 18323aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (void) probe_device_descriptor(libusb_device, NULL); 18333aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18343aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18353aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18363aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Assign endpoints to usbinfo... */ 18373aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev find_interface_and_endpoints(libusb_device, 18383aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &ptp_usb->interface, 18393aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &ptp_usb->inep, 18403aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &ptp_usb->inep_maxpacket, 18413aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &ptp_usb->outep, 18423aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &ptp_usb->outep_maxpacket, 18433aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev &ptp_usb->intep); 18443aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18453aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Attempt to initialize this device */ 18463aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (init_ptp_usb(params, ptp_usb, libusb_device) < 0) { 18473aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "LIBMTP PANIC: Unable to initialize device\n"); 18483aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_CONNECTING; 18493aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18503aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18513aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* 18523aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * This works in situations where previous bad applications 18533aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev * have not used LIBMTP_Release_Device on exit 18543aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev */ 18553aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if ((ret = ptp_opensession(params, 1)) == PTP_ERROR_IO) { 18563aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "PTP_ERROR_IO: Trying again after re-initializing USB interface\n"); 18573aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev close_usb(ptp_usb); 18583aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18593aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if(init_ptp_usb(params, ptp_usb, libusb_device) <0) { 18603aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "LIBMTP PANIC: Could not open session on device\n"); 18613aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_CONNECTING; 18623aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18633aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18643aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Device has been reset, try again */ 18653aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_opensession(params, 1); 18663aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18673aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18683aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* Was the transaction id invalid? Try again */ 18693aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret == PTP_RC_InvalidTransactionID) { 18703aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "LIBMTP WARNING: Transaction ID was invalid, increment and try again\n"); 18713aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev params->transaction_id += 10; 18723aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret = ptp_opensession(params, 1); 18733aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18743aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18753aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ret != PTP_RC_SessionAlreadyOpened && ret != PTP_RC_OK) { 18763aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr, "LIBMTP PANIC: Could not open session! " 18773aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev "(Return code %d)\n Try to reset the device.\n", 18783aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ret); 18793aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev usb_release_interface(ptp_usb->handle, 18803aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev (int) ptp_usb->interface); 18813aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_CONNECTING; 18823aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev } 18833aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18843aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev /* OK configured properly */ 18853aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *usbinfo = (void *) ptp_usb; 18863aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return LIBMTP_ERROR_NONE; 18873aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 18883aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18893aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18903aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevvoid close_device (PTP_USB *ptp_usb, PTPParams *params) 18913aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 18923aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev if (ptp_closesession(params)!=PTP_RC_OK) 18933aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev fprintf(stderr,"ERROR: Could not close session!\n"); 18943aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev close_usb(ptp_usb); 18953aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 18963aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 18973aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevvoid set_usb_device_timeout(PTP_USB *ptp_usb, int timeout) 18983aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 18993aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ptp_usb->timeout = timeout; 19003aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 19013aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 19023aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevvoid get_usb_device_timeout(PTP_USB *ptp_usb, int *timeout) 19033aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 19043aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev *timeout = ptp_usb->timeout; 19053aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 19063aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 19073aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep) 19083aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 19093aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 19103aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return (usb_control_msg(ptp_usb->handle, 19113aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, USB_FEATURE_HALT, 19123aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev ep, NULL, 0, ptp_usb->timeout)); 19133aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 19143aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev 19153aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishevstatic int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status) 19163aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev{ 19173aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev return (usb_control_msg(ptp_usb->handle, 19183aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev USB_DP_DTH|USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS, 19193aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev USB_FEATURE_HALT, ep, (char *)status, 2, ptp_usb->timeout)); 19203aa430dc5437a98734b36f996f9b17081a589143Yavor Goulishev} 1921