libusb1-glue.c revision 3df1589b0b5b81484ebc507ac4b96d1e04891d9b
1fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* 2fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * \file libusb1-glue.c 3fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Low-level USB interface glue towards libusb. 4fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 5fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Copyright (C) 2005-2007 Richard A. Low <richard@wentnet.com> 67433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij * Copyright (C) 2005-2012 Linus Walleij <triad@df.lth.se> 7bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij * Copyright (C) 2006-2012 Marcus Meissner 8fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Copyright (C) 2007 Ted Bullock 9fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Copyright (C) 2008 Chris Bagwell <chris@cnpbagwell.com> 10fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 11fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This library is free software; you can redistribute it and/or 12fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * modify it under the terms of the GNU Lesser General Public 13fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * License as published by the Free Software Foundation; either 14fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * version 2 of the License, or (at your option) any later version. 15fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 16fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This library is distributed in the hope that it will be useful, 17fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * but WITHOUT ANY WARRANTY; without even the implied warranty of 18fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Lesser General Public License for more details. 20fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 21fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * You should have received a copy of the GNU Lesser General Public 22fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * License along with this library; if not, write to the 23fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 24fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Boston, MA 02111-1307, USA. 25fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 26fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Created by Richard Low on 24/12/2005. (as mtp-utils.c) 27fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Modified by Linus Walleij 2006-03-06 28fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * (Notice that Anglo-Saxons use little-endian dates and Swedes 29fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * use big-endian dates.) 30fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 31fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 32fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include "config.h" 33fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include "libmtp.h" 3426ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij#include "libusb-glue.h" 35fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include "device-flags.h" 36fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include "util.h" 37fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include "ptp.h" 38fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 39fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include <errno.h> 40fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include <stdio.h> 41fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include <stdlib.h> 42fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include <string.h> 4326ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij#include <unistd.h> 44fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 45fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include "ptp-pack.c" 46fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 47fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* 48fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Default USB timeout length. This can be overridden as needed 49fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * but should start with a reasonable value so most common 50fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * requests can be completed. The original value of 4000 was 51fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * not long enough for large file transfer. Also, players can 52fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * spend a bit of time collecting data. Higher values also 53fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * make connecting/disconnecting more reliable. 54fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 55fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define USB_TIMEOUT_DEFAULT 20000 56fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define USB_TIMEOUT_LONG 60000 57fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic inline int get_timeout(PTP_USB* ptp_usb) 58fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 59fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_LONG_TIMEOUT(ptp_usb)) { 60fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return USB_TIMEOUT_LONG; 61fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 62fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return USB_TIMEOUT_DEFAULT; 63fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 64fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 65fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* USB Feature selector HALT */ 66fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#ifndef USB_FEATURE_HALT 67fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define USB_FEATURE_HALT 0x00 68fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#endif 69fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 70fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* Internal data types */ 71fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstruct mtpdevice_list_struct { 72fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device *device; 73fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPParams *params; 74fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb; 75fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint32_t bus_location; 76fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct mtpdevice_list_struct *next; 77fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij}; 78fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijtypedef struct mtpdevice_list_struct mtpdevice_list_t; 79fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 80fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic const LIBMTP_device_entry_t mtp_device_table[] = { 81fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* We include an .h file which is shared between us and libgphoto2 */ 82fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#include "music-players.h" 83fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij}; 84fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic const int mtp_device_table_size = sizeof(mtp_device_table) / sizeof(LIBMTP_device_entry_t); 85fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 86fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij// Local functions 873df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhangstatic LIBMTP_error_number_t init_usb(); 88fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void close_usb(PTP_USB* ptp_usb); 89fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic int find_interface_and_endpoints(libusb_device *dev, 9015d18e31458be5006eb229df68869df2fff93495Linus Walleij uint8_t *conf, 91fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint8_t *interface, 9215d18e31458be5006eb229df68869df2fff93495Linus Walleij uint8_t *altsetting, 93fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* inep, 94fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* inep_maxpacket, 95fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* outep, 96fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* outep_maxpacket, 97fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* intep); 98fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void clear_stall(PTP_USB* ptp_usb); 99fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic int init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, libusb_device* dev); 100fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic short ptp_write_func (unsigned long,PTPDataHandler*,void *data,unsigned long*); 101fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic short ptp_read_func (unsigned long,PTPDataHandler*,void *data,unsigned long*,int); 102fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status); 103fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 104fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 105fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Get a list of the supported USB devices. 106fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 107fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * The developers depend on users of this library to constantly 108fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * add in to the list of supported devices. What we need is the 109fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * device name, USB Vendor ID (VID) and USB Product ID (PID). 110fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * put this into a bug ticket at the project homepage, please. 111fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * The VID/PID is used to let e.g. udev lift the device to 112fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * console userspace access when it's plugged in. 113fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 114fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param devices a pointer to a pointer that will hold a device 115fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * list after the call to this function, if it was 116fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * successful. 117fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param numdevs a pointer to an integer that will hold the number 118fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * of devices in the device list if the call was successful. 119fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return 0 if the list was successfull retrieved, any other 120fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * value means failure. 121fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 122fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijint LIBMTP_Get_Supported_Devices_List(LIBMTP_device_entry_t ** const devices, int * const numdevs) 123fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 124fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *devices = (LIBMTP_device_entry_t *) &mtp_device_table; 125fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *numdevs = mtp_device_table_size; 126fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 127fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 128fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 129fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1303df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhangstatic LIBMTP_error_number_t init_usb() 131fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 132fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 133fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Some additional libusb debugging please. 134fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * We use the same level debug between MTP and USB. 135fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1363df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang if (libusb_init(NULL) < 0) { 1373df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang LIBMTP_ERROR("Libusb1 init failed\n"); 1383df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang return LIBMTP_ERROR_USB_LAYER; 1393df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang } 140fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 141fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if ((LIBMTP_debug & LIBMTP_DEBUG_USB) != 0) 142fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_set_debug(NULL,9); 1433df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang return LIBMTP_ERROR_NONE; 144fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 145fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 146fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 147fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Small recursive function to append a new usb_device to the linked list of 148fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * USB MTP devices 149fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param devlist dynamic linked list of pointers to usb devices with MTP 150fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * properties, to be extended with new device. 151fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param newdevice the new device to add. 152fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param bus_location bus for this device. 153fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return an extended array or NULL on failure. 154fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 155fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic mtpdevice_list_t *append_to_mtpdevice_list(mtpdevice_list_t *devlist, 156fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device *newdevice, 157fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 158fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint32_t bus_location) 159fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 160fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtpdevice_list_t *new_list_entry; 161fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 162fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij new_list_entry = (mtpdevice_list_t *) malloc(sizeof(mtpdevice_list_t)); 163fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (new_list_entry == NULL) { 164fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return NULL; 165fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 166fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Fill in USB device, if we *HAVE* to make a copy of the device do it here. 167fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij new_list_entry->device = newdevice; 168fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij new_list_entry->bus_location = bus_location; 169fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij new_list_entry->next = NULL; 170fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 171fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (devlist == NULL) { 172fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return new_list_entry; 173fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else { 174fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtpdevice_list_t *tmp = devlist; 175fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (tmp->next != NULL) { 176fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij tmp = tmp->next; 177fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 178fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij tmp->next = new_list_entry; 179fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 180fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return devlist; 181fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 182fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 183fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 184fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Small recursive function to free dynamic memory allocated to the linked list 185fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * of USB MTP devices 186fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param devlist dynamic linked list of pointers to usb devices with MTP 187fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * properties. 188fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return nothing 189fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 190fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void free_mtpdevice_list(mtpdevice_list_t *devlist) 191fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 192fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtpdevice_list_t *tmplist = devlist; 193fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 194fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (devlist == NULL) 195fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return; 196fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (tmplist != NULL) { 197fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtpdevice_list_t *tmp = tmplist; 198fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij tmplist = tmplist->next; 199fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Do not free() the fields (ptp_usb, params)! These are used elsewhere. 200fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free(tmp); 201fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 202fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return; 203fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 204fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 205fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 206fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This checks if a device has an MTP descriptor. The descriptor was 207fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * elaborated about in gPhoto bug 1482084, and some official documentation 208fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * with no strings attached was published by Microsoft at 209fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * http://www.microsoft.com/whdc/system/bus/USB/USBFAQ_intermed.mspx#E3HAC 210fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 211fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param dev a device struct from libusb. 212fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param dumpfile set to non-NULL to make the descriptors dump out 213fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * to this file in human-readable hex so we can scruitinze them. 214fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return 1 if the device is MTP compliant, 0 if not. 215fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 216fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic int probe_device_descriptor(libusb_device *dev, FILE *dumpfile) 217fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 218fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device_handle *devh; 219fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char buf[1024], cmd; 220fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int i; 221fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 222fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* This is to indicate if we find some vendor interface */ 223fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int found_vendor_spec_interface = 0; 224fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 225fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 226fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_get_device_descriptor (dev, &desc); 227fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) return 0; 228fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 229fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Don't examine devices that are not likely to 230fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * contain any MTP interface, update this the day 231fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * you find some weird combination... 232fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 23326ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij if (!(desc.bDeviceClass == LIBUSB_CLASS_PER_INTERFACE || 23426ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij desc.bDeviceClass == LIBUSB_CLASS_COMM || 23526ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij desc.bDeviceClass == LIBUSB_CLASS_PTP || 236fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.bDeviceClass == 0xEF || /* Intf. Association Desc.*/ 23726ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij desc.bDeviceClass == LIBUSB_CLASS_VENDOR_SPEC)) { 238fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 239fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 240fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 241bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij /* 242bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij * Attempt to open Device on this port 243bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij * 244bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij * TODO: is there a way to check the number of endpoints etc WITHOUT 245bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij * opening the device? Some color calibration devices are REALLY 246bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij * sensitive to this, and I found a Canon custom scanner that doesn't 247bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij * like it at all either :-( 248bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij */ 249fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_open(dev, &devh); 250fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) { 251fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Could not open this device */ 252fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 253fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 254fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 255fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 256fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Loop over the device configurations and interfaces. Nokia MTP-capable 257fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * handsets (possibly others) typically have the string "MTP" in their 258fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * MTP interface descriptions, that's how they can be detected, before 259fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * we try the more esoteric "OS descriptors" (below). 260fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 261fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (i = 0; i < desc.bNumConfigurations; i++) { 262fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint8_t j; 263fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_config_descriptor *config; 264fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 265fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_get_config_descriptor (dev, i, &config); 266fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) { 267fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("configdescriptor %d get failed with ret %d in probe_device_descriptor yet dev->descriptor.bNumConfigurations > 0\n", i, ret); 268fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 269fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 270fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 271fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (j = 0; j < config->bNumInterfaces; j++) { 272fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int k; 273fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (k = 0; k < config->interface[j].num_altsetting; k++) { 274fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Current interface descriptor */ 275fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij const struct libusb_interface_descriptor *intf = 276fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &config->interface[j].altsetting[k]; 277fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 278fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 279fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * MTP interfaces have three endpoints, two bulk and one 280fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * interrupt. Don't probe anything else. 281fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 282fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (intf->bNumEndpoints != 3) 283fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 284fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 285fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 286fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * We only want to probe for the OS descriptor if the 28726ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij * device is LIBUSB_CLASS_VENDOR_SPEC or one of the interfaces 288fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * in it is, so flag if we find an interface like this. 289fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 29026ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij if (intf->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC) { 291fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij found_vendor_spec_interface = 1; 292fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 293fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 294fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 295fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Check for Still Image Capture class with PIMA 15740 protocol, 296fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * also known as PTP 297fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 298fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#if 0 29926ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij if (intf->bInterfaceClass == LIBUSB_CLASS_PTP 300fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij && intf->bInterfaceSubClass == 0x01 301fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij && intf->bInterfaceProtocol == 0x01) { 302fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dumpfile != NULL) { 30315d18e31458be5006eb229df68869df2fff93495Linus Walleij fprintf(dumpfile, "Configuration %d, interface %d, altsetting %d:\n", i, j, k); 304fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf(dumpfile, " Found PTP device, check vendor " 305fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "extension...\n"); 306fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 307bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij /* 308bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij * This is where we may insert code to open a PTP 309bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij * session and query the vendor extension ID to see 310bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij * if it is 0xffffffff, i.e. MTP according to the spec. 311bda39ab9dec06c34236d1d7b01492fe13ca3d595Linus Walleij */ 312fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (was_mtp_extension) { 313fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(devh); 314fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 1; 315fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 316fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 317fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#endif 318fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 319fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 320fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Next we search for the MTP substring in the interface name. 321fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * For example : "RIM MS/MTP" should work. 322fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 323fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij buf[0] = '\0'; 324fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_get_string_descriptor_ascii(devh, 325fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij config->interface[j].altsetting[k].iInterface, 326fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij buf, 327fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1024); 328fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret < 3) 329fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 330fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (strstr((char *) buf, "MTP") != NULL) { 331fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dumpfile != NULL) { 332fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf(dumpfile, "Configuration %d, interface %d, altsetting %d:\n", i, j, k); 333fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf(dumpfile, " Interface description contains the string \"MTP\"\n"); 334fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf(dumpfile, " Device recognized as MTP, no further probing.\n"); 335fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 33615d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 337fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(devh); 338fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 1; 339fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 340fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (libusb_kernel_driver_active(devh, config->interface[j].altsetting[k].iInterface)) 341fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij { 342fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 343fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Specifically avoid probing anything else than USB mass storage devices 344fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * and non-associated drivers in Linux. 345fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 34626ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij if (config->interface[j].altsetting[k].bInterfaceClass != 34726ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij LIBUSB_CLASS_MASS_STORAGE) { 348fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("avoid probing device using attached kernel interface\n"); 34915d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 350be4a1b25d1bf8df0f9ae15d7aa0a89d2877120cdLinus Walleij libusb_close(devh); 351fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 352fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 353fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 354fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 35515d18e31458be5006eb229df68869df2fff93495Linus Walleij } 35615d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 35715d18e31458be5006eb229df68869df2fff93495Linus Walleij } 358fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 359fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 360fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Only probe for OS descriptor if the device is vendor specific 361fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * or one of the interfaces found is. 362fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 36326ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij if (desc.bDeviceClass == LIBUSB_CLASS_VENDOR_SPEC || 364fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij found_vendor_spec_interface) { 365fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 366fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Read the special descriptor */ 367fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_get_descriptor(devh, 0x03, 0xee, buf, sizeof(buf)); 368fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 369fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 370fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * If something failed we're probably stalled to we need 371fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * to clear the stall off the endpoint and say this is not 372fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * MTP. 373fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 374fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret < 0) { 375fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* EP0 is the default control endpoint */ 376fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_clear_halt (devh, 0); 377fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(devh); 378fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 379fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 380fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 381fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Dump it, if requested 382fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dumpfile != NULL && ret > 0) { 383fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf(dumpfile, "Microsoft device descriptor 0xee:\n"); 384fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij data_dump_ascii(dumpfile, buf, ret, 16); 385fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 386fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 387fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Check if descriptor length is at least 10 bytes */ 388fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret < 10) { 389fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(devh); 390fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 391fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 392fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 393fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Check if this device has a Microsoft Descriptor */ 394fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!((buf[2] == 'M') && (buf[4] == 'S') && 395fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (buf[6] == 'F') && (buf[8] == 'T'))) { 396fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(devh); 397fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 398fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 399fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 400fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Check if device responds to control message 1 or if there is an error */ 401fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij cmd = buf[16]; 402fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer (devh, 403fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE | LIBUSB_REQUEST_TYPE_VENDOR, 404fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij cmd, 405fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0, 406fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 4, 407fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij buf, 408fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(buf), 409fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij USB_TIMEOUT_DEFAULT); 410fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 411fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Dump it, if requested 412fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dumpfile != NULL && ret > 0) { 413fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf(dumpfile, "Microsoft device response to control message 1, CMD 0x%02x:\n", cmd); 414fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij data_dump_ascii(dumpfile, buf, ret, 16); 415fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 416fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 417fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* If this is true, the device either isn't MTP or there was an error */ 418fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret <= 0x15) { 419fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* TODO: If there was an error, flag it and let the user know somehow */ 420fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* if(ret == -1) {} */ 421fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(devh); 422fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 423fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 424fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 425fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Check if device is MTP or if it is something like a USB Mass Storage 426fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij device with Janus DRM support */ 427fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) { 428fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(devh); 429fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 430fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 431fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 432fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* After this point we are probably dealing with an MTP device */ 433fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 434fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 435fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Check if device responds to control message 2, which is 436fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * the extended device parameters. Most devices will just 437fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * respond with a copy of the same message as for the first 438fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * message, some respond with zero-length (which is OK) 439fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * and some with pure garbage. We're not parsing the result 440fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * so this is not very important. 441fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 442fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer (devh, 443fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE | LIBUSB_REQUEST_TYPE_VENDOR, 444fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij cmd, 445fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0, 446fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 5, 447fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij buf, 448fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(buf), 449fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij USB_TIMEOUT_DEFAULT); 450fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 451fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Dump it, if requested 452fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dumpfile != NULL && ret > 0) { 453fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf(dumpfile, "Microsoft device response to control message 2, CMD 0x%02x:\n", cmd); 454fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij data_dump_ascii(dumpfile, buf, ret, 16); 455fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 456fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 457fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* If this is true, the device errored against control message 2 */ 458fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret == -1) { 459fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* TODO: Implement callback function to let managing program know there 460fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij was a problem, along with description of the problem */ 461fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("Potential MTP Device with VendorID:%04x and " 462fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "ProductID:%04x encountered an error responding to " 463fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "control message 2.\n" 464fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "Problems may arrise but continuing\n", 465fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idVendor, desc.idProduct); 466fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if (dumpfile != NULL && ret == 0) { 467fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf(dumpfile, "Zero-length response to control message 2 (OK)\n"); 468fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if (dumpfile != NULL) { 469fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf(dumpfile, "Device responds to control message 2 with some data.\n"); 470fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 471fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Close the USB device handle */ 472fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(devh); 473fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 1; 474fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 475fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 476fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Close the USB device handle */ 477fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(devh); 478fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 479fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 480fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 481fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 482fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This function scans through the connected usb devices on a machine and 483fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * if they match known Vendor and Product identifiers appends them to the 484fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * dynamic array mtp_device_list. Be sure to call 485fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * <code>free_mtpdevice_list(mtp_device_list)</code> when you are done 486fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * with it, assuming it is not NULL. 487fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param mtp_device_list dynamic array of pointers to usb devices with MTP 488fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * properties (if this list is not empty, new entries will be appended 489fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * to the list). 490fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return LIBMTP_ERROR_NONE implies that devices have been found, scan the list 491fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * appropriately. LIBMTP_ERROR_NO_DEVICE_ATTACHED implies that no 492fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * devices have been found. 493fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 494fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic LIBMTP_error_number_t get_mtp_usb_device_list(mtpdevice_list_t ** mtp_device_list) 495fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 496fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ssize_t nrofdevs; 497fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device **devs = NULL; 498fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret, i; 4993df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang LIBMTP_error_number_t init_usb_ret; 500fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 5013df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang init_usb_ret = init_usb(); 5023df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang if (init_usb_ret != LIBMTP_ERROR_NONE) 5033df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang return init_usb_ret; 504fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 505fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij nrofdevs = libusb_get_device_list (NULL, &devs); 506fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (i = 0; i < nrofdevs ; i++) { 507fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device *dev = devs[i]; 508fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 509fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 510fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_get_device_descriptor(dev, &desc); 511fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) continue; 512fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 51326ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij if (desc.bDeviceClass != LIBUSB_CLASS_HUB) { 514fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int i; 515fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int found = 0; 516fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 517fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // First check if we know about the device already. 518fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Devices well known to us will not have their descriptors 519fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // probed, it caused problems with some devices. 520fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for(i = 0; i < mtp_device_table_size; i++) { 521fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if(desc.idVendor == mtp_device_table[i].vendor_id && 522fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idProduct == mtp_device_table[i].product_id) { 523fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Append this usb device to the MTP device list */ 524fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *mtp_device_list = append_to_mtpdevice_list(*mtp_device_list, 525fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev, 526fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_get_bus_number(dev)); 527fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij found = 1; 528fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 529fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 530fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 531fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // If we didn't know it, try probing the "OS Descriptor". 532fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!found) { 533fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (probe_device_descriptor(dev, NULL)) { 534fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Append this usb device to the MTP USB Device List */ 535fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *mtp_device_list = append_to_mtpdevice_list(*mtp_device_list, 536fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev, 537fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_get_bus_number(dev)); 538fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 539fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 540fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * By thomas_-_s: Also append devices that are no MTP but PTP devices 541fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * if this is commented out. 542fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 543fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 544fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else { 545fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Check whether the device is no USB hub but a PTP. 54626ceac867dc93babdb17e2d1bd9ee947802afce9Linus Walleij if ( dev->config != NULL &&dev->config->interface->altsetting->bInterfaceClass == LIBUSB_CLASS_PTP && dev->descriptor.bDeviceClass != LIBUSB_CLASS_HUB ) { 547fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *mtp_device_list = append_to_mtpdevice_list(*mtp_device_list, dev, bus->location); 548fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 549fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 550fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 551fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 552fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 553fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 554fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 555fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* If nothing was found we end up here. */ 556fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if(*mtp_device_list == NULL) { 557fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NO_DEVICE_ATTACHED; 558fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 559fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NONE; 560fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 561fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 562fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 563fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Checks if a specific device with a certain bus and device 564fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * number has an MTP type device descriptor. 565fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 566fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param busno the bus number of the device to check 567fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param deviceno the device number of the device to check 568fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return 1 if the device is MTP else 0 569fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 570fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijint LIBMTP_Check_Specific_Device(int busno, int devno) 571fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 572fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ssize_t nrofdevs; 573fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device **devs = NULL; 574fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int i; 5753df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang LIBMTP_error_number_t init_usb_ret; 576fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 5773df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang init_usb_ret = init_usb(); 5783df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang if (init_usb_ret != LIBMTP_ERROR_NONE) 5793df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang return 0; 580fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 581fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij nrofdevs = libusb_get_device_list (NULL, &devs); 582fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (i = 0; i < nrofdevs ; i++ ) { 58330f9acdc94c087209d3feb80bf545ce3cf1033a0Jonas Salling 58430f9acdc94c087209d3feb80bf545ce3cf1033a0Jonas Salling if (libusb_get_bus_number(devs[i]) != busno) 585fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 58630f9acdc94c087209d3feb80bf545ce3cf1033a0Jonas Salling if (libusb_get_device_address(devs[i]) != devno) 587fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 58830f9acdc94c087209d3feb80bf545ce3cf1033a0Jonas Salling 589fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (probe_device_descriptor(devs[i], NULL)) 590fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 1; 591fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 592fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 593fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 594fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 595fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 596fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Detect the raw MTP device descriptors and return a list of 597fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * of the devices found. 598fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 599fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param devices a pointer to a variable that will hold 600fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * the list of raw devices found. This may be NULL 601fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * on return if the number of detected devices is zero. 602fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * The user shall simply <code>free()</code> this 603fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * variable when finished with the raw devices, 604fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * in order to release memory. 605fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param numdevs a pointer to an integer that will hold 606fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * the number of devices in the list. This may 607fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * be 0. 608fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return 0 if successful, any other value means failure. 609fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 610fbbef8b16876568f760986e4ff8f4921b8373fd5Linus WalleijLIBMTP_error_number_t LIBMTP_Detect_Raw_Devices(LIBMTP_raw_device_t ** devices, 611fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int * numdevs) 612fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 613fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtpdevice_list_t *devlist = NULL; 614fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtpdevice_list_t *dev; 615fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_error_number_t ret; 616fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_raw_device_t *retdevs; 617fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int devs = 0; 618fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int i, j; 619fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 620fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = get_mtp_usb_device_list(&devlist); 621fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret == LIBMTP_ERROR_NO_DEVICE_ATTACHED) { 622fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *devices = NULL; 623fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *numdevs = 0; 624fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 625fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if (ret != LIBMTP_ERROR_NONE) { 626fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: get_mtp_usb_device_list() " 627fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "error code: %d on line %d\n", ret, __LINE__); 628fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 629fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 630fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 631fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Get list size 632fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = devlist; 633fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (dev != NULL) { 634fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij devs++; 635fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = dev->next; 636fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 637fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (devs == 0) { 638fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *devices = NULL; 639fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *numdevs = 0; 640fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NONE; 641fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 642fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Conjure a device list 643fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs = (LIBMTP_raw_device_t *) malloc(sizeof(LIBMTP_raw_device_t) * devs); 644fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (retdevs == NULL) { 645fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Out of memory 646fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *devices = NULL; 647fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *numdevs = 0; 648fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_MEMORY_ALLOCATION; 649fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 650fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = devlist; 651fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij i = 0; 652fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (dev != NULL) { 653fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int device_known = 0; 654fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 655fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 656fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_get_device_descriptor (dev->device, &desc); 657fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Assign default device info 658fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.vendor = NULL; 659fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.vendor_id = desc.idVendor; 660fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.product = NULL; 661fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.product_id = desc.idProduct; 662fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.device_flags = 0x00000000U; 663fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // See if we can locate some additional vendor info and device flags 664fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for(j = 0; j < mtp_device_table_size; j++) { 665fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if(desc.idVendor == mtp_device_table[j].vendor_id && 666fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idProduct == mtp_device_table[j].product_id) { 667fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij device_known = 1; 668fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.vendor = mtp_device_table[j].vendor; 669fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.product = mtp_device_table[j].product; 670fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.device_flags = mtp_device_table[j].device_flags; 671fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 672fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This device is known to the developers 673fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("Device %d (VID=%04x and PID=%04x) is a %s %s.\n", 674fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij i, 675fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idVendor, 676fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idProduct, 677fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtp_device_table[j].vendor, 678fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtp_device_table[j].product); 679fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 680fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 681fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 682fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!device_known) { 683fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This device is unknown to the developers 684fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("Device %d (VID=%04x and PID=%04x) is UNKNOWN.\n", 685fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij i, 686fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idVendor, 687fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idProduct); 688fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("Please report this VID/PID and the device model to the " 689fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "libmtp development team\n"); 690fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 691fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Trying to get iManufacturer or iProduct from the device at this 692fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * point would require opening a device handle, that we don't want 693fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * to do right now. (Takes time for no good enough reason.) 694fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 695fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 696fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Save the location on the bus 697fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].bus_location = libusb_get_bus_number (dev->device); 698fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].devnum = libusb_get_device_address (dev->device); 699fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij i++; 700fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = dev->next; 701fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 702fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *devices = retdevs; 703fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *numdevs = i; 704fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free_mtpdevice_list(devlist); 705fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NONE; 706fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 707fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 708fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 709fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This routine just dumps out low-level 710fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * USB information about the current device. 711fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param ptp_usb the USB device to get information from. 712fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 713fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijvoid dump_usbinfo(PTP_USB *ptp_usb) 714fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 715fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device *dev; 716fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 717fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 718fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (libusb_kernel_driver_active(ptp_usb->handle, ptp_usb->interface)) 719fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Interface has a kernel driver attached.\n"); 720fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 721fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = libusb_get_device (ptp_usb->handle); 722fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_get_device_descriptor (dev, &desc); 723fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 724fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" bcdUSB: %d\n", desc.bcdUSB); 725fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" bDeviceClass: %d\n", desc.bDeviceClass); 726fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" bDeviceSubClass: %d\n", desc.bDeviceSubClass); 727fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" bDeviceProtocol: %d\n", desc.bDeviceProtocol); 728fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" idVendor: %04x\n", desc.idVendor); 729fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" idProduct: %04x\n", desc.idProduct); 730fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" IN endpoint maxpacket: %d bytes\n", ptp_usb->inep_maxpacket); 731fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" OUT endpoint maxpacket: %d bytes\n", ptp_usb->outep_maxpacket); 732fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Raw device info:\n"); 733fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Bus location: %d\n", ptp_usb->rawdevice.bus_location); 734fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Device number: %d\n", ptp_usb->rawdevice.devnum); 735fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Device entry info:\n"); 736fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Vendor: %s\n", ptp_usb->rawdevice.device_entry.vendor); 737fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Vendor id: 0x%04x\n", ptp_usb->rawdevice.device_entry.vendor_id); 738fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Product: %s\n", ptp_usb->rawdevice.device_entry.product); 739fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Vendor id: 0x%04x\n", ptp_usb->rawdevice.device_entry.product_id); 740fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Device flags: 0x%08x\n", ptp_usb->rawdevice.device_entry.device_flags); 741fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (void) probe_device_descriptor(dev, stdout); 742fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 743fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 744fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 745fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Retrieve the apropriate playlist extension for this 746fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * device. Rather hacky at the moment. This is probably 747fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * desired by the managing software, but when creating 748fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * lists on the device itself you notice certain preferences. 749fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param ptp_usb the USB device to get suggestion for. 750fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return the suggested playlist extension. 751fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 752fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijconst char *get_playlist_extension(PTP_USB *ptp_usb) 753fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 754fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device *dev; 755fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 756fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij static char creative_pl_extension[] = ".zpl"; 757fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij static char default_pl_extension[] = ".pla"; 758fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 759fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = libusb_get_device(ptp_usb->handle); 760fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_get_device_descriptor (dev, &desc); 761fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (desc.idVendor == 0x041e) 762fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return creative_pl_extension; 763fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return default_pl_extension; 764fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 765fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 766fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void 767fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijlibusb_glue_debug (PTPParams *params, const char *format, ...) 768fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 769fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_list args; 770fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 771fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_start (args, format); 772fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (params->debug_func!=NULL) 773fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->debug_func (params->data, format, args); 774fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else 775fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij { 776fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij vfprintf (stderr, format, args); 777fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf (stderr,"\n"); 778fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fflush (stderr); 779fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 780fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_end (args); 781fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 782fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 783fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void 784fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijlibusb_glue_error (PTPParams *params, const char *format, ...) 785fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 786fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_list args; 787fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 788fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_start (args, format); 789fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (params->error_func!=NULL) 790fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->error_func (params->data, format, args); 791fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else 792fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij { 793fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij vfprintf (stderr, format, args); 794fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf (stderr,"\n"); 795fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fflush (stderr); 796fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 797fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_end (args); 798fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 799fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 800fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 801fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* 802fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * ptp_read_func() and ptp_write_func() are 803fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * based on same functions usb.c in libgphoto2. 804fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Much reading packet logs and having fun with trials and errors 805fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * reveals that WMP / Windows is probably using an algorithm like this 806fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * for large transfers: 807fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 808fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 1. Send the command (0x0c bytes) if headers are split, else, send 809fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * command plus sizeof(endpoint) - 0x0c bytes. 810fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 2. Send first packet, max size to be sizeof(endpoint) but only when using 811fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * split headers. Else goto 3. 812fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 3. REPEAT send 0x10000 byte chunks UNTIL remaining bytes < 0x10000 813fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * We call 0x10000 CONTEXT_BLOCK_SIZE. 814fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 4. Send remaining bytes MOD sizeof(endpoint) 815fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 5. Send remaining bytes. If this happens to be exactly sizeof(endpoint) 816fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * then also send a zero-length package. 817fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 818fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Further there is some special quirks to handle zero reads from the 819fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * device, since some devices can't do them at all due to shortcomings 820fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * of the USB slave controller in the device. 821fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 822fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define CONTEXT_BLOCK_SIZE_1 0x3e00 823fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define CONTEXT_BLOCK_SIZE_2 0x200 824fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define CONTEXT_BLOCK_SIZE CONTEXT_BLOCK_SIZE_1+CONTEXT_BLOCK_SIZE_2 825fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic short 826fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_read_func ( 827fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long size, PTPDataHandler *handler,void *data, 828fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long *readbytes, 829fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int readzero 830fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 831fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *)data; 832fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long toread = 0; 833fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret = 0; 834fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int xread; 835fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long curread = 0; 836fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long written; 837fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char *bytes; 838fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int expect_terminator_byte = 0; 839fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 840fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This is the largest block we'll need to read in. 841fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes = malloc(CONTEXT_BLOCK_SIZE); 842fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (curread < size) { 843fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 844fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Remaining size to read: 0x%04lx bytes\n", size - curread); 845fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 846fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // check equal to condition here 847fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (size - curread < CONTEXT_BLOCK_SIZE) 848fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij { 849fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // this is the last packet 850fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread = size - curread; 851fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // this is equivalent to zero read for these devices 852fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (readzero && FLAG_NO_ZERO_READS(ptp_usb) && toread % 64 == 0) { 853fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread += 1; 854fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij expect_terminator_byte = 1; 855fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 856fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 857fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else if (curread == 0) 858fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // we are first packet, but not last packet 859fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread = CONTEXT_BLOCK_SIZE_1; 860fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else if (toread == CONTEXT_BLOCK_SIZE_1) 861fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread = CONTEXT_BLOCK_SIZE_2; 862fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else if (toread == CONTEXT_BLOCK_SIZE_2) 863fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread = CONTEXT_BLOCK_SIZE_1; 864fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else 865fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("unexpected toread size 0x%04x, 0x%04x remaining bytes\n", 866fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned int) toread, (unsigned int) (size-curread)); 867fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 868fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Reading in 0x%04lx bytes\n", toread); 869fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 870fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = USB_BULK_READ(ptp_usb->handle, 871fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->inep, 872fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes, 873fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread, 874fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 875fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 876fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 877fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Result of read: 0x%04x (%d bytes)\n", ret, xread); 878fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 879fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) 880fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 881fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 882fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("<==USB IN\n"); 883fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (xread == 0) 884fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Zero Read\n"); 885fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else 886fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(bytes, xread, 16); 887fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 888fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // want to discard extra byte 889fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (expect_terminator_byte && xread == toread) 890fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij { 891fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("<==USB IN\nDiscarding extra byte\n"); 892fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 893fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij xread--; 894fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 895fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 896fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int putfunc_ret = handler->putfunc(NULL, handler->priv, xread, bytes, &written); 897fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (putfunc_ret != PTP_RC_OK) 898fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return putfunc_ret; 899fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 900fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_complete += xread; 901fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij curread += xread; 902fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 903fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Increase counters, call callback 904fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->callback_active) { 905fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) { 906fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // send last update and disable callback. 907fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total; 908fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->callback_active = 0; 909fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 910fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->current_transfer_callback != NULL) { 911fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 912fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete, 913fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_total, 914fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_callback_data); 915fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != 0) { 916fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_CANCEL; 917fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 918fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 919fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 920fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 921fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (xread < toread) /* short reads are common */ 922fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 923fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 924fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (readbytes) *readbytes = curread; 925fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free (bytes); 926fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 927fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // there might be a zero packet waiting for us... 928fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (readzero && 929fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij !FLAG_NO_ZERO_READS(ptp_usb) && 930fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij curread % ptp_usb->outep_maxpacket == 0) { 931fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char temp; 932fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int zeroresult = 0, xread; 933fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 934fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("<==USB IN\n"); 935fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Zero Read\n"); 936fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 937fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij zeroresult = USB_BULK_READ(ptp_usb->handle, 938fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->inep, 939fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &temp, 940fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0, 941fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 942fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 943fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (zeroresult != LIBUSB_SUCCESS) 944fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("LIBMTP panic: unable to read in zero packet, response 0x%04x", zeroresult); 945fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 946fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 947fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 948fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 949fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 950fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic short 951fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_write_func ( 952fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long size, 953fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPDataHandler *handler, 954fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij void *data, 955fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long *written 956fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 957fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *)data; 958fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long towrite = 0; 959fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret = 0; 960fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long curwrite = 0; 961fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char *bytes; 962fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 963fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This is the largest block we'll need to read in. 964fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes = malloc(CONTEXT_BLOCK_SIZE); 965fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!bytes) { 966fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 967fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 968fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (curwrite < size) { 969fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long usbwritten = 0; 970fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int xwritten; 971fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 972fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite = size-curwrite; 973fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (towrite > CONTEXT_BLOCK_SIZE) { 974fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite = CONTEXT_BLOCK_SIZE; 975fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else { 976fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This magic makes packets the same size that WMP send them. 977fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (towrite > ptp_usb->outep_maxpacket && towrite % ptp_usb->outep_maxpacket != 0) { 978fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite -= towrite % ptp_usb->outep_maxpacket; 979fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 980fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 981fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int getfunc_ret = handler->getfunc(NULL, handler->priv,towrite,bytes,&towrite); 982fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (getfunc_ret != PTP_RC_OK) 983fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return getfunc_ret; 984fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (usbwritten < towrite) { 985fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = USB_BULK_WRITE(ptp_usb->handle, 986fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->outep, 987fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes+usbwritten, 988fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite-usbwritten, 989fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xwritten, 990fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 991fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 992fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("USB OUT==>\n"); 993fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 994fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) { 995fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 996fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 997fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(bytes+usbwritten, xwritten, 16); 998fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // check for result == 0 perhaps too. 999fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Increase counters 1000fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_complete += xwritten; 1001fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij curwrite += xwritten; 1002fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbwritten += xwritten; 1003fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1004fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // call callback 1005fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->callback_active) { 1006fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) { 1007fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // send last update and disable callback. 1008fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total; 1009fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->callback_active = 0; 1010fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1011fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->current_transfer_callback != NULL) { 1012fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 1013fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete, 1014fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_total, 1015fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_callback_data); 1016fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != 0) { 1017fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_CANCEL; 1018fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1019fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1020fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1021fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (xwritten < towrite) /* short writes happen */ 1022fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1023fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1024fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free (bytes); 1025fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (written) { 1026fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *written = curwrite; 1027fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1028fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1029fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // If this is the last transfer send a zero write if required 1030fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) { 1031fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if ((towrite % ptp_usb->outep_maxpacket) == 0) { 1032fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int xwritten; 1033fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1034fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("USB OUT==>\n"); 1035fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Zero Write\n"); 1036fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1037fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret =USB_BULK_WRITE(ptp_usb->handle, 1038fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->outep, 1039fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) "x", 1040fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0, 1041fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xwritten, 1042fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 1043fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1044fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1045fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1046fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) 1047fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 1048fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1049fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1050fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1051fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* memory data get/put handler */ 1052fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijtypedef struct { 1053fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char *data; 1054fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long size, curoff; 1055fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} PTPMemHandlerPrivate; 1056fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1057fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1058fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijmemory_getfunc(PTPParams* params, void* private, 1059fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long wantlen, unsigned char *data, 1060fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long *gotlen 1061fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 1062fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)private; 1063fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long tocopy = wantlen; 1064fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1065fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (priv->curoff + tocopy > priv->size) 1066fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij tocopy = priv->size - priv->curoff; 1067fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy (data, priv->data + priv->curoff, tocopy); 1068fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->curoff += tocopy; 1069fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *gotlen = tocopy; 1070fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1071fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1072fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1073fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1074fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijmemory_putfunc(PTPParams* params, void* private, 1075fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long sendlen, unsigned char *data, 1076fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long *putlen 1077fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 1078fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)private; 1079fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1080fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (priv->curoff + sendlen > priv->size) { 1081fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->data = realloc (priv->data, priv->curoff+sendlen); 1082fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->size = priv->curoff + sendlen; 1083fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1084fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy (priv->data + priv->curoff, data, sendlen); 1085fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->curoff += sendlen; 1086fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *putlen = sendlen; 1087fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1088fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1089fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1090fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* init private struct for receiving data. */ 1091fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1092fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_init_recv_memory_handler(PTPDataHandler *handler) { 1093fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv; 1094fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv = malloc (sizeof(PTPMemHandlerPrivate)); 1095fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->priv = priv; 1096fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->getfunc = memory_getfunc; 1097fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->putfunc = memory_putfunc; 1098fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->data = NULL; 1099fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->size = 0; 1100fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->curoff = 0; 1101fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1102fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1103fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1104fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* init private struct and put data in for sending data. 1105fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * data is still owned by caller. 1106fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1107fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1108fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_init_send_memory_handler(PTPDataHandler *handler, 1109fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char *data, unsigned long len 1110fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 1111fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv; 1112fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv = malloc (sizeof(PTPMemHandlerPrivate)); 1113fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!priv) 1114fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_GeneralError; 1115fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->priv = priv; 1116fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->getfunc = memory_getfunc; 1117fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->putfunc = memory_putfunc; 1118fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->data = data; 1119fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->size = len; 1120fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->curoff = 0; 1121fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1122fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1123fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1124fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* free private struct + data */ 1125fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1126fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_exit_send_memory_handler (PTPDataHandler *handler) { 1127fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)handler->priv; 1128fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* data is owned by caller */ 1129fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free (priv); 1130fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1131fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1132fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1133fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* hand over our internal data to caller */ 1134fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1135fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_exit_recv_memory_handler (PTPDataHandler *handler, 1136fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char **data, unsigned long *size 1137fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 1138fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)handler->priv; 1139fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *data = priv->data; 1140fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *size = priv->size; 1141fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free (priv); 1142fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1143fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1144fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1145fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* send / receive functions */ 1146fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1147fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1148fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_sendreq (PTPParams* params, PTPContainer* req) 1149fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1150fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1151fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBBulkContainer usbreq; 1152fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPDataHandler memhandler; 1153fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long written = 0; 1154fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long towrite; 1155fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1156fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij char txt[256]; 1157fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1158fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (void) ptp_render_opcode (params, req->Code, sizeof(txt), txt); 1159fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("REQUEST: 0x%04x, %s\n", req->Code, txt); 1160fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1161fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* build appropriate USB container */ 1162fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.length=htod32(PTP_USB_BULK_REQ_LEN- 1163fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (sizeof(uint32_t)*(5-req->Nparam))); 1164fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.type=htod16(PTP_USB_CONTAINER_COMMAND); 1165fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.code=htod16(req->Code); 1166fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.trans_id=htod32(req->Transaction_ID); 1167fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.payload.params.param1=htod32(req->Param1); 1168fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.payload.params.param2=htod32(req->Param2); 1169fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.payload.params.param3=htod32(req->Param3); 1170fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.payload.params.param4=htod32(req->Param4); 1171fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.payload.params.param5=htod32(req->Param5); 1172fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* send it to responder */ 1173fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite = PTP_USB_BULK_REQ_LEN-(sizeof(uint32_t)*(5-req->Nparam)); 1174fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_init_send_memory_handler (&memhandler, (unsigned char*)&usbreq, towrite); 1175fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret=ptp_write_func( 1176fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite, 1177fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &memhandler, 1178fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->data, 1179fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &written 1180fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ); 1181fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_exit_send_memory_handler (&memhandler); 1182fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK && ret != PTP_ERROR_CANCEL) { 1183fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1184fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1185fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (written != towrite && ret != PTP_ERROR_CANCEL && ret != PTP_ERROR_IO) { 1186fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_error (params, 1187fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP: request code 0x%04x sending req wrote only %ld bytes instead of %d", 1188fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij req->Code, written, towrite 1189fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ); 1190fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1191fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1192fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1193fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1194fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1195fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1196fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_senddata (PTPParams* params, PTPContainer* ptp, 1197b3aaade14e14a67419c3edf6367b50599eec134fLinus Walleij uint64_t size, PTPDataHandler *handler 1198fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 1199fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1200fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int wlen, datawlen; 1201fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long written; 1202fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBBulkContainer usbdata; 1203fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint32_t bytes_left_to_transfer; 1204fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPDataHandler memhandler; 1205fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1206fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1207fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("SEND DATA PHASE\n"); 1208fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1209fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* build appropriate USB container */ 1210fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.length = htod32(PTP_USB_BULK_HDR_LEN+size); 1211fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.type = htod16(PTP_USB_CONTAINER_DATA); 1212fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.code = htod16(ptp->Code); 1213fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.trans_id= htod32(ptp->Transaction_ID); 1214fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1215fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ((PTP_USB*)params->data)->current_transfer_complete = 0; 1216fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ((PTP_USB*)params->data)->current_transfer_total = size+PTP_USB_BULK_HDR_LEN; 1217fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1218fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (params->split_header_data) { 1219fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij datawlen = 0; 1220fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij wlen = PTP_USB_BULK_HDR_LEN; 1221fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else { 1222fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long gotlen; 1223fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* For all camera devices. */ 1224fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij datawlen = (size<PTP_USB_BULK_PAYLOAD_LEN_WRITE)?size:PTP_USB_BULK_PAYLOAD_LEN_WRITE; 1225fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij wlen = PTP_USB_BULK_HDR_LEN + datawlen; 1226fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1227fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = handler->getfunc(params, handler->priv, datawlen, usbdata.payload.data, &gotlen); 1228fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != PTP_RC_OK) 1229fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1230fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (gotlen != datawlen) 1231fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_GeneralError; 1232fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1233fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_init_send_memory_handler (&memhandler, (unsigned char *)&usbdata, wlen); 1234fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* send first part of data */ 1235fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_write_func(wlen, &memhandler, params->data, &written); 1236fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_exit_send_memory_handler (&memhandler); 1237fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1238fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1239fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1240fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (size <= datawlen) return ret; 1241fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* if everything OK send the rest */ 1242fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes_left_to_transfer = size-datawlen; 1243fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_RC_OK; 1244fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while(bytes_left_to_transfer > 0) { 1245fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_write_func (bytes_left_to_transfer, handler, params->data, &written); 1246fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != PTP_RC_OK) 1247fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1248fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (written == 0) { 1249fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1250fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1251fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1252fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes_left_to_transfer -= written; 1253fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1254fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK && ret != PTP_ERROR_CANCEL) 1255fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1256fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1257fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1258fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1259fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t ptp_usb_getpacket(PTPParams *params, 1260fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBBulkContainer *packet, unsigned long *rlen) 1261fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1262fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPDataHandler memhandler; 1263fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1264fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char *x = NULL; 1265fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1266fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* read the header and potentially the first data */ 1267fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (params->response_packet_size > 0) { 1268fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* If there is a buffered packet, just use it. */ 1269fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy(packet, params->response_packet, params->response_packet_size); 1270fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *rlen = params->response_packet_size; 1271fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free(params->response_packet); 1272fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->response_packet = NULL; 1273fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->response_packet_size = 0; 1274fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Here this signifies a "virtual read" */ 1275fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1276fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1277fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_init_recv_memory_handler (&memhandler); 1278fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_read_func(PTP_USB_BULK_HS_MAX_PACKET_LEN_READ, &memhandler, params->data, rlen, 0); 1279fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_exit_recv_memory_handler (&memhandler, &x, rlen); 1280fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (x) { 1281fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy (packet, x, *rlen); 1282fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free (x); 1283fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1284fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1285fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1286fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1287fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1288fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_getdata (PTPParams* params, PTPContainer* ptp, PTPDataHandler *handler) 1289fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1290fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1291fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBBulkContainer usbdata; 1292fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long written; 1293fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *) params->data; 1294fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int putfunc_ret; 1295fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1296fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("GET DATA PHASE\n"); 1297fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1298fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memset(&usbdata,0,sizeof(usbdata)); 1299fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij do { 1300fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long len, rlen; 1301fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1302fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_usb_getpacket(params, &usbdata, &rlen); 1303fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1304fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1305fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1306fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1307fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dtoh16(usbdata.type)!=PTP_USB_CONTAINER_DATA) { 1308fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_DATA_EXPECTED; 1309fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1310fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1311fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dtoh16(usbdata.code)!=ptp->Code) { 1312fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_IGNORE_HEADER_ERRORS(ptp_usb)) { 1313fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_debug (params, "ptp2/ptp_usb_getdata: detected a broken " 1314fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP header, code field insane, expect problems! (But continuing)"); 1315fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Repair the header, so it won't wreak more havoc, don't just ignore it. 1316fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Typically these two fields will be broken. 1317fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.code = htod16(ptp->Code); 1318fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.trans_id = htod32(ptp->Transaction_ID); 1319fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_RC_OK; 1320fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else { 1321fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = dtoh16(usbdata.code); 1322fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This filters entirely insane garbage return codes, but still 1323fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // makes it possible to return error codes in the code field when 1324fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // getting data. It appears Windows ignores the contents of this 1325fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // field entirely. 1326fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret < PTP_RC_Undefined || ret > PTP_RC_SpecificationOfDestinationUnsupported) { 1327fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_debug (params, "ptp2/ptp_usb_getdata: detected a broken " 1328fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP header, code field insane."); 1329fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1330fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1331fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1332fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1333fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1334fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (usbdata.length == 0xffffffffU) { 1335fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Copy first part of data to 'data' */ 1336fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij putfunc_ret = 1337fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->putfunc( 1338fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params, handler->priv, rlen - PTP_USB_BULK_HDR_LEN, usbdata.payload.data, 1339fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &written 1340fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ); 1341fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (putfunc_ret != PTP_RC_OK) 1342fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return putfunc_ret; 1343fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1344fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* stuff data directly to passed data handler */ 1345fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (1) { 1346fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long readdata; 1347fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t xret; 1348fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1349fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij xret = ptp_read_func( 1350fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB_BULK_HS_MAX_PACKET_LEN_READ, 1351fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler, 1352fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->data, 1353fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &readdata, 1354fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0 1355fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ); 1356fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (xret != PTP_RC_OK) 1357fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return xret; 1358fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (readdata < PTP_USB_BULK_HS_MAX_PACKET_LEN_READ) 1359fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1360fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1361fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1362fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1363fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (rlen > dtoh32(usbdata.length)) { 1364fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1365fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Buffer the surplus response packet if it is >= 1366fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * PTP_USB_BULK_HDR_LEN 1367fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * (i.e. it is probably an entire package) 1368fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * else discard it as erroneous surplus data. 1369fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This will even work if more than 2 packets appear 1370fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * in the same transaction, they will just be handled 1371fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * iteratively. 1372fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 1373fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Marcus observed stray bytes on iRiver devices; 1374fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * these are still discarded. 1375fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1376fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned int packlen = dtoh32(usbdata.length); 1377fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned int surplen = rlen - packlen; 1378fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1379fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (surplen >= PTP_USB_BULK_HDR_LEN) { 1380fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->response_packet = malloc(surplen); 1381fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy(params->response_packet, 1382fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (uint8_t *) &usbdata + packlen, surplen); 1383fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->response_packet_size = surplen; 1384fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Ignore reading one extra byte if device flags have been set */ 1385fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if(!FLAG_NO_ZERO_READS(ptp_usb) && 1386fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (rlen - dtoh32(usbdata.length) == 1)) { 1387fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_debug (params, "ptp2/ptp_usb_getdata: read %d bytes " 1388fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "too much, expect problems!", 1389fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij rlen - dtoh32(usbdata.length)); 1390fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1391fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij rlen = packlen; 1392fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1393fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1394fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* For most PTP devices rlen is 512 == sizeof(usbdata) 1395fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * here. For MTP devices splitting header and data it might 1396fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * be 12. 1397fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1398fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Evaluate full data length. */ 1399fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij len=dtoh32(usbdata.length)-PTP_USB_BULK_HDR_LEN; 1400fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1401fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* autodetect split header/data MTP devices */ 1402fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dtoh32(usbdata.length) > 12 && (rlen==12)) 1403fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->split_header_data = 1; 1404fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1405fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Copy first part of data to 'data' */ 1406fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij putfunc_ret = 1407fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->putfunc( 1408fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params, handler->priv, rlen - PTP_USB_BULK_HDR_LEN, 1409fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.payload.data, 1410fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &written 1411fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ); 1412fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (putfunc_ret != PTP_RC_OK) 1413fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return putfunc_ret; 1414fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1415fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_NO_ZERO_READS(ptp_usb) && 1416fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij len+PTP_USB_BULK_HDR_LEN == PTP_USB_BULK_HS_MAX_PACKET_LEN_READ) { 1417fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1418fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Reading in extra terminating byte\n"); 1419fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1420fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // need to read in extra byte and discard it 1421fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int result = 0, xread; 1422fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char byte = 0; 1423fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij result = USB_BULK_READ(ptp_usb->handle, 1424fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->inep, 1425fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &byte, 1426fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1, 1427fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1428fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 1429fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1430fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (result != 1) 1431fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("Could not read in extra byte for PTP_USB_BULK_HS_MAX_PACKET_LEN_READ long file, return value 0x%04x\n", result); 1432fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if (len+PTP_USB_BULK_HDR_LEN == PTP_USB_BULK_HS_MAX_PACKET_LEN_READ && params->split_header_data == 0) { 1433fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int zeroresult = 0, xread; 1434fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char zerobyte = 0; 1435fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1436fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("Reading in zero packet after header\n"); 1437fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1438fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij zeroresult = USB_BULK_READ(ptp_usb->handle, 1439fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->inep, 1440fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &zerobyte, 1441fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0, 1442fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1443fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 1444fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1445fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (zeroresult != 0) 1446fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("LIBMTP panic: unable to read in zero packet, response 0x%04x", zeroresult); 1447fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1448fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1449fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Is that all of data? */ 1450fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (len+PTP_USB_BULK_HDR_LEN<=rlen) { 1451fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1452fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1453fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1454fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_read_func(len - (rlen - PTP_USB_BULK_HDR_LEN), 1455fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler, 1456fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->data, &rlen, 1); 1457fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1458fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1459fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1460fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1461fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } while (0); 1462fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1463fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1464fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1465fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1466fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_getresp (PTPParams* params, PTPContainer* resp) 1467fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1468fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1469fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long rlen; 1470fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBBulkContainer usbresp; 1471fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *)(params->data); 1472fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1473fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1474fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("RESPONSE: "); 1475fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1476fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memset(&usbresp,0,sizeof(usbresp)); 1477fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* read response, it should never be longer than sizeof(usbresp) */ 1478fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_usb_getpacket(params, &usbresp, &rlen); 1479fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1480fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Fix for bevahiour reported by Scott Snyder on Samsung YP-U3. The player 1481fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // sends a packet containing just zeroes of length 2 (up to 4 has been seen too) 1482fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // after a NULL packet when it should send the response. This code ignores 1483fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // such illegal packets. 1484fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (ret==PTP_RC_OK && rlen<PTP_USB_BULK_HDR_LEN && usbresp.length==0) { 1485fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_debug (params, "ptp_usb_getresp: detected short response " 1486fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "of %d bytes, expect problems! (re-reading " 1487fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "response), rlen"); 1488fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_usb_getpacket(params, &usbresp, &rlen); 1489fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1490fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1491fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1492fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1493fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else 1494fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dtoh16(usbresp.type)!=PTP_USB_CONTAINER_RESPONSE) { 1495fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_RESP_EXPECTED; 1496fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else 1497fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dtoh16(usbresp.code)!=resp->Code) { 1498fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = dtoh16(usbresp.code); 1499fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1500fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1501fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("%04x\n", ret); 1502fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1503fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1504fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* libusb_glue_error (params, 1505fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP: request code 0x%04x getting resp error 0x%04x", 1506fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Code, ret);*/ 1507fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1508fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1509fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* build an appropriate PTPContainer */ 1510fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Code=dtoh16(usbresp.code); 1511fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->SessionID=params->session_id; 1512fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Transaction_ID=dtoh32(usbresp.trans_id); 1513fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_IGNORE_HEADER_ERRORS(ptp_usb)) { 1514fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (resp->Transaction_ID != params->transaction_id-1) { 1515fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_debug (params, "ptp_usb_getresp: detected a broken " 1516fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP header, transaction ID insane, expect " 1517fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "problems! (But continuing)"); 1518fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Repair the header, so it won't wreak more havoc. 1519fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Transaction_ID = params->transaction_id-1; 1520fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1521fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1522fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Param1=dtoh32(usbresp.payload.params.param1); 1523fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Param2=dtoh32(usbresp.payload.params.param2); 1524fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Param3=dtoh32(usbresp.payload.params.param3); 1525fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Param4=dtoh32(usbresp.payload.params.param4); 1526fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Param5=dtoh32(usbresp.payload.params.param5); 1527fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1528fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1529fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1530fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* Event handling functions */ 1531fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1532fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* PTP Events wait for or check mode */ 1533fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define PTP_EVENT_CHECK 0x0000 /* waits for */ 1534fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define PTP_EVENT_CHECK_FAST 0x0001 /* checks */ 1535fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1536fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic inline uint16_t 1537fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_event (PTPParams* params, PTPContainer* event, int wait) 1538fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1539fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1540fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int result, xread; 1541fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long rlen; 1542fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBEventContainer usbevent; 1543fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *)(params->data); 1544fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1545fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memset(&usbevent,0,sizeof(usbevent)); 1546fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1547fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if ((params==NULL) || (event==NULL)) 1548fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_BADPARAM; 1549fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_RC_OK; 1550fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij switch(wait) { 1551fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij case PTP_EVENT_CHECK: 15527433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij result = USB_BULK_READ(ptp_usb->handle, 1553fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->intep, 1554fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) &usbevent, 1555fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(usbevent), 1556fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1557fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0); 15587433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij if (xread == 0) 1559fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij result = USB_BULK_READ(ptp_usb->handle, 1560fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->intep, 1561fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) &usbevent, 1562fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(usbevent), 1563fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1564fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0); 1565fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (result < 0) ret = PTP_ERROR_IO; 1566fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1567fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij case PTP_EVENT_CHECK_FAST: 15687433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij result = USB_BULK_READ(ptp_usb->handle, 1569fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->intep, 1570fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) &usbevent, 1571fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(usbevent), 1572fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1573fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 15747433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij if (xread == 0) 1575fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij result = USB_BULK_READ(ptp_usb->handle, 1576fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->intep, 1577fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) &usbevent, 1578fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(usbevent), 1579fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1580fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 1581fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (result < 0) ret = PTP_ERROR_IO; 1582fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1583fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij default: 15847433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij ret = PTP_ERROR_BADPARAM; 1585fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1586fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1587fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1588fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_error (params, 1589fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP: reading event an error 0x%04x occurred", ret); 1590fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 1591fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 15927433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij rlen = xread; 1593fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (rlen < 8) { 1594fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_error (params, 1595fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP: reading event an short read of %ld bytes occurred", rlen); 1596fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 1597fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1598fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* if we read anything over interrupt endpoint it must be an event */ 1599fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* build an appropriate PTPContainer */ 1600fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->Code=dtoh16(usbevent.code); 1601fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->SessionID=params->session_id; 1602fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->Transaction_ID=dtoh32(usbevent.trans_id); 1603fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->Param1=dtoh32(usbevent.param1); 1604fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->Param2=dtoh32(usbevent.param2); 1605fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->Param3=dtoh32(usbevent.param3); 1606fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1607fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1608fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1609fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1610fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_event_check (PTPParams* params, PTPContainer* event) { 1611fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1612fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ptp_usb_event (params, event, PTP_EVENT_CHECK_FAST); 1613fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1614fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1615fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1616fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_event_wait (PTPParams* params, PTPContainer* event) { 1617fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1618fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ptp_usb_event (params, event, PTP_EVENT_CHECK); 1619fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1620fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1621fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1622fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_control_cancel_request (PTPParams *params, uint32_t transactionid) { 1623fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *)(params->data); 1624fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 1625fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char buffer[6]; 1626fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1627fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij htod16a(&buffer[0],PTP_EC_CancelTransaction); 1628fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij htod32a(&buffer[2],transactionid); 1629fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer(ptp_usb->handle, 1630fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 1631fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0x64, 0x0000, 0x0000, 1632fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij buffer, 1633fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(buffer), 1634fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 1635fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret < sizeof(buffer)) 1636fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 1637fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1638fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1639fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 164015d18e31458be5006eb229df68869df2fff93495Linus Walleijstatic int init_ptp_usb(PTPParams* params, PTP_USB* ptp_usb, libusb_device* dev) 1641fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1642fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device_handle *device_handle; 1643fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char buf[255]; 1644fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret, usbresult; 164515d18e31458be5006eb229df68869df2fff93495Linus Walleij struct libusb_config_descriptor *config; 1646fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1647fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->sendreq_func=ptp_usb_sendreq; 1648fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->senddata_func=ptp_usb_senddata; 1649fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->getresp_func=ptp_usb_getresp; 1650fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->getdata_func=ptp_usb_getdata; 1651fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->cancelreq_func=ptp_usb_control_cancel_request; 1652fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->data=ptp_usb; 1653fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->transaction_id=0; 1654fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1655fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This is hardcoded here since we have no devices whatsoever that are BE. 1656fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Change this the day we run into our first BE device (if ever). 1657fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1658fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->byteorder = PTP_DL_LE; 1659fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1660fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout = get_timeout(ptp_usb); 1661fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1662fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_open(dev, &device_handle); 1663fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) { 166415d18e31458be5006eb229df68869df2fff93495Linus Walleij perror("libusb_open() failed!"); 1665fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return -1; 1666fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1667fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->handle = device_handle; 166815d18e31458be5006eb229df68869df2fff93495Linus Walleij 1669fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1670fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * If this device is known to be wrongfully claimed by other kernel 1671fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * drivers (such as mass storage), then try to unload it to make it 1672fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * accessible from user space. 1673fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1674fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_UNLOAD_DRIVER(ptp_usb) && 167515d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_kernel_driver_active(device_handle, ptp_usb->interface) 1676fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ) { 167715d18e31458be5006eb229df68869df2fff93495Linus Walleij if (LIBUSB_SUCCESS != libusb_detach_kernel_driver(device_handle, ptp_usb->interface)) { 167815d18e31458be5006eb229df68869df2fff93495Linus Walleij perror("libusb_detach_kernel_driver() failed, continuing anyway..."); 1679fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1680fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 168115d18e31458be5006eb229df68869df2fff93495Linus Walleij 168215d18e31458be5006eb229df68869df2fff93495Linus Walleij /* 168315d18e31458be5006eb229df68869df2fff93495Linus Walleij * Check if the config is set to something else than what we want 168415d18e31458be5006eb229df68869df2fff93495Linus Walleij * to use. Only set the configuration if we absolutely have to. 168515d18e31458be5006eb229df68869df2fff93495Linus Walleij * Also do not bail out if we fail. 1686d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij * 1687d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij * Note that Darwin will not set the configuration for vendor-specific 1688d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij * devices so we need to go in and set it. 168915d18e31458be5006eb229df68869df2fff93495Linus Walleij */ 169015d18e31458be5006eb229df68869df2fff93495Linus Walleij ret = libusb_get_active_config_descriptor(dev, &config); 169115d18e31458be5006eb229df68869df2fff93495Linus Walleij if (ret != LIBUSB_SUCCESS) { 169215d18e31458be5006eb229df68869df2fff93495Linus Walleij perror("libusb_get_active_config_descriptor(1) failed"); 1693d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij fprintf(stderr, "no active configuration, trying to set configuration\n"); 1694d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij if (libusb_set_configuration(device_handle, ptp_usb->config) != LIBUSB_SUCCESS) { 1695d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij perror("libusb_set_configuration() failed, continuing anyway..."); 1696d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij } 1697d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij ret = libusb_get_active_config_descriptor(dev, &config); 1698d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij if (ret != LIBUSB_SUCCESS) { 1699d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij perror("libusb_get_active_config_descriptor(2) failed"); 1700d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij return -1; 1701d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij } 1702fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 170315d18e31458be5006eb229df68869df2fff93495Linus Walleij if (config->bConfigurationValue != ptp_usb->config) { 170415d18e31458be5006eb229df68869df2fff93495Linus Walleij fprintf(stderr, "desired configuration different from current, trying to set configuration\n"); 170515d18e31458be5006eb229df68869df2fff93495Linus Walleij if (libusb_set_configuration(device_handle, ptp_usb->config)) { 170615d18e31458be5006eb229df68869df2fff93495Linus Walleij perror("libusb_set_configuration() failed, continuing anyway..."); 170715d18e31458be5006eb229df68869df2fff93495Linus Walleij } 170815d18e31458be5006eb229df68869df2fff93495Linus Walleij /* Re-fetch the config descriptor if we changed */ 170915d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 171015d18e31458be5006eb229df68869df2fff93495Linus Walleij ret = libusb_get_active_config_descriptor(dev, &config); 171115d18e31458be5006eb229df68869df2fff93495Linus Walleij if (ret != LIBUSB_SUCCESS) { 171215d18e31458be5006eb229df68869df2fff93495Linus Walleij perror("libusb_get_active_config_descriptor(2) failed"); 171315d18e31458be5006eb229df68869df2fff93495Linus Walleij return -1; 171415d18e31458be5006eb229df68869df2fff93495Linus Walleij } 171515d18e31458be5006eb229df68869df2fff93495Linus Walleij } 171615d18e31458be5006eb229df68869df2fff93495Linus Walleij 171715d18e31458be5006eb229df68869df2fff93495Linus Walleij /* 171815d18e31458be5006eb229df68869df2fff93495Linus Walleij * It seems like on kernel 2.6.31 if we already have it open on another 171915d18e31458be5006eb229df68869df2fff93495Linus Walleij * pthread in our app, we'll get an error if we try to claim it again, 172015d18e31458be5006eb229df68869df2fff93495Linus Walleij * but that error is harmless because our process already claimed the interface 172115d18e31458be5006eb229df68869df2fff93495Linus Walleij */ 1722fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbresult = libusb_claim_interface(device_handle, ptp_usb->interface); 1723fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1724fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (usbresult != 0) 172515d18e31458be5006eb229df68869df2fff93495Linus Walleij fprintf(stderr, "ignoring libusb_claim_interface() = %d", usbresult); 172615d18e31458be5006eb229df68869df2fff93495Linus Walleij 172715d18e31458be5006eb229df68869df2fff93495Linus Walleij /* 172815d18e31458be5006eb229df68869df2fff93495Linus Walleij * If the altsetting is set to something different than we want, switch 172915d18e31458be5006eb229df68869df2fff93495Linus Walleij * it. 173015d18e31458be5006eb229df68869df2fff93495Linus Walleij * 173115d18e31458be5006eb229df68869df2fff93495Linus Walleij * FIXME: this seems to cause trouble on the Mac:s so disable it. Retry 173215d18e31458be5006eb229df68869df2fff93495Linus Walleij * this on the Mac now that it only sets this when the altsetting differs. 173315d18e31458be5006eb229df68869df2fff93495Linus Walleij */ 1734fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#ifndef __APPLE__ 173515d18e31458be5006eb229df68869df2fff93495Linus Walleij#if 0 /* Disable this always, no idea on how to handle it */ 173615d18e31458be5006eb229df68869df2fff93495Linus Walleij if (config->interface[].altsetting[].bAlternateSetting != 173715d18e31458be5006eb229df68869df2fff93495Linus Walleij ptp_usb->altsetting) { 173815d18e31458be5006eb229df68869df2fff93495Linus Walleij fprintf(stderr, "desired altsetting different from current, trying to set altsetting\n"); 173915d18e31458be5006eb229df68869df2fff93495Linus Walleij usbresult = libusb_set_interface_alt_setting(device_handle, 174015d18e31458be5006eb229df68869df2fff93495Linus Walleij ptp_usb->interface, 174115d18e31458be5006eb229df68869df2fff93495Linus Walleij ptp_usb->altsetting); 174215d18e31458be5006eb229df68869df2fff93495Linus Walleij if (usbresult != 0) 174315d18e31458be5006eb229df68869df2fff93495Linus Walleij fprintf(stderr, "ignoring libusb_set_interface_alt_setting() = %d\n", usbresult); 174415d18e31458be5006eb229df68869df2fff93495Linus Walleij } 174515d18e31458be5006eb229df68869df2fff93495Linus Walleij#endif 1746fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#endif 1747fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 174815d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 174915d18e31458be5006eb229df68869df2fff93495Linus Walleij 1750fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_SWITCH_MODE_BLACKBERRY(ptp_usb)) { 1751fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 1752fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1753fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // FIXME : Only for BlackBerry Storm 1754fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // What does it mean? Maybe switch mode... 1755fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This first control message is absolutely necessary 1756fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usleep(1000); 1757fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer(device_handle, 1758fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, 1759fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0xaa, 0x00, 0x04, buf, 0x40, 1000); 1760fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("BlackBerry magic part 1:\n"); 1761fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(buf, ret, 16); 1762fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1763fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usleep(1000); 1764fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This control message is unnecessary 1765fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer(device_handle, 1766fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, 1767fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0xa5, 0x00, 0x01, buf, 0x02, 1000); 1768fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("BlackBerry magic part 2:\n"); 1769fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(buf, ret, 16); 1770fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1771fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usleep(1000); 1772fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This control message is unnecessary 1773fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer(device_handle, 1774fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, 1775fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0xa8, 0x00, 0x01, buf, 0x05, 1000); 1776fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("BlackBerry magic part 3:\n"); 1777fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(buf, ret, 16); 1778fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1779fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usleep(1000); 1780fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This control message is unnecessary 1781fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer(device_handle, 1782fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, 1783fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0xa8, 0x00, 0x01, buf, 0x11, 1000); 1784fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("BlackBerry magic part 4:\n"); 1785fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(buf, ret, 16); 1786fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1787fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usleep(1000); 1788fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1789fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 1790fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1791fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1792fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void clear_stall(PTP_USB* ptp_usb) 1793fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1794fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t status; 1795fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 1796fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1797fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* check the inep status */ 1798fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij status = 0; 1799fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status); 1800fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret<0) { 1801fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror ("inep: usb_get_endpoint_status()"); 1802fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if (status) { 1803fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("Clearing stall on IN endpoint\n"); 1804fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_clear_halt (ptp_usb->handle, ptp_usb->inep); 1805fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) { 1806fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror ("usb_clear_stall_feature()"); 1807fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1808fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1809fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1810fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* check the outep status */ 1811fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij status=0; 1812fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status); 1813fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret<0) { 1814fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror("outep: usb_get_endpoint_status()"); 1815fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if (status) { 1816fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("Clearing stall on OUT endpoint\n"); 1817fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_clear_halt (ptp_usb->handle, ptp_usb->outep); 1818fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) { 1819fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror("usb_clear_stall_feature()"); 1820fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1821fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1822fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1823fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* TODO: do we need this for INTERRUPT (ptp_usb->intep) too? */ 1824fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1825fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1826fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void clear_halt(PTP_USB* ptp_usb) 1827fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1828fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 1829fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1830fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_clear_halt(ptp_usb->handle,ptp_usb->inep); 1831fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret<0) { 1832fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror("usb_clear_halt() on IN endpoint"); 1833fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1834fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_clear_halt(ptp_usb->handle,ptp_usb->outep); 1835fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret<0) { 1836fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror("usb_clear_halt() on OUT endpoint"); 1837fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1838fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_clear_halt(ptp_usb->handle,ptp_usb->intep); 1839fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret<0) { 1840fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror("usb_clear_halt() on INTERRUPT endpoint"); 1841fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1842fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1843fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1844fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void close_usb(PTP_USB* ptp_usb) 1845fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1846fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!FLAG_NO_RELEASE_INTERFACE(ptp_usb)) { 1847fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1848fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Clear any stalled endpoints 1849fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * On misbehaving devices designed for Windows/Mac, quote from: 1850fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * http://www2.one-eyed-alien.net/~mdharm/linux-usb/target_offenses.txt 1851fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Device does Bad Things(tm) when it gets a GET_STATUS after CLEAR_HALT 1852fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * (...) Windows, when clearing a stall, only sends the CLEAR_HALT command, 1853fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * and presumes that the stall has cleared. Some devices actually choke 1854fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * if the CLEAR_HALT is followed by a GET_STATUS (used to determine if the 1855fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * STALL is persistant or not). 1856fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1857fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij clear_stall(ptp_usb); 1858fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Clear halts on any endpoints 1859fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij clear_halt(ptp_usb); 1860fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Added to clear some stuff on the OUT endpoint 1861fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // TODO: is this good on the Mac too? 1862fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // HINT: some devices may need that you comment these two out too. 1863fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_clear_halt(ptp_usb->handle, ptp_usb->outep); 1864fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_release_interface(ptp_usb->handle, (int) ptp_usb->interface); 1865fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1866fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_FORCE_RESET_ON_CLOSE(ptp_usb)) { 1867fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1868fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Some devices really love to get reset after being 1869fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * disconnected. Again, since Windows never disconnects 1870fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * a device closing behaviour is seldom or never exercised 1871fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * on devices when engineered and often error prone. 1872fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Reset may help some. 1873fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1874fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_reset_device (ptp_usb->handle); 1875fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1876fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(ptp_usb->handle); 1877fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1878fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1879fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 1880fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Self-explanatory? 1881fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1882fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic int find_interface_and_endpoints(libusb_device *dev, 188315d18e31458be5006eb229df68869df2fff93495Linus Walleij uint8_t *conf, 1884fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint8_t *interface, 188515d18e31458be5006eb229df68869df2fff93495Linus Walleij uint8_t *altsetting, 1886fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* inep, 1887fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* inep_maxpacket, 1888fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* outep, 1889fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int *outep_maxpacket, 1890fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* intep) 1891fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 189215d18e31458be5006eb229df68869df2fff93495Linus Walleij uint8_t i, ret; 1893fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 1894fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 189515d18e31458be5006eb229df68869df2fff93495Linus Walleij ret = libusb_get_device_descriptor(dev, &desc); 189615d18e31458be5006eb229df68869df2fff93495Linus Walleij if (ret != LIBUSB_SUCCESS) 189715d18e31458be5006eb229df68869df2fff93495Linus Walleij return -1; 1898fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1899fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Loop over the device configurations 1900fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (i = 0; i < desc.bNumConfigurations; i++) { 1901fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint8_t j; 1902fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_config_descriptor *config; 1903fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 190415d18e31458be5006eb229df68869df2fff93495Linus Walleij ret = libusb_get_config_descriptor(dev, i, &config); 190515d18e31458be5006eb229df68869df2fff93495Linus Walleij if (ret != 0) 190615d18e31458be5006eb229df68869df2fff93495Linus Walleij continue; 190715d18e31458be5006eb229df68869df2fff93495Linus Walleij 190815d18e31458be5006eb229df68869df2fff93495Linus Walleij *conf = config->bConfigurationValue; 190915d18e31458be5006eb229df68869df2fff93495Linus Walleij 1910fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) continue; 1911fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Loop over each configurations interfaces 1912fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (j = 0; j < config->bNumInterfaces; j++) { 191315d18e31458be5006eb229df68869df2fff93495Linus Walleij uint8_t k, l; 1914fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint8_t no_ep; 1915fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int found_inep = 0; 1916fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int found_outep = 0; 1917fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int found_intep = 0; 1918fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij const struct libusb_endpoint_descriptor *ep; 1919fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 192015d18e31458be5006eb229df68869df2fff93495Linus Walleij // Inspect the altsettings of this interface... 192115d18e31458be5006eb229df68869df2fff93495Linus Walleij for (k = 0; k < config->interface[j].num_altsetting; k++) { 192215d18e31458be5006eb229df68869df2fff93495Linus Walleij 192315d18e31458be5006eb229df68869df2fff93495Linus Walleij // MTP devices shall have 3 endpoints, ignore those interfaces 192415d18e31458be5006eb229df68869df2fff93495Linus Walleij // that haven't. 192515d18e31458be5006eb229df68869df2fff93495Linus Walleij no_ep = config->interface[j].altsetting[k].bNumEndpoints; 192615d18e31458be5006eb229df68869df2fff93495Linus Walleij if (no_ep != 3) 192715d18e31458be5006eb229df68869df2fff93495Linus Walleij continue; 192815d18e31458be5006eb229df68869df2fff93495Linus Walleij 192915d18e31458be5006eb229df68869df2fff93495Linus Walleij *interface = config->interface[j].altsetting[k].bInterfaceNumber; 193015d18e31458be5006eb229df68869df2fff93495Linus Walleij *altsetting = config->interface[j].altsetting[k].bAlternateSetting; 193115d18e31458be5006eb229df68869df2fff93495Linus Walleij ep = config->interface[j].altsetting[k].endpoint; 193215d18e31458be5006eb229df68869df2fff93495Linus Walleij 193315d18e31458be5006eb229df68869df2fff93495Linus Walleij // Loop over the three endpoints to locate two bulk and 193415d18e31458be5006eb229df68869df2fff93495Linus Walleij // one interrupt endpoint and FAIL if we cannot, and continue. 193515d18e31458be5006eb229df68869df2fff93495Linus Walleij for (l = 0; l < no_ep; l++) { 193615d18e31458be5006eb229df68869df2fff93495Linus Walleij if (ep[l].bmAttributes == LIBUSB_TRANSFER_TYPE_BULK) { 193715d18e31458be5006eb229df68869df2fff93495Linus Walleij if ((ep[l].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == 193815d18e31458be5006eb229df68869df2fff93495Linus Walleij LIBUSB_ENDPOINT_DIR_MASK) { 193915d18e31458be5006eb229df68869df2fff93495Linus Walleij *inep = ep[l].bEndpointAddress; 194015d18e31458be5006eb229df68869df2fff93495Linus Walleij *inep_maxpacket = ep[l].wMaxPacketSize; 194115d18e31458be5006eb229df68869df2fff93495Linus Walleij found_inep = 1; 194215d18e31458be5006eb229df68869df2fff93495Linus Walleij } 194315d18e31458be5006eb229df68869df2fff93495Linus Walleij if ((ep[l].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == 0) { 194415d18e31458be5006eb229df68869df2fff93495Linus Walleij *outep = ep[l].bEndpointAddress; 194515d18e31458be5006eb229df68869df2fff93495Linus Walleij *outep_maxpacket = ep[l].wMaxPacketSize; 194615d18e31458be5006eb229df68869df2fff93495Linus Walleij found_outep = 1; 194715d18e31458be5006eb229df68869df2fff93495Linus Walleij } 194815d18e31458be5006eb229df68869df2fff93495Linus Walleij } else if (ep[l].bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT) { 194915d18e31458be5006eb229df68869df2fff93495Linus Walleij if ((ep[l].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == 195015d18e31458be5006eb229df68869df2fff93495Linus Walleij LIBUSB_ENDPOINT_DIR_MASK) { 195115d18e31458be5006eb229df68869df2fff93495Linus Walleij *intep = ep[l].bEndpointAddress; 195215d18e31458be5006eb229df68869df2fff93495Linus Walleij found_intep = 1; 195315d18e31458be5006eb229df68869df2fff93495Linus Walleij } 1954fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1955fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 195615d18e31458be5006eb229df68869df2fff93495Linus Walleij if (found_inep && found_outep && found_intep) { 195715d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 195815d18e31458be5006eb229df68869df2fff93495Linus Walleij // We assigned the endpoints so return here. 195915d18e31458be5006eb229df68869df2fff93495Linus Walleij return 0; 196015d18e31458be5006eb229df68869df2fff93495Linus Walleij } 196115d18e31458be5006eb229df68869df2fff93495Linus Walleij } // Next altsetting 196215d18e31458be5006eb229df68869df2fff93495Linus Walleij } // Next interface 196315d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 196415d18e31458be5006eb229df68869df2fff93495Linus Walleij } // Next config 1965fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return -1; 1966fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1967fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1968fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 1969fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This function assigns params and usbinfo given a raw device 1970fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * as input. 1971fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param device the device to be assigned. 1972fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param usbinfo a pointer to the new usbinfo. 1973fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return an error code. 1974fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1975fbbef8b16876568f760986e4ff8f4921b8373fd5Linus WalleijLIBMTP_error_number_t configure_usb_device(LIBMTP_raw_device_t *device, 1976fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPParams *params, 1977fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij void **usbinfo) 1978fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1979fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb; 1980fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device *ldevice; 1981fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret = 0; 1982fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int err, found = 0, i; 1983fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ssize_t nrofdevs; 1984fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device **devs = NULL; 1985fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 19863df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang LIBMTP_error_number_t init_usb_ret; 1987fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1988fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* See if we can find this raw device again... */ 19893df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang init_usb_ret = init_usb(); 19903df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang if (init_usb_ret != LIBMTP_ERROR_NONE) 19913df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang return init_usb_ret; 1992fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 199315d18e31458be5006eb229df68869df2fff93495Linus Walleij nrofdevs = libusb_get_device_list(NULL, &devs); 1994fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (i = 0; i < nrofdevs ; i++) { 199515d18e31458be5006eb229df68869df2fff93495Linus Walleij if (libusb_get_bus_number(devs[i]) != device->bus_location) 1996fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 199715d18e31458be5006eb229df68869df2fff93495Linus Walleij if (libusb_get_device_address(devs[i]) != device->devnum) 1998fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 1999fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 200015d18e31458be5006eb229df68869df2fff93495Linus Walleij ret = libusb_get_device_descriptor(devs[i], &desc); 2001fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) continue; 2002fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2003fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if(desc.idVendor == device->device_entry.vendor_id && 2004fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idProduct == device->device_entry.product_id ) { 2005fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ldevice = devs[i]; 2006fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij found = 1; 2007fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 2008fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2009fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2010fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Device has gone since detecting raw devices! */ 2011fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!found) { 2012fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_free_device_list (devs, 0); 2013fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NO_DEVICE_ATTACHED; 2014fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2015fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2016fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Allocate structs */ 2017fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb = (PTP_USB *) malloc(sizeof(PTP_USB)); 2018fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb == NULL) { 2019fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_free_device_list (devs, 0); 2020fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_MEMORY_ALLOCATION; 2021fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2022fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Start with a blank slate (includes setting device_flags to 0) */ 2023fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memset(ptp_usb, 0, sizeof(PTP_USB)); 2024fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2025fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Copy the raw device */ 2026fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy(&ptp_usb->rawdevice, device, sizeof(LIBMTP_raw_device_t)); 2027fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2028fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 2029fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Some devices must have their "OS Descriptor" massaged in order 2030fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * to work. 2031fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 2032fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_ALWAYS_PROBE_DESCRIPTOR(ptp_usb)) { 2033fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Massage the device descriptor 2034fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (void) probe_device_descriptor(ldevice, NULL); 2035fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2036fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2037fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Assign interface and endpoints to usbinfo... */ 2038fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij err = find_interface_and_endpoints(ldevice, 203915d18e31458be5006eb229df68869df2fff93495Linus Walleij &ptp_usb->config, 2040fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->interface, 204115d18e31458be5006eb229df68869df2fff93495Linus Walleij &ptp_usb->altsetting, 2042fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->inep, 2043fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->inep_maxpacket, 2044fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->outep, 2045fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->outep_maxpacket, 2046fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->intep); 2047fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2048fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (err) { 2049fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_free_device_list (devs, 0); 2050fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: Unable to find interface & endpoints of device\n"); 2051fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_CONNECTING; 2052fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2053fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2054fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Copy USB version number */ 2055fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->bcdusb = desc.bcdUSB; 2056fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2057fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Attempt to initialize this device */ 2058fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (init_ptp_usb(params, ptp_usb, ldevice) < 0) { 2059fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: Unable to initialize device\n"); 2060fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_CONNECTING; 2061fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2062fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2063fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 2064fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This works in situations where previous bad applications 2065fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * have not used LIBMTP_Release_Device on exit 2066fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 2067fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if ((ret = ptp_opensession(params, 1)) == PTP_ERROR_IO) { 2068fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("PTP_ERROR_IO: failed to open session, trying again after resetting USB interface\n"); 2069fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP libusb: Attempt to reset device\n"); 2070fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_reset_device (ptp_usb->handle); 2071fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij close_usb(ptp_usb); 2072fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2073fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if(init_ptp_usb(params, ptp_usb, ldevice) <0) { 2074fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: Could not init USB on second attempt\n"); 2075fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_CONNECTING; 2076fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2077fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2078fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Device has been reset, try again */ 2079fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if ((ret = ptp_opensession(params, 1)) == PTP_ERROR_IO) { 2080fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: failed to open session on second attempt\n"); 2081fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_CONNECTING; 2082fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2083fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2084fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2085fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Was the transaction id invalid? Try again */ 2086fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret == PTP_RC_InvalidTransactionID) { 2087fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP WARNING: Transaction ID was invalid, increment and try again\n"); 2088fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->transaction_id += 10; 2089fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_opensession(params, 1); 2090fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2091fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2092fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != PTP_RC_SessionAlreadyOpened && ret != PTP_RC_OK) { 2093fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: Could not open session! " 2094fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "(Return code %d)\n Try to reset the device.\n", 2095fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret); 2096fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_release_interface(ptp_usb->handle, ptp_usb->interface); 2097fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_CONNECTING; 2098fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2099fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2100fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* OK configured properly */ 2101fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *usbinfo = (void *) ptp_usb; 2102fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NONE; 2103fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2104fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2105fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2106fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijvoid close_device (PTP_USB *ptp_usb, PTPParams *params) 2107fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 2108fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_closesession(params)!=PTP_RC_OK) 2109fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("ERROR: Could not close session!\n"); 2110fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij close_usb(ptp_usb); 2111fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2112fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2113fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijvoid set_usb_device_timeout(PTP_USB *ptp_usb, int timeout) 2114fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 2115fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout = timeout; 2116fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2117fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2118fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijvoid get_usb_device_timeout(PTP_USB *ptp_usb, int *timeout) 2119fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 2120fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *timeout = ptp_usb->timeout; 2121fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2122fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2123fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijint guess_usb_speed(PTP_USB *ptp_usb) 2124fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 2125fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int bytes_per_second; 2126fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2127fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 2128fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * We don't know the actual speeds so these are rough guesses 2129fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * from the info you can find here: 2130fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * http://en.wikipedia.org/wiki/USB#Transfer_rates 2131fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * http://www.barefeats.com/usb2.html 2132fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 2133fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij switch (ptp_usb->bcdusb & 0xFF00) { 2134fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij case 0x0100: 2135fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1.x USB versions let's say 1MiB/s */ 2136fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes_per_second = 1*1024*1024; 2137fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 2138fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij case 0x0200: 2139fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij case 0x0300: 2140fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* USB 2.0 nominal speed 18MiB/s */ 2141fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* USB 3.0 won't be worse? */ 2142fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes_per_second = 18*1024*1024; 2143fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 2144fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij default: 2145fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Half-guess something? */ 2146fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes_per_second = 1*1024*1024; 2147fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 2148fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2149fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return bytes_per_second; 2150fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2151fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2152fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status) 2153fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 2154fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return libusb_control_transfer(ptp_usb->handle, 2155fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_ENDPOINT, 2156fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_GET_STATUS, 2157fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij USB_FEATURE_HALT, 2158fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ep, 2159fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) status, 2160fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2, 2161fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 2162fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2163