blob: cd75036ed7c9bc4dc9d9a371cd707e2147a28243 [file] [log] [blame]
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001/*
Linus Walleij2f45d222007-02-02 22:47:39 +00002 * \file libusb-glue.c
3 * Low-level USB interface glue towards libusb.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00004 *
Linus Walleij2f45d222007-02-02 22:47:39 +00005 * Copyright (C) 2005-2007 Richard A. Low <richard@wentnet.com>
Linus Walleij00411ee2008-01-27 12:24:51 +00006 * Copyright (C) 2005-2008 Linus Walleij <triad@df.lth.se>
Linus Walleij2f45d222007-02-02 22:47:39 +00007 * Copyright (C) 2006-2007 Marcus Meissner
8 * Copyright (C) 2007 Ted Bullock
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00009 *
Linus Walleij2f45d222007-02-02 22:47:39 +000010 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
Linus Walleij2e1c8a32007-01-22 06:46:08 +000014 *
Linus Walleij2f45d222007-02-02 22:47:39 +000015 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
Linus Walleij2e1c8a32007-01-22 06:46:08 +000019 *
Linus Walleij2f45d222007-02-02 22:47:39 +000020 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
24 *
25 * Created by Richard Low on 24/12/2005. (as mtp-utils.c)
26 * Modified by Linus Walleij 2006-03-06
27 * (Notice that Anglo-Saxons use little-endian dates and Swedes
28 * use big-endian dates.)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000029 *
30 */
Linus Walleij7beba572006-11-29 08:56:12 +000031#include "libmtp.h"
32#include "libusb-glue.h"
Linus Walleij3e667ae2007-10-29 23:29:39 +000033#include "device-flags.h"
Linus Walleij7beba572006-11-29 08:56:12 +000034#include "util.h"
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000035#include "ptp.h"
Linus Walleij7beba572006-11-29 08:56:12 +000036
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000037#include <errno.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000041#include <usb.h>
42
Linus Walleija0323272007-01-07 12:21:30 +000043#include "ptp-pack.c"
44
Linus Walleije78de6d2006-10-31 14:46:36 +000045/* To enable debug prints, switch on this */
46//#define ENABLE_USB_BULK_DEBUG
47
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000048/* this must not be too short - the original 4000 was not long
49 enough for big file transfers. I imagine the player spends a
50 bit of time gearing up to receiving lots of data. This also makes
51 connecting/disconnecting more reliable */
52#define USB_TIMEOUT 10000
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000053
54/* USB control message data phase direction */
55#ifndef USB_DP_HTD
56#define USB_DP_HTD (0x00 << 7) /* host to device */
57#endif
58#ifndef USB_DP_DTH
59#define USB_DP_DTH (0x01 << 7) /* device to host */
60#endif
61
62/* USB Feature selector HALT */
63#ifndef USB_FEATURE_HALT
64#define USB_FEATURE_HALT 0x00
65#endif
66
Linus Walleij6fd2f082006-03-28 07:19:22 +000067static const LIBMTP_device_entry_t mtp_device_table[] = {
Linus Walleij1a673de2007-10-29 23:10:05 +000068/* We include an .h file which is shared between us and libgphoto2 */
69#include "music-players.h"
Linus Walleija5483642006-03-09 09:20:38 +000070};
Linus Walleij6fd2f082006-03-28 07:19:22 +000071static const int mtp_device_table_size = sizeof(mtp_device_table) / sizeof(LIBMTP_device_entry_t);
Linus Walleija5483642006-03-09 09:20:38 +000072
Linus Walleijd6a49972006-05-02 08:24:54 +000073// Local functions
Linus Walleij1fd2d272006-05-08 09:22:01 +000074static struct usb_bus* init_usb();
Linus Walleijb0ab5482007-08-29 21:08:54 +000075static void close_usb(PTP_USB* ptp_usb);
76static void find_interface_and_endpoints(struct usb_device *dev,
77 uint8_t *interface,
78 int* inep,
79 int* inep_maxpacket,
80 int* outep,
81 int* outep_maxpacket,
82 int* intep);
Linus Walleijd6a49972006-05-02 08:24:54 +000083static void clear_stall(PTP_USB* ptp_usb);
Linus Walleij9eb3d312006-08-04 19:25:59 +000084static int init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev);
Linus Walleij784ac3f2006-12-29 10:36:51 +000085static short ptp_write_func (unsigned long,PTPDataHandler*,void *data,unsigned long*);
Richard Low4df32f82007-01-11 20:04:39 +000086static short ptp_read_func (unsigned long,PTPDataHandler*,void *data,unsigned long*,int);
Linus Walleijd6a49972006-05-02 08:24:54 +000087static int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep);
88static int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status);
Linus Walleij1fd2d272006-05-08 09:22:01 +000089
Linus Walleij552ba322007-01-22 11:49:59 +000090/**
91 * Get a list of the supported USB devices.
92 *
93 * The developers depend on users of this library to constantly
94 * add in to the list of supported devices. What we need is the
95 * device name, USB Vendor ID (VID) and USB Product ID (PID).
96 * put this into a bug ticket at the project homepage, please.
97 * The VID/PID is used to let e.g. udev lift the device to
98 * console userspace access when it's plugged in.
99 *
100 * @param devices a pointer to a pointer that will hold a device
101 * list after the call to this function, if it was
102 * successful.
103 * @param numdevs a pointer to an integer that will hold the number
104 * of devices in the device list if the call was successful.
105 * @return 0 if the list was successfull retrieved, any other
106 * value means failure.
107 */
108int LIBMTP_Get_Supported_Devices_List(LIBMTP_device_entry_t ** const devices, int * const numdevs)
Linus Walleij6fd2f082006-03-28 07:19:22 +0000109{
110 *devices = (LIBMTP_device_entry_t *) &mtp_device_table;
111 *numdevs = mtp_device_table_size;
112 return 0;
113}
114
Linus Walleij552ba322007-01-22 11:49:59 +0000115
Linus Walleij1fd2d272006-05-08 09:22:01 +0000116static struct usb_bus* init_usb()
117{
118 usb_init();
119 usb_find_busses();
120 usb_find_devices();
121 return (usb_get_busses());
122}
123
124/**
tedbullock0f033cb2007-02-14 20:56:54 +0000125 * Small recursive function to append a new usb_device to the linked list of
126 * USB MTP devices
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000127 * @param devlist dynamic linked list of pointers to usb devices with MTP
tedbullock0f033cb2007-02-14 20:56:54 +0000128 * properties.
129 * @param next New USB MTP device to be added to list
130 * @return nothing
131 */
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000132static mtpdevice_list_t *append_to_mtpdevice_list(mtpdevice_list_t *devlist,
133 struct usb_device *newdevice)
tedbullock0f033cb2007-02-14 20:56:54 +0000134{
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000135 mtpdevice_list_t *new_list_entry;
tedbullock0f033cb2007-02-14 20:56:54 +0000136
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000137 new_list_entry = (mtpdevice_list_t *) malloc(sizeof(mtpdevice_list_t));
138 if (new_list_entry == NULL) {
139 return NULL;
140 }
141 // Fill in USB device, if we *HAVE* to make a copy of the device do it here.
142 new_list_entry->libusb_device = newdevice;
143 new_list_entry->next = NULL;
144
145 if (devlist == NULL) {
146 return new_list_entry;
147 } else {
148 mtpdevice_list_t *tmp = devlist;
149 while (tmp->next != NULL) {
150 tmp = tmp->next;
151 }
152 tmp->next = new_list_entry;
153 }
154 return devlist;
tedbullock0f033cb2007-02-14 20:56:54 +0000155}
156
157/**
158 * Small recursive function to free dynamic memory allocated to the linked list
159 * of USB MTP devices
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000160 * @param devlist dynamic linked list of pointers to usb devices with MTP
tedbullock0f033cb2007-02-14 20:56:54 +0000161 * properties.
162 * @return nothing
163 */
Linus Walleij45a86372007-03-07 09:36:19 +0000164void free_mtpdevice_list(mtpdevice_list_t *devlist)
tedbullock0f033cb2007-02-14 20:56:54 +0000165{
Linus Walleijac061862007-03-07 08:28:33 +0000166 mtpdevice_list_t *tmplist = devlist;
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000167
168 if (devlist == NULL)
169 return;
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000170 while (tmplist != NULL) {
171 mtpdevice_list_t *tmp = tmplist;
172 tmplist = tmplist->next;
Richard Low61edc1a2007-09-23 10:35:48 +0000173 // Do not free() the fields (ptp_usb, params)! These are used elsewhere.
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000174 free(tmp);
tedbullock0f033cb2007-02-14 20:56:54 +0000175 }
tedbullock0f033cb2007-02-14 20:56:54 +0000176 return;
177}
178
179/**
Linus Walleij9521e2b2007-07-10 21:50:42 +0000180 * This checks if a device has an MTP descriptor. The descriptor was
181 * elaborated about in gPhoto bug 1482084, and some official documentation
182 * with no strings attached was published by Microsoft at
183 * http://www.microsoft.com/whdc/system/bus/USB/USBFAQ_intermed.mspx#E3HAC
184 *
Linus Walleija4942fc2007-03-12 19:23:21 +0000185 * @param dev a device struct from libusb.
Linus Walleij9521e2b2007-07-10 21:50:42 +0000186 * @param dumpfile set to non-NULL to make the descriptors dump out
187 * to this file in human-readable hex so we can scruitinze them.
Linus Walleija4942fc2007-03-12 19:23:21 +0000188 * @return 1 if the device is MTP compliant, 0 if not.
189 */
Linus Walleij9521e2b2007-07-10 21:50:42 +0000190static int probe_device_descriptor(struct usb_device *dev, FILE *dumpfile)
Linus Walleija4942fc2007-03-12 19:23:21 +0000191{
192 usb_dev_handle *devh;
193 unsigned char buf[1024], cmd;
Linus Walleijbc550bc2007-11-08 23:25:09 +0000194 int i;
Linus Walleija4942fc2007-03-12 19:23:21 +0000195 int ret;
196
197 /* Don't examine hubs (no point in that) */
198 if (dev->descriptor.bDeviceClass == USB_CLASS_HUB) {
199 return 0;
200 }
201
202 /* Attempt to open Device on this port */
203 devh = usb_open(dev);
204 if (devh == NULL) {
205 /* Could not open this device */
206 return 0;
207 }
Linus Walleijbc550bc2007-11-08 23:25:09 +0000208
209 /*
210 * Loop over the device configurations and interfaces. Nokia MTP-capable
211 * handsets (possibly others) typically have the string "MTP" in their
212 * MTP interface descriptions, that's how they can be detected, before
213 * we try the more esoteric "OS descriptors" (below).
214 */
215 for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
216 uint8_t j;
217
218 for (j = 0; j < dev->config[i].bNumInterfaces; j++) {
219 int k;
220 for (k = 0; k < dev->config[i].interface[j].num_altsetting; k++) {
221 buf[0] = '\0';
222 ret = usb_get_string_simple(devh,
223 dev->config[i].interface[j].altsetting[k].iInterface,
224 (char *) buf,
225 1024);
226 if (ret < 3)
227 continue;
228 if (strcmp((char *) buf, "MTP") == 0) {
229 if (dumpfile != NULL) {
230 fprintf(dumpfile, "Configuration %d, interface %d, altsetting %d:\n", i, j, k);
231 fprintf(dumpfile, " Interface description contains the string \"MTP\"\n");
232 fprintf(dumpfile, " Device recognized as MTP, no further probing.\n");
233 }
234 usb_close(devh);
235 return 1;
236 }
237 }
238 }
239 }
Linus Walleija4942fc2007-03-12 19:23:21 +0000240
241 /* Read the special descriptor */
242 ret = usb_get_descriptor(devh, 0x03, 0xee, buf, sizeof(buf));
Linus Walleij9521e2b2007-07-10 21:50:42 +0000243
244 // Dump it, if requested
245 if (dumpfile != NULL && ret > 0) {
246 fprintf(dumpfile, "Microsoft device descriptor 0xee:\n");
247 data_dump_ascii(dumpfile, buf, ret, 16);
248 }
Linus Walleija4942fc2007-03-12 19:23:21 +0000249
250 /* Check if descriptor length is at least 10 bytes */
251 if (ret < 10) {
252 usb_close(devh);
253 return 0;
254 }
255
256 /* Check if this device has a Microsoft Descriptor */
257 if (!((buf[2] == 'M') && (buf[4] == 'S') &&
258 (buf[6] == 'F') && (buf[8] == 'T'))) {
259 usb_close(devh);
260 return 0;
261 }
262
263 /* Check if device responds to control message 1 or if there is an error */
264 cmd = buf[16];
265 ret = usb_control_msg (devh,
266 USB_ENDPOINT_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR,
267 cmd,
268 0,
269 4,
270 (char *) buf,
271 sizeof(buf),
Linus Walleij913a3062007-09-28 21:42:39 +0000272 USB_TIMEOUT);
Linus Walleij9521e2b2007-07-10 21:50:42 +0000273
274 // Dump it, if requested
275 if (dumpfile != NULL && ret > 0) {
276 fprintf(dumpfile, "Microsoft device response to control message 1, CMD 0x%02x:\n", cmd);
277 data_dump_ascii(dumpfile, buf, ret, 16);
278 }
Linus Walleija4942fc2007-03-12 19:23:21 +0000279
280 /* If this is true, the device either isn't MTP or there was an error */
281 if (ret <= 0x15) {
282 /* TODO: If there was an error, flag it and let the user know somehow */
283 /* if(ret == -1) {} */
284 usb_close(devh);
285 return 0;
286 }
287
288 /* Check if device is MTP or if it is something like a USB Mass Storage
289 device with Janus DRM support */
290 if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) {
291 usb_close(devh);
292 return 0;
293 }
294
295 /* After this point we are probably dealing with an MTP device */
296
297 /* Check if device responds to control message 2 or if there is an error*/
298 ret = usb_control_msg (devh,
299 USB_ENDPOINT_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR,
300 cmd,
301 0,
302 5,
303 (char *) buf,
304 sizeof(buf),
Linus Walleij913a3062007-09-28 21:42:39 +0000305 USB_TIMEOUT);
Linus Walleij9521e2b2007-07-10 21:50:42 +0000306
307 // Dump it, if requested
308 if (dumpfile != NULL && ret > 0) {
309 fprintf(dumpfile, "Microsoft device response to control message 2, CMD 0x%02x:\n", cmd);
310 data_dump_ascii(dumpfile, buf, ret, 16);
311 }
Linus Walleija4942fc2007-03-12 19:23:21 +0000312
313 /* If this is true, the device errored against control message 2 */
314 if (ret == -1) {
315 /* TODO: Implement callback function to let managing program know there
316 was a problem, along with description of the problem */
317 fprintf(stderr, "Potential MTP Device with VendorID:%04x and "
318 "ProductID:%04x encountered an error responding to "
319 "control message 2.\n"
320 "Problems may arrise but continuing\n",
321 dev->descriptor.idVendor, dev->descriptor.idProduct);
322 } else if (ret <= 0x15) {
323 /* TODO: Implement callback function to let managing program know there
324 was a problem, along with description of the problem */
325 fprintf(stderr, "Potential MTP Device with VendorID:%04x and "
326 "ProductID:%04x responded to control message 2 with a "
327 "response that was too short. Problems may arrise but "
328 "continuing\n",
329 dev->descriptor.idVendor, dev->descriptor.idProduct);
330 } else if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) {
331 /* TODO: Implement callback function to let managing program know there
332 was a problem, along with description of the problem */
333 fprintf(stderr, "Potential MTP Device with VendorID:%04x and "
334 "ProductID:%04x encountered an error responding to "
335 "control message 2\n"
336 "Problems may arrise but continuing\n",
337 dev->descriptor.idVendor, dev->descriptor.idProduct);
338 }
339
340 /* Close the USB device handle */
341 usb_close(devh);
342 return 1;
343}
344
345/**
346 * This function scans through the connected usb devices on a machine and
347 * if they match known Vendor and Product identifiers appends them to the
348 * dynamic array mtp_device_list. Be sure to call
349 * <code>free(mtp_device_list)</code> when you are done with it, assuming it
350 * is not NULL.
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000351 * @param mtp_device_list dynamic array of pointers to usb devices with MTP
Linus Walleij45a86372007-03-07 09:36:19 +0000352 * properties (if this list is not empty, new entries will be appended
353 * to the list).
Linus Walleija4942fc2007-03-12 19:23:21 +0000354 * @return LIBMTP_ERROR_NONE implies that devices have been found, scan the list
Linus Walleij9c6c1542007-09-19 13:43:06 +0000355 * appropriately. LIBMTP_ERROR_NO_DEVICE_ATTACHED implies that no
356 * devices have been found.
Linus Walleij2e1c8a32007-01-22 06:46:08 +0000357 */
Linus Walleij45a86372007-03-07 09:36:19 +0000358static LIBMTP_error_number_t get_mtp_usb_device_list(mtpdevice_list_t ** mtp_device_list)
Linus Walleij2e1c8a32007-01-22 06:46:08 +0000359{
Linus Walleij2e1c8a32007-01-22 06:46:08 +0000360 struct usb_bus *bus = init_usb();
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000361 for (; bus != NULL; bus = bus->next) {
Linus Walleij2e1c8a32007-01-22 06:46:08 +0000362 struct usb_device *dev = bus->devices;
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000363 for (; dev != NULL; dev = dev->next) {
Richard Lowe9f205f2007-09-16 16:25:50 +0000364 if (dev->descriptor.bDeviceClass != USB_CLASS_HUB) {
Linus Walleij9c6c1542007-09-19 13:43:06 +0000365 int i;
366 int found = 0;
367
368 // First check if we know about the device already.
369 // Devices well known to us will not have their descriptors
370 // probed, it caused problems with some devices.
Richard Lowe9f205f2007-09-16 16:25:50 +0000371 for(i = 0; i < mtp_device_table_size; i++) {
372 if(dev->descriptor.idVendor == mtp_device_table[i].vendor_id &&
373 dev->descriptor.idProduct == mtp_device_table[i].product_id) {
374 /* Append this usb device to the MTP device list */
375 *mtp_device_list = append_to_mtpdevice_list(*mtp_device_list, dev);
376 found = 1;
377 break;
378 }
379 }
Linus Walleij9c6c1542007-09-19 13:43:06 +0000380 // If we didn't know it, try probing the "OS Descriptor".
Richard Lowe9f205f2007-09-16 16:25:50 +0000381 if (!found) {
Richard Lowe9f205f2007-09-16 16:25:50 +0000382 if (probe_device_descriptor(dev, NULL)) {
383 /* Append this usb device to the MTP USB Device List */
384 *mtp_device_list = append_to_mtpdevice_list(*mtp_device_list, dev);
385 }
386 }
Linus Walleij9c6c1542007-09-19 13:43:06 +0000387 }
Linus Walleij2e1c8a32007-01-22 06:46:08 +0000388 }
389 }
Linus Walleijf27d1cd2007-03-05 14:23:00 +0000390
Linus Walleij2e1c8a32007-01-22 06:46:08 +0000391 /* If nothing was found we end up here. */
Linus Walleija4942fc2007-03-12 19:23:21 +0000392 if(*mtp_device_list == NULL) {
tedbullock433d2172007-02-23 22:39:12 +0000393 return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
Linus Walleija4942fc2007-03-12 19:23:21 +0000394 }
395 return LIBMTP_ERROR_NONE;
Linus Walleij2e1c8a32007-01-22 06:46:08 +0000396}
397
398/**
Linus Walleij1fd2d272006-05-08 09:22:01 +0000399 * Detect the MTP device descriptor and return the VID and PID
400 * of the first device found. This is a very low-level function
401 * which is intended for use with <b>udev</b> or other hotplug
402 * mechanisms. The idea is that a script may want to know if the
403 * just plugged-in device was an MTP device or not.
tedbullock2b45f2e2007-02-23 20:16:37 +0000404 *
Linus Walleij1fd2d272006-05-08 09:22:01 +0000405 * @param vid the Vendor ID (VID) of the first device found.
406 * @param pid the Product ID (PID) of the first device found.
407 * @return the number of detected devices or -1 if the call
408 * was unsuccessful.
409 */
410int LIBMTP_Detect_Descriptor(uint16_t *vid, uint16_t *pid)
411{
Linus Walleijb6b69132007-03-07 09:45:05 +0000412 mtpdevice_list_t *devlist;
413 LIBMTP_error_number_t ret;
414
415 ret = get_mtp_usb_device_list(&devlist);
416 if (ret != LIBMTP_ERROR_NONE) {
417 *vid = *pid = 0;
418 return -1;
419 }
420 *vid = devlist->libusb_device->descriptor.idVendor;
421 *pid = devlist->libusb_device->descriptor.idProduct;
422 free_mtpdevice_list(devlist);
Linus Walleij1fd2d272006-05-08 09:22:01 +0000423 return 1;
424}
425
Linus Walleijc6210fb2006-05-08 11:11:41 +0000426/**
427 * This routine just dumps out low-level
428 * USB information about the current device.
429 * @param ptp_usb the USB device to get information from.
430 */
431void dump_usbinfo(PTP_USB *ptp_usb)
432{
433 int res;
434 struct usb_device *dev;
435
436#ifdef LIBUSB_HAS_GET_DRIVER_NP
437 char devname[0x10];
438
439 devname[0] = '\0';
Linus Walleijb0ab5482007-08-29 21:08:54 +0000440 res = usb_get_driver_np(ptp_usb->handle, (int) ptp_usb->interface, devname, sizeof(devname));
Linus Walleijc6210fb2006-05-08 11:11:41 +0000441 if (devname[0] != '\0') {
442 printf(" Using kernel interface \"%s\"\n", devname);
443 }
444#endif
445 dev = usb_device(ptp_usb->handle);
446 printf(" bcdUSB: %d\n", dev->descriptor.bcdUSB);
447 printf(" bDeviceClass: %d\n", dev->descriptor.bDeviceClass);
448 printf(" bDeviceSubClass: %d\n", dev->descriptor.bDeviceSubClass);
449 printf(" bDeviceProtocol: %d\n", dev->descriptor.bDeviceProtocol);
Linus Walleijc6210fb2006-05-08 11:11:41 +0000450 printf(" idVendor: %04x\n", dev->descriptor.idVendor);
451 printf(" idProduct: %04x\n", dev->descriptor.idProduct);
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000452 printf(" IN endpoint maxpacket: %d bytes\n", ptp_usb->inep_maxpacket);
453 printf(" OUT endpoint maxpacket: %d bytes\n", ptp_usb->outep_maxpacket);
Linus Walleij0558ac52006-09-07 06:55:03 +0000454 printf(" Device flags: 0x%08x\n", ptp_usb->device_flags);
Linus Walleijc6210fb2006-05-08 11:11:41 +0000455 // TODO: add in string dumps for iManufacturer, iProduct, iSerialnumber...
Linus Walleij9521e2b2007-07-10 21:50:42 +0000456 (void) probe_device_descriptor(dev, stdout);
Linus Walleijc6210fb2006-05-08 11:11:41 +0000457}
458
Linus Walleija0323272007-01-07 12:21:30 +0000459static void
460ptp_debug (PTPParams *params, const char *format, ...)
461{
462 va_list args;
463
464 va_start (args, format);
465 if (params->debug_func!=NULL)
466 params->debug_func (params->data, format, args);
467 else
468 {
469 vfprintf (stderr, format, args);
470 fprintf (stderr,"\n");
471 fflush (stderr);
472 }
473 va_end (args);
474}
475
476static void
477ptp_error (PTPParams *params, const char *format, ...)
478{
479 va_list args;
480
481 va_start (args, format);
482 if (params->error_func!=NULL)
483 params->error_func (params->data, format, args);
484 else
485 {
486 vfprintf (stderr, format, args);
487 fprintf (stderr,"\n");
488 fflush (stderr);
489 }
490 va_end (args);
491}
492
Linus Walleijc6210fb2006-05-08 11:11:41 +0000493
Linus Walleij99ed83c2007-01-02 18:46:02 +0000494/*
495 * ptp_read_func() and ptp_write_func() are
Linus Walleijc0a11432007-03-02 21:21:18 +0000496 * based on same functions usb.c in libgphoto2.
Linus Walleij99ed83c2007-01-02 18:46:02 +0000497 * Much reading packet logs and having fun with trials and errors
498 * reveals that WMP / Windows is probably using an algorithm like this
499 * for large transfers:
500 *
501 * 1. Send the command (0x0c bytes) if headers are split, else, send
502 * command plus sizeof(endpoint) - 0x0c bytes.
503 * 2. Send first packet, max size to be sizeof(endpoint) but only when using
504 * split headers. Else goto 3.
505 * 3. REPEAT send 0x10000 byte chunks UNTIL remaining bytes < 0x10000
506 * We call 0x10000 CONTEXT_BLOCK_SIZE.
507 * 4. Send remaining bytes MOD sizeof(endpoint)
508 * 5. Send remaining bytes. If this happens to be exactly sizeof(endpoint)
509 * then also send a zero-length package.
Linus Walleij049f50c2007-03-03 20:30:43 +0000510 *
511 * Further there is some special quirks to handle zero reads from the
512 * device, since some devices can't do them at all due to shortcomings
513 * of the USB slave controller in the device.
Linus Walleij99ed83c2007-01-02 18:46:02 +0000514 */
Richard Low4fd59d62007-03-03 16:34:37 +0000515#define CONTEXT_BLOCK_SIZE_1 0x3e00
516#define CONTEXT_BLOCK_SIZE_2 0x200
517#define CONTEXT_BLOCK_SIZE CONTEXT_BLOCK_SIZE_1+CONTEXT_BLOCK_SIZE_2
Linus Walleijb02a0662006-04-25 08:05:09 +0000518static short
Linus Walleij784ac3f2006-12-29 10:36:51 +0000519ptp_read_func (
520 unsigned long size, PTPDataHandler *handler,void *data,
Richard Low4df32f82007-01-11 20:04:39 +0000521 unsigned long *readbytes,
522 int readzero
Linus Walleij784ac3f2006-12-29 10:36:51 +0000523) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000524 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000525 unsigned long toread = 0;
Linus Walleijd6a49972006-05-02 08:24:54 +0000526 int result = 0;
Linus Walleij99ed83c2007-01-02 18:46:02 +0000527 unsigned long curread = 0;
528 unsigned long written;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000529 unsigned char *bytes;
Linus Walleij049f50c2007-03-03 20:30:43 +0000530 int expect_terminator_byte = 0;
Linus Walleij99ed83c2007-01-02 18:46:02 +0000531
532 // This is the largest block we'll need to read in.
Linus Walleij784ac3f2006-12-29 10:36:51 +0000533 bytes = malloc(CONTEXT_BLOCK_SIZE);
Linus Walleijd6a49972006-05-02 08:24:54 +0000534 while (curread < size) {
Richard Low4fd59d62007-03-03 16:34:37 +0000535
536#ifdef ENABLE_USB_BULK_DEBUG
537 printf("Remaining size to read: 0x%04x bytes\n", size - curread);
538#endif
539 // check equal to condition here
540 if (size - curread < CONTEXT_BLOCK_SIZE)
541 {
542 // this is the last packet
543 toread = size - curread;
544 // this is equivalent to zero read for these devices
Linus Walleij049f50c2007-03-03 20:30:43 +0000545 if (readzero && ptp_usb->device_flags & DEVICE_FLAG_NO_ZERO_READS && toread % 64 == 0) {
Richard Low4fd59d62007-03-03 16:34:37 +0000546 toread += 1;
Linus Walleij049f50c2007-03-03 20:30:43 +0000547 expect_terminator_byte = 1;
Richard Low4fd59d62007-03-03 16:34:37 +0000548 }
Linus Walleijc49c6372007-01-09 00:18:51 +0000549 }
Richard Low4fd59d62007-03-03 16:34:37 +0000550 else if (curread == 0)
551 // we are first packet, but not last packet
552 toread = CONTEXT_BLOCK_SIZE_1;
553 else if (toread == CONTEXT_BLOCK_SIZE_1)
554 toread = CONTEXT_BLOCK_SIZE_2;
555 else if (toread == CONTEXT_BLOCK_SIZE_2)
556 toread = CONTEXT_BLOCK_SIZE_1;
557 else
Linus Walleij4cec9872007-03-03 21:00:53 +0000558 printf("unexpected toread size 0x%04x, 0x%04x remaining bytes\n",
559 (unsigned int) toread, (unsigned int) (size-curread));
Linus Walleij784ac3f2006-12-29 10:36:51 +0000560
Richard Lowd284f072007-02-17 08:52:41 +0000561#ifdef ENABLE_USB_BULK_DEBUG
562 printf("Reading in 0x%04x bytes\n", toread);
563#endif
Linus Walleij913a3062007-09-28 21:42:39 +0000564 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, (char*)bytes, toread, USB_TIMEOUT);
Richard Lowd284f072007-02-17 08:52:41 +0000565#ifdef ENABLE_USB_BULK_DEBUG
566 printf("Result of read: 0x%04x\n", result);
567#endif
Richard Low4fd59d62007-03-03 16:34:37 +0000568
Linus Walleijc49c6372007-01-09 00:18:51 +0000569 if (result < 0) {
Richard Low43fdb882006-09-06 16:19:05 +0000570 return PTP_ERROR_IO;
Linus Walleijc49c6372007-01-09 00:18:51 +0000571 }
Linus Walleije78de6d2006-10-31 14:46:36 +0000572#ifdef ENABLE_USB_BULK_DEBUG
573 printf("<==USB IN\n");
Richard Low4df32f82007-01-11 20:04:39 +0000574 if (result == 0)
575 printf("Zero Read\n");
576 else
577 data_dump_ascii (stdout,bytes,result,16);
Linus Walleije78de6d2006-10-31 14:46:36 +0000578#endif
Richard Low4fd59d62007-03-03 16:34:37 +0000579
580 // want to discard extra byte
Linus Walleij049f50c2007-03-03 20:30:43 +0000581 if (expect_terminator_byte && result == toread)
Richard Lowbf2675c2007-03-18 18:20:26 +0000582 {
583#ifdef ENABLE_USB_BULK_DEBUG
584 printf("<==USB IN\nDiscarding extra byte\n");
585#endif
Richard Low4fd59d62007-03-03 16:34:37 +0000586 result--;
Richard Lowbf2675c2007-03-18 18:20:26 +0000587 }
Richard Low4fd59d62007-03-03 16:34:37 +0000588
Linus Walleijc49c6372007-01-09 00:18:51 +0000589 handler->putfunc(NULL, handler->private, result, bytes, &written);
Richard Lowbf2675c2007-03-18 18:20:26 +0000590
Linus Walleijc49c6372007-01-09 00:18:51 +0000591 ptp_usb->current_transfer_complete += result;
Linus Walleijd6a49972006-05-02 08:24:54 +0000592 curread += result;
Linus Walleijc49c6372007-01-09 00:18:51 +0000593
594 // Increase counters, call callback
595 if (ptp_usb->callback_active) {
596 if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) {
597 // send last update and disable callback.
598 ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total;
599 ptp_usb->callback_active = 0;
600 }
601 if (ptp_usb->current_transfer_callback != NULL) {
Linus Walleijbd3bf9e2007-09-14 19:31:54 +0000602 int ret;
603 ret = ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete,
604 ptp_usb->current_transfer_total,
605 ptp_usb->current_transfer_callback_data);
606 if (ret != 0) {
607 return PTP_ERROR_CANCEL;
608 }
Linus Walleijc49c6372007-01-09 00:18:51 +0000609 }
610 }
611
Linus Walleijd6a49972006-05-02 08:24:54 +0000612 if (result < toread) /* short reads are common */
613 break;
614 }
Linus Walleij784ac3f2006-12-29 10:36:51 +0000615 if (readbytes) *readbytes = curread;
616 free (bytes);
Linus Walleijee73ef22006-08-27 19:56:00 +0000617
Richard Low4df32f82007-01-11 20:04:39 +0000618 // there might be a zero packet waiting for us...
Linus Walleij049f50c2007-03-03 20:30:43 +0000619 if (readzero &&
620 !(ptp_usb->device_flags & DEVICE_FLAG_NO_ZERO_READS) &&
621 curread % ptp_usb->outep_maxpacket == 0) {
Richard Low4df32f82007-01-11 20:04:39 +0000622 char temp;
623 int zeroresult = 0;
Linus Walleij049f50c2007-03-03 20:30:43 +0000624
Richard Low4df32f82007-01-11 20:04:39 +0000625#ifdef ENABLE_USB_BULK_DEBUG
626 printf("<==USB IN\n");
627 printf("Zero Read\n");
628#endif
Linus Walleij913a3062007-09-28 21:42:39 +0000629 zeroresult = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, &temp, 0, USB_TIMEOUT);
Richard Low4df32f82007-01-11 20:04:39 +0000630 if (zeroresult != 0)
631 printf("LIBMTP panic: unable to read in zero packet, response 0x%04x", zeroresult);
632 }
633
Linus Walleijd6a49972006-05-02 08:24:54 +0000634 if (result > 0) {
Linus Walleijd6a49972006-05-02 08:24:54 +0000635 return (PTP_RC_OK);
636 } else {
637 return PTP_ERROR_IO;
638 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000639}
640
Linus Walleijb02a0662006-04-25 08:05:09 +0000641static short
Linus Walleij784ac3f2006-12-29 10:36:51 +0000642ptp_write_func (
643 unsigned long size,
644 PTPDataHandler *handler,
645 void *data,
646 unsigned long *written
647) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000648 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000649 unsigned long towrite = 0;
Linus Walleijd6a49972006-05-02 08:24:54 +0000650 int result = 0;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000651 unsigned long curwrite = 0;
652 unsigned char *bytes;
Linus Walleij99ed83c2007-01-02 18:46:02 +0000653
654 // This is the largest block we'll need to read in.
Linus Walleij784ac3f2006-12-29 10:36:51 +0000655 bytes = malloc(CONTEXT_BLOCK_SIZE);
Linus Walleijc49c6372007-01-09 00:18:51 +0000656 if (!bytes) {
657 return PTP_ERROR_IO;
658 }
Linus Walleijd6a49972006-05-02 08:24:54 +0000659 while (curwrite < size) {
660 towrite = size-curwrite;
Linus Walleijc49c6372007-01-09 00:18:51 +0000661 if (towrite > CONTEXT_BLOCK_SIZE) {
Richard Low43fdb882006-09-06 16:19:05 +0000662 towrite = CONTEXT_BLOCK_SIZE;
Linus Walleijc49c6372007-01-09 00:18:51 +0000663 } else {
664 // This magic makes packets the same size that WMP send them.
665 if (towrite > ptp_usb->outep_maxpacket && towrite % ptp_usb->outep_maxpacket != 0) {
Richard Low021421e2007-01-01 18:08:57 +0000666 towrite -= towrite % ptp_usb->outep_maxpacket;
Linus Walleijc49c6372007-01-09 00:18:51 +0000667 }
668 }
669 handler->getfunc(NULL, handler->private,towrite,bytes,&towrite);
Linus Walleij913a3062007-09-28 21:42:39 +0000670 result = USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char*)bytes,towrite,USB_TIMEOUT);
Linus Walleije78de6d2006-10-31 14:46:36 +0000671#ifdef ENABLE_USB_BULK_DEBUG
672 printf("USB OUT==>\n");
Richard Lowedd61832006-12-30 12:38:18 +0000673 data_dump_ascii (stdout,bytes,towrite,16);
Linus Walleije78de6d2006-10-31 14:46:36 +0000674#endif
Linus Walleijc49c6372007-01-09 00:18:51 +0000675 if (result < 0) {
Richard Low43fdb882006-09-06 16:19:05 +0000676 return PTP_ERROR_IO;
Linus Walleijc49c6372007-01-09 00:18:51 +0000677 }
678 // Increase counters
679 ptp_usb->current_transfer_complete += result;
Linus Walleijd6a49972006-05-02 08:24:54 +0000680 curwrite += result;
Linus Walleijc49c6372007-01-09 00:18:51 +0000681
682 // call callback
683 if (ptp_usb->callback_active) {
684 if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) {
685 // send last update and disable callback.
686 ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total;
687 ptp_usb->callback_active = 0;
688 }
689 if (ptp_usb->current_transfer_callback != NULL) {
Linus Walleijbd3bf9e2007-09-14 19:31:54 +0000690 int ret;
691 ret = ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete,
692 ptp_usb->current_transfer_total,
693 ptp_usb->current_transfer_callback_data);
694 if (ret != 0) {
695 return PTP_ERROR_CANCEL;
696 }
Linus Walleijc49c6372007-01-09 00:18:51 +0000697 }
698 }
Linus Walleijd6a49972006-05-02 08:24:54 +0000699 if (result < towrite) /* short writes happen */
700 break;
701 }
Linus Walleij784ac3f2006-12-29 10:36:51 +0000702 free (bytes);
Linus Walleijc49c6372007-01-09 00:18:51 +0000703 if (written) {
704 *written = curwrite;
Linus Walleij80d134a2006-08-22 21:41:37 +0000705 }
Linus Walleijd214b9b2006-08-26 22:08:37 +0000706
Linus Walleijc49c6372007-01-09 00:18:51 +0000707
Richard Lowef05b892007-01-03 21:18:56 +0000708 // If this is the last transfer send a zero write if required
709 if (ptp_usb->current_transfer_complete >= ptp_usb->current_transfer_total) {
Richard Low68f45882007-01-03 10:08:31 +0000710 if ((towrite % ptp_usb->outep_maxpacket) == 0) {
Richard Low021421e2007-01-01 18:08:57 +0000711#ifdef ENABLE_USB_BULK_DEBUG
712 printf("USB OUT==>\n");
713 printf("Zero Write\n");
714#endif
Linus Walleij913a3062007-09-28 21:42:39 +0000715 result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)"x",0,USB_TIMEOUT);
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000716 }
Linus Walleijd214b9b2006-08-26 22:08:37 +0000717 }
Linus Walleijc49c6372007-01-09 00:18:51 +0000718
Linus Walleijd6a49972006-05-02 08:24:54 +0000719 if (result < 0)
720 return PTP_ERROR_IO;
721 return PTP_RC_OK;
Linus Walleijb02a0662006-04-25 08:05:09 +0000722}
723
Linus Walleija0323272007-01-07 12:21:30 +0000724/* memory data get/put handler */
725typedef struct {
726 unsigned char *data;
727 unsigned long size, curoff;
728} PTPMemHandlerPrivate;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000729
Linus Walleija0323272007-01-07 12:21:30 +0000730static uint16_t
731memory_getfunc(PTPParams* params, void* private,
732 unsigned long wantlen, unsigned char *data,
733 unsigned long *gotlen
734) {
735 PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)private;
736 unsigned long tocopy = wantlen;
737
738 if (priv->curoff + tocopy > priv->size)
739 tocopy = priv->size - priv->curoff;
740 memcpy (data, priv->data + priv->curoff, tocopy);
741 priv->curoff += tocopy;
742 *gotlen = tocopy;
743 return PTP_RC_OK;
Linus Walleijb02a0662006-04-25 08:05:09 +0000744}
745
Linus Walleija0323272007-01-07 12:21:30 +0000746static uint16_t
747memory_putfunc(PTPParams* params, void* private,
748 unsigned long sendlen, unsigned char *data,
749 unsigned long *putlen
750) {
751 PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)private;
752
753 if (priv->curoff + sendlen > priv->size) {
754 priv->data = realloc (priv->data, priv->curoff+sendlen);
755 priv->size = priv->curoff + sendlen;
756 }
757 memcpy (priv->data + priv->curoff, data, sendlen);
758 priv->curoff += sendlen;
759 *putlen = sendlen;
760 return PTP_RC_OK;
761}
762
763/* init private struct for receiving data. */
764static uint16_t
765ptp_init_recv_memory_handler(PTPDataHandler *handler) {
766 PTPMemHandlerPrivate* priv;
767 priv = malloc (sizeof(PTPMemHandlerPrivate));
768 handler->private = priv;
769 handler->getfunc = memory_getfunc;
770 handler->putfunc = memory_putfunc;
771 priv->data = NULL;
772 priv->size = 0;
773 priv->curoff = 0;
774 return PTP_RC_OK;
775}
776
777/* init private struct and put data in for sending data.
778 * data is still owned by caller.
779 */
780static uint16_t
781ptp_init_send_memory_handler(PTPDataHandler *handler,
782 unsigned char *data, unsigned long len
783) {
784 PTPMemHandlerPrivate* priv;
785 priv = malloc (sizeof(PTPMemHandlerPrivate));
786 if (!priv)
787 return PTP_RC_GeneralError;
788 handler->private = priv;
789 handler->getfunc = memory_getfunc;
790 handler->putfunc = memory_putfunc;
791 priv->data = data;
792 priv->size = len;
793 priv->curoff = 0;
794 return PTP_RC_OK;
795}
796
797/* free private struct + data */
798static uint16_t
799ptp_exit_send_memory_handler (PTPDataHandler *handler) {
800 PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)handler->private;
801 /* data is owned by caller */
802 free (priv);
803 return PTP_RC_OK;
804}
805
806/* hand over our internal data to caller */
807static uint16_t
808ptp_exit_recv_memory_handler (PTPDataHandler *handler,
809 unsigned char **data, unsigned long *size
810) {
811 PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)handler->private;
812 *data = priv->data;
813 *size = priv->size;
814 free (priv);
815 return PTP_RC_OK;
816}
817
818/* send / receive functions */
819
820uint16_t
821ptp_usb_sendreq (PTPParams* params, PTPContainer* req)
822{
823 uint16_t ret;
824 PTPUSBBulkContainer usbreq;
825 PTPDataHandler memhandler;
826 unsigned long written, towrite;
827
828 /* build appropriate USB container */
829 usbreq.length=htod32(PTP_USB_BULK_REQ_LEN-
830 (sizeof(uint32_t)*(5-req->Nparam)));
831 usbreq.type=htod16(PTP_USB_CONTAINER_COMMAND);
832 usbreq.code=htod16(req->Code);
833 usbreq.trans_id=htod32(req->Transaction_ID);
834 usbreq.payload.params.param1=htod32(req->Param1);
835 usbreq.payload.params.param2=htod32(req->Param2);
836 usbreq.payload.params.param3=htod32(req->Param3);
837 usbreq.payload.params.param4=htod32(req->Param4);
838 usbreq.payload.params.param5=htod32(req->Param5);
839 /* send it to responder */
840 towrite = PTP_USB_BULK_REQ_LEN-(sizeof(uint32_t)*(5-req->Nparam));
841 ptp_init_send_memory_handler (&memhandler, (unsigned char*)&usbreq, towrite);
842 ret=ptp_write_func(
843 towrite,
844 &memhandler,
845 params->data,
846 &written
847 );
848 ptp_exit_send_memory_handler (&memhandler);
Linus Walleijff01cb12007-09-16 19:49:48 +0000849 if (ret!=PTP_RC_OK && ret!=PTP_ERROR_CANCEL) {
Linus Walleija0323272007-01-07 12:21:30 +0000850 ret = PTP_ERROR_IO;
Linus Walleija0323272007-01-07 12:21:30 +0000851 }
Linus Walleij724f0102007-09-17 20:10:12 +0000852 if (written != towrite && ret != PTP_ERROR_CANCEL && ret != PTP_ERROR_IO) {
Linus Walleija0323272007-01-07 12:21:30 +0000853 ptp_error (params,
854 "PTP: request code 0x%04x sending req wrote only %ld bytes instead of %d",
Richard Lowd284f072007-02-17 08:52:41 +0000855 req->Code, written, towrite
Linus Walleija0323272007-01-07 12:21:30 +0000856 );
857 ret = PTP_ERROR_IO;
858 }
859 return ret;
860}
861
862uint16_t
863ptp_usb_senddata (PTPParams* params, PTPContainer* ptp,
864 unsigned long size, PTPDataHandler *handler
865) {
866 uint16_t ret;
867 int wlen, datawlen;
868 unsigned long written;
869 PTPUSBBulkContainer usbdata;
870 uint32_t bytes_left_to_transfer;
871 PTPDataHandler memhandler;
872
873 /* build appropriate USB container */
874 usbdata.length = htod32(PTP_USB_BULK_HDR_LEN+size);
875 usbdata.type = htod16(PTP_USB_CONTAINER_DATA);
876 usbdata.code = htod16(ptp->Code);
877 usbdata.trans_id= htod32(ptp->Transaction_ID);
878
879 ((PTP_USB*)params->data)->current_transfer_complete = 0;
Richard Low4eb01122007-02-24 10:11:32 +0000880 ((PTP_USB*)params->data)->current_transfer_total = size+PTP_USB_BULK_HDR_LEN;
Linus Walleija0323272007-01-07 12:21:30 +0000881
882 if (params->split_header_data) {
883 datawlen = 0;
884 wlen = PTP_USB_BULK_HDR_LEN;
885 } else {
886 unsigned long gotlen;
887 /* For all camera devices. */
Richard Low02724f62007-02-17 09:47:26 +0000888 datawlen = (size<PTP_USB_BULK_PAYLOAD_LEN_WRITE)?size:PTP_USB_BULK_PAYLOAD_LEN_WRITE;
Linus Walleija0323272007-01-07 12:21:30 +0000889 wlen = PTP_USB_BULK_HDR_LEN + datawlen;
890 ret = handler->getfunc(params, handler->private, datawlen, usbdata.payload.data, &gotlen);
891 if (ret != PTP_RC_OK)
892 return ret;
893 if (gotlen != datawlen)
894 return PTP_RC_GeneralError;
895 }
896 ptp_init_send_memory_handler (&memhandler, (unsigned char *)&usbdata, wlen);
897 /* send first part of data */
898 ret = ptp_write_func(wlen, &memhandler, params->data, &written);
899 ptp_exit_send_memory_handler (&memhandler);
900 if (ret!=PTP_RC_OK) {
Linus Walleija0323272007-01-07 12:21:30 +0000901 return ret;
902 }
903 if (size <= datawlen) return ret;
904 /* if everything OK send the rest */
905 bytes_left_to_transfer = size-datawlen;
906 ret = PTP_RC_OK;
907 while(bytes_left_to_transfer > 0) {
908 ret = ptp_write_func (bytes_left_to_transfer, handler, params->data, &written);
909 if (ret != PTP_RC_OK)
910 break;
911 if (written == 0) {
912 ret = PTP_ERROR_IO;
913 break;
914 }
915 bytes_left_to_transfer -= written;
916 }
Linus Walleijff01cb12007-09-16 19:49:48 +0000917 if (ret!=PTP_RC_OK && ret!=PTP_ERROR_CANCEL)
Linus Walleija0323272007-01-07 12:21:30 +0000918 ret = PTP_ERROR_IO;
919 return ret;
920}
921
922static uint16_t ptp_usb_getpacket(PTPParams *params,
923 PTPUSBBulkContainer *packet, unsigned long *rlen)
924{
925 PTPDataHandler memhandler;
926 uint16_t ret;
927 unsigned char *x = NULL;
928
929 /* read the header and potentially the first data */
930 if (params->response_packet_size > 0) {
931 /* If there is a buffered packet, just use it. */
932 memcpy(packet, params->response_packet, params->response_packet_size);
933 *rlen = params->response_packet_size;
934 free(params->response_packet);
935 params->response_packet = NULL;
936 params->response_packet_size = 0;
937 /* Here this signifies a "virtual read" */
938 return PTP_RC_OK;
939 }
940 ptp_init_recv_memory_handler (&memhandler);
Richard Low02724f62007-02-17 09:47:26 +0000941 ret = ptp_read_func(PTP_USB_BULK_HS_MAX_PACKET_LEN_READ, &memhandler, params->data, rlen, 0);
Linus Walleija0323272007-01-07 12:21:30 +0000942 ptp_exit_recv_memory_handler (&memhandler, &x, rlen);
943 if (x) {
944 memcpy (packet, x, *rlen);
945 free (x);
946 }
947 return ret;
948}
949
950uint16_t
951ptp_usb_getdata (PTPParams* params, PTPContainer* ptp, PTPDataHandler *handler)
952{
953 uint16_t ret;
954 PTPUSBBulkContainer usbdata;
Linus Walleija0323272007-01-07 12:21:30 +0000955 unsigned long written;
Linus Walleij8e3af002007-09-28 19:21:54 +0000956 PTP_USB *ptp_usb = (PTP_USB *) params->data;
Linus Walleija0323272007-01-07 12:21:30 +0000957
958 memset(&usbdata,0,sizeof(usbdata));
959 do {
960 unsigned long len, rlen;
961
962 ret = ptp_usb_getpacket(params, &usbdata, &rlen);
963 if (ret!=PTP_RC_OK) {
964 ret = PTP_ERROR_IO;
965 break;
Linus Walleij8e3af002007-09-28 19:21:54 +0000966 }
Linus Walleija0323272007-01-07 12:21:30 +0000967 if (dtoh16(usbdata.type)!=PTP_USB_CONTAINER_DATA) {
968 ret = PTP_ERROR_DATA_EXPECTED;
969 break;
Linus Walleij8e3af002007-09-28 19:21:54 +0000970 }
Linus Walleija0323272007-01-07 12:21:30 +0000971 if (dtoh16(usbdata.code)!=ptp->Code) {
Linus Walleij8e3af002007-09-28 19:21:54 +0000972 if (ptp_usb->device_flags & DEVICE_FLAG_IGNORE_HEADER_ERRORS) {
973 ptp_debug (params, "ptp2/ptp_usb_getdata: detected a broken "
Linus Walleij913a3062007-09-28 21:42:39 +0000974 "PTP header, code field insane, expect problems! (But continuing)");
Linus Walleij06542122007-10-14 22:13:48 +0000975 // Repair the header, so it won't wreak more havoc, don't just ignore it.
976 // Typically these two fields will be broken.
977 usbdata.code = htod16(ptp->Code);
978 usbdata.trans_id = htod32(ptp->Transaction_ID);
Linus Walleij94cd9722007-09-28 21:29:53 +0000979 ret = PTP_RC_OK;
Linus Walleij8e3af002007-09-28 19:21:54 +0000980 } else {
Linus Walleij913a3062007-09-28 21:42:39 +0000981 ret = dtoh16(usbdata.code);
982 // This filters entirely insane garbage return codes, but still
983 // makes it possible to return error codes in the code field when
984 // getting data. It appears Windows ignores the contents of this
985 // field entirely.
986 if (ret < PTP_RC_Undefined || ret > PTP_RC_SpecificationOfDestinationUnsupported) {
987 ptp_debug (params, "ptp2/ptp_usb_getdata: detected a broken "
988 "PTP header, code field insane.");
989 ret = PTP_ERROR_IO;
990 }
Linus Walleij8e3af002007-09-28 19:21:54 +0000991 break;
992 }
Linus Walleija0323272007-01-07 12:21:30 +0000993 }
994 if (usbdata.length == 0xffffffffU) {
995 /* stuff data directly to passed data handler */
996 while (1) {
997 unsigned long readdata;
998 int xret;
999
1000 xret = ptp_read_func(
Richard Low02724f62007-02-17 09:47:26 +00001001 PTP_USB_BULK_HS_MAX_PACKET_LEN_READ,
Linus Walleija0323272007-01-07 12:21:30 +00001002 handler,
1003 params->data,
Richard Low4df32f82007-01-11 20:04:39 +00001004 &readdata,
Linus Walleijc0a11432007-03-02 21:21:18 +00001005 0
Linus Walleija0323272007-01-07 12:21:30 +00001006 );
Linus Walleijff01cb12007-09-16 19:49:48 +00001007 if (xret != PTP_RC_OK)
1008 return ret;
Richard Low02724f62007-02-17 09:47:26 +00001009 if (readdata < PTP_USB_BULK_HS_MAX_PACKET_LEN_READ)
Linus Walleija0323272007-01-07 12:21:30 +00001010 break;
1011 }
1012 return PTP_RC_OK;
1013 }
1014 if (rlen > dtoh32(usbdata.length)) {
1015 /*
1016 * Buffer the surplus response packet if it is >=
1017 * PTP_USB_BULK_HDR_LEN
1018 * (i.e. it is probably an entire package)
1019 * else discard it as erroneous surplus data.
1020 * This will even work if more than 2 packets appear
1021 * in the same transaction, they will just be handled
1022 * iteratively.
1023 *
1024 * Marcus observed stray bytes on iRiver devices;
1025 * these are still discarded.
1026 */
1027 unsigned int packlen = dtoh32(usbdata.length);
1028 unsigned int surplen = rlen - packlen;
1029
1030 if (surplen >= PTP_USB_BULK_HDR_LEN) {
1031 params->response_packet = malloc(surplen);
1032 memcpy(params->response_packet,
1033 (uint8_t *) &usbdata + packlen, surplen);
1034 params->response_packet_size = surplen;
tedbullock36f2afb2007-03-03 22:16:44 +00001035 /* Ignore reading one extra byte if device flags have been set */
Linus Walleij8e3af002007-09-28 19:21:54 +00001036 } else if(( !(ptp_usb->device_flags & DEVICE_FLAG_NO_ZERO_READS) &&
1037 rlen - dtoh32(usbdata.length) == 1)) {
1038 ptp_debug (params, "ptp2/ptp_usb_getdata: read %d bytes "
1039 "too much, expect problems!",
1040 rlen - dtoh32(usbdata.length));
Linus Walleija0323272007-01-07 12:21:30 +00001041 }
1042 rlen = packlen;
1043 }
1044
1045 /* For most PTP devices rlen is 512 == sizeof(usbdata)
1046 * here. For MTP devices splitting header and data it might
1047 * be 12.
1048 */
1049 /* Evaluate full data length. */
1050 len=dtoh32(usbdata.length)-PTP_USB_BULK_HDR_LEN;
1051
1052 /* autodetect split header/data MTP devices */
1053 if (dtoh32(usbdata.length) > 12 && (rlen==12))
1054 params->split_header_data = 1;
1055
Linus Walleija0323272007-01-07 12:21:30 +00001056 /* Copy first part of data to 'data' */
1057 handler->putfunc(
1058 params, handler->private, rlen - PTP_USB_BULK_HDR_LEN, usbdata.payload.data,
1059 &written
1060 );
Richard Low4fd59d62007-03-03 16:34:37 +00001061
Linus Walleij8e3af002007-09-28 19:21:54 +00001062 if (ptp_usb->device_flags & DEVICE_FLAG_NO_ZERO_READS &&
Linus Walleij049f50c2007-03-03 20:30:43 +00001063 len+PTP_USB_BULK_HDR_LEN == PTP_USB_BULK_HS_MAX_PACKET_LEN_READ) {
Richard Low057ea772007-03-24 13:37:38 +00001064#ifdef ENABLE_USB_BULK_DEBUG
Linus Walleij049f50c2007-03-03 20:30:43 +00001065 printf("Reading in extra terminating byte\n");
Richard Low4fd59d62007-03-03 16:34:37 +00001066#endif
Linus Walleij049f50c2007-03-03 20:30:43 +00001067 // need to read in extra byte and discard it
1068 int result = 0;
1069 char byte = 0;
Linus Walleij913a3062007-09-28 21:42:39 +00001070 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, &byte, 1, USB_TIMEOUT);
Linus Walleij049f50c2007-03-03 20:30:43 +00001071
1072 if (result != 1)
1073 printf("Could not read in extra byte for PTP_USB_BULK_HS_MAX_PACKET_LEN_READ long file, return value 0x%04x\n", result);
Richard Low057ea772007-03-24 13:37:38 +00001074 } else if (len+PTP_USB_BULK_HDR_LEN == PTP_USB_BULK_HS_MAX_PACKET_LEN_READ && params->split_header_data == 0) {
Linus Walleij94cd9722007-09-28 21:29:53 +00001075 int zeroresult = 0;
1076 char zerobyte = 0;
1077
Richard Low057ea772007-03-24 13:37:38 +00001078#ifdef ENABLE_USB_BULK_DEBUG
Linus Walleij94cd9722007-09-28 21:29:53 +00001079 printf("Reading in zero packet after header\n");
Richard Low057ea772007-03-24 13:37:38 +00001080#endif
Linus Walleij913a3062007-09-28 21:42:39 +00001081 zeroresult = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, &zerobyte, 0, USB_TIMEOUT);
Linus Walleij94cd9722007-09-28 21:29:53 +00001082
1083 if (zeroresult != 0)
1084 printf("LIBMTP panic: unable to read in zero packet, response 0x%04x", zeroresult);
1085 }
1086
Linus Walleija0323272007-01-07 12:21:30 +00001087 /* Is that all of data? */
Linus Walleij94cd9722007-09-28 21:29:53 +00001088 if (len+PTP_USB_BULK_HDR_LEN<=rlen) {
1089 break;
1090 }
Linus Walleij049f50c2007-03-03 20:30:43 +00001091
Linus Walleij913a3062007-09-28 21:42:39 +00001092 ret = ptp_read_func(len - (rlen - PTP_USB_BULK_HDR_LEN),
1093 handler,
1094 params->data, &rlen, 1);
Linus Walleij049f50c2007-03-03 20:30:43 +00001095
Linus Walleija0323272007-01-07 12:21:30 +00001096 if (ret!=PTP_RC_OK) {
Linus Walleij049f50c2007-03-03 20:30:43 +00001097 break;
Linus Walleija0323272007-01-07 12:21:30 +00001098 }
1099 } while (0);
Linus Walleija0323272007-01-07 12:21:30 +00001100 return ret;
1101}
1102
1103uint16_t
1104ptp_usb_getresp (PTPParams* params, PTPContainer* resp)
1105{
1106 uint16_t ret;
1107 unsigned long rlen;
1108 PTPUSBBulkContainer usbresp;
Linus Walleij3e4b1142007-11-01 23:54:16 +00001109 PTP_USB *ptp_usb = (PTP_USB *)(params->data);
Linus Walleija0323272007-01-07 12:21:30 +00001110
1111 memset(&usbresp,0,sizeof(usbresp));
1112 /* read response, it should never be longer than sizeof(usbresp) */
1113 ret = ptp_usb_getpacket(params, &usbresp, &rlen);
1114
Linus Walleij00411ee2008-01-27 12:24:51 +00001115 while (ret==PTP_RC_OK && rlen<=2) {
1116 ptp_debug (params, "ptp_usb_getresp: detected a response less or "
1117 "equal to two bytes, expect problems! (re-reading "
1118 "response)");
1119 ret = ptp_usb_getpacket(params, &usbresp, &rlen);
1120 }
1121
Linus Walleija0323272007-01-07 12:21:30 +00001122 if (ret!=PTP_RC_OK) {
1123 ret = PTP_ERROR_IO;
1124 } else
1125 if (dtoh16(usbresp.type)!=PTP_USB_CONTAINER_RESPONSE) {
1126 ret = PTP_ERROR_RESP_EXPECTED;
1127 } else
1128 if (dtoh16(usbresp.code)!=resp->Code) {
1129 ret = dtoh16(usbresp.code);
1130 }
1131 if (ret!=PTP_RC_OK) {
1132/* ptp_error (params,
1133 "PTP: request code 0x%04x getting resp error 0x%04x",
1134 resp->Code, ret);*/
1135 return ret;
1136 }
1137 /* build an appropriate PTPContainer */
1138 resp->Code=dtoh16(usbresp.code);
1139 resp->SessionID=params->session_id;
1140 resp->Transaction_ID=dtoh32(usbresp.trans_id);
Linus Walleij3e4b1142007-11-01 23:54:16 +00001141 if (ptp_usb->device_flags & DEVICE_FLAG_IGNORE_HEADER_ERRORS) {
1142 if (resp->Transaction_ID != params->transaction_id-1) {
1143 ptp_debug (params, "ptp_usb_getresp: detected a broken "
Linus Walleij00411ee2008-01-27 12:24:51 +00001144 "PTP header, transaction ID insane, expect "
1145 "problems! (But continuing)");
Linus Walleij3e4b1142007-11-01 23:54:16 +00001146 // Repair the header, so it won't wreak more havoc.
1147 resp->Transaction_ID = params->transaction_id-1;
1148 }
1149 }
Linus Walleija0323272007-01-07 12:21:30 +00001150 resp->Param1=dtoh32(usbresp.payload.params.param1);
1151 resp->Param2=dtoh32(usbresp.payload.params.param2);
1152 resp->Param3=dtoh32(usbresp.payload.params.param3);
1153 resp->Param4=dtoh32(usbresp.payload.params.param4);
1154 resp->Param5=dtoh32(usbresp.payload.params.param5);
1155 return ret;
1156}
1157
1158/* Event handling functions */
1159
1160/* PTP Events wait for or check mode */
1161#define PTP_EVENT_CHECK 0x0000 /* waits for */
1162#define PTP_EVENT_CHECK_FAST 0x0001 /* checks */
1163
1164static inline uint16_t
1165ptp_usb_event (PTPParams* params, PTPContainer* event, int wait)
1166{
1167 uint16_t ret;
1168 int result;
1169 unsigned long rlen;
1170 PTPUSBEventContainer usbevent;
1171 PTP_USB *ptp_usb = (PTP_USB *)(params->data);
1172
1173 memset(&usbevent,0,sizeof(usbevent));
1174
1175 if ((params==NULL) || (event==NULL))
1176 return PTP_ERROR_BADPARAM;
1177 ret = PTP_RC_OK;
1178 switch(wait) {
1179 case PTP_EVENT_CHECK:
Linus Walleij913a3062007-09-28 21:42:39 +00001180 result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)&usbevent,sizeof(usbevent),USB_TIMEOUT);
Linus Walleija0323272007-01-07 12:21:30 +00001181 if (result==0)
Linus Walleij913a3062007-09-28 21:42:39 +00001182 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *) &usbevent, sizeof(usbevent), USB_TIMEOUT);
Linus Walleija0323272007-01-07 12:21:30 +00001183 if (result < 0) ret = PTP_ERROR_IO;
1184 break;
1185 case PTP_EVENT_CHECK_FAST:
Linus Walleij913a3062007-09-28 21:42:39 +00001186 result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)&usbevent,sizeof(usbevent),USB_TIMEOUT);
Linus Walleija0323272007-01-07 12:21:30 +00001187 if (result==0)
Linus Walleij913a3062007-09-28 21:42:39 +00001188 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *) &usbevent, sizeof(usbevent), USB_TIMEOUT);
Linus Walleija0323272007-01-07 12:21:30 +00001189 if (result < 0) ret = PTP_ERROR_IO;
1190 break;
1191 default:
1192 ret=PTP_ERROR_BADPARAM;
1193 break;
1194 }
1195 if (ret!=PTP_RC_OK) {
1196 ptp_error (params,
1197 "PTP: reading event an error 0x%04x occurred", ret);
1198 return PTP_ERROR_IO;
1199 }
1200 rlen = result;
1201 if (rlen < 8) {
1202 ptp_error (params,
1203 "PTP: reading event an short read of %ld bytes occurred", rlen);
1204 return PTP_ERROR_IO;
1205 }
1206 /* if we read anything over interrupt endpoint it must be an event */
1207 /* build an appropriate PTPContainer */
1208 event->Code=dtoh16(usbevent.code);
1209 event->SessionID=params->session_id;
1210 event->Transaction_ID=dtoh32(usbevent.trans_id);
1211 event->Param1=dtoh32(usbevent.param1);
1212 event->Param2=dtoh32(usbevent.param2);
1213 event->Param3=dtoh32(usbevent.param3);
1214 return ret;
1215}
1216
1217uint16_t
1218ptp_usb_event_check (PTPParams* params, PTPContainer* event) {
1219
1220 return ptp_usb_event (params, event, PTP_EVENT_CHECK_FAST);
1221}
1222
1223uint16_t
1224ptp_usb_event_wait (PTPParams* params, PTPContainer* event) {
1225
1226 return ptp_usb_event (params, event, PTP_EVENT_CHECK);
1227}
1228
Linus Walleijbd3bf9e2007-09-14 19:31:54 +00001229uint16_t
1230ptp_usb_control_cancel_request (PTPParams *params, uint32_t transactionid) {
1231 PTP_USB *ptp_usb = (PTP_USB *)(params->data);
1232 int ret;
1233 unsigned char buffer[6];
1234
1235 htod16a(&buffer[0],PTP_EC_CancelTransaction);
1236 htod32a(&buffer[2],transactionid);
1237 ret = usb_control_msg(ptp_usb->handle,
1238 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
Linus Walleij913a3062007-09-28 21:42:39 +00001239 0x64, 0x0000, 0x0000, (char *) buffer, sizeof(buffer), USB_TIMEOUT);
Linus Walleijbd3bf9e2007-09-14 19:31:54 +00001240 if (ret < sizeof(buffer))
1241 return PTP_ERROR_IO;
1242 return PTP_RC_OK;
1243}
Linus Walleija0323272007-01-07 12:21:30 +00001244
Linus Walleij9eb3d312006-08-04 19:25:59 +00001245static int init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001246{
Linus Walleijd6a49972006-05-02 08:24:54 +00001247 usb_dev_handle *device_handle;
1248
Linus Walleijd6a49972006-05-02 08:24:54 +00001249 params->error_func=NULL;
1250 params->debug_func=NULL;
1251 params->sendreq_func=ptp_usb_sendreq;
1252 params->senddata_func=ptp_usb_senddata;
1253 params->getresp_func=ptp_usb_getresp;
1254 params->getdata_func=ptp_usb_getdata;
Linus Walleijff01cb12007-09-16 19:49:48 +00001255 params->cancelreq_func=ptp_usb_control_cancel_request;
Linus Walleijd6a49972006-05-02 08:24:54 +00001256 params->data=ptp_usb;
1257 params->transaction_id=0;
Linus Walleij462a5e72007-02-13 06:54:56 +00001258 /*
1259 * This is hardcoded here since we have no devices whatsoever that are BE.
1260 * Change this the day we run into our first BE device (if ever).
1261 */
Linus Walleijd6a49972006-05-02 08:24:54 +00001262 params->byteorder = PTP_DL_LE;
1263
Linus Walleij0ed2a9f2006-05-04 05:31:34 +00001264 if ((device_handle = usb_open(dev))){
Linus Walleijd6a49972006-05-02 08:24:54 +00001265 if (!device_handle) {
1266 perror("usb_open()");
Linus Walleij9eb3d312006-08-04 19:25:59 +00001267 return -1;
Linus Walleijd6a49972006-05-02 08:24:54 +00001268 }
Linus Walleij0ed2a9f2006-05-04 05:31:34 +00001269 ptp_usb->handle = device_handle;
Linus Walleij501ba4d2006-10-16 06:17:04 +00001270#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
1271 /*
1272 * If this device is known to be wrongfully claimed by other kernel
1273 * drivers (such as mass storage), then try to unload it to make it
1274 * accessible from user space.
1275 */
1276 if (ptp_usb->device_flags & DEVICE_FLAG_UNLOAD_DRIVER) {
Linus Walleijb0ab5482007-08-29 21:08:54 +00001277 if (usb_detach_kernel_driver_np(device_handle, (int) ptp_usb->interface)) {
Linus Walleij7beba572006-11-29 08:56:12 +00001278 // Totally ignore this error!
1279 // perror("usb_detach_kernel_driver_np()");
Linus Walleij501ba4d2006-10-16 06:17:04 +00001280 }
1281 }
1282#endif
Linus Walleijeac1e002006-11-30 22:06:02 +00001283#ifdef __WIN32__
Linus Walleij99ed83c2007-01-02 18:46:02 +00001284 // Only needed on Windows, and cause problems on other platforms.
Linus Walleij7beba572006-11-29 08:56:12 +00001285 if (usb_set_configuration(device_handle, dev->config->bConfigurationValue)) {
1286 perror("usb_set_configuration()");
1287 return -1;
1288 }
Linus Walleijeac1e002006-11-30 22:06:02 +00001289#endif
Linus Walleijb0ab5482007-08-29 21:08:54 +00001290 if (usb_claim_interface(device_handle, (int) ptp_usb->interface)) {
Linus Walleij0ed2a9f2006-05-04 05:31:34 +00001291 perror("usb_claim_interface()");
Linus Walleij9eb3d312006-08-04 19:25:59 +00001292 return -1;
Linus Walleij0ed2a9f2006-05-04 05:31:34 +00001293 }
Linus Walleijd6a49972006-05-02 08:24:54 +00001294 }
Linus Walleij9eb3d312006-08-04 19:25:59 +00001295 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001296}
1297
Linus Walleijd6a49972006-05-02 08:24:54 +00001298static void clear_stall(PTP_USB* ptp_usb)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001299{
Linus Walleij58b62792007-01-07 12:38:59 +00001300 uint16_t status;
Linus Walleijd6a49972006-05-02 08:24:54 +00001301 int ret;
1302
1303 /* check the inep status */
Linus Walleij58b62792007-01-07 12:38:59 +00001304 status = 0;
Linus Walleij1fd2d272006-05-08 09:22:01 +00001305 ret = usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status);
Linus Walleij58b62792007-01-07 12:38:59 +00001306 if (ret<0) {
1307 perror ("inep: usb_get_endpoint_status()");
1308 } else if (status) {
1309 printf("Clearing stall on IN endpoint\n");
1310 ret = usb_clear_stall_feature(ptp_usb,ptp_usb->inep);
1311 if (ret<0) {
1312 perror ("usb_clear_stall_feature()");
1313 }
Linus Walleijd6a49972006-05-02 08:24:54 +00001314 }
Linus Walleijd6a49972006-05-02 08:24:54 +00001315
1316 /* check the outep status */
Linus Walleij58b62792007-01-07 12:38:59 +00001317 status=0;
1318 ret = usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status);
1319 if (ret<0) {
1320 perror("outep: usb_get_endpoint_status()");
1321 } else if (status) {
1322 printf("Clearing stall on OUT endpoint\n");
1323 ret = usb_clear_stall_feature(ptp_usb,ptp_usb->outep);
1324 if (ret<0) {
1325 perror("usb_clear_stall_feature()");
1326 }
Linus Walleijd6a49972006-05-02 08:24:54 +00001327 }
Linus Walleij58b62792007-01-07 12:38:59 +00001328
1329 /* TODO: do we need this for INTERRUPT (ptp_usb->intep) too? */
1330}
1331
1332static void clear_halt(PTP_USB* ptp_usb)
1333{
1334 int ret;
1335
1336 ret = usb_clear_halt(ptp_usb->handle,ptp_usb->inep);
1337 if (ret<0) {
1338 perror("usb_clear_halt() on IN endpoint");
1339 }
1340 ret = usb_clear_halt(ptp_usb->handle,ptp_usb->outep);
1341 if (ret<0) {
1342 perror("usb_clear_halt() on OUT endpoint");
1343 }
1344 ret = usb_clear_halt(ptp_usb->handle,ptp_usb->intep);
1345 if (ret<0) {
1346 perror("usb_clear_halt() on INTERRUPT endpoint");
1347 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001348}
1349
Linus Walleijb0ab5482007-08-29 21:08:54 +00001350static void close_usb(PTP_USB* ptp_usb)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001351{
Linus Walleijda17cda2007-09-18 21:12:05 +00001352 // Commented out since it was confusing some
1353 // devices to do these things.
Linus Walleij29f03ba2007-09-25 19:22:12 +00001354 if (!(ptp_usb->device_flags & DEVICE_FLAG_NO_RELEASE_INTERFACE)) {
1355 // Clear any stalled endpoints
1356 clear_stall(ptp_usb);
1357 // Clear halts on any endpoints
1358 clear_halt(ptp_usb);
1359 // Added to clear some stuff on the OUT endpoint
1360 // TODO: is this good on the Mac too?
1361 // HINT: some devices may need that you comment these two out too.
1362 usb_resetep(ptp_usb->handle, ptp_usb->outep);
1363 usb_release_interface(ptp_usb->handle, (int) ptp_usb->interface);
1364 }
Linus Walleijd6a49972006-05-02 08:24:54 +00001365 // Brutally reset device
1366 // TODO: is this good on the Mac too?
1367 usb_reset(ptp_usb->handle);
1368 usb_close(ptp_usb->handle);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001369}
1370
Linus Walleij45a86372007-03-07 09:36:19 +00001371static LIBMTP_error_number_t prime_device_memory(mtpdevice_list_t *devlist)
tedbullock0f033cb2007-02-14 20:56:54 +00001372{
Linus Walleij45a86372007-03-07 09:36:19 +00001373 mtpdevice_list_t *tmplist = devlist;
Linus Walleijbfcb7922007-03-06 20:14:04 +00001374
Linus Walleij45a86372007-03-07 09:36:19 +00001375 while (tmplist != NULL) {
tedbullock0f033cb2007-02-14 20:56:54 +00001376 /* Allocate a parameter box */
Linus Walleij45a86372007-03-07 09:36:19 +00001377 tmplist->params = (PTPParams *) malloc(sizeof(PTPParams));
1378 tmplist->ptp_usb = (PTP_USB *) malloc(sizeof(PTP_USB));
Linus Walleijbfcb7922007-03-06 20:14:04 +00001379
tedbullock0f033cb2007-02-14 20:56:54 +00001380 /* Check for allocation Error */
Linus Walleij45a86372007-03-07 09:36:19 +00001381 if(tmplist->params == NULL || tmplist->ptp_usb == NULL) {
Linus Walleijbfcb7922007-03-06 20:14:04 +00001382 /* Error and deallocation of memory will be handled by caller. */
tedbullock0f033cb2007-02-14 20:56:54 +00001383 return LIBMTP_ERROR_MEMORY_ALLOCATION;
1384 }
1385
tedbullock69a445b2007-02-15 07:41:04 +00001386 /* Start with a blank slate (includes setting device_flags to 0) */
Linus Walleij45a86372007-03-07 09:36:19 +00001387 memset(tmplist->params, 0, sizeof(PTPParams));
1388 memset(tmplist->ptp_usb, 0, sizeof(PTP_USB));
1389 tmplist = tmplist->next;
tedbullock0f033cb2007-02-14 20:56:54 +00001390 }
tedbullock0f033cb2007-02-14 20:56:54 +00001391 return LIBMTP_ERROR_NONE;
1392}
1393
Linus Walleij45a86372007-03-07 09:36:19 +00001394static void assign_known_device_flags(mtpdevice_list_t *devlist)
tedbullock0f033cb2007-02-14 20:56:54 +00001395{
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001396 int i;
Linus Walleij27c50c52007-03-06 20:34:48 +00001397 mtpdevice_list_t *tmplist = devlist;
1398 uint8_t current_device = 0;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001399
tedbullock0f033cb2007-02-14 20:56:54 +00001400 /* Search through known device list and set correct device flags */
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001401 while (tmplist != NULL) {
1402 int device_known = 0;
1403
1404 for(i = 0; i < mtp_device_table_size; i++) {
1405 if(tmplist->libusb_device->descriptor.idVendor == mtp_device_table[i].vendor_id &&
1406 tmplist->libusb_device->descriptor.idProduct == mtp_device_table[i].product_id) {
1407 /* This device is known, assign the correct device flags */
1408 /* Note that ptp_usb[current_device] could potentially be NULL */
Linus Walleij45a86372007-03-07 09:36:19 +00001409 if(tmplist->ptp_usb != NULL) {
1410 tmplist->ptp_usb->device_flags = mtp_device_table[i].device_flags;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001411
1412 /*
1413 * TODO:
1414 * Preferable to not do this with #ifdef ENABLE_USB_BULK_DEBUG but there is
1415 * currently no other compile time debug option
1416 */
1417
1418 device_known = 1;
tedbullock65a05772007-03-03 22:56:56 +00001419#ifdef ENABLE_USB_BULK_DEBUG
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001420 /* This device is known to the developers */
Richard Low6b6d36b2007-10-18 19:32:00 +00001421 fprintf(stderr, "Device %d (VID=%04x and PID=%04x) is a %s %s.\n",
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001422 current_device + 1,
1423 tmplist->libusb_device->descriptor.idVendor,
1424 tmplist->libusb_device->descriptor.idProduct,
Richard Low6b6d36b2007-10-18 19:32:00 +00001425 mtp_device_table[i].vendor, mtp_device_table[i].product);
tedbullock65a05772007-03-03 22:56:56 +00001426#endif
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001427 }
1428 break;
1429 }
tedbullock0f033cb2007-02-14 20:56:54 +00001430 }
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001431 if (!device_known) {
1432 /* This device is unknown to the developers */
1433 fprintf(stderr, "Device %d (VID=%04x and PID=%04x) is UNKNOWN.\n",
1434 current_device + 1,
1435 tmplist->libusb_device->descriptor.idVendor,
1436 tmplist->libusb_device->descriptor.idProduct);
1437 fprintf(stderr, "Please report this VID/PID and the device model to the "
1438 "libmtp development team\n");
1439 }
1440 tmplist = tmplist->next;
Linus Walleijbfcb7922007-03-06 20:14:04 +00001441 current_device++;
tedbullock0f033cb2007-02-14 20:56:54 +00001442 }
tedbullock0f033cb2007-02-14 20:56:54 +00001443}
1444
tedbullock0f033cb2007-02-14 20:56:54 +00001445
Linus Walleij45a86372007-03-07 09:36:19 +00001446static LIBMTP_error_number_t configure_usb_devices(mtpdevice_list_t *devicelist)
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001447{
1448 mtpdevice_list_t *tmplist = devicelist;
1449 uint16_t ret = 0;
1450 uint8_t current_device = 0;
1451
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001452 while (tmplist != NULL) {
Linus Walleij45a86372007-03-07 09:36:19 +00001453 /* This is erroneous, there must be a PTP_USB instance that we can initialize. */
1454 if(tmplist->ptp_usb == NULL) {
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001455 return LIBMTP_ERROR_MEMORY_ALLOCATION;
tedbullock0f033cb2007-02-14 20:56:54 +00001456 }
1457
Linus Walleij3e418e22007-09-15 20:30:14 +00001458 /* Pointer back to params */
1459 tmplist->ptp_usb->params = tmplist->params;
1460
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001461 /* TODO: Will this always be little endian? */
Linus Walleij45a86372007-03-07 09:36:19 +00001462 tmplist->params->byteorder = PTP_DL_LE;
1463 tmplist->params->cd_locale_to_ucs2 = iconv_open("UCS-2LE", "UTF-8");
1464 tmplist->params->cd_ucs2_to_locale = iconv_open("UTF-8", "UCS-2LE");
tedbullock0f033cb2007-02-14 20:56:54 +00001465
Linus Walleij45a86372007-03-07 09:36:19 +00001466 if(tmplist->params->cd_locale_to_ucs2 == (iconv_t) -1 ||
1467 tmplist->params->cd_ucs2_to_locale == (iconv_t) -1) {
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001468 fprintf(stderr, "LIBMTP PANIC: Cannot open iconv() converters to/from UCS-2!\n"
1469 "Too old stdlibc, glibc and libiconv?\n");
Linus Walleij35c0ef12007-03-06 20:49:09 +00001470 return LIBMTP_ERROR_CONNECTING;
tedbullock0f033cb2007-02-14 20:56:54 +00001471 }
1472
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001473 // ep = device->config->interface->altsetting->endpoint;
1474 // no_of_ep = device->config->interface->altsetting->bNumEndpoints;
tedbullock0f033cb2007-02-14 20:56:54 +00001475
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001476 /* Assign endpoints to usbinfo... */
Linus Walleijb0ab5482007-08-29 21:08:54 +00001477 find_interface_and_endpoints(tmplist->libusb_device,
1478 &tmplist->ptp_usb->interface,
Linus Walleij45a86372007-03-07 09:36:19 +00001479 &tmplist->ptp_usb->inep,
1480 &tmplist->ptp_usb->inep_maxpacket,
1481 &tmplist->ptp_usb->outep,
1482 &tmplist->ptp_usb->outep_maxpacket,
1483 &tmplist->ptp_usb->intep);
tedbullock0f033cb2007-02-14 20:56:54 +00001484
Linus Walleij45a86372007-03-07 09:36:19 +00001485 /* Attempt to initialize this device */
1486 if (init_ptp_usb(tmplist->params, tmplist->ptp_usb, tmplist->libusb_device) < 0) {
1487 fprintf(stderr, "LIBMTP PANIC: Unable to initialize device %d\n", current_device+1);
1488 // FIXME: perhaps use "continue" to keep trying the other devices.
Linus Walleij35c0ef12007-03-06 20:49:09 +00001489 return LIBMTP_ERROR_CONNECTING;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001490 }
1491
1492 /*
1493 * This works in situations where previous bad applications
1494 * have not used LIBMTP_Release_Device on exit
1495 */
Linus Walleij45a86372007-03-07 09:36:19 +00001496 if ((ret = ptp_opensession(tmplist->params, 1)) == PTP_ERROR_IO) {
Linus Walleijf1cfc5e2007-08-29 11:14:36 +00001497 fprintf(stderr, "PTP_ERROR_IO: Trying again after re-initializing USB interface\n");
Linus Walleijb0ab5482007-08-29 21:08:54 +00001498 close_usb(tmplist->ptp_usb);
tedbullock0f033cb2007-02-14 20:56:54 +00001499
Linus Walleij45a86372007-03-07 09:36:19 +00001500 if(init_ptp_usb(tmplist->params, tmplist->ptp_usb, tmplist->libusb_device) <0) {
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001501 fprintf(stderr, "LIBMTP PANIC: Could not open session on device %d\n", current_device+1);
Linus Walleij35c0ef12007-03-06 20:49:09 +00001502 return LIBMTP_ERROR_CONNECTING;
tedbullock0f033cb2007-02-14 20:56:54 +00001503 }
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001504
1505 /* Device has been reset, try again */
Linus Walleij45a86372007-03-07 09:36:19 +00001506 ret = ptp_opensession(tmplist->params, 1);
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001507 }
1508
1509 /* Was the transaction id invalid? Try again */
1510 if (ret == PTP_RC_InvalidTransactionID) {
Linus Walleij45a86372007-03-07 09:36:19 +00001511 fprintf(stderr, "LIBMTP WARNING: Transaction ID was invalid, increment and try again\n");
1512 tmplist->params->transaction_id += 10;
1513 ret = ptp_opensession(tmplist->params, 1);
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001514 }
1515
1516 if (ret != PTP_RC_SessionAlreadyOpened && ret != PTP_RC_OK) {
Linus Walleij45a86372007-03-07 09:36:19 +00001517 fprintf(stderr, "LIBMTP PANIC: Could not open session! "
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001518 "(Return code %d)\n Try to reset the device.\n",
1519 ret);
Linus Walleij45a86372007-03-07 09:36:19 +00001520 usb_release_interface(tmplist->ptp_usb->handle,
Linus Walleijb0ab5482007-08-29 21:08:54 +00001521 (int) tmplist->ptp_usb->interface);
tedbullock0f033cb2007-02-14 20:56:54 +00001522 return LIBMTP_ERROR_CONNECTING;
1523 }
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001524
1525 tmplist = tmplist->next;
1526 current_device++;
tedbullock0f033cb2007-02-14 20:56:54 +00001527 }
1528
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001529 /* Exit with the nice list */
1530 return LIBMTP_ERROR_NONE;
tedbullock0f033cb2007-02-14 20:56:54 +00001531}
1532
Linus Walleij550d6d52007-01-24 14:32:51 +00001533/**
1534 * This function scans through the results of the get_mtp_usb_device_list
1535 * function and attempts to connect to those devices listed using the
1536 * mtp_device_table at the top of the file. Returns a LIBMTP_error_number_t.
1537 *
Linus Walleij45a86372007-03-07 09:36:19 +00001538 * @param devlist a list of devices with primed PTP_USB and params structs.
Linus Walleij550d6d52007-01-24 14:32:51 +00001539 * @return Error Codes as per the type definition
1540 */
Linus Walleij45a86372007-03-07 09:36:19 +00001541LIBMTP_error_number_t find_usb_devices(mtpdevice_list_t **devlist)
Linus Walleij550d6d52007-01-24 14:32:51 +00001542{
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001543 mtpdevice_list_t *mtp_device_list = NULL;
tedbullock0f033cb2007-02-14 20:56:54 +00001544 LIBMTP_error_number_t ret;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001545
Linus Walleija4942fc2007-03-12 19:23:21 +00001546 /*
1547 * Recover list of attached USB devices that match MTP criteria, i.e.
1548 * it either has an MTP device descriptor or it is in the known
1549 * devices list.
1550 */
Linus Walleij45a86372007-03-07 09:36:19 +00001551 ret = get_mtp_usb_device_list (&mtp_device_list);
Linus Walleijac061862007-03-07 08:28:33 +00001552 if (ret != LIBMTP_ERROR_NONE) {
1553 return ret;
Linus Walleij550d6d52007-01-24 14:32:51 +00001554 }
1555
Linus Walleij45a86372007-03-07 09:36:19 +00001556 // Then prime them
1557 ret = prime_device_memory(mtp_device_list);
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001558 if(ret) {
Linus Walleijac061862007-03-07 08:28:33 +00001559 fprintf(stderr, "LIBMTP PANIC: prime_device_memory() error code: %d on line %d\n", ret, __LINE__);
Linus Walleij45a86372007-03-07 09:36:19 +00001560 goto find_usb_devices_error_exit;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001561 }
tedbullock0f033cb2007-02-14 20:56:54 +00001562
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001563 /* Assign specific device flags and detect unknown devices */
Linus Walleij45a86372007-03-07 09:36:19 +00001564 assign_known_device_flags(mtp_device_list);
Linus Walleij550d6d52007-01-24 14:32:51 +00001565
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001566 /* Configure the devices */
Linus Walleij45a86372007-03-07 09:36:19 +00001567 ret = configure_usb_devices(mtp_device_list);
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001568 if(ret) {
Linus Walleijac061862007-03-07 08:28:33 +00001569 fprintf(stderr, "LIBMTP PANIC: configure_usb_devices() error code: %d on line %d\n", ret, __LINE__);
Linus Walleij45a86372007-03-07 09:36:19 +00001570 goto find_usb_devices_error_exit;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001571 }
Linus Walleij550d6d52007-01-24 14:32:51 +00001572
Linus Walleij45a86372007-03-07 09:36:19 +00001573 /* we're connected to all devices, return the list and OK */
1574 *devlist = mtp_device_list;
1575 return LIBMTP_ERROR_NONE;
1576
1577 find_usb_devices_error_exit:
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001578 if(mtp_device_list != NULL) {
1579 free_mtpdevice_list(mtp_device_list);
1580 mtp_device_list = NULL;
Linus Walleij550d6d52007-01-24 14:32:51 +00001581 }
Linus Walleij45a86372007-03-07 09:36:19 +00001582 *devlist = NULL;
tedbullock0f033cb2007-02-14 20:56:54 +00001583 return ret;
Linus Walleij550d6d52007-01-24 14:32:51 +00001584}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001585
Linus Walleijb0ab5482007-08-29 21:08:54 +00001586static void find_interface_and_endpoints(struct usb_device *dev,
1587 uint8_t *interface,
1588 int* inep,
1589 int* inep_maxpacket,
1590 int* outep,
1591 int *outep_maxpacket,
1592 int* intep)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001593{
Linus Walleijd7373cd2007-08-28 21:42:05 +00001594 int i;
1595
1596 // Loop over the device configurations
1597 for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
Linus Walleijb0ab5482007-08-29 21:08:54 +00001598 uint8_t j;
Linus Walleijd7373cd2007-08-28 21:42:05 +00001599
1600 for (j = 0; j < dev->config[i].bNumInterfaces; j++) {
Linus Walleijb0ab5482007-08-29 21:08:54 +00001601 uint8_t k;
1602 uint8_t no_ep;
Linus Walleijd7373cd2007-08-28 21:42:05 +00001603 struct usb_endpoint_descriptor *ep;
Linus Walleijd7373cd2007-08-28 21:42:05 +00001604
Linus Walleijb0ab5482007-08-29 21:08:54 +00001605 if (dev->descriptor.bNumConfigurations > 1 || dev->config[i].bNumInterfaces > 1) {
1606 // OK This device has more than one interface, so we have to find out
1607 // which one to use!
1608 // FIXME: Probe the interface.
1609 // FIXME: Release modules attached to all other interfaces in Linux...?
1610 }
1611
1612 *interface = dev->config[i].interface[j].altsetting->bInterfaceNumber;
1613 ep = dev->config[i].interface[j].altsetting->endpoint;
1614 no_ep = dev->config[i].interface[j].altsetting->bNumEndpoints;
1615
1616 for (k = 0; k < no_ep; k++) {
Linus Walleijd7373cd2007-08-28 21:42:05 +00001617 if (ep[k].bmAttributes==USB_ENDPOINT_TYPE_BULK) {
1618 if ((ep[k].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
1619 USB_ENDPOINT_DIR_MASK)
1620 {
1621 *inep=ep[k].bEndpointAddress;
1622 *inep_maxpacket=ep[k].wMaxPacketSize;
1623 }
1624 if ((ep[k].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==0)
1625 {
1626 *outep=ep[k].bEndpointAddress;
1627 *outep_maxpacket=ep[k].wMaxPacketSize;
1628 }
1629 } else if (ep[k].bmAttributes==USB_ENDPOINT_TYPE_INTERRUPT){
1630 if ((ep[k].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
1631 USB_ENDPOINT_DIR_MASK)
1632 {
1633 *intep=ep[k].bEndpointAddress;
1634 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001635 }
Linus Walleijd7373cd2007-08-28 21:42:05 +00001636 }
1637 // We assigned the endpoints so return here.
1638 return;
Linus Walleijd6a49972006-05-02 08:24:54 +00001639 }
1640 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001641}
1642
Linus Walleijb0ab5482007-08-29 21:08:54 +00001643void close_device (PTP_USB *ptp_usb, PTPParams *params)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001644{
Linus Walleijd6a49972006-05-02 08:24:54 +00001645 if (ptp_closesession(params)!=PTP_RC_OK)
1646 fprintf(stderr,"ERROR: Could not close session!\n");
Linus Walleijb0ab5482007-08-29 21:08:54 +00001647 close_usb(ptp_usb);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001648}
1649
Linus Walleijd6a49972006-05-02 08:24:54 +00001650static int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001651{
Linus Walleijd6a49972006-05-02 08:24:54 +00001652
1653 return (usb_control_msg(ptp_usb->handle,
1654 USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, USB_FEATURE_HALT,
Linus Walleij913a3062007-09-28 21:42:39 +00001655 ep, NULL, 0, USB_TIMEOUT));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001656}
1657
Linus Walleijd6a49972006-05-02 08:24:54 +00001658static int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001659{
Linus Walleijd6a49972006-05-02 08:24:54 +00001660 return (usb_control_msg(ptp_usb->handle,
1661 USB_DP_DTH|USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS,
Linus Walleij913a3062007-09-28 21:42:39 +00001662 USB_FEATURE_HALT, ep, (char *)status, 2, USB_TIMEOUT));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001663}