blob: 2d38b6fa12c136496fb0f8ce997f680a78f1efc9 [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 Walleij3191bba2008-02-10 21:16:25 +00001115 while (ret==PTP_RC_OK && rlen<PTP_USB_BULK_HDR_LEN && usbresp.length==0) {
1116 ptp_debug (params, "ptp_usb_getresp: detected short response "
1117 "of %d bytes, expect problems! (re-reading "
1118 "response), rlen");
Linus Walleij00411ee2008-01-27 12:24:51 +00001119 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)) {
Linus Walleijeabc2312008-02-13 00:02:00 +00001355 /*
1356 * Clear any stalled endpoints
1357 * On misbehaving devices designed for Windows/Mac, quote from:
1358 * http://www2.one-eyed-alien.net/~mdharm/linux-usb/target_offenses.txt
1359 * Device does Bad Things(tm) when it gets a GET_STATUS after CLEAR_HALT
1360 * (...) Windows, when clearing a stall, only sends the CLEAR_HALT command,
1361 * and presumes that the stall has cleared. Some devices actually choke
1362 * if the CLEAR_HALT is followed by a GET_STATUS (used to determine if the
1363 * STALL is persistant or not).
1364 */
Linus Walleij29f03ba2007-09-25 19:22:12 +00001365 clear_stall(ptp_usb);
1366 // Clear halts on any endpoints
1367 clear_halt(ptp_usb);
1368 // Added to clear some stuff on the OUT endpoint
1369 // TODO: is this good on the Mac too?
1370 // HINT: some devices may need that you comment these two out too.
1371 usb_resetep(ptp_usb->handle, ptp_usb->outep);
1372 usb_release_interface(ptp_usb->handle, (int) ptp_usb->interface);
1373 }
Linus Walleijd6a49972006-05-02 08:24:54 +00001374 // Brutally reset device
1375 // TODO: is this good on the Mac too?
1376 usb_reset(ptp_usb->handle);
1377 usb_close(ptp_usb->handle);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001378}
1379
Linus Walleij45a86372007-03-07 09:36:19 +00001380static LIBMTP_error_number_t prime_device_memory(mtpdevice_list_t *devlist)
tedbullock0f033cb2007-02-14 20:56:54 +00001381{
Linus Walleij45a86372007-03-07 09:36:19 +00001382 mtpdevice_list_t *tmplist = devlist;
Linus Walleijbfcb7922007-03-06 20:14:04 +00001383
Linus Walleij45a86372007-03-07 09:36:19 +00001384 while (tmplist != NULL) {
tedbullock0f033cb2007-02-14 20:56:54 +00001385 /* Allocate a parameter box */
Linus Walleij45a86372007-03-07 09:36:19 +00001386 tmplist->params = (PTPParams *) malloc(sizeof(PTPParams));
1387 tmplist->ptp_usb = (PTP_USB *) malloc(sizeof(PTP_USB));
Linus Walleijbfcb7922007-03-06 20:14:04 +00001388
tedbullock0f033cb2007-02-14 20:56:54 +00001389 /* Check for allocation Error */
Linus Walleij45a86372007-03-07 09:36:19 +00001390 if(tmplist->params == NULL || tmplist->ptp_usb == NULL) {
Linus Walleijbfcb7922007-03-06 20:14:04 +00001391 /* Error and deallocation of memory will be handled by caller. */
tedbullock0f033cb2007-02-14 20:56:54 +00001392 return LIBMTP_ERROR_MEMORY_ALLOCATION;
1393 }
1394
tedbullock69a445b2007-02-15 07:41:04 +00001395 /* Start with a blank slate (includes setting device_flags to 0) */
Linus Walleij45a86372007-03-07 09:36:19 +00001396 memset(tmplist->params, 0, sizeof(PTPParams));
1397 memset(tmplist->ptp_usb, 0, sizeof(PTP_USB));
1398 tmplist = tmplist->next;
tedbullock0f033cb2007-02-14 20:56:54 +00001399 }
tedbullock0f033cb2007-02-14 20:56:54 +00001400 return LIBMTP_ERROR_NONE;
1401}
1402
Linus Walleij45a86372007-03-07 09:36:19 +00001403static void assign_known_device_flags(mtpdevice_list_t *devlist)
tedbullock0f033cb2007-02-14 20:56:54 +00001404{
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001405 int i;
Linus Walleij27c50c52007-03-06 20:34:48 +00001406 mtpdevice_list_t *tmplist = devlist;
1407 uint8_t current_device = 0;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001408
tedbullock0f033cb2007-02-14 20:56:54 +00001409 /* Search through known device list and set correct device flags */
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001410 while (tmplist != NULL) {
1411 int device_known = 0;
1412
1413 for(i = 0; i < mtp_device_table_size; i++) {
1414 if(tmplist->libusb_device->descriptor.idVendor == mtp_device_table[i].vendor_id &&
1415 tmplist->libusb_device->descriptor.idProduct == mtp_device_table[i].product_id) {
1416 /* This device is known, assign the correct device flags */
1417 /* Note that ptp_usb[current_device] could potentially be NULL */
Linus Walleij45a86372007-03-07 09:36:19 +00001418 if(tmplist->ptp_usb != NULL) {
1419 tmplist->ptp_usb->device_flags = mtp_device_table[i].device_flags;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001420
1421 /*
1422 * TODO:
1423 * Preferable to not do this with #ifdef ENABLE_USB_BULK_DEBUG but there is
1424 * currently no other compile time debug option
1425 */
1426
1427 device_known = 1;
tedbullock65a05772007-03-03 22:56:56 +00001428#ifdef ENABLE_USB_BULK_DEBUG
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001429 /* This device is known to the developers */
Richard Low6b6d36b2007-10-18 19:32:00 +00001430 fprintf(stderr, "Device %d (VID=%04x and PID=%04x) is a %s %s.\n",
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001431 current_device + 1,
1432 tmplist->libusb_device->descriptor.idVendor,
1433 tmplist->libusb_device->descriptor.idProduct,
Richard Low6b6d36b2007-10-18 19:32:00 +00001434 mtp_device_table[i].vendor, mtp_device_table[i].product);
tedbullock65a05772007-03-03 22:56:56 +00001435#endif
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001436 }
1437 break;
1438 }
tedbullock0f033cb2007-02-14 20:56:54 +00001439 }
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001440 if (!device_known) {
1441 /* This device is unknown to the developers */
1442 fprintf(stderr, "Device %d (VID=%04x and PID=%04x) is UNKNOWN.\n",
1443 current_device + 1,
1444 tmplist->libusb_device->descriptor.idVendor,
1445 tmplist->libusb_device->descriptor.idProduct);
1446 fprintf(stderr, "Please report this VID/PID and the device model to the "
1447 "libmtp development team\n");
1448 }
1449 tmplist = tmplist->next;
Linus Walleijbfcb7922007-03-06 20:14:04 +00001450 current_device++;
tedbullock0f033cb2007-02-14 20:56:54 +00001451 }
tedbullock0f033cb2007-02-14 20:56:54 +00001452}
1453
tedbullock0f033cb2007-02-14 20:56:54 +00001454
Linus Walleij45a86372007-03-07 09:36:19 +00001455static LIBMTP_error_number_t configure_usb_devices(mtpdevice_list_t *devicelist)
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001456{
1457 mtpdevice_list_t *tmplist = devicelist;
1458 uint16_t ret = 0;
1459 uint8_t current_device = 0;
1460
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001461 while (tmplist != NULL) {
Linus Walleij45a86372007-03-07 09:36:19 +00001462 /* This is erroneous, there must be a PTP_USB instance that we can initialize. */
1463 if(tmplist->ptp_usb == NULL) {
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001464 return LIBMTP_ERROR_MEMORY_ALLOCATION;
tedbullock0f033cb2007-02-14 20:56:54 +00001465 }
1466
Linus Walleij3e418e22007-09-15 20:30:14 +00001467 /* Pointer back to params */
1468 tmplist->ptp_usb->params = tmplist->params;
1469
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001470 /* TODO: Will this always be little endian? */
Linus Walleij45a86372007-03-07 09:36:19 +00001471 tmplist->params->byteorder = PTP_DL_LE;
1472 tmplist->params->cd_locale_to_ucs2 = iconv_open("UCS-2LE", "UTF-8");
1473 tmplist->params->cd_ucs2_to_locale = iconv_open("UTF-8", "UCS-2LE");
tedbullock0f033cb2007-02-14 20:56:54 +00001474
Linus Walleij45a86372007-03-07 09:36:19 +00001475 if(tmplist->params->cd_locale_to_ucs2 == (iconv_t) -1 ||
1476 tmplist->params->cd_ucs2_to_locale == (iconv_t) -1) {
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001477 fprintf(stderr, "LIBMTP PANIC: Cannot open iconv() converters to/from UCS-2!\n"
1478 "Too old stdlibc, glibc and libiconv?\n");
Linus Walleij35c0ef12007-03-06 20:49:09 +00001479 return LIBMTP_ERROR_CONNECTING;
tedbullock0f033cb2007-02-14 20:56:54 +00001480 }
1481
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001482 // ep = device->config->interface->altsetting->endpoint;
1483 // no_of_ep = device->config->interface->altsetting->bNumEndpoints;
tedbullock0f033cb2007-02-14 20:56:54 +00001484
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001485 /* Assign endpoints to usbinfo... */
Linus Walleijb0ab5482007-08-29 21:08:54 +00001486 find_interface_and_endpoints(tmplist->libusb_device,
1487 &tmplist->ptp_usb->interface,
Linus Walleij45a86372007-03-07 09:36:19 +00001488 &tmplist->ptp_usb->inep,
1489 &tmplist->ptp_usb->inep_maxpacket,
1490 &tmplist->ptp_usb->outep,
1491 &tmplist->ptp_usb->outep_maxpacket,
1492 &tmplist->ptp_usb->intep);
tedbullock0f033cb2007-02-14 20:56:54 +00001493
Linus Walleij45a86372007-03-07 09:36:19 +00001494 /* Attempt to initialize this device */
1495 if (init_ptp_usb(tmplist->params, tmplist->ptp_usb, tmplist->libusb_device) < 0) {
1496 fprintf(stderr, "LIBMTP PANIC: Unable to initialize device %d\n", current_device+1);
1497 // FIXME: perhaps use "continue" to keep trying the other devices.
Linus Walleij35c0ef12007-03-06 20:49:09 +00001498 return LIBMTP_ERROR_CONNECTING;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001499 }
1500
1501 /*
1502 * This works in situations where previous bad applications
1503 * have not used LIBMTP_Release_Device on exit
1504 */
Linus Walleij45a86372007-03-07 09:36:19 +00001505 if ((ret = ptp_opensession(tmplist->params, 1)) == PTP_ERROR_IO) {
Linus Walleijf1cfc5e2007-08-29 11:14:36 +00001506 fprintf(stderr, "PTP_ERROR_IO: Trying again after re-initializing USB interface\n");
Linus Walleijb0ab5482007-08-29 21:08:54 +00001507 close_usb(tmplist->ptp_usb);
tedbullock0f033cb2007-02-14 20:56:54 +00001508
Linus Walleij45a86372007-03-07 09:36:19 +00001509 if(init_ptp_usb(tmplist->params, tmplist->ptp_usb, tmplist->libusb_device) <0) {
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001510 fprintf(stderr, "LIBMTP PANIC: Could not open session on device %d\n", current_device+1);
Linus Walleij35c0ef12007-03-06 20:49:09 +00001511 return LIBMTP_ERROR_CONNECTING;
tedbullock0f033cb2007-02-14 20:56:54 +00001512 }
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001513
1514 /* Device has been reset, try again */
Linus Walleij45a86372007-03-07 09:36:19 +00001515 ret = ptp_opensession(tmplist->params, 1);
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001516 }
1517
1518 /* Was the transaction id invalid? Try again */
1519 if (ret == PTP_RC_InvalidTransactionID) {
Linus Walleij45a86372007-03-07 09:36:19 +00001520 fprintf(stderr, "LIBMTP WARNING: Transaction ID was invalid, increment and try again\n");
1521 tmplist->params->transaction_id += 10;
1522 ret = ptp_opensession(tmplist->params, 1);
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001523 }
1524
1525 if (ret != PTP_RC_SessionAlreadyOpened && ret != PTP_RC_OK) {
Linus Walleij45a86372007-03-07 09:36:19 +00001526 fprintf(stderr, "LIBMTP PANIC: Could not open session! "
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001527 "(Return code %d)\n Try to reset the device.\n",
1528 ret);
Linus Walleij45a86372007-03-07 09:36:19 +00001529 usb_release_interface(tmplist->ptp_usb->handle,
Linus Walleijb0ab5482007-08-29 21:08:54 +00001530 (int) tmplist->ptp_usb->interface);
tedbullock0f033cb2007-02-14 20:56:54 +00001531 return LIBMTP_ERROR_CONNECTING;
1532 }
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001533
1534 tmplist = tmplist->next;
1535 current_device++;
tedbullock0f033cb2007-02-14 20:56:54 +00001536 }
1537
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001538 /* Exit with the nice list */
1539 return LIBMTP_ERROR_NONE;
tedbullock0f033cb2007-02-14 20:56:54 +00001540}
1541
Linus Walleij550d6d52007-01-24 14:32:51 +00001542/**
1543 * This function scans through the results of the get_mtp_usb_device_list
1544 * function and attempts to connect to those devices listed using the
1545 * mtp_device_table at the top of the file. Returns a LIBMTP_error_number_t.
1546 *
Linus Walleij45a86372007-03-07 09:36:19 +00001547 * @param devlist a list of devices with primed PTP_USB and params structs.
Linus Walleij550d6d52007-01-24 14:32:51 +00001548 * @return Error Codes as per the type definition
1549 */
Linus Walleij45a86372007-03-07 09:36:19 +00001550LIBMTP_error_number_t find_usb_devices(mtpdevice_list_t **devlist)
Linus Walleij550d6d52007-01-24 14:32:51 +00001551{
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001552 mtpdevice_list_t *mtp_device_list = NULL;
tedbullock0f033cb2007-02-14 20:56:54 +00001553 LIBMTP_error_number_t ret;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001554
Linus Walleija4942fc2007-03-12 19:23:21 +00001555 /*
1556 * Recover list of attached USB devices that match MTP criteria, i.e.
1557 * it either has an MTP device descriptor or it is in the known
1558 * devices list.
1559 */
Linus Walleij45a86372007-03-07 09:36:19 +00001560 ret = get_mtp_usb_device_list (&mtp_device_list);
Linus Walleijac061862007-03-07 08:28:33 +00001561 if (ret != LIBMTP_ERROR_NONE) {
1562 return ret;
Linus Walleij550d6d52007-01-24 14:32:51 +00001563 }
1564
Linus Walleij45a86372007-03-07 09:36:19 +00001565 // Then prime them
1566 ret = prime_device_memory(mtp_device_list);
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001567 if(ret) {
Linus Walleijac061862007-03-07 08:28:33 +00001568 fprintf(stderr, "LIBMTP PANIC: prime_device_memory() error code: %d on line %d\n", ret, __LINE__);
Linus Walleij45a86372007-03-07 09:36:19 +00001569 goto find_usb_devices_error_exit;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001570 }
tedbullock0f033cb2007-02-14 20:56:54 +00001571
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001572 /* Assign specific device flags and detect unknown devices */
Linus Walleij45a86372007-03-07 09:36:19 +00001573 assign_known_device_flags(mtp_device_list);
Linus Walleij550d6d52007-01-24 14:32:51 +00001574
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001575 /* Configure the devices */
Linus Walleij45a86372007-03-07 09:36:19 +00001576 ret = configure_usb_devices(mtp_device_list);
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001577 if(ret) {
Linus Walleijac061862007-03-07 08:28:33 +00001578 fprintf(stderr, "LIBMTP PANIC: configure_usb_devices() error code: %d on line %d\n", ret, __LINE__);
Linus Walleij45a86372007-03-07 09:36:19 +00001579 goto find_usb_devices_error_exit;
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001580 }
Linus Walleij550d6d52007-01-24 14:32:51 +00001581
Linus Walleij45a86372007-03-07 09:36:19 +00001582 /* we're connected to all devices, return the list and OK */
1583 *devlist = mtp_device_list;
1584 return LIBMTP_ERROR_NONE;
1585
1586 find_usb_devices_error_exit:
Linus Walleijf27d1cd2007-03-05 14:23:00 +00001587 if(mtp_device_list != NULL) {
1588 free_mtpdevice_list(mtp_device_list);
1589 mtp_device_list = NULL;
Linus Walleij550d6d52007-01-24 14:32:51 +00001590 }
Linus Walleij45a86372007-03-07 09:36:19 +00001591 *devlist = NULL;
tedbullock0f033cb2007-02-14 20:56:54 +00001592 return ret;
Linus Walleij550d6d52007-01-24 14:32:51 +00001593}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001594
Linus Walleijb0ab5482007-08-29 21:08:54 +00001595static void find_interface_and_endpoints(struct usb_device *dev,
1596 uint8_t *interface,
1597 int* inep,
1598 int* inep_maxpacket,
1599 int* outep,
1600 int *outep_maxpacket,
1601 int* intep)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001602{
Linus Walleijd7373cd2007-08-28 21:42:05 +00001603 int i;
1604
1605 // Loop over the device configurations
1606 for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
Linus Walleijb0ab5482007-08-29 21:08:54 +00001607 uint8_t j;
Linus Walleijd7373cd2007-08-28 21:42:05 +00001608
1609 for (j = 0; j < dev->config[i].bNumInterfaces; j++) {
Linus Walleijb0ab5482007-08-29 21:08:54 +00001610 uint8_t k;
1611 uint8_t no_ep;
Linus Walleijd7373cd2007-08-28 21:42:05 +00001612 struct usb_endpoint_descriptor *ep;
Linus Walleijd7373cd2007-08-28 21:42:05 +00001613
Linus Walleijb0ab5482007-08-29 21:08:54 +00001614 if (dev->descriptor.bNumConfigurations > 1 || dev->config[i].bNumInterfaces > 1) {
1615 // OK This device has more than one interface, so we have to find out
1616 // which one to use!
1617 // FIXME: Probe the interface.
1618 // FIXME: Release modules attached to all other interfaces in Linux...?
1619 }
1620
1621 *interface = dev->config[i].interface[j].altsetting->bInterfaceNumber;
1622 ep = dev->config[i].interface[j].altsetting->endpoint;
1623 no_ep = dev->config[i].interface[j].altsetting->bNumEndpoints;
1624
1625 for (k = 0; k < no_ep; k++) {
Linus Walleijd7373cd2007-08-28 21:42:05 +00001626 if (ep[k].bmAttributes==USB_ENDPOINT_TYPE_BULK) {
1627 if ((ep[k].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
1628 USB_ENDPOINT_DIR_MASK)
1629 {
1630 *inep=ep[k].bEndpointAddress;
1631 *inep_maxpacket=ep[k].wMaxPacketSize;
1632 }
1633 if ((ep[k].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==0)
1634 {
1635 *outep=ep[k].bEndpointAddress;
1636 *outep_maxpacket=ep[k].wMaxPacketSize;
1637 }
1638 } else if (ep[k].bmAttributes==USB_ENDPOINT_TYPE_INTERRUPT){
1639 if ((ep[k].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
1640 USB_ENDPOINT_DIR_MASK)
1641 {
1642 *intep=ep[k].bEndpointAddress;
1643 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001644 }
Linus Walleijd7373cd2007-08-28 21:42:05 +00001645 }
1646 // We assigned the endpoints so return here.
1647 return;
Linus Walleijd6a49972006-05-02 08:24:54 +00001648 }
1649 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001650}
1651
Linus Walleijb0ab5482007-08-29 21:08:54 +00001652void close_device (PTP_USB *ptp_usb, PTPParams *params)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001653{
Linus Walleijd6a49972006-05-02 08:24:54 +00001654 if (ptp_closesession(params)!=PTP_RC_OK)
1655 fprintf(stderr,"ERROR: Could not close session!\n");
Linus Walleijb0ab5482007-08-29 21:08:54 +00001656 close_usb(ptp_usb);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001657}
1658
Linus Walleijd6a49972006-05-02 08:24:54 +00001659static int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001660{
Linus Walleijd6a49972006-05-02 08:24:54 +00001661
1662 return (usb_control_msg(ptp_usb->handle,
1663 USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, USB_FEATURE_HALT,
Linus Walleij913a3062007-09-28 21:42:39 +00001664 ep, NULL, 0, USB_TIMEOUT));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001665}
1666
Linus Walleijd6a49972006-05-02 08:24:54 +00001667static int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001668{
Linus Walleijd6a49972006-05-02 08:24:54 +00001669 return (usb_control_msg(ptp_usb->handle,
1670 USB_DP_DTH|USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS,
Linus Walleij913a3062007-09-28 21:42:39 +00001671 USB_FEATURE_HALT, ep, (char *)status, 2, USB_TIMEOUT));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001672}