libusb1-glue.c revision 1e5c80e148681f409c6d16d27336b9cd195f3387
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 } 5541e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang libusb_free_device_list (devs, 0); 555fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 556fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* If nothing was found we end up here. */ 557fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if(*mtp_device_list == NULL) { 558fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NO_DEVICE_ATTACHED; 559fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 560fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NONE; 561fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 562fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 563fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 564fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Checks if a specific device with a certain bus and device 565fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * number has an MTP type device descriptor. 566fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 567fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param busno the bus number of the device to check 568fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param deviceno the device number of the device to check 569fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return 1 if the device is MTP else 0 570fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 571fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijint LIBMTP_Check_Specific_Device(int busno, int devno) 572fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 573fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ssize_t nrofdevs; 574fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device **devs = NULL; 575fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int i; 5763df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang LIBMTP_error_number_t init_usb_ret; 577fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 5783df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang init_usb_ret = init_usb(); 5793df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang if (init_usb_ret != LIBMTP_ERROR_NONE) 5803df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang return 0; 581fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 582fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij nrofdevs = libusb_get_device_list (NULL, &devs); 583fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (i = 0; i < nrofdevs ; i++ ) { 58430f9acdc94c087209d3feb80bf545ce3cf1033a0Jonas Salling 58530f9acdc94c087209d3feb80bf545ce3cf1033a0Jonas Salling if (libusb_get_bus_number(devs[i]) != busno) 586fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 58730f9acdc94c087209d3feb80bf545ce3cf1033a0Jonas Salling if (libusb_get_device_address(devs[i]) != devno) 588fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 58930f9acdc94c087209d3feb80bf545ce3cf1033a0Jonas Salling 590fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (probe_device_descriptor(devs[i], NULL)) 591fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 1; 592fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 593fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 594fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 595fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 596fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 597fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Detect the raw MTP device descriptors and return a list of 598fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * of the devices found. 599fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 600fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param devices a pointer to a variable that will hold 601fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * the list of raw devices found. This may be NULL 602fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * on return if the number of detected devices is zero. 603fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * The user shall simply <code>free()</code> this 604fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * variable when finished with the raw devices, 605fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * in order to release memory. 606fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param numdevs a pointer to an integer that will hold 607fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * the number of devices in the list. This may 608fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * be 0. 609fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return 0 if successful, any other value means failure. 610fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 611fbbef8b16876568f760986e4ff8f4921b8373fd5Linus WalleijLIBMTP_error_number_t LIBMTP_Detect_Raw_Devices(LIBMTP_raw_device_t ** devices, 612fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int * numdevs) 613fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 614fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtpdevice_list_t *devlist = NULL; 615fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtpdevice_list_t *dev; 616fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_error_number_t ret; 617fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_raw_device_t *retdevs; 618fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int devs = 0; 619fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int i, j; 620fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 621fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = get_mtp_usb_device_list(&devlist); 622fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret == LIBMTP_ERROR_NO_DEVICE_ATTACHED) { 623fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *devices = NULL; 624fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *numdevs = 0; 625fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 626fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if (ret != LIBMTP_ERROR_NONE) { 627fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: get_mtp_usb_device_list() " 628fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "error code: %d on line %d\n", ret, __LINE__); 629fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 630fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 631fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 632fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Get list size 633fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = devlist; 634fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (dev != NULL) { 635fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij devs++; 636fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = dev->next; 637fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 638fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (devs == 0) { 639fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *devices = NULL; 640fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *numdevs = 0; 641fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NONE; 642fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 643fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Conjure a device list 644fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs = (LIBMTP_raw_device_t *) malloc(sizeof(LIBMTP_raw_device_t) * devs); 645fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (retdevs == NULL) { 646fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Out of memory 647fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *devices = NULL; 648fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *numdevs = 0; 649fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_MEMORY_ALLOCATION; 650fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 651fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = devlist; 652fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij i = 0; 653fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (dev != NULL) { 654fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int device_known = 0; 655fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 656fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 657fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_get_device_descriptor (dev->device, &desc); 658fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Assign default device info 659fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.vendor = NULL; 660fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.vendor_id = desc.idVendor; 661fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.product = NULL; 662fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.product_id = desc.idProduct; 663fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.device_flags = 0x00000000U; 664fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // See if we can locate some additional vendor info and device flags 665fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for(j = 0; j < mtp_device_table_size; j++) { 666fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if(desc.idVendor == mtp_device_table[j].vendor_id && 667fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idProduct == mtp_device_table[j].product_id) { 668fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij device_known = 1; 669fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.vendor = mtp_device_table[j].vendor; 670fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.product = mtp_device_table[j].product; 671fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].device_entry.device_flags = mtp_device_table[j].device_flags; 672fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 673fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This device is known to the developers 674fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("Device %d (VID=%04x and PID=%04x) is a %s %s.\n", 675fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij i, 676fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idVendor, 677fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idProduct, 678fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtp_device_table[j].vendor, 679fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij mtp_device_table[j].product); 680fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 681fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 682fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 683fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!device_known) { 684fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This device is unknown to the developers 685fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("Device %d (VID=%04x and PID=%04x) is UNKNOWN.\n", 686fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij i, 687fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idVendor, 688fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idProduct); 689fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("Please report this VID/PID and the device model to the " 690fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "libmtp development team\n"); 691fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 692fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Trying to get iManufacturer or iProduct from the device at this 693fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * point would require opening a device handle, that we don't want 694fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * to do right now. (Takes time for no good enough reason.) 695fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 696fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 697fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Save the location on the bus 698fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].bus_location = libusb_get_bus_number (dev->device); 699fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij retdevs[i].devnum = libusb_get_device_address (dev->device); 700fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij i++; 701fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = dev->next; 702fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 703fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *devices = retdevs; 704fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *numdevs = i; 705fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free_mtpdevice_list(devlist); 706fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NONE; 707fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 708fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 709fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 710fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This routine just dumps out low-level 711fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * USB information about the current device. 712fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param ptp_usb the USB device to get information from. 713fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 714fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijvoid dump_usbinfo(PTP_USB *ptp_usb) 715fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 716fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device *dev; 717fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 718fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 719fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (libusb_kernel_driver_active(ptp_usb->handle, ptp_usb->interface)) 720fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Interface has a kernel driver attached.\n"); 721fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 722fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = libusb_get_device (ptp_usb->handle); 723fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_get_device_descriptor (dev, &desc); 724fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 725fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" bcdUSB: %d\n", desc.bcdUSB); 726fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" bDeviceClass: %d\n", desc.bDeviceClass); 727fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" bDeviceSubClass: %d\n", desc.bDeviceSubClass); 728fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" bDeviceProtocol: %d\n", desc.bDeviceProtocol); 729fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" idVendor: %04x\n", desc.idVendor); 730fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" idProduct: %04x\n", desc.idProduct); 731fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" IN endpoint maxpacket: %d bytes\n", ptp_usb->inep_maxpacket); 732fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" OUT endpoint maxpacket: %d bytes\n", ptp_usb->outep_maxpacket); 733fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Raw device info:\n"); 734fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Bus location: %d\n", ptp_usb->rawdevice.bus_location); 735fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Device number: %d\n", ptp_usb->rawdevice.devnum); 736fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Device entry info:\n"); 737fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Vendor: %s\n", ptp_usb->rawdevice.device_entry.vendor); 738fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Vendor id: 0x%04x\n", ptp_usb->rawdevice.device_entry.vendor_id); 739fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Product: %s\n", ptp_usb->rawdevice.device_entry.product); 740fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Vendor id: 0x%04x\n", ptp_usb->rawdevice.device_entry.product_id); 741fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO(" Device flags: 0x%08x\n", ptp_usb->rawdevice.device_entry.device_flags); 742fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (void) probe_device_descriptor(dev, stdout); 743fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 744fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 745fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 746fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Retrieve the apropriate playlist extension for this 747fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * device. Rather hacky at the moment. This is probably 748fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * desired by the managing software, but when creating 749fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * lists on the device itself you notice certain preferences. 750fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param ptp_usb the USB device to get suggestion for. 751fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return the suggested playlist extension. 752fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 753fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijconst char *get_playlist_extension(PTP_USB *ptp_usb) 754fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 755fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device *dev; 756fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 757fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij static char creative_pl_extension[] = ".zpl"; 758fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij static char default_pl_extension[] = ".pla"; 759fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 760fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij dev = libusb_get_device(ptp_usb->handle); 761fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_get_device_descriptor (dev, &desc); 762fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (desc.idVendor == 0x041e) 763fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return creative_pl_extension; 764fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return default_pl_extension; 765fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 766fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 767fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void 768fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijlibusb_glue_debug (PTPParams *params, const char *format, ...) 769fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 770fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_list args; 771fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 772fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_start (args, format); 773fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (params->debug_func!=NULL) 774fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->debug_func (params->data, format, args); 775fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else 776fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij { 777fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij vfprintf (stderr, format, args); 778fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf (stderr,"\n"); 779fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fflush (stderr); 780fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 781fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_end (args); 782fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 783fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 784fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void 785fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijlibusb_glue_error (PTPParams *params, const char *format, ...) 786fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 787fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_list args; 788fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 789fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_start (args, format); 790fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (params->error_func!=NULL) 791fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->error_func (params->data, format, args); 792fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else 793fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij { 794fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij vfprintf (stderr, format, args); 795fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fprintf (stderr,"\n"); 796fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij fflush (stderr); 797fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 798fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij va_end (args); 799fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 800fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 801fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 802fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* 803fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * ptp_read_func() and ptp_write_func() are 804fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * based on same functions usb.c in libgphoto2. 805fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Much reading packet logs and having fun with trials and errors 806fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * reveals that WMP / Windows is probably using an algorithm like this 807fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * for large transfers: 808fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 809fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 1. Send the command (0x0c bytes) if headers are split, else, send 810fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * command plus sizeof(endpoint) - 0x0c bytes. 811fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 2. Send first packet, max size to be sizeof(endpoint) but only when using 812fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * split headers. Else goto 3. 813fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 3. REPEAT send 0x10000 byte chunks UNTIL remaining bytes < 0x10000 814fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * We call 0x10000 CONTEXT_BLOCK_SIZE. 815fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 4. Send remaining bytes MOD sizeof(endpoint) 816fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 5. Send remaining bytes. If this happens to be exactly sizeof(endpoint) 817fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * then also send a zero-length package. 818fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 819fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Further there is some special quirks to handle zero reads from the 820fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * device, since some devices can't do them at all due to shortcomings 821fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * of the USB slave controller in the device. 822fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 823fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define CONTEXT_BLOCK_SIZE_1 0x3e00 824fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define CONTEXT_BLOCK_SIZE_2 0x200 825fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define CONTEXT_BLOCK_SIZE CONTEXT_BLOCK_SIZE_1+CONTEXT_BLOCK_SIZE_2 826fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic short 827fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_read_func ( 828fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long size, PTPDataHandler *handler,void *data, 829fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long *readbytes, 830fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int readzero 831fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 832fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *)data; 833fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long toread = 0; 834fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret = 0; 835fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int xread; 836fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long curread = 0; 837fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long written; 838fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char *bytes; 839fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int expect_terminator_byte = 0; 840fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 841fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This is the largest block we'll need to read in. 842fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes = malloc(CONTEXT_BLOCK_SIZE); 843fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (curread < size) { 844fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 845fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Remaining size to read: 0x%04lx bytes\n", size - curread); 846fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 847fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // check equal to condition here 848fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (size - curread < CONTEXT_BLOCK_SIZE) 849fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij { 850fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // this is the last packet 851fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread = size - curread; 852fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // this is equivalent to zero read for these devices 853fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (readzero && FLAG_NO_ZERO_READS(ptp_usb) && toread % 64 == 0) { 854fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread += 1; 855fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij expect_terminator_byte = 1; 856fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 857fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 858fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else if (curread == 0) 859fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // we are first packet, but not last packet 860fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread = CONTEXT_BLOCK_SIZE_1; 861fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else if (toread == CONTEXT_BLOCK_SIZE_1) 862fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread = CONTEXT_BLOCK_SIZE_2; 863fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else if (toread == CONTEXT_BLOCK_SIZE_2) 864fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread = CONTEXT_BLOCK_SIZE_1; 865fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else 866fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("unexpected toread size 0x%04x, 0x%04x remaining bytes\n", 867fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned int) toread, (unsigned int) (size-curread)); 868fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 869fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Reading in 0x%04lx bytes\n", toread); 870fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 871fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = USB_BULK_READ(ptp_usb->handle, 872fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->inep, 873fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes, 874fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij toread, 875fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 876fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 877fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 878fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Result of read: 0x%04x (%d bytes)\n", ret, xread); 879fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 880fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) 881fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 882fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 883fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("<==USB IN\n"); 884fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (xread == 0) 885fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Zero Read\n"); 886fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij else 887fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(bytes, xread, 16); 888fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 889fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // want to discard extra byte 890fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (expect_terminator_byte && xread == toread) 891fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij { 892fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("<==USB IN\nDiscarding extra byte\n"); 893fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 894fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij xread--; 895fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 896fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 897fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int putfunc_ret = handler->putfunc(NULL, handler->priv, xread, bytes, &written); 898fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (putfunc_ret != PTP_RC_OK) 899fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return putfunc_ret; 900fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 901fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_complete += xread; 902fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij curread += xread; 903fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 904fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Increase counters, call callback 905fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->callback_active) { 906fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) { 907fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // send last update and disable callback. 908fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total; 909fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->callback_active = 0; 910fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 911fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->current_transfer_callback != NULL) { 912fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 913fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete, 914fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_total, 915fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_callback_data); 916fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != 0) { 917fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_CANCEL; 918fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 919fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 920fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 921fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 922fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (xread < toread) /* short reads are common */ 923fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 924fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 925fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (readbytes) *readbytes = curread; 926fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free (bytes); 927fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 928fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // there might be a zero packet waiting for us... 929fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (readzero && 930fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij !FLAG_NO_ZERO_READS(ptp_usb) && 931fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij curread % ptp_usb->outep_maxpacket == 0) { 932fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char temp; 933fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int zeroresult = 0, xread; 934fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 935fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("<==USB IN\n"); 936fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Zero Read\n"); 937fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 938fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij zeroresult = USB_BULK_READ(ptp_usb->handle, 939fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->inep, 940fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &temp, 941fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0, 942fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 943fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 944fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (zeroresult != LIBUSB_SUCCESS) 945fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("LIBMTP panic: unable to read in zero packet, response 0x%04x", zeroresult); 946fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 947fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 948fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 949fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 950fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 951fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic short 952fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_write_func ( 953fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long size, 954fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPDataHandler *handler, 955fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij void *data, 956fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long *written 957fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 958fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *)data; 959fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long towrite = 0; 960fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret = 0; 961fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long curwrite = 0; 962fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char *bytes; 963fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 964fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This is the largest block we'll need to read in. 965fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes = malloc(CONTEXT_BLOCK_SIZE); 966fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!bytes) { 967fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 968fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 969fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (curwrite < size) { 970fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long usbwritten = 0; 971fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int xwritten; 972fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 973fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite = size-curwrite; 974fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (towrite > CONTEXT_BLOCK_SIZE) { 975fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite = CONTEXT_BLOCK_SIZE; 976fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else { 977fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This magic makes packets the same size that WMP send them. 978fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (towrite > ptp_usb->outep_maxpacket && towrite % ptp_usb->outep_maxpacket != 0) { 979fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite -= towrite % ptp_usb->outep_maxpacket; 980fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 981fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 982fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int getfunc_ret = handler->getfunc(NULL, handler->priv,towrite,bytes,&towrite); 9831e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang if (getfunc_ret != PTP_RC_OK) { 9841e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang free(bytes); 985fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return getfunc_ret; 9861e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang } 987fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (usbwritten < towrite) { 988fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = USB_BULK_WRITE(ptp_usb->handle, 989fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->outep, 990fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes+usbwritten, 991fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite-usbwritten, 992fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xwritten, 993fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 994fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 995fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("USB OUT==>\n"); 996fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 997fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) { 9981e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang free(bytes); 999fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 1000fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1001fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(bytes+usbwritten, xwritten, 16); 1002fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // check for result == 0 perhaps too. 1003fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Increase counters 1004fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_complete += xwritten; 1005fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij curwrite += xwritten; 1006fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbwritten += xwritten; 1007fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1008fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // call callback 1009fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->callback_active) { 1010fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) { 1011fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // send last update and disable callback. 1012fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total; 1013fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->callback_active = 0; 1014fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1015fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->current_transfer_callback != NULL) { 1016fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 1017fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete, 1018fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_total, 1019fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->current_transfer_callback_data); 1020fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != 0) { 10211e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang free(bytes); 1022fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_CANCEL; 1023fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1024fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1025fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1026fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (xwritten < towrite) /* short writes happen */ 1027fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1028fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1029fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free (bytes); 1030fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (written) { 1031fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *written = curwrite; 1032fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1033fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1034fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // If this is the last transfer send a zero write if required 1035fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) { 1036fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if ((towrite % ptp_usb->outep_maxpacket) == 0) { 1037fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int xwritten; 1038fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1039fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("USB OUT==>\n"); 1040fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Zero Write\n"); 1041fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1042fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret =USB_BULK_WRITE(ptp_usb->handle, 1043fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->outep, 1044fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) "x", 1045fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0, 1046fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xwritten, 1047fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 1048fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1049fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1050fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1051fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) 1052fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 1053fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1054fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1055fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1056fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* memory data get/put handler */ 1057fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijtypedef struct { 1058fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char *data; 1059fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long size, curoff; 1060fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} PTPMemHandlerPrivate; 1061fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1062fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1063fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijmemory_getfunc(PTPParams* params, void* private, 1064fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long wantlen, unsigned char *data, 1065fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long *gotlen 1066fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 1067fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)private; 1068fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long tocopy = wantlen; 1069fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1070fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (priv->curoff + tocopy > priv->size) 1071fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij tocopy = priv->size - priv->curoff; 1072fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy (data, priv->data + priv->curoff, tocopy); 1073fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->curoff += tocopy; 1074fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *gotlen = tocopy; 1075fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1076fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1077fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1078fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1079fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijmemory_putfunc(PTPParams* params, void* private, 1080fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long sendlen, unsigned char *data, 1081fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long *putlen 1082fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 1083fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)private; 1084fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1085fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (priv->curoff + sendlen > priv->size) { 1086fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->data = realloc (priv->data, priv->curoff+sendlen); 1087fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->size = priv->curoff + sendlen; 1088fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1089fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy (priv->data + priv->curoff, data, sendlen); 1090fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->curoff += sendlen; 1091fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *putlen = sendlen; 1092fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1093fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1094fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1095fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* init private struct for receiving data. */ 1096fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1097fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_init_recv_memory_handler(PTPDataHandler *handler) { 1098fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv; 1099fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv = malloc (sizeof(PTPMemHandlerPrivate)); 1100fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->priv = priv; 1101fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->getfunc = memory_getfunc; 1102fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->putfunc = memory_putfunc; 1103fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->data = NULL; 1104fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->size = 0; 1105fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->curoff = 0; 1106fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1107fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1108fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1109fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* init private struct and put data in for sending data. 1110fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * data is still owned by caller. 1111fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1112fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1113fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_init_send_memory_handler(PTPDataHandler *handler, 1114fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char *data, unsigned long len 1115fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 1116fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv; 1117fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv = malloc (sizeof(PTPMemHandlerPrivate)); 1118fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!priv) 1119fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_GeneralError; 1120fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->priv = priv; 1121fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->getfunc = memory_getfunc; 1122fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->putfunc = memory_putfunc; 1123fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->data = data; 1124fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->size = len; 1125fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij priv->curoff = 0; 1126fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1127fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1128fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1129fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* free private struct + data */ 1130fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1131fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_exit_send_memory_handler (PTPDataHandler *handler) { 1132fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)handler->priv; 1133fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* data is owned by caller */ 1134fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free (priv); 1135fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1136fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1137fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1138fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* hand over our internal data to caller */ 1139fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t 1140fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_exit_recv_memory_handler (PTPDataHandler *handler, 1141fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char **data, unsigned long *size 1142fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 1143fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)handler->priv; 1144fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *data = priv->data; 1145fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *size = priv->size; 1146fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free (priv); 1147fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1148fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1149fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1150fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* send / receive functions */ 1151fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1152fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1153fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_sendreq (PTPParams* params, PTPContainer* req) 1154fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1155fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1156fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBBulkContainer usbreq; 1157fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPDataHandler memhandler; 1158fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long written = 0; 1159fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long towrite; 1160fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1161fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij char txt[256]; 1162fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1163fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (void) ptp_render_opcode (params, req->Code, sizeof(txt), txt); 1164fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("REQUEST: 0x%04x, %s\n", req->Code, txt); 1165fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1166fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* build appropriate USB container */ 1167fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.length=htod32(PTP_USB_BULK_REQ_LEN- 1168fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (sizeof(uint32_t)*(5-req->Nparam))); 1169fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.type=htod16(PTP_USB_CONTAINER_COMMAND); 1170fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.code=htod16(req->Code); 1171fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.trans_id=htod32(req->Transaction_ID); 1172fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.payload.params.param1=htod32(req->Param1); 1173fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.payload.params.param2=htod32(req->Param2); 1174fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.payload.params.param3=htod32(req->Param3); 1175fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.payload.params.param4=htod32(req->Param4); 1176fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbreq.payload.params.param5=htod32(req->Param5); 1177fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* send it to responder */ 1178fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite = PTP_USB_BULK_REQ_LEN-(sizeof(uint32_t)*(5-req->Nparam)); 1179fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_init_send_memory_handler (&memhandler, (unsigned char*)&usbreq, towrite); 1180fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret=ptp_write_func( 1181fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij towrite, 1182fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &memhandler, 1183fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->data, 1184fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &written 1185fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ); 1186fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_exit_send_memory_handler (&memhandler); 1187fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK && ret != PTP_ERROR_CANCEL) { 1188fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1189fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1190fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (written != towrite && ret != PTP_ERROR_CANCEL && ret != PTP_ERROR_IO) { 1191fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_error (params, 1192fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP: request code 0x%04x sending req wrote only %ld bytes instead of %d", 1193fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij req->Code, written, towrite 1194fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ); 1195fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1196fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1197fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1198fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1199fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1200fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1201fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_senddata (PTPParams* params, PTPContainer* ptp, 1202b3aaade14e14a67419c3edf6367b50599eec134fLinus Walleij uint64_t size, PTPDataHandler *handler 1203fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij) { 1204fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1205fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int wlen, datawlen; 1206fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long written; 1207fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBBulkContainer usbdata; 1208fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint32_t bytes_left_to_transfer; 1209fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPDataHandler memhandler; 1210fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1211fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1212fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("SEND DATA PHASE\n"); 1213fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1214fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* build appropriate USB container */ 1215fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.length = htod32(PTP_USB_BULK_HDR_LEN+size); 1216fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.type = htod16(PTP_USB_CONTAINER_DATA); 1217fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.code = htod16(ptp->Code); 1218fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.trans_id= htod32(ptp->Transaction_ID); 1219fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1220fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ((PTP_USB*)params->data)->current_transfer_complete = 0; 1221fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ((PTP_USB*)params->data)->current_transfer_total = size+PTP_USB_BULK_HDR_LEN; 1222fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1223fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (params->split_header_data) { 1224fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij datawlen = 0; 1225fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij wlen = PTP_USB_BULK_HDR_LEN; 1226fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else { 1227fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long gotlen; 1228fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* For all camera devices. */ 1229fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij datawlen = (size<PTP_USB_BULK_PAYLOAD_LEN_WRITE)?size:PTP_USB_BULK_PAYLOAD_LEN_WRITE; 1230fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij wlen = PTP_USB_BULK_HDR_LEN + datawlen; 1231fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1232fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = handler->getfunc(params, handler->priv, datawlen, usbdata.payload.data, &gotlen); 1233fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != PTP_RC_OK) 1234fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1235fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (gotlen != datawlen) 1236fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_GeneralError; 1237fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1238fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_init_send_memory_handler (&memhandler, (unsigned char *)&usbdata, wlen); 1239fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* send first part of data */ 1240fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_write_func(wlen, &memhandler, params->data, &written); 1241fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_exit_send_memory_handler (&memhandler); 1242fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1243fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1244fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1245fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (size <= datawlen) return ret; 1246fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* if everything OK send the rest */ 1247fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes_left_to_transfer = size-datawlen; 1248fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_RC_OK; 1249fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while(bytes_left_to_transfer > 0) { 1250fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_write_func (bytes_left_to_transfer, handler, params->data, &written); 1251fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != PTP_RC_OK) 1252fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1253fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (written == 0) { 1254fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1255fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1256fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1257fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes_left_to_transfer -= written; 1258fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1259fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK && ret != PTP_ERROR_CANCEL) 1260fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1261fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1262fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1263fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1264fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic uint16_t ptp_usb_getpacket(PTPParams *params, 1265fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBBulkContainer *packet, unsigned long *rlen) 1266fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1267fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPDataHandler memhandler; 1268fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1269fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char *x = NULL; 1270fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1271fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* read the header and potentially the first data */ 1272fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (params->response_packet_size > 0) { 1273fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* If there is a buffered packet, just use it. */ 1274fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy(packet, params->response_packet, params->response_packet_size); 1275fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *rlen = params->response_packet_size; 1276fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free(params->response_packet); 1277fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->response_packet = NULL; 1278fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->response_packet_size = 0; 1279fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Here this signifies a "virtual read" */ 1280fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1281fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1282fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_init_recv_memory_handler (&memhandler); 1283fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_read_func(PTP_USB_BULK_HS_MAX_PACKET_LEN_READ, &memhandler, params->data, rlen, 0); 1284fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_exit_recv_memory_handler (&memhandler, &x, rlen); 1285fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (x) { 1286fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy (packet, x, *rlen); 1287fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij free (x); 1288fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1289fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1290fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1291fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1292fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1293fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_getdata (PTPParams* params, PTPContainer* ptp, PTPDataHandler *handler) 1294fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1295fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1296fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBBulkContainer usbdata; 1297fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long written; 1298fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *) params->data; 1299fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int putfunc_ret; 1300fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1301fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("GET DATA PHASE\n"); 1302fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1303fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memset(&usbdata,0,sizeof(usbdata)); 1304fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij do { 1305fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long len, rlen; 1306fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1307fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_usb_getpacket(params, &usbdata, &rlen); 1308fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1309fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1310fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1311fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1312fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dtoh16(usbdata.type)!=PTP_USB_CONTAINER_DATA) { 1313fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_DATA_EXPECTED; 1314fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1315fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1316fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dtoh16(usbdata.code)!=ptp->Code) { 1317fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_IGNORE_HEADER_ERRORS(ptp_usb)) { 1318fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_debug (params, "ptp2/ptp_usb_getdata: detected a broken " 1319fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP header, code field insane, expect problems! (But continuing)"); 1320fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Repair the header, so it won't wreak more havoc, don't just ignore it. 1321fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Typically these two fields will be broken. 1322fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.code = htod16(ptp->Code); 1323fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.trans_id = htod32(ptp->Transaction_ID); 1324fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_RC_OK; 1325fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else { 1326fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = dtoh16(usbdata.code); 1327fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This filters entirely insane garbage return codes, but still 1328fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // makes it possible to return error codes in the code field when 1329fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // getting data. It appears Windows ignores the contents of this 1330fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // field entirely. 1331fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret < PTP_RC_Undefined || ret > PTP_RC_SpecificationOfDestinationUnsupported) { 1332fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_debug (params, "ptp2/ptp_usb_getdata: detected a broken " 1333fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP header, code field insane."); 1334fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1335fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1336fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1337fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1338fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1339fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (usbdata.length == 0xffffffffU) { 1340fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Copy first part of data to 'data' */ 1341fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij putfunc_ret = 1342fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->putfunc( 1343fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params, handler->priv, rlen - PTP_USB_BULK_HDR_LEN, usbdata.payload.data, 1344fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &written 1345fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ); 1346fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (putfunc_ret != PTP_RC_OK) 1347fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return putfunc_ret; 1348fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1349fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* stuff data directly to passed data handler */ 1350fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (1) { 1351fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long readdata; 1352fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t xret; 1353fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1354fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij xret = ptp_read_func( 1355fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB_BULK_HS_MAX_PACKET_LEN_READ, 1356fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler, 1357fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->data, 1358fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &readdata, 1359fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0 1360fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ); 1361fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (xret != PTP_RC_OK) 1362fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return xret; 1363fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (readdata < PTP_USB_BULK_HS_MAX_PACKET_LEN_READ) 1364fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1365fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1366fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1367fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1368fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (rlen > dtoh32(usbdata.length)) { 1369fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1370fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Buffer the surplus response packet if it is >= 1371fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * PTP_USB_BULK_HDR_LEN 1372fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * (i.e. it is probably an entire package) 1373fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * else discard it as erroneous surplus data. 1374fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This will even work if more than 2 packets appear 1375fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * in the same transaction, they will just be handled 1376fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * iteratively. 1377fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * 1378fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Marcus observed stray bytes on iRiver devices; 1379fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * these are still discarded. 1380fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1381fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned int packlen = dtoh32(usbdata.length); 1382fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned int surplen = rlen - packlen; 1383fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1384fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (surplen >= PTP_USB_BULK_HDR_LEN) { 1385fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->response_packet = malloc(surplen); 1386fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy(params->response_packet, 1387fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (uint8_t *) &usbdata + packlen, surplen); 1388fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->response_packet_size = surplen; 1389fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Ignore reading one extra byte if device flags have been set */ 1390fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if(!FLAG_NO_ZERO_READS(ptp_usb) && 1391fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (rlen - dtoh32(usbdata.length) == 1)) { 1392fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_debug (params, "ptp2/ptp_usb_getdata: read %d bytes " 1393fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "too much, expect problems!", 1394fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij rlen - dtoh32(usbdata.length)); 1395fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1396fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij rlen = packlen; 1397fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1398fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1399fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* For most PTP devices rlen is 512 == sizeof(usbdata) 1400fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * here. For MTP devices splitting header and data it might 1401fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * be 12. 1402fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1403fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Evaluate full data length. */ 1404fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij len=dtoh32(usbdata.length)-PTP_USB_BULK_HDR_LEN; 1405fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1406fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* autodetect split header/data MTP devices */ 1407fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dtoh32(usbdata.length) > 12 && (rlen==12)) 1408fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->split_header_data = 1; 1409fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1410fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Copy first part of data to 'data' */ 1411fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij putfunc_ret = 1412fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler->putfunc( 1413fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params, handler->priv, rlen - PTP_USB_BULK_HDR_LEN, 1414fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbdata.payload.data, 1415fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &written 1416fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ); 1417fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (putfunc_ret != PTP_RC_OK) 1418fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return putfunc_ret; 1419fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1420fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_NO_ZERO_READS(ptp_usb) && 1421fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij len+PTP_USB_BULK_HDR_LEN == PTP_USB_BULK_HS_MAX_PACKET_LEN_READ) { 1422fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1423fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("Reading in extra terminating byte\n"); 1424fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1425fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // need to read in extra byte and discard it 1426fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int result = 0, xread; 1427fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char byte = 0; 1428fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij result = USB_BULK_READ(ptp_usb->handle, 1429fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->inep, 1430fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &byte, 1431fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1, 1432fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1433fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 1434fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1435fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (result != 1) 1436fbbef8b16876568f760986e4ff8f4921b8373fd5Linus 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); 1437fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if (len+PTP_USB_BULK_HDR_LEN == PTP_USB_BULK_HS_MAX_PACKET_LEN_READ && params->split_header_data == 0) { 1438fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int zeroresult = 0, xread; 1439fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char zerobyte = 0; 1440fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1441fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("Reading in zero packet after header\n"); 1442fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1443fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij zeroresult = USB_BULK_READ(ptp_usb->handle, 1444fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->inep, 1445fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &zerobyte, 1446fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0, 1447fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1448fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 1449fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1450fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (zeroresult != 0) 1451fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("LIBMTP panic: unable to read in zero packet, response 0x%04x", zeroresult); 1452fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1453fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1454fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Is that all of data? */ 1455fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (len+PTP_USB_BULK_HDR_LEN<=rlen) { 1456fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1457fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1458fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1459fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_read_func(len - (rlen - PTP_USB_BULK_HDR_LEN), 1460fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij handler, 1461fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->data, &rlen, 1); 1462fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1463fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1464fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1465fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1466fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } while (0); 1467fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1468fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1469fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1470fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1471fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_getresp (PTPParams* params, PTPContainer* resp) 1472fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1473fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1474fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long rlen; 1475fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBBulkContainer usbresp; 1476fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *)(params->data); 1477fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1478fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1479fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("RESPONSE: "); 1480fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1481fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memset(&usbresp,0,sizeof(usbresp)); 1482fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* read response, it should never be longer than sizeof(usbresp) */ 1483fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_usb_getpacket(params, &usbresp, &rlen); 1484fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1485fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Fix for bevahiour reported by Scott Snyder on Samsung YP-U3. The player 1486fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // sends a packet containing just zeroes of length 2 (up to 4 has been seen too) 1487fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // after a NULL packet when it should send the response. This code ignores 1488fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // such illegal packets. 1489fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij while (ret==PTP_RC_OK && rlen<PTP_USB_BULK_HDR_LEN && usbresp.length==0) { 1490fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_debug (params, "ptp_usb_getresp: detected short response " 1491fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "of %d bytes, expect problems! (re-reading " 1492fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "response), rlen"); 1493fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_usb_getpacket(params, &usbresp, &rlen); 1494fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1495fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1496fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1497fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_IO; 1498fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else 1499fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dtoh16(usbresp.type)!=PTP_USB_CONTAINER_RESPONSE) { 1500fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_ERROR_RESP_EXPECTED; 1501fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else 1502fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (dtoh16(usbresp.code)!=resp->Code) { 1503fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = dtoh16(usbresp.code); 1504fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1505fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1506fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("%04x\n", ret); 1507fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1508fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1509fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* libusb_glue_error (params, 1510fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP: request code 0x%04x getting resp error 0x%04x", 1511fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Code, ret);*/ 1512fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1513fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1514fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* build an appropriate PTPContainer */ 1515fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Code=dtoh16(usbresp.code); 1516fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->SessionID=params->session_id; 1517fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Transaction_ID=dtoh32(usbresp.trans_id); 1518fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_IGNORE_HEADER_ERRORS(ptp_usb)) { 1519fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (resp->Transaction_ID != params->transaction_id-1) { 1520fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_debug (params, "ptp_usb_getresp: detected a broken " 1521fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP header, transaction ID insane, expect " 1522fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "problems! (But continuing)"); 1523fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Repair the header, so it won't wreak more havoc. 1524fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Transaction_ID = params->transaction_id-1; 1525fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1526fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1527fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Param1=dtoh32(usbresp.payload.params.param1); 1528fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Param2=dtoh32(usbresp.payload.params.param2); 1529fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Param3=dtoh32(usbresp.payload.params.param3); 1530fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Param4=dtoh32(usbresp.payload.params.param4); 1531fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij resp->Param5=dtoh32(usbresp.payload.params.param5); 1532fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1533fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1534fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1535fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* Event handling functions */ 1536fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1537fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/* PTP Events wait for or check mode */ 1538fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define PTP_EVENT_CHECK 0x0000 /* waits for */ 1539fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#define PTP_EVENT_CHECK_FAST 0x0001 /* checks */ 1540fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1541fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic inline uint16_t 1542fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_event (PTPParams* params, PTPContainer* event, int wait) 1543fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1544fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret; 1545fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int result, xread; 1546fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned long rlen; 1547fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPUSBEventContainer usbevent; 1548fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *)(params->data); 1549fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1550fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memset(&usbevent,0,sizeof(usbevent)); 1551fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1552fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if ((params==NULL) || (event==NULL)) 1553fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_BADPARAM; 1554fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = PTP_RC_OK; 1555fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij switch(wait) { 1556fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij case PTP_EVENT_CHECK: 15577433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij result = USB_BULK_READ(ptp_usb->handle, 1558fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->intep, 1559fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) &usbevent, 1560fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(usbevent), 1561fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1562fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0); 15637433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij if (xread == 0) 1564fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij result = USB_BULK_READ(ptp_usb->handle, 1565fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->intep, 1566fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) &usbevent, 1567fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(usbevent), 1568fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1569fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0); 1570fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (result < 0) ret = PTP_ERROR_IO; 1571fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1572fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij case PTP_EVENT_CHECK_FAST: 15737433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij result = USB_BULK_READ(ptp_usb->handle, 1574fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->intep, 1575fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) &usbevent, 1576fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(usbevent), 1577fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1578fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 15797433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij if (xread == 0) 1580fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij result = USB_BULK_READ(ptp_usb->handle, 1581fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->intep, 1582fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) &usbevent, 1583fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(usbevent), 1584fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &xread, 1585fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 1586fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (result < 0) ret = PTP_ERROR_IO; 1587fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1588fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij default: 15897433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij ret = PTP_ERROR_BADPARAM; 1590fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 1591fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1592fbd8e95f4ff7abfcd38a27c3c56537b8fc28203eLinus Walleij if (ret != PTP_RC_OK) { 1593fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_error (params, 1594fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP: reading event an error 0x%04x occurred", ret); 1595fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 1596fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 15977433938937cb07f52a5672e839f286ec1a2a7633Linus Walleij rlen = xread; 1598fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (rlen < 8) { 1599fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_glue_error (params, 1600fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "PTP: reading event an short read of %ld bytes occurred", rlen); 1601fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 1602fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1603fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* if we read anything over interrupt endpoint it must be an event */ 1604fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* build an appropriate PTPContainer */ 1605fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->Code=dtoh16(usbevent.code); 1606fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->SessionID=params->session_id; 1607fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->Transaction_ID=dtoh32(usbevent.trans_id); 1608fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->Param1=dtoh32(usbevent.param1); 1609fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->Param2=dtoh32(usbevent.param2); 1610fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij event->Param3=dtoh32(usbevent.param3); 1611fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ret; 1612fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1613fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1614fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1615fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_event_check (PTPParams* params, PTPContainer* event) { 1616fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1617fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ptp_usb_event (params, event, PTP_EVENT_CHECK_FAST); 1618fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1619fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1620fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1621fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_event_wait (PTPParams* params, PTPContainer* event) { 1622fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1623fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return ptp_usb_event (params, event, PTP_EVENT_CHECK); 1624fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1625fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1626fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijuint16_t 1627fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijptp_usb_control_cancel_request (PTPParams *params, uint32_t transactionid) { 1628fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb = (PTP_USB *)(params->data); 1629fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 1630fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char buffer[6]; 1631fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1632fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij htod16a(&buffer[0],PTP_EC_CancelTransaction); 1633fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij htod32a(&buffer[2],transactionid); 1634fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer(ptp_usb->handle, 1635fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 1636fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0x64, 0x0000, 0x0000, 1637fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij buffer, 1638fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij sizeof(buffer), 1639fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 1640fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret < sizeof(buffer)) 1641fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_ERROR_IO; 1642fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return PTP_RC_OK; 1643fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1644fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 164515d18e31458be5006eb229df68869df2fff93495Linus Walleijstatic int init_ptp_usb(PTPParams* params, PTP_USB* ptp_usb, libusb_device* dev) 1646fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1647fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device_handle *device_handle; 1648fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij unsigned char buf[255]; 1649fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret, usbresult; 165015d18e31458be5006eb229df68869df2fff93495Linus Walleij struct libusb_config_descriptor *config; 1651fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1652fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->sendreq_func=ptp_usb_sendreq; 1653fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->senddata_func=ptp_usb_senddata; 1654fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->getresp_func=ptp_usb_getresp; 1655fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->getdata_func=ptp_usb_getdata; 1656fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->cancelreq_func=ptp_usb_control_cancel_request; 1657fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->data=ptp_usb; 1658fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->transaction_id=0; 1659fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1660fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This is hardcoded here since we have no devices whatsoever that are BE. 1661fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Change this the day we run into our first BE device (if ever). 1662fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1663fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->byteorder = PTP_DL_LE; 1664fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1665fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout = get_timeout(ptp_usb); 1666fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1667fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_open(dev, &device_handle); 1668fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) { 166915d18e31458be5006eb229df68869df2fff93495Linus Walleij perror("libusb_open() failed!"); 1670fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return -1; 1671fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1672fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->handle = device_handle; 167315d18e31458be5006eb229df68869df2fff93495Linus Walleij 1674fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1675fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * If this device is known to be wrongfully claimed by other kernel 1676fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * drivers (such as mass storage), then try to unload it to make it 1677fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * accessible from user space. 1678fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1679fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_UNLOAD_DRIVER(ptp_usb) && 168015d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_kernel_driver_active(device_handle, ptp_usb->interface) 1681fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ) { 168215d18e31458be5006eb229df68869df2fff93495Linus Walleij if (LIBUSB_SUCCESS != libusb_detach_kernel_driver(device_handle, ptp_usb->interface)) { 168315d18e31458be5006eb229df68869df2fff93495Linus Walleij perror("libusb_detach_kernel_driver() failed, continuing anyway..."); 1684fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1685fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 168615d18e31458be5006eb229df68869df2fff93495Linus Walleij 168715d18e31458be5006eb229df68869df2fff93495Linus Walleij /* 168815d18e31458be5006eb229df68869df2fff93495Linus Walleij * Check if the config is set to something else than what we want 168915d18e31458be5006eb229df68869df2fff93495Linus Walleij * to use. Only set the configuration if we absolutely have to. 169015d18e31458be5006eb229df68869df2fff93495Linus Walleij * Also do not bail out if we fail. 1691d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij * 1692d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij * Note that Darwin will not set the configuration for vendor-specific 1693d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij * devices so we need to go in and set it. 169415d18e31458be5006eb229df68869df2fff93495Linus Walleij */ 169515d18e31458be5006eb229df68869df2fff93495Linus Walleij ret = libusb_get_active_config_descriptor(dev, &config); 169615d18e31458be5006eb229df68869df2fff93495Linus Walleij if (ret != LIBUSB_SUCCESS) { 169715d18e31458be5006eb229df68869df2fff93495Linus Walleij perror("libusb_get_active_config_descriptor(1) failed"); 1698d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij fprintf(stderr, "no active configuration, trying to set configuration\n"); 1699d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij if (libusb_set_configuration(device_handle, ptp_usb->config) != LIBUSB_SUCCESS) { 1700d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij perror("libusb_set_configuration() failed, continuing anyway..."); 1701d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij } 1702d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij ret = libusb_get_active_config_descriptor(dev, &config); 1703d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij if (ret != LIBUSB_SUCCESS) { 1704d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij perror("libusb_get_active_config_descriptor(2) failed"); 1705d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij return -1; 1706d76ae6e8ede659fd4bd13908798d3c5c86c1f1d4Linus Walleij } 1707fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 170815d18e31458be5006eb229df68869df2fff93495Linus Walleij if (config->bConfigurationValue != ptp_usb->config) { 170915d18e31458be5006eb229df68869df2fff93495Linus Walleij fprintf(stderr, "desired configuration different from current, trying to set configuration\n"); 171015d18e31458be5006eb229df68869df2fff93495Linus Walleij if (libusb_set_configuration(device_handle, ptp_usb->config)) { 171115d18e31458be5006eb229df68869df2fff93495Linus Walleij perror("libusb_set_configuration() failed, continuing anyway..."); 171215d18e31458be5006eb229df68869df2fff93495Linus Walleij } 171315d18e31458be5006eb229df68869df2fff93495Linus Walleij /* Re-fetch the config descriptor if we changed */ 171415d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 171515d18e31458be5006eb229df68869df2fff93495Linus Walleij ret = libusb_get_active_config_descriptor(dev, &config); 171615d18e31458be5006eb229df68869df2fff93495Linus Walleij if (ret != LIBUSB_SUCCESS) { 171715d18e31458be5006eb229df68869df2fff93495Linus Walleij perror("libusb_get_active_config_descriptor(2) failed"); 171815d18e31458be5006eb229df68869df2fff93495Linus Walleij return -1; 171915d18e31458be5006eb229df68869df2fff93495Linus Walleij } 172015d18e31458be5006eb229df68869df2fff93495Linus Walleij } 172115d18e31458be5006eb229df68869df2fff93495Linus Walleij 172215d18e31458be5006eb229df68869df2fff93495Linus Walleij /* 172315d18e31458be5006eb229df68869df2fff93495Linus Walleij * It seems like on kernel 2.6.31 if we already have it open on another 172415d18e31458be5006eb229df68869df2fff93495Linus Walleij * pthread in our app, we'll get an error if we try to claim it again, 172515d18e31458be5006eb229df68869df2fff93495Linus Walleij * but that error is harmless because our process already claimed the interface 172615d18e31458be5006eb229df68869df2fff93495Linus Walleij */ 1727fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usbresult = libusb_claim_interface(device_handle, ptp_usb->interface); 1728fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1729fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (usbresult != 0) 173015d18e31458be5006eb229df68869df2fff93495Linus Walleij fprintf(stderr, "ignoring libusb_claim_interface() = %d", usbresult); 173115d18e31458be5006eb229df68869df2fff93495Linus Walleij 173215d18e31458be5006eb229df68869df2fff93495Linus Walleij /* 173315d18e31458be5006eb229df68869df2fff93495Linus Walleij * If the altsetting is set to something different than we want, switch 173415d18e31458be5006eb229df68869df2fff93495Linus Walleij * it. 173515d18e31458be5006eb229df68869df2fff93495Linus Walleij * 173615d18e31458be5006eb229df68869df2fff93495Linus Walleij * FIXME: this seems to cause trouble on the Mac:s so disable it. Retry 173715d18e31458be5006eb229df68869df2fff93495Linus Walleij * this on the Mac now that it only sets this when the altsetting differs. 173815d18e31458be5006eb229df68869df2fff93495Linus Walleij */ 1739fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#ifndef __APPLE__ 174015d18e31458be5006eb229df68869df2fff93495Linus Walleij#if 0 /* Disable this always, no idea on how to handle it */ 174115d18e31458be5006eb229df68869df2fff93495Linus Walleij if (config->interface[].altsetting[].bAlternateSetting != 174215d18e31458be5006eb229df68869df2fff93495Linus Walleij ptp_usb->altsetting) { 174315d18e31458be5006eb229df68869df2fff93495Linus Walleij fprintf(stderr, "desired altsetting different from current, trying to set altsetting\n"); 174415d18e31458be5006eb229df68869df2fff93495Linus Walleij usbresult = libusb_set_interface_alt_setting(device_handle, 174515d18e31458be5006eb229df68869df2fff93495Linus Walleij ptp_usb->interface, 174615d18e31458be5006eb229df68869df2fff93495Linus Walleij ptp_usb->altsetting); 174715d18e31458be5006eb229df68869df2fff93495Linus Walleij if (usbresult != 0) 174815d18e31458be5006eb229df68869df2fff93495Linus Walleij fprintf(stderr, "ignoring libusb_set_interface_alt_setting() = %d\n", usbresult); 174915d18e31458be5006eb229df68869df2fff93495Linus Walleij } 175015d18e31458be5006eb229df68869df2fff93495Linus Walleij#endif 1751fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij#endif 1752fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 175315d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 175415d18e31458be5006eb229df68869df2fff93495Linus Walleij 1755fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_SWITCH_MODE_BLACKBERRY(ptp_usb)) { 1756fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 1757fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1758fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // FIXME : Only for BlackBerry Storm 1759fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // What does it mean? Maybe switch mode... 1760fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This first control message is absolutely necessary 1761fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usleep(1000); 1762fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer(device_handle, 1763fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, 1764fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0xaa, 0x00, 0x04, buf, 0x40, 1000); 1765fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("BlackBerry magic part 1:\n"); 1766fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(buf, ret, 16); 1767fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1768fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usleep(1000); 1769fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This control message is unnecessary 1770fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer(device_handle, 1771fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, 1772fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0xa5, 0x00, 0x01, buf, 0x02, 1000); 1773fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("BlackBerry magic part 2:\n"); 1774fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(buf, ret, 16); 1775fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1776fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usleep(1000); 1777fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This control message is unnecessary 1778fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer(device_handle, 1779fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, 1780fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0xa8, 0x00, 0x01, buf, 0x05, 1000); 1781fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("BlackBerry magic part 3:\n"); 1782fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(buf, ret, 16); 1783fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1784fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usleep(1000); 1785fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // This control message is unnecessary 1786fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_control_transfer(device_handle, 1787fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, 1788fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 0xa8, 0x00, 0x01, buf, 0x11, 1000); 1789fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DEBUG("BlackBerry magic part 4:\n"); 1790fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_USB_DATA(buf, ret, 16); 1791fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1792fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij usleep(1000); 1793fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1794fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return 0; 1795fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1796fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1797fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void clear_stall(PTP_USB* ptp_usb) 1798fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1799fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t status; 1800fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 1801fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1802fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* check the inep status */ 1803fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij status = 0; 1804fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status); 1805fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret<0) { 1806fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror ("inep: usb_get_endpoint_status()"); 1807fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if (status) { 1808fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("Clearing stall on IN endpoint\n"); 1809fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_clear_halt (ptp_usb->handle, ptp_usb->inep); 1810fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) { 1811fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror ("usb_clear_stall_feature()"); 1812fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1813fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1814fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1815fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* check the outep status */ 1816fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij status=0; 1817fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status); 1818fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret<0) { 1819fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror("outep: usb_get_endpoint_status()"); 1820fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } else if (status) { 1821fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_INFO("Clearing stall on OUT endpoint\n"); 1822fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_clear_halt (ptp_usb->handle, ptp_usb->outep); 1823fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) { 1824fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror("usb_clear_stall_feature()"); 1825fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1826fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1827fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1828fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* TODO: do we need this for INTERRUPT (ptp_usb->intep) too? */ 1829fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1830fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1831fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void clear_halt(PTP_USB* ptp_usb) 1832fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1833fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int ret; 1834fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1835fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_clear_halt(ptp_usb->handle,ptp_usb->inep); 1836fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret<0) { 1837fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror("usb_clear_halt() on IN endpoint"); 1838fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1839fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_clear_halt(ptp_usb->handle,ptp_usb->outep); 1840fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret<0) { 1841fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror("usb_clear_halt() on OUT endpoint"); 1842fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1843fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = libusb_clear_halt(ptp_usb->handle,ptp_usb->intep); 1844fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret<0) { 1845fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij perror("usb_clear_halt() on INTERRUPT endpoint"); 1846fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1847fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1848fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1849fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic void close_usb(PTP_USB* ptp_usb) 1850fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1851fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!FLAG_NO_RELEASE_INTERFACE(ptp_usb)) { 1852fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1853fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Clear any stalled endpoints 1854fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * On misbehaving devices designed for Windows/Mac, quote from: 1855fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * http://www2.one-eyed-alien.net/~mdharm/linux-usb/target_offenses.txt 1856fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Device does Bad Things(tm) when it gets a GET_STATUS after CLEAR_HALT 1857fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * (...) Windows, when clearing a stall, only sends the CLEAR_HALT command, 1858fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * and presumes that the stall has cleared. Some devices actually choke 1859fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * if the CLEAR_HALT is followed by a GET_STATUS (used to determine if the 1860fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * STALL is persistant or not). 1861fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1862fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij clear_stall(ptp_usb); 1863fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Clear halts on any endpoints 1864fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij clear_halt(ptp_usb); 1865fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Added to clear some stuff on the OUT endpoint 1866fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // TODO: is this good on the Mac too? 1867fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // HINT: some devices may need that you comment these two out too. 1868fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_clear_halt(ptp_usb->handle, ptp_usb->outep); 1869fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_release_interface(ptp_usb->handle, (int) ptp_usb->interface); 1870fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1871fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_FORCE_RESET_ON_CLOSE(ptp_usb)) { 1872fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1873fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Some devices really love to get reset after being 1874fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * disconnected. Again, since Windows never disconnects 1875fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * a device closing behaviour is seldom or never exercised 1876fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * on devices when engineered and often error prone. 1877fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Reset may help some. 1878fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1879fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_reset_device (ptp_usb->handle); 1880fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1881fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_close(ptp_usb->handle); 1882fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1883fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1884fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 1885fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Self-explanatory? 1886fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1887fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic int find_interface_and_endpoints(libusb_device *dev, 188815d18e31458be5006eb229df68869df2fff93495Linus Walleij uint8_t *conf, 1889fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint8_t *interface, 189015d18e31458be5006eb229df68869df2fff93495Linus Walleij uint8_t *altsetting, 1891fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* inep, 1892fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* inep_maxpacket, 1893fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* outep, 1894fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int *outep_maxpacket, 1895fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int* intep) 1896fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 189715d18e31458be5006eb229df68869df2fff93495Linus Walleij uint8_t i, ret; 1898fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 1899fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 190015d18e31458be5006eb229df68869df2fff93495Linus Walleij ret = libusb_get_device_descriptor(dev, &desc); 190115d18e31458be5006eb229df68869df2fff93495Linus Walleij if (ret != LIBUSB_SUCCESS) 190215d18e31458be5006eb229df68869df2fff93495Linus Walleij return -1; 1903fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1904fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Loop over the device configurations 1905fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (i = 0; i < desc.bNumConfigurations; i++) { 1906fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint8_t j; 1907fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_config_descriptor *config; 1908fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 190915d18e31458be5006eb229df68869df2fff93495Linus Walleij ret = libusb_get_config_descriptor(dev, i, &config); 191015d18e31458be5006eb229df68869df2fff93495Linus Walleij if (ret != 0) 191115d18e31458be5006eb229df68869df2fff93495Linus Walleij continue; 191215d18e31458be5006eb229df68869df2fff93495Linus Walleij 191315d18e31458be5006eb229df68869df2fff93495Linus Walleij *conf = config->bConfigurationValue; 191415d18e31458be5006eb229df68869df2fff93495Linus Walleij 1915fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) continue; 1916fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Loop over each configurations interfaces 1917fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (j = 0; j < config->bNumInterfaces; j++) { 191815d18e31458be5006eb229df68869df2fff93495Linus Walleij uint8_t k, l; 1919fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint8_t no_ep; 1920fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int found_inep = 0; 1921fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int found_outep = 0; 1922fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int found_intep = 0; 1923fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij const struct libusb_endpoint_descriptor *ep; 1924fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 192515d18e31458be5006eb229df68869df2fff93495Linus Walleij // Inspect the altsettings of this interface... 192615d18e31458be5006eb229df68869df2fff93495Linus Walleij for (k = 0; k < config->interface[j].num_altsetting; k++) { 192715d18e31458be5006eb229df68869df2fff93495Linus Walleij 192815d18e31458be5006eb229df68869df2fff93495Linus Walleij // MTP devices shall have 3 endpoints, ignore those interfaces 192915d18e31458be5006eb229df68869df2fff93495Linus Walleij // that haven't. 193015d18e31458be5006eb229df68869df2fff93495Linus Walleij no_ep = config->interface[j].altsetting[k].bNumEndpoints; 193115d18e31458be5006eb229df68869df2fff93495Linus Walleij if (no_ep != 3) 193215d18e31458be5006eb229df68869df2fff93495Linus Walleij continue; 193315d18e31458be5006eb229df68869df2fff93495Linus Walleij 193415d18e31458be5006eb229df68869df2fff93495Linus Walleij *interface = config->interface[j].altsetting[k].bInterfaceNumber; 193515d18e31458be5006eb229df68869df2fff93495Linus Walleij *altsetting = config->interface[j].altsetting[k].bAlternateSetting; 193615d18e31458be5006eb229df68869df2fff93495Linus Walleij ep = config->interface[j].altsetting[k].endpoint; 193715d18e31458be5006eb229df68869df2fff93495Linus Walleij 193815d18e31458be5006eb229df68869df2fff93495Linus Walleij // Loop over the three endpoints to locate two bulk and 193915d18e31458be5006eb229df68869df2fff93495Linus Walleij // one interrupt endpoint and FAIL if we cannot, and continue. 194015d18e31458be5006eb229df68869df2fff93495Linus Walleij for (l = 0; l < no_ep; l++) { 194115d18e31458be5006eb229df68869df2fff93495Linus Walleij if (ep[l].bmAttributes == LIBUSB_TRANSFER_TYPE_BULK) { 194215d18e31458be5006eb229df68869df2fff93495Linus Walleij if ((ep[l].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == 194315d18e31458be5006eb229df68869df2fff93495Linus Walleij LIBUSB_ENDPOINT_DIR_MASK) { 194415d18e31458be5006eb229df68869df2fff93495Linus Walleij *inep = ep[l].bEndpointAddress; 194515d18e31458be5006eb229df68869df2fff93495Linus Walleij *inep_maxpacket = ep[l].wMaxPacketSize; 194615d18e31458be5006eb229df68869df2fff93495Linus Walleij found_inep = 1; 194715d18e31458be5006eb229df68869df2fff93495Linus Walleij } 194815d18e31458be5006eb229df68869df2fff93495Linus Walleij if ((ep[l].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == 0) { 194915d18e31458be5006eb229df68869df2fff93495Linus Walleij *outep = ep[l].bEndpointAddress; 195015d18e31458be5006eb229df68869df2fff93495Linus Walleij *outep_maxpacket = ep[l].wMaxPacketSize; 195115d18e31458be5006eb229df68869df2fff93495Linus Walleij found_outep = 1; 195215d18e31458be5006eb229df68869df2fff93495Linus Walleij } 195315d18e31458be5006eb229df68869df2fff93495Linus Walleij } else if (ep[l].bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT) { 195415d18e31458be5006eb229df68869df2fff93495Linus Walleij if ((ep[l].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == 195515d18e31458be5006eb229df68869df2fff93495Linus Walleij LIBUSB_ENDPOINT_DIR_MASK) { 195615d18e31458be5006eb229df68869df2fff93495Linus Walleij *intep = ep[l].bEndpointAddress; 195715d18e31458be5006eb229df68869df2fff93495Linus Walleij found_intep = 1; 195815d18e31458be5006eb229df68869df2fff93495Linus Walleij } 1959fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 1960fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 196115d18e31458be5006eb229df68869df2fff93495Linus Walleij if (found_inep && found_outep && found_intep) { 196215d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 196315d18e31458be5006eb229df68869df2fff93495Linus Walleij // We assigned the endpoints so return here. 196415d18e31458be5006eb229df68869df2fff93495Linus Walleij return 0; 196515d18e31458be5006eb229df68869df2fff93495Linus Walleij } 196615d18e31458be5006eb229df68869df2fff93495Linus Walleij } // Next altsetting 196715d18e31458be5006eb229df68869df2fff93495Linus Walleij } // Next interface 196815d18e31458be5006eb229df68869df2fff93495Linus Walleij libusb_free_config_descriptor(config); 196915d18e31458be5006eb229df68869df2fff93495Linus Walleij } // Next config 1970fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return -1; 1971fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 1972fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1973fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij/** 1974fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This function assigns params and usbinfo given a raw device 1975fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * as input. 1976fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param device the device to be assigned. 1977fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @param usbinfo a pointer to the new usbinfo. 1978fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * @return an error code. 1979fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 1980fbbef8b16876568f760986e4ff8f4921b8373fd5Linus WalleijLIBMTP_error_number_t configure_usb_device(LIBMTP_raw_device_t *device, 1981fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTPParams *params, 1982fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij void **usbinfo) 1983fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 1984fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij PTP_USB *ptp_usb; 1985fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device *ldevice; 1986fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij uint16_t ret = 0; 1987fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int err, found = 0, i; 1988fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ssize_t nrofdevs; 1989fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_device **devs = NULL; 1990fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij struct libusb_device_descriptor desc; 19913df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang LIBMTP_error_number_t init_usb_ret; 1992fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 1993fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* See if we can find this raw device again... */ 19943df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang init_usb_ret = init_usb(); 19953df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang if (init_usb_ret != LIBMTP_ERROR_NONE) 19963df1589b0b5b81484ebc507ac4b96d1e04891d9bLei Zhang return init_usb_ret; 1997fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 199815d18e31458be5006eb229df68869df2fff93495Linus Walleij nrofdevs = libusb_get_device_list(NULL, &devs); 1999fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij for (i = 0; i < nrofdevs ; i++) { 200015d18e31458be5006eb229df68869df2fff93495Linus Walleij if (libusb_get_bus_number(devs[i]) != device->bus_location) 2001fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 200215d18e31458be5006eb229df68869df2fff93495Linus Walleij if (libusb_get_device_address(devs[i]) != device->devnum) 2003fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij continue; 2004fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 200515d18e31458be5006eb229df68869df2fff93495Linus Walleij ret = libusb_get_device_descriptor(devs[i], &desc); 2006fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != LIBUSB_SUCCESS) continue; 2007fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2008fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if(desc.idVendor == device->device_entry.vendor_id && 2009fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij desc.idProduct == device->device_entry.product_id ) { 2010fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ldevice = devs[i]; 2011fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij found = 1; 2012fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 2013fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2014fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2015fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Device has gone since detecting raw devices! */ 2016fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (!found) { 2017fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_free_device_list (devs, 0); 2018fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NO_DEVICE_ATTACHED; 2019fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2020fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2021fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Allocate structs */ 2022fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb = (PTP_USB *) malloc(sizeof(PTP_USB)); 2023fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_usb == NULL) { 2024fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_free_device_list (devs, 0); 2025fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_MEMORY_ALLOCATION; 2026fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2027fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Start with a blank slate (includes setting device_flags to 0) */ 2028fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memset(ptp_usb, 0, sizeof(PTP_USB)); 2029fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2030fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Copy the raw device */ 2031fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij memcpy(&ptp_usb->rawdevice, device, sizeof(LIBMTP_raw_device_t)); 2032fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2033fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 2034fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * Some devices must have their "OS Descriptor" massaged in order 2035fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * to work. 2036fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 2037fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (FLAG_ALWAYS_PROBE_DESCRIPTOR(ptp_usb)) { 2038fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij // Massage the device descriptor 2039fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (void) probe_device_descriptor(ldevice, NULL); 2040fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2041fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2042fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Assign interface and endpoints to usbinfo... */ 2043fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij err = find_interface_and_endpoints(ldevice, 204415d18e31458be5006eb229df68869df2fff93495Linus Walleij &ptp_usb->config, 2045fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->interface, 204615d18e31458be5006eb229df68869df2fff93495Linus Walleij &ptp_usb->altsetting, 2047fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->inep, 2048fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->inep_maxpacket, 2049fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->outep, 2050fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->outep_maxpacket, 2051fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij &ptp_usb->intep); 2052fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2053fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (err) { 2054fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_free_device_list (devs, 0); 2055fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: Unable to find interface & endpoints of device\n"); 2056fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_CONNECTING; 2057fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2058fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2059fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Copy USB version number */ 2060fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->bcdusb = desc.bcdUSB; 2061fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2062fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Attempt to initialize this device */ 2063fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (init_ptp_usb(params, ptp_usb, ldevice) < 0) { 2064fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: Unable to initialize device\n"); 20651e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang libusb_free_device_list (devs, 0); 2066fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_CONNECTING; 2067fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2068fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2069fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 2070fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * This works in situations where previous bad applications 2071fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * have not used LIBMTP_Release_Device on exit 2072fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 2073fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if ((ret = ptp_opensession(params, 1)) == PTP_ERROR_IO) { 2074fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("PTP_ERROR_IO: failed to open session, trying again after resetting USB interface\n"); 2075fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP libusb: Attempt to reset device\n"); 2076fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_reset_device (ptp_usb->handle); 2077fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij close_usb(ptp_usb); 2078fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2079fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if(init_ptp_usb(params, ptp_usb, ldevice) <0) { 2080fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: Could not init USB on second attempt\n"); 20811e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang libusb_free_device_list (devs, 0); 2082fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_CONNECTING; 2083fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2084fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2085fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Device has been reset, try again */ 2086fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if ((ret = ptp_opensession(params, 1)) == PTP_ERROR_IO) { 2087fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: failed to open session on second attempt\n"); 20881e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang libusb_free_device_list (devs, 0); 2089fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_CONNECTING; 2090fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2091fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2092fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2093fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Was the transaction id invalid? Try again */ 2094fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret == PTP_RC_InvalidTransactionID) { 2095fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP WARNING: Transaction ID was invalid, increment and try again\n"); 2096fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij params->transaction_id += 10; 2097fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret = ptp_opensession(params, 1); 2098fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2099fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2100fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ret != PTP_RC_SessionAlreadyOpened && ret != PTP_RC_OK) { 2101fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("LIBMTP PANIC: Could not open session! " 2102fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij "(Return code %d)\n Try to reset the device.\n", 2103fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ret); 2104fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij libusb_release_interface(ptp_usb->handle, ptp_usb->interface); 21051e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang libusb_free_device_list (devs, 0); 2106fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_CONNECTING; 2107fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2108fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2109fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* OK configured properly */ 2110fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *usbinfo = (void *) ptp_usb; 21111e5c80e148681f409c6d16d27336b9cd195f3387Lei Zhang libusb_free_device_list (devs, 0); 2112fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return LIBMTP_ERROR_NONE; 2113fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2114fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2115fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2116fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijvoid close_device (PTP_USB *ptp_usb, PTPParams *params) 2117fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 2118fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij if (ptp_closesession(params)!=PTP_RC_OK) 2119fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBMTP_ERROR("ERROR: Could not close session!\n"); 2120fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij close_usb(ptp_usb); 2121fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2122fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2123fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijvoid set_usb_device_timeout(PTP_USB *ptp_usb, int timeout) 2124fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 2125fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout = timeout; 2126fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2127fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2128fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijvoid get_usb_device_timeout(PTP_USB *ptp_usb, int *timeout) 2129fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 2130fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij *timeout = ptp_usb->timeout; 2131fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2132fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2133fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijint guess_usb_speed(PTP_USB *ptp_usb) 2134fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 2135fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij int bytes_per_second; 2136fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2137fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 2138fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * We don't know the actual speeds so these are rough guesses 2139fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * from the info you can find here: 2140fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * http://en.wikipedia.org/wiki/USB#Transfer_rates 2141fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij * http://www.barefeats.com/usb2.html 2142fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij */ 2143fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij switch (ptp_usb->bcdusb & 0xFF00) { 2144fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij case 0x0100: 2145fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* 1.x USB versions let's say 1MiB/s */ 2146fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes_per_second = 1*1024*1024; 2147fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 2148fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij case 0x0200: 2149fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij case 0x0300: 2150fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* USB 2.0 nominal speed 18MiB/s */ 2151fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* USB 3.0 won't be worse? */ 2152fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes_per_second = 18*1024*1024; 2153fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 2154fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij default: 2155fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij /* Half-guess something? */ 2156fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij bytes_per_second = 1*1024*1024; 2157fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij break; 2158fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij } 2159fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return bytes_per_second; 2160fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2161fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2162fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleijstatic int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status) 2163fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij{ 2164fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij return libusb_control_transfer(ptp_usb->handle, 2165fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_ENDPOINT, 2166fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij LIBUSB_REQUEST_GET_STATUS, 2167fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij USB_FEATURE_HALT, 2168fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ep, 2169fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij (unsigned char *) status, 2170fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij 2, 2171fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij ptp_usb->timeout); 2172fbbef8b16876568f760986e4ff8f4921b8373fd5Linus Walleij} 2173