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