blob: afb6684bea4b162909b247780423e74aa9b89afa [file] [log] [blame]
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001/*
Linus Walleij15e344f2006-03-06 15:15:00 +00002 * libusb-glue.c
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00003 *
Linus Walleij15e344f2006-03-06 15:15:00 +00004 * Created by Richard Low on 24/12/2005. (as mtp-utils.c)
Linus Walleija5483642006-03-09 09:20:38 +00005 * Modified by Linus Walleij 2006-03-06
6 * (Notice that Anglo-Saxons use little-endian dates and Swedes use big-endian dates.)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00007 *
8 * This file adds some utils (many copied from ptpcam.c from libptp2) to
9 * use MTP devices. Include mtp-utils.h to use any of the ptp/mtp functions.
10 *
11 */
Linus Walleij7beba572006-11-29 08:56:12 +000012#include "libmtp.h"
13#include "libusb-glue.h"
14#include "util.h"
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000015#include "ptp.h"
Linus Walleij7beba572006-11-29 08:56:12 +000016
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000017#include <errno.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000021#include <usb.h>
22
Linus Walleije78de6d2006-10-31 14:46:36 +000023/* To enable debug prints, switch on this */
24//#define ENABLE_USB_BULK_DEBUG
25
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000026/* OUR APPLICATION USB URB (2MB) ;) */
27#define PTPCAM_USB_URB 2097152
28
29/* this must not be too short - the original 4000 was not long
30 enough for big file transfers. I imagine the player spends a
31 bit of time gearing up to receiving lots of data. This also makes
32 connecting/disconnecting more reliable */
33#define USB_TIMEOUT 10000
34#define USB_CAPTURE_TIMEOUT 20000
35
36/* USB control message data phase direction */
37#ifndef USB_DP_HTD
38#define USB_DP_HTD (0x00 << 7) /* host to device */
39#endif
40#ifndef USB_DP_DTH
41#define USB_DP_DTH (0x01 << 7) /* device to host */
42#endif
43
44/* USB Feature selector HALT */
45#ifndef USB_FEATURE_HALT
46#define USB_FEATURE_HALT 0x00
47#endif
48
Linus Walleija5483642006-03-09 09:20:38 +000049/*
Linus Walleije8c54642006-03-28 09:45:00 +000050 * MTP device list, trying real bad to get all devices into
51 * this list by stealing from everyone I know.
Linus Walleija5483642006-03-09 09:20:38 +000052 */
Linus Walleij6fd2f082006-03-28 07:19:22 +000053static const LIBMTP_device_entry_t mtp_device_table[] = {
Linus Walleij3d2c7842006-08-18 09:35:08 +000054
55 /*
56 * Creative Technology
Linus Walleijcc4dd482006-11-25 21:58:30 +000057 * Initially the Creative devices was all we supported so these are
58 * the most thoroughly tested devices.
Linus Walleij3d2c7842006-08-18 09:35:08 +000059 */
Linus Walleij0558ac52006-09-07 06:55:03 +000060 { "Creative Zen Vision", 0x041e, 0x411f, DEVICE_FLAG_NONE },
61 { "Creative Portable Media Center", 0x041e, 0x4123, DEVICE_FLAG_NONE },
62 { "Creative Zen Xtra (MTP mode)", 0x041e, 0x4128, DEVICE_FLAG_NONE },
63 { "Second generation Dell DJ", 0x041e, 0x412f, DEVICE_FLAG_NONE },
64 { "Creative Zen Micro (MTP mode)", 0x041e, 0x4130, DEVICE_FLAG_NONE },
65 { "Creative Zen Touch (MTP mode)", 0x041e, 0x4131, DEVICE_FLAG_NONE },
66 { "Dell Pocket DJ (MTP mode)", 0x041e, 0x4132, DEVICE_FLAG_NONE },
67 { "Creative Zen Sleek (MTP mode)", 0x041e, 0x4137, DEVICE_FLAG_NONE },
68 { "Creative Zen MicroPhoto", 0x041e, 0x413c, DEVICE_FLAG_NONE },
69 { "Creative Zen Sleek Photo", 0x041e, 0x413d, DEVICE_FLAG_NONE },
70 { "Creative Zen Vision:M", 0x041e, 0x413e, DEVICE_FLAG_NONE },
Linus Walleijbdd006b2006-09-15 04:54:13 +000071 // Reported by marazm@o2.pl
72 { "Creative Zen V", 0x041e, 0x4150, DEVICE_FLAG_NONE },
Linus Walleij92a84962006-11-11 20:04:37 +000073 // Reported by danielw@iinet.net.au
74 { "Creative Zen Vision:M (DVP-HD0004)", 0x041e, 0x4151, DEVICE_FLAG_NONE },
Linus Walleij550bc672006-10-10 11:11:29 +000075 // Reported by Darel on the XNJB forums
Richard Lowe1f06922006-11-12 16:38:39 +000076 { "Creative Zen V Plus", 0x041e, 0x4152, DEVICE_FLAG_NONE },
77 { "Creative Zen Vision W", 0x041e, 0x4153, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +000078
79 /*
80 * Samsung
Linus Walleij0558ac52006-09-07 06:55:03 +000081 * We suspect that more of these are dual mode.
Linus Walleij3d2c7842006-08-18 09:35:08 +000082 */
83 // From libgphoto2
Linus Walleij0558ac52006-09-07 06:55:03 +000084 { "Samsung YH-820", 0x04e8, 0x502e, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +000085 // Contributed by polux2001@users.sourceforge.net
Linus Walleij0558ac52006-09-07 06:55:03 +000086 { "Samsung YH-925", 0x04e8, 0x502f, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +000087 // Contributed by anonymous person on SourceForge
Linus Walleij0558ac52006-09-07 06:55:03 +000088 { "Samsung YP-T7J", 0x04e8, 0x5047, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +000089 // Reported by cstrickler@gmail.com
Linus Walleij0558ac52006-09-07 06:55:03 +000090 { "Samsung YP-U2J (YP-U2JXB/XAA)", 0x04e8, 0x5054, DEVICE_FLAG_NONE },
Linus Walleij82ed6612006-08-31 08:06:19 +000091 // Reported by Andrew Benson
Linus Walleij0558ac52006-09-07 06:55:03 +000092 { "Samsung YP-F2J", 0x04e8, 0x5057, DEVICE_FLAG_DUALMODE },
Linus Walleij19be4212006-11-16 09:00:48 +000093 // Reported by Patrick <skibler@gmail.com>
Linus Walleijabdf6072006-11-24 07:34:02 +000094 { "Samsung YP-K5", 0x04e8, 0x505a, DEVICE_FLAG_NONE },
Linus Walleija5073c72006-11-24 07:55:12 +000095 // Reported by Matthew Wilcox <matthew@wil.cx>
Richard Lowc046fdf2006-11-24 09:19:33 +000096 { "Samsung Yepp T9", 0x04e8, 0x507f, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +000097 // From a rouge .INF file
Linus Walleij0558ac52006-09-07 06:55:03 +000098 { "Samsung YH-999 Portable Media Center", 0x04e8, 0x5a0f, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +000099
100 /*
101 * Intel
102 */
Linus Walleij0558ac52006-09-07 06:55:03 +0000103 { "Intel Bandon Portable Media Center", 0x045e, 0x00c9, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000104
105 /*
106 * JVC
107 */
108 // From Mark Veinot
Linus Walleij0558ac52006-09-07 06:55:03 +0000109 { "JVC Alneo XA-HD500", 0x04f1, 0x6105, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000110
111 /*
Linus Walleij093ca0a2006-11-02 21:15:00 +0000112 * Philips
Linus Walleij3d2c7842006-08-18 09:35:08 +0000113 */
114 // From libgphoto2 source
Linus Walleij093ca0a2006-11-02 21:15:00 +0000115 { "Philips HDD6320", 0x0471, 0x01eb, DEVICE_FLAG_NONE },
Linus Walleijbf7fc272006-11-10 21:35:06 +0000116 { "Philips HDD6320/00", 0x0471, 0x014b, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000117 // Anonymous SourceForge user
Linus Walleij093ca0a2006-11-02 21:15:00 +0000118 { "Philips HDD1630/17", 0x0471, 0x014c, DEVICE_FLAG_NONE },
119 // From Gerhard Mekenkamp
120 { "Philips GoGear Audio", 0x0471, 0x0165, DEVICE_FLAG_NONE },
Richard Lowa6c924c2006-12-29 17:44:28 +0000121 // from XNJB forum
122 { "Philips GoGear SA9200", 0x0471, 0x014f, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000123
124 /*
125 * SanDisk
126 */
127 // Reported by Brian Robison
Linus Walleij0558ac52006-09-07 06:55:03 +0000128 { "SanDisk Sansa m240", 0x0781, 0x7400, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000129 // Reported by tangent_@users.sourceforge.net
Linus Walleij0558ac52006-09-07 06:55:03 +0000130 { "SanDisk Sansa c150", 0x0781, 0x7410, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000131 // From libgphoto2 source
Linus Walleij0558ac52006-09-07 06:55:03 +0000132 { "SanDisk Sansa e200", 0x0781, 0x7420, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000133 // Reported by gonkflea@users.sourceforge.net
Linus Walleij0558ac52006-09-07 06:55:03 +0000134 { "SanDisk Sansa e260", 0x0781, 0x7420, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000135
136 /*
137 * iRiver
Linus Walleij1a1b2d12006-11-23 13:32:17 +0000138 * we assume that PTP_OC_MTP_GetObjPropList is essentially
Linus Walleijfabffc02006-12-17 00:18:57 +0000139 * broken on all iRiver devices, meaning it simply won't return
140 * all properties for a file when asking for metadata 0xffffffff.
141 * Please test on your device if you believe it isn't broken!
142 * Some devices from http://www.mtp-ums.net/viewdeviceinfo.php
Linus Walleij3d2c7842006-08-18 09:35:08 +0000143 */
Linus Walleij1a1b2d12006-11-23 13:32:17 +0000144 { "iRiver Portable Media Center", 0x1006, 0x4002, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
145 { "iRiver Portable Media Center", 0x1006, 0x4003, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000146 // From libgphoto2 source
Linus Walleij1a1b2d12006-11-23 13:32:17 +0000147 { "iRiver T10", 0x4102, 0x1113, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
148 { "iRiver T20 FM", 0x4102, 0x1114, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
Linus Walleijfabffc02006-12-17 00:18:57 +0000149 // This appears at the MTP-UMS site
150 { "iRiver T20", 0x4102, 0x1115, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
Linus Walleij1a1b2d12006-11-23 13:32:17 +0000151 { "iRiver U10", 0x4102, 0x1116, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
152 { "iRiver T10", 0x4102, 0x1117, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
153 { "iRiver T20", 0x4102, 0x1118, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
154 { "iRiver T30", 0x4102, 0x1119, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
Linus Walleij77e047c2006-09-11 19:09:06 +0000155 // Reported by David Wolpoff
Linus Walleij1a1b2d12006-11-23 13:32:17 +0000156 { "iRiver T10 2GB", 0x4102, 0x1120, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
Linus Walleij87099812006-12-17 00:29:58 +0000157 // Rough guess this is the MTP device ID...
158 { "iRiver N12", 0x4102, 0x1122, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
Linus Walleij04377da2006-08-30 13:03:35 +0000159 // Reported by Adam Torgerson
Linus Walleij1a1b2d12006-11-23 13:32:17 +0000160 { "iRiver Clix", 0x4102, 0x112a, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000161 // Reported by Scott Call
Linus Walleij1a1b2d12006-11-23 13:32:17 +0000162 { "iRiver H10 20GB", 0x4102, 0x2101, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
163 { "iRiver H10", 0x4102, 0x2102, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000164
165 /*
166 * Dell
167 */
Linus Walleij0558ac52006-09-07 06:55:03 +0000168 { "Dell DJ Itty", 0x413c, 0x4500, DEVICE_FLAG_NONE },
Linus Walleij3d2c7842006-08-18 09:35:08 +0000169
170 /*
171 * Toshiba
172 */
Linus Walleij0558ac52006-09-07 06:55:03 +0000173 { "Toshiba Gigabeat MEGF-40", 0x0930, 0x0009, DEVICE_FLAG_NONE },
174 { "Toshiba Gigabeat", 0x0930, 0x000c, DEVICE_FLAG_NONE },
Linus Walleij405e2392006-10-23 07:13:49 +0000175 // From libgphoto2
176 { "Toshiba Gigabeat S", 0x0930, 0x0010, DEVICE_FLAG_NONE },
Linus Walleij402e4bd2006-09-12 07:50:56 +0000177 // Reported by Rob Brown
178 { "Toshiba Gigabeat P10", 0x0930, 0x0011, DEVICE_FLAG_NONE },
Linus Walleijb01d18b2006-12-13 12:49:15 +0000179
Linus Walleij6f680562006-08-19 22:49:33 +0000180 /*
181 * Archos
182 */
183 // Reported by gudul1@users.sourceforge.net
Linus Walleije5430902006-10-08 14:46:03 +0000184 { "Archos 104 (MTP mode)", 0x0e79, 0x120a, DEVICE_FLAG_NONE },
185
186 /*
Linus Walleij2a9d2f02006-10-15 20:44:27 +0000187 * Dunlop (OEM of EGOMAN ltd?) reported by Nanomad
Linus Walleij550bc672006-10-10 11:11:29 +0000188 * This unit is falsely detected as USB mass storage in Linux
Linus Walleijcc4dd482006-11-25 21:58:30 +0000189 * prior to kernel 2.6.19 (fixed by patch from Alan Stern)
190 * so on older kernels special care is needed to remove the
191 * USB mass storage driver that erroneously binds to the device
192 * interface.
Linus Walleije5430902006-10-08 14:46:03 +0000193 */
Richard Lowc7d48d22006-11-29 18:24:55 +0000194 { "Dunlop MP3 player 1GB / EGOMAN MD223AFD", 0x10d6, 0x2200, DEVICE_FLAG_UNLOAD_DRIVER},
195
196 /*
197 * Microsoft
198 */
199 // Reported by Farooq Zaman
200 { "Microsoft Zune", 0x045e, 0x0710, DEVICE_FLAG_NONE },
201
202 /*
203 * Sirius
204 */
Linus Walleijb01d18b2006-12-13 12:49:15 +0000205 { "Sirius Stiletto", 0x18f6, 0x0102, DEVICE_FLAG_NONE },
206
207 /*
208 * Canon
209 * This is actually a camera, but it has a Microsoft device descriptor
210 * and reports itself as supporting the MTP extension.
211 */
212 {"Canon PowerShot A640 (PTP/MTP mode)", 0x04a9, 0x3139, DEVICE_FLAG_NONE }
Linus Walleije5430902006-10-08 14:46:03 +0000213
Linus Walleija5483642006-03-09 09:20:38 +0000214};
Linus Walleij6fd2f082006-03-28 07:19:22 +0000215static const int mtp_device_table_size = sizeof(mtp_device_table) / sizeof(LIBMTP_device_entry_t);
Linus Walleija5483642006-03-09 09:20:38 +0000216
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000217int ptpcam_usb_timeout = USB_TIMEOUT;
218
Linus Walleijd6a49972006-05-02 08:24:54 +0000219// Local functions
Linus Walleij1fd2d272006-05-08 09:22:01 +0000220static struct usb_bus* init_usb();
221static struct usb_device *probe_usb_bus_for_mtp_devices(void);
Linus Walleijd6a49972006-05-02 08:24:54 +0000222static void close_usb(PTP_USB* ptp_usb, uint8_t interfaceNumber);
223static struct usb_device* find_device (int busn, int devicen, short force);
224static void find_endpoints(struct usb_device *dev, int* inep, int* inep_maxpacket, int* outep, int* outep_maxpacket, int* intep);
225static void clear_stall(PTP_USB* ptp_usb);
Linus Walleij9eb3d312006-08-04 19:25:59 +0000226static int init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev);
Linus Walleij784ac3f2006-12-29 10:36:51 +0000227static short ptp_write_func (unsigned long,PTPDataHandler*,void *data,unsigned long*);
228static short ptp_read_func (unsigned long,PTPDataHandler*,void *data,unsigned long*);
229static short ptp_check_int (unsigned long,PTPDataHandler*,void *, unsigned long *);
Linus Walleijd6a49972006-05-02 08:24:54 +0000230static int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep);
231static int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status);
Linus Walleij1fd2d272006-05-08 09:22:01 +0000232
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000233
Linus Walleij6fd2f082006-03-28 07:19:22 +0000234int get_device_list(LIBMTP_device_entry_t ** const devices, int * const numdevs)
235{
236 *devices = (LIBMTP_device_entry_t *) &mtp_device_table;
237 *numdevs = mtp_device_table_size;
238 return 0;
239}
240
Linus Walleij1fd2d272006-05-08 09:22:01 +0000241static struct usb_bus* init_usb()
242{
243 usb_init();
244 usb_find_busses();
245 usb_find_devices();
246 return (usb_get_busses());
247}
248
249/**
250 * Check for the Microsoft OS device descriptor and returns device struct
251 * if the device is MTP-compliant. The function will only recognize
252 * a single device connected to the USB bus.
253 *
254 * @return an MTP-compliant USB device if one was found, else NULL.
255 */
256static struct usb_device *probe_usb_bus_for_mtp_devices(void)
257{
258 struct usb_bus *bus;
259
260 bus = init_usb();
261 for (; bus; bus = bus->next) {
262 struct usb_device *dev;
263
264 for (dev = bus->devices; dev; dev = dev->next) {
265 usb_dev_handle *devh;
266 unsigned char buf[1024], cmd;
267 int ret;
268
269 devh = usb_open(dev);
270 if (devh == NULL) {
271 continue;
272 }
273
274 // Read the special descripor, if possible...
275 ret = usb_get_descriptor(devh, 0x03, 0xee, buf, sizeof(buf));
276
277 if (ret < 10) {
278 // printf("Device: VID %04x/PID %04x: no extended device property...\n",
279 // dev->descriptor.idVendor,
280 // dev->descriptor.idProduct);
281 usb_close(devh);
282 continue;
283 }
Linus Walleijd5d51c82006-09-11 06:57:50 +0000284
285 // It is atleast 10 bytes...
Linus Walleij1fd2d272006-05-08 09:22:01 +0000286 if (!((buf[2] == 'M') && (buf[4]=='S') && (buf[6]=='F') && (buf[8]=='T'))) {
Linus Walleijd5d51c82006-09-11 06:57:50 +0000287 printf("This is not a Microsoft MTP descriptor...\n");
288 printf("Device response to read device property 0xee:\n");
289 data_dump_ascii (stdout, buf, ret, 0);
Linus Walleij1fd2d272006-05-08 09:22:01 +0000290 usb_close(devh);
291 continue;
292 }
293
294 cmd = buf[16];
295 ret = usb_control_msg (devh, USB_ENDPOINT_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR,
296 cmd, 0, 4, (char *) buf, sizeof(buf), 1000);
297 if (ret == -1) {
298 //printf("Decice could not respond to control message 1.\n");
299 usb_close(devh);
Linus Walleijd5d51c82006-09-11 06:57:50 +0000300 continue;
Linus Walleij1fd2d272006-05-08 09:22:01 +0000301 }
302
Linus Walleijd5d51c82006-09-11 06:57:50 +0000303 if (ret > 0x15) {
304 if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) {
305 printf("The device has a Microsoft device descriptor, but it's not MTP.\n");
306 printf("This is not an MTP device. Presumable it is USB mass storage\n");
307 printf("with some additional Janus (DRM) support.\n");
308 printf("Device response to control message 1:\n");
309 data_dump_ascii (stdout, buf, ret, 0);
310 continue;
311 }
312 } else {
313 // Not MTP or broken
314 continue;
Linus Walleij1fd2d272006-05-08 09:22:01 +0000315 }
316
317 ret = usb_control_msg (devh, USB_ENDPOINT_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR,
318 cmd, 0, 5, (char *) buf, sizeof(buf), 1000);
319 if (ret == -1) {
320 //printf("Device could not respond to control message 2.\n");
321 usb_close(devh);
Linus Walleijd5d51c82006-09-11 06:57:50 +0000322 // Return the device anyway, it said previously it was MTP, right?
Linus Walleij1fd2d272006-05-08 09:22:01 +0000323 return dev;
324 }
325
Linus Walleijd5d51c82006-09-11 06:57:50 +0000326 if (ret > 0x15) {
327 if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) {
328 printf("This device does not respond with MTP characteristics on\n");
329 printf("the second device property read (0x05), but will be regarded\n");
330 printf("as MTP anyway.\n");
331 printf("Device response to control message 2:\n");
332 data_dump_ascii (stdout, buf, ret, 0);
333 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000334 }
Linus Walleijd5d51c82006-09-11 06:57:50 +0000335
Linus Walleij1fd2d272006-05-08 09:22:01 +0000336 usb_close(devh);
337 // We can return the device here, it will be the first.
338 // If it was not MTP, the loop continues before it reaches this point.
339 return dev;
340 }
341 }
342 // If nothing was found we end up here.
343 return NULL;
344}
345
346/**
347 * Detect the MTP device descriptor and return the VID and PID
348 * of the first device found. This is a very low-level function
349 * which is intended for use with <b>udev</b> or other hotplug
350 * mechanisms. The idea is that a script may want to know if the
351 * just plugged-in device was an MTP device or not.
352 * @param vid the Vendor ID (VID) of the first device found.
353 * @param pid the Product ID (PID) of the first device found.
354 * @return the number of detected devices or -1 if the call
355 * was unsuccessful.
356 */
357int LIBMTP_Detect_Descriptor(uint16_t *vid, uint16_t *pid)
358{
359 struct usb_device *dev = probe_usb_bus_for_mtp_devices();
360 if (dev == NULL) {
361 return 0;
362 }
363 *vid = dev->descriptor.idVendor;
364 *pid = dev->descriptor.idProduct;
365 return 1;
366}
367
Linus Walleijc6210fb2006-05-08 11:11:41 +0000368/**
369 * This routine just dumps out low-level
370 * USB information about the current device.
371 * @param ptp_usb the USB device to get information from.
372 */
373void dump_usbinfo(PTP_USB *ptp_usb)
374{
375 int res;
376 struct usb_device *dev;
377
378#ifdef LIBUSB_HAS_GET_DRIVER_NP
379 char devname[0x10];
380
381 devname[0] = '\0';
382 res = usb_get_driver_np(ptp_usb->handle, ptp_usb->interface, devname, sizeof(devname));
383 if (devname[0] != '\0') {
384 printf(" Using kernel interface \"%s\"\n", devname);
385 }
386#endif
387 dev = usb_device(ptp_usb->handle);
388 printf(" bcdUSB: %d\n", dev->descriptor.bcdUSB);
389 printf(" bDeviceClass: %d\n", dev->descriptor.bDeviceClass);
390 printf(" bDeviceSubClass: %d\n", dev->descriptor.bDeviceSubClass);
391 printf(" bDeviceProtocol: %d\n", dev->descriptor.bDeviceProtocol);
Linus Walleijc6210fb2006-05-08 11:11:41 +0000392 printf(" idVendor: %04x\n", dev->descriptor.idVendor);
393 printf(" idProduct: %04x\n", dev->descriptor.idProduct);
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000394 printf(" IN endpoint maxpacket: %d bytes\n", ptp_usb->inep_maxpacket);
395 printf(" OUT endpoint maxpacket: %d bytes\n", ptp_usb->outep_maxpacket);
Linus Walleij0558ac52006-09-07 06:55:03 +0000396 printf(" Device flags: 0x%08x\n", ptp_usb->device_flags);
Linus Walleijc6210fb2006-05-08 11:11:41 +0000397 // TODO: add in string dumps for iManufacturer, iProduct, iSerialnumber...
398}
399
400
Linus Walleij99ed83c2007-01-02 18:46:02 +0000401/*
402 * ptp_read_func() and ptp_write_func() are
403 * based on same functions in library.c in libgphoto2.
404 * Much reading packet logs and having fun with trials and errors
405 * reveals that WMP / Windows is probably using an algorithm like this
406 * for large transfers:
407 *
408 * 1. Send the command (0x0c bytes) if headers are split, else, send
409 * command plus sizeof(endpoint) - 0x0c bytes.
410 * 2. Send first packet, max size to be sizeof(endpoint) but only when using
411 * split headers. Else goto 3.
412 * 3. REPEAT send 0x10000 byte chunks UNTIL remaining bytes < 0x10000
413 * We call 0x10000 CONTEXT_BLOCK_SIZE.
414 * 4. Send remaining bytes MOD sizeof(endpoint)
415 * 5. Send remaining bytes. If this happens to be exactly sizeof(endpoint)
416 * then also send a zero-length package.
417 */
Richard Low021421e2007-01-01 18:08:57 +0000418#define CONTEXT_BLOCK_SIZE 0x10000
Linus Walleijb02a0662006-04-25 08:05:09 +0000419static short
Linus Walleij784ac3f2006-12-29 10:36:51 +0000420ptp_read_func (
421 unsigned long size, PTPDataHandler *handler,void *data,
422 unsigned long *readbytes
423) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000424 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000425 unsigned long toread = 0;
Linus Walleijd6a49972006-05-02 08:24:54 +0000426 int result = 0;
Linus Walleij99ed83c2007-01-02 18:46:02 +0000427 unsigned long curread = 0;
428 unsigned long written;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000429 unsigned char *bytes;
Linus Walleij99ed83c2007-01-02 18:46:02 +0000430
431 // This is the largest block we'll need to read in.
Linus Walleij784ac3f2006-12-29 10:36:51 +0000432 bytes = malloc(CONTEXT_BLOCK_SIZE);
Linus Walleijd6a49972006-05-02 08:24:54 +0000433 while (curread < size) {
434 toread = size - curread;
Richard Low43fdb882006-09-06 16:19:05 +0000435 if (toread > CONTEXT_BLOCK_SIZE)
436 toread = CONTEXT_BLOCK_SIZE;
Richard Lowb89ea942007-01-02 11:47:19 +0000437 else if (toread > ptp_usb->outep_maxpacket)
438 toread -= toread % ptp_usb->outep_maxpacket;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000439
440 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, (char*)bytes, toread, ptpcam_usb_timeout);
Linus Walleijd6a49972006-05-02 08:24:54 +0000441 if (result == 0) {
Linus Walleij784ac3f2006-12-29 10:36:51 +0000442 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, (char*)bytes, toread, ptpcam_usb_timeout);
Linus Walleijd6a49972006-05-02 08:24:54 +0000443 }
444 if (result < 0)
Richard Low43fdb882006-09-06 16:19:05 +0000445 return PTP_ERROR_IO;
Linus Walleije78de6d2006-10-31 14:46:36 +0000446#ifdef ENABLE_USB_BULK_DEBUG
447 printf("<==USB IN\n");
Linus Walleij784ac3f2006-12-29 10:36:51 +0000448 data_dump_ascii (stdout,bytes,result,16);
Linus Walleije78de6d2006-10-31 14:46:36 +0000449#endif
Linus Walleij784ac3f2006-12-29 10:36:51 +0000450 handler->putfunc (NULL, handler->private, result, bytes, &written);
Linus Walleijd6a49972006-05-02 08:24:54 +0000451 curread += result;
452 if (result < toread) /* short reads are common */
453 break;
454 }
Linus Walleij784ac3f2006-12-29 10:36:51 +0000455 if (readbytes) *readbytes = curread;
456 free (bytes);
Linus Walleijee73ef22006-08-27 19:56:00 +0000457
458 // Increase counters, call callback
459 if (ptp_usb->callback_active) {
460 ptp_usb->current_transfer_complete += curread;
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000461 if (ptp_usb->current_transfer_complete > ptp_usb->current_transfer_total) {
462 // Fishy... but some commands have unpredictable lengths.
463 // send last update and disable callback.
464 ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total;
465 ptp_usb->callback_active = 0;
466 }
Linus Walleijee73ef22006-08-27 19:56:00 +0000467 if (ptp_usb->current_transfer_callback != NULL) {
468 (void) ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete,
469 ptp_usb->current_transfer_total,
470 ptp_usb->current_transfer_callback_data);
471 }
472 }
473
Linus Walleijd6a49972006-05-02 08:24:54 +0000474 if (result > 0) {
Linus Walleijd6a49972006-05-02 08:24:54 +0000475 return (PTP_RC_OK);
476 } else {
477 return PTP_ERROR_IO;
478 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000479}
480
Linus Walleijb02a0662006-04-25 08:05:09 +0000481static short
Linus Walleij784ac3f2006-12-29 10:36:51 +0000482ptp_write_func (
483 unsigned long size,
484 PTPDataHandler *handler,
485 void *data,
486 unsigned long *written
487) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000488 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000489 unsigned long towrite = 0;
Linus Walleijd6a49972006-05-02 08:24:54 +0000490 int result = 0;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000491 unsigned long curwrite = 0;
492 unsigned char *bytes;
Linus Walleij99ed83c2007-01-02 18:46:02 +0000493
494 // This is the largest block we'll need to read in.
Linus Walleij784ac3f2006-12-29 10:36:51 +0000495 bytes = malloc(CONTEXT_BLOCK_SIZE);
496 if (!bytes) return PTP_ERROR_IO;
Linus Walleijd6a49972006-05-02 08:24:54 +0000497 while (curwrite < size) {
498 towrite = size-curwrite;
Richard Low43fdb882006-09-06 16:19:05 +0000499 if (towrite > CONTEXT_BLOCK_SIZE)
500 towrite = CONTEXT_BLOCK_SIZE;
Richard Low021421e2007-01-01 18:08:57 +0000501 else
502 if (towrite > ptp_usb->outep_maxpacket && towrite % ptp_usb->outep_maxpacket != 0)
503 towrite -= towrite % ptp_usb->outep_maxpacket;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000504 handler->getfunc (NULL, handler->private,towrite,bytes,&towrite);
505 result = USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char*)bytes,towrite,ptpcam_usb_timeout);
Linus Walleije78de6d2006-10-31 14:46:36 +0000506#ifdef ENABLE_USB_BULK_DEBUG
507 printf("USB OUT==>\n");
Richard Lowedd61832006-12-30 12:38:18 +0000508 data_dump_ascii (stdout,bytes,towrite,16);
Linus Walleije78de6d2006-10-31 14:46:36 +0000509#endif
Linus Walleijd6a49972006-05-02 08:24:54 +0000510 if (result < 0)
Richard Low43fdb882006-09-06 16:19:05 +0000511 return PTP_ERROR_IO;
Linus Walleijd6a49972006-05-02 08:24:54 +0000512 curwrite += result;
513 if (result < towrite) /* short writes happen */
514 break;
515 }
Linus Walleij784ac3f2006-12-29 10:36:51 +0000516 free (bytes);
517 if (written) *written = curwrite;
Linus Walleijd214b9b2006-08-26 22:08:37 +0000518
519 // Increase counters, call callback
520 if (ptp_usb->callback_active) {
Linus Walleij4af6fbe2006-08-27 09:33:52 +0000521 ptp_usb->current_transfer_complete += curwrite;
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000522 if (ptp_usb->current_transfer_complete > ptp_usb->current_transfer_total) {
523 // Fishy... but some commands have unpredictable lengths.
524 // send last update and disable callback.
525 ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total;
526 ptp_usb->callback_active = 0;
527 }
Linus Walleijd214b9b2006-08-26 22:08:37 +0000528 if (ptp_usb->current_transfer_callback != NULL) {
529 (void) ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete,
530 ptp_usb->current_transfer_total,
531 ptp_usb->current_transfer_callback_data);
532 }
Linus Walleij80d134a2006-08-22 21:41:37 +0000533 }
Linus Walleijd214b9b2006-08-26 22:08:37 +0000534
535 // If this is the last transfer (callbacks only active if this function called repeatedly with
536 // new data, otherwise this is a single large transaction which ends here).
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000537 // a request and the bulk send header.
538 if (!ptp_usb->callback_active) {
Linus Walleijd214b9b2006-08-26 22:08:37 +0000539 // Then terminate an even packet boundary write with a zero length packet
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000540 if ((size % ptp_usb->outep_maxpacket) == 0) {
Richard Low021421e2007-01-01 18:08:57 +0000541#ifdef ENABLE_USB_BULK_DEBUG
542 printf("USB OUT==>\n");
543 printf("Zero Write\n");
544#endif
Linus Walleijd214b9b2006-08-26 22:08:37 +0000545 result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)"x",0,ptpcam_usb_timeout);
546 }
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000547 } else if (ptp_usb->current_transfer_complete == ptp_usb->current_transfer_total) {
548 // This is the amount actually transfered in this large transaction.
549 uint64_t actual_xfer_size = ptp_usb->current_transfer_total - 2*PTP_USB_BULK_HDR_LEN;
550
551 if ((actual_xfer_size % ptp_usb->outep_maxpacket) == 0) {
Richard Low021421e2007-01-01 18:08:57 +0000552#ifdef ENABLE_USB_BULK_DEBUG
553 printf("USB OUT==>\n");
554 printf("Zero Write\n");
555#endif
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000556 result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)"x",0,ptpcam_usb_timeout);
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000557 }
558 // Set as complete and disable callback, just as good.
559 // This also blocks callbacks from the following response command.
560 if (ptp_usb->current_transfer_callback != NULL) {
561 (void) ptp_usb->current_transfer_callback(ptp_usb->current_transfer_total, // Both total = 100%
562 ptp_usb->current_transfer_total, // Both total = 100%
563 ptp_usb->current_transfer_callback_data);
564 }
565 ptp_usb->callback_active = 0;
Linus Walleijd214b9b2006-08-26 22:08:37 +0000566 }
567
Linus Walleijd6a49972006-05-02 08:24:54 +0000568 if (result < 0)
569 return PTP_ERROR_IO;
570 return PTP_RC_OK;
Linus Walleijb02a0662006-04-25 08:05:09 +0000571}
572
Linus Walleijd6a49972006-05-02 08:24:54 +0000573// This is a bit hackish at the moment. I wonder if it even works.
Linus Walleij784ac3f2006-12-29 10:36:51 +0000574static short ptp_check_int (
575 unsigned long size, PTPDataHandler *handler,void *data,
576 unsigned long *readbytes
577) {
Linus Walleijd6a49972006-05-02 08:24:54 +0000578 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleijb02a0662006-04-25 08:05:09 +0000579 int result;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000580 unsigned char bytes[64];
581
582 if (size>64) return PTP_ERROR_IO;
Linus Walleijb02a0662006-04-25 08:05:09 +0000583
584 result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)bytes,size,ptpcam_usb_timeout);
585 if (result==0)
586 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *) bytes, size, ptpcam_usb_timeout);
587 if (result >= 0) {
Linus Walleij784ac3f2006-12-29 10:36:51 +0000588 handler->putfunc (NULL, handler->private, result, bytes, readbytes);
Linus Walleijb02a0662006-04-25 08:05:09 +0000589 return (PTP_RC_OK);
590 } else {
591 return PTP_ERROR_IO;
592 }
593}
594
Linus Walleij9eb3d312006-08-04 19:25:59 +0000595static int init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000596{
Linus Walleijd6a49972006-05-02 08:24:54 +0000597 usb_dev_handle *device_handle;
598
599 params->write_func=ptp_write_func;
600 params->read_func=ptp_read_func;
601 params->check_int_func=ptp_check_int;
602 params->check_int_fast_func=ptp_check_int;
603 params->error_func=NULL;
604 params->debug_func=NULL;
605 params->sendreq_func=ptp_usb_sendreq;
606 params->senddata_func=ptp_usb_senddata;
607 params->getresp_func=ptp_usb_getresp;
608 params->getdata_func=ptp_usb_getdata;
609 params->data=ptp_usb;
610 params->transaction_id=0;
611 params->byteorder = PTP_DL_LE;
612
Linus Walleij0ed2a9f2006-05-04 05:31:34 +0000613 if ((device_handle = usb_open(dev))){
Linus Walleijd6a49972006-05-02 08:24:54 +0000614 if (!device_handle) {
615 perror("usb_open()");
Linus Walleij9eb3d312006-08-04 19:25:59 +0000616 return -1;
Linus Walleijd6a49972006-05-02 08:24:54 +0000617 }
Linus Walleij0ed2a9f2006-05-04 05:31:34 +0000618 ptp_usb->handle = device_handle;
Linus Walleij501ba4d2006-10-16 06:17:04 +0000619#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
620 /*
621 * If this device is known to be wrongfully claimed by other kernel
622 * drivers (such as mass storage), then try to unload it to make it
623 * accessible from user space.
624 */
625 if (ptp_usb->device_flags & DEVICE_FLAG_UNLOAD_DRIVER) {
626 if (usb_detach_kernel_driver_np(device_handle, dev->config->interface->altsetting->bInterfaceNumber)) {
Linus Walleij7beba572006-11-29 08:56:12 +0000627 // Totally ignore this error!
628 // perror("usb_detach_kernel_driver_np()");
Linus Walleij501ba4d2006-10-16 06:17:04 +0000629 }
630 }
631#endif
Linus Walleijeac1e002006-11-30 22:06:02 +0000632#ifdef __WIN32__
Linus Walleij99ed83c2007-01-02 18:46:02 +0000633 // Only needed on Windows, and cause problems on other platforms.
Linus Walleij7beba572006-11-29 08:56:12 +0000634 if (usb_set_configuration(device_handle, dev->config->bConfigurationValue)) {
635 perror("usb_set_configuration()");
636 return -1;
637 }
Linus Walleijeac1e002006-11-30 22:06:02 +0000638#endif
Linus Walleijef5cca92006-05-05 07:19:08 +0000639 if (usb_claim_interface(device_handle, dev->config->interface->altsetting->bInterfaceNumber)) {
Linus Walleij0ed2a9f2006-05-04 05:31:34 +0000640 perror("usb_claim_interface()");
Linus Walleij9eb3d312006-08-04 19:25:59 +0000641 return -1;
Linus Walleij0ed2a9f2006-05-04 05:31:34 +0000642 }
Linus Walleijc6210fb2006-05-08 11:11:41 +0000643 ptp_usb->interface = dev->config->interface->altsetting->bInterfaceNumber;
Linus Walleijd6a49972006-05-02 08:24:54 +0000644 }
Linus Walleij9eb3d312006-08-04 19:25:59 +0000645 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000646}
647
Linus Walleijd6a49972006-05-02 08:24:54 +0000648static void clear_stall(PTP_USB* ptp_usb)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000649{
Linus Walleijd6a49972006-05-02 08:24:54 +0000650 uint16_t status=0;
651 int ret;
652
653 /* check the inep status */
Linus Walleij1fd2d272006-05-08 09:22:01 +0000654 ret = usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status);
Linus Walleijd6a49972006-05-02 08:24:54 +0000655 if (ret<0) perror ("inep: usb_get_endpoint_status()");
656 /* and clear the HALT condition if happend */
657 else if (status) {
658 printf("Resetting input pipe!\n");
659 ret=usb_clear_stall_feature(ptp_usb,ptp_usb->inep);
660 /*usb_clear_halt(ptp_usb->handle,ptp_usb->inep); */
661 if (ret<0)perror ("usb_clear_stall_feature()");
662 }
663 status=0;
664
665 /* check the outep status */
666 ret=usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status);
667 if (ret<0) perror ("outep: usb_get_endpoint_status()");
668 /* and clear the HALT condition if happend */
669 else if (status) {
670 printf("Resetting output pipe!\n");
671 ret=usb_clear_stall_feature(ptp_usb,ptp_usb->outep);
672 /*usb_clear_halt(ptp_usb->handle,ptp_usb->outep); */
673 if (ret<0)perror ("usb_clear_stall_feature()");
674 }
675
676 /*usb_clear_halt(ptp_usb->handle,ptp_usb->intep); */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000677}
678
Linus Walleijd6a49972006-05-02 08:24:54 +0000679static void close_usb(PTP_USB* ptp_usb, uint8_t interfaceNumber)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000680{
Linus Walleijd6a49972006-05-02 08:24:54 +0000681 clear_stall(ptp_usb);
682 // Added to clear some stuff on the OUT endpoint
683 // TODO: is this good on the Mac too?
684 usb_resetep(ptp_usb->handle, ptp_usb->outep);
685 usb_release_interface(ptp_usb->handle, interfaceNumber);
686 // Brutally reset device
687 // TODO: is this good on the Mac too?
688 usb_reset(ptp_usb->handle);
689 usb_close(ptp_usb->handle);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000690}
691
692
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000693/*
694 find_device() returns the pointer to a usb_device structure matching
695 given busn, devicen numbers. If any or both of arguments are 0 then the
696 first matching PTP device structure is returned.
697 */
Linus Walleijd6a49972006-05-02 08:24:54 +0000698static struct usb_device* find_device (int busn, int devn, short force)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000699{
Linus Walleijd6a49972006-05-02 08:24:54 +0000700 struct usb_bus *bus;
701 struct usb_device *dev;
702
703 bus=init_usb();
704 for (; bus; bus = bus->next)
705 for (dev = bus->devices; dev; dev = dev->next)
706 /* somtimes dev->config is null, not sure why... */
707 if (dev->config != NULL)
708 if (dev->descriptor.bDeviceClass!=USB_CLASS_HUB)
709 {
710 int curbusn, curdevn;
711
712 curbusn=strtol(bus->dirname,NULL,10);
713 curdevn=strtol(dev->filename,NULL,10);
714
715 if (devn==0) {
716 if (busn==0) return dev;
717 if (curbusn==busn) return dev;
718 } else {
719 if ((busn==0)&&(curdevn==devn)) return dev;
720 if ((curbusn==busn)&&(curdevn==devn)) return dev;
721 }
722 }
723 return NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000724}
725
Linus Walleij6946ac52006-03-21 06:51:22 +0000726/**
727 * This function scans through the device list to see if there are
728 * some devices to connect to. The table at the top of this file is
729 * used to identify potential devices.
730 */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000731uint16_t connect_first_device(PTPParams *params, PTP_USB *ptp_usb, uint8_t *interfaceNumber)
732{
Linus Walleij6946ac52006-03-21 06:51:22 +0000733 struct usb_bus *bus;
734 struct usb_device *dev;
Linus Walleij1fd2d272006-05-08 09:22:01 +0000735 struct usb_endpoint_descriptor *ep;
736 PTPDeviceInfo deviceinfo;
737 uint16_t ret=0;
738 int n;
Linus Walleij6946ac52006-03-21 06:51:22 +0000739
Linus Walleij0558ac52006-09-07 06:55:03 +0000740 // Reset device flags
741 ptp_usb->device_flags = DEVICE_FLAG_NONE;
Linus Walleij1fd2d272006-05-08 09:22:01 +0000742 // First try to locate the device using the extended
743 // device descriptor.
744 dev = probe_usb_bus_for_mtp_devices();
745
746 if (dev != NULL) {
747 int i;
748
749 // See if we can find the name of this beast
750 for (i = 0; i < mtp_device_table_size; i++) {
751 LIBMTP_device_entry_t const *mtp_device = &mtp_device_table[i];
752 if (dev->descriptor.idVendor == mtp_device->vendor_id &&
753 dev->descriptor.idProduct == mtp_device->product_id ) {
754 printf("Autodetected device \"%s\" (VID=%04x,PID=%04x) is known.\n",
755 mtp_device->name, dev->descriptor.idVendor, dev->descriptor.idProduct);
Linus Walleij0558ac52006-09-07 06:55:03 +0000756 ptp_usb->device_flags = mtp_device->device_flags;
Linus Walleij1fd2d272006-05-08 09:22:01 +0000757 break;
758 }
759 }
760 if (i == mtp_device_table_size) {
761 printf("Autodetected device with VID=%04x and PID=%04x is UNKNOWN.\n",
762 dev->descriptor.idVendor, dev->descriptor.idProduct);
763 printf("Please report this VID/PID and the device model name etc to the\n");
764 printf("libmtp development team!\n");
765 }
766 }
767
768 // If autodetection fails, scan the bus for well known devices.
769 if (dev == NULL) {
770 bus = init_usb();
771 for (; bus; bus = bus->next) {
772 for (dev = bus->devices; dev; dev = dev->next) {
773 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000774
Linus Walleij1fd2d272006-05-08 09:22:01 +0000775 // Loop over the list of supported devices
776 for (i = 0; i < mtp_device_table_size; i++) {
777 LIBMTP_device_entry_t const *mtp_device = &mtp_device_table[i];
Linus Walleij6946ac52006-03-21 06:51:22 +0000778
Linus Walleij1fd2d272006-05-08 09:22:01 +0000779 if (dev->descriptor.bDeviceClass != USB_CLASS_HUB &&
780 dev->descriptor.idVendor == mtp_device->vendor_id &&
781 dev->descriptor.idProduct == mtp_device->product_id ) {
782
783 printf("Found non-autodetected device \"%s\" on USB bus...\n", mtp_device->name);
Linus Walleij0558ac52006-09-07 06:55:03 +0000784 ptp_usb->device_flags = mtp_device->device_flags;
Linus Walleijd3fdd972006-05-30 15:51:37 +0000785 goto next_step;
Linus Walleij1fd2d272006-05-08 09:22:01 +0000786
Linus Walleijb02a0662006-04-25 08:05:09 +0000787 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000788 }
Linus Walleij6946ac52006-03-21 06:51:22 +0000789 }
790 }
791 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000792
Linus Walleijd3fdd972006-05-30 15:51:37 +0000793next_step:
Linus Walleij1fd2d272006-05-08 09:22:01 +0000794 // Still not found any?
795 if (dev == NULL) {
796 return PTP_CD_RC_NO_DEVICES;
797 }
798
Linus Walleij0558ac52006-09-07 06:55:03 +0000799 // Found a device, then assign endpoints to ptp_usb...
Linus Walleij1fd2d272006-05-08 09:22:01 +0000800 ep = dev->config->interface->altsetting->endpoint;
801 n = dev->config->interface->altsetting->bNumEndpoints;
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000802 find_endpoints(dev, &ptp_usb->inep, &ptp_usb->inep_maxpacket,
803 &ptp_usb->outep, &ptp_usb->outep_maxpacket, &ptp_usb->intep);
Linus Walleij1fd2d272006-05-08 09:22:01 +0000804
805 // printf("Init PTP USB...\n");
Linus Walleij9eb3d312006-08-04 19:25:59 +0000806 if (init_ptp_usb(params, ptp_usb, dev) < 0) {
807 return PTP_CD_RC_ERROR_CONNECTING;
808 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000809
810 ret = ptp_opensession(params,1);
Linus Walleij48a2d462006-11-19 14:07:59 +0000811
812 // This works in situations where previous bad applications have not used LIBMTP_Release_Device on exit
813 if (ret == PTP_ERROR_IO) {
814 printf("%s\n","PTP ERROR IO: Trying again after resetting USB");
815 // printf("%s\n","Closing USB interface...");
816 close_usb(ptp_usb,dev->config->interface->altsetting->bInterfaceNumber);
817 // printf("%s\n","Init PTP USB...");
818 if (init_ptp_usb(params, ptp_usb, dev) < 0) {
819 return PTP_CD_RC_ERROR_CONNECTING;
820 }
821
822 ret = ptp_opensession(params,1);
823 }
824
Linus Walleij1fd2d272006-05-08 09:22:01 +0000825 // printf("Session open (%d)...\n", ret);
826 if (ret == PTP_RC_InvalidTransactionID) {
827 params->transaction_id += 10;
828 ret = ptp_opensession(params,1);
829 }
830 if (ret != PTP_RC_SessionAlreadyOpened && ret != PTP_RC_OK) {
831 printf("Could not open session! (Return code %d)\n Try to reset the device.\n", ret);
832 usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber);
833 }
834
835 // It is actually permissible to call this before opening the session
836 ret = ptp_getdeviceinfo(params, &deviceinfo);
837 if (ret != PTP_RC_OK) {
838 printf("Could not get device info!\n");
839 usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber);
840 return PTP_CD_RC_ERROR_CONNECTING;
841 }
842
843 // we're connected, return OK
844 *interfaceNumber = dev->config->interface->altsetting->bInterfaceNumber;
845 return PTP_CD_RC_CONNECTED;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000846}
847
Linus Walleijd6a49972006-05-02 08:24:54 +0000848static void find_endpoints(struct usb_device *dev, int* inep, int* inep_maxpacket, int* outep, int *outep_maxpacket, int* intep)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000849{
Linus Walleijd6a49972006-05-02 08:24:54 +0000850 int i,n;
851 struct usb_endpoint_descriptor *ep;
852
853 ep = dev->config->interface->altsetting->endpoint;
854 n=dev->config->interface->altsetting->bNumEndpoints;
855
856 for (i=0;i<n;i++) {
857 if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_BULK) {
858 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
859 USB_ENDPOINT_DIR_MASK)
860 {
861 *inep=ep[i].bEndpointAddress;
862 *inep_maxpacket=ep[i].wMaxPacketSize;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000863 }
Linus Walleijd6a49972006-05-02 08:24:54 +0000864 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==0)
865 {
866 *outep=ep[i].bEndpointAddress;
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000867 *outep_maxpacket=ep[i].wMaxPacketSize;
Linus Walleijd6a49972006-05-02 08:24:54 +0000868 }
869 } else if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_INTERRUPT){
870 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
871 USB_ENDPOINT_DIR_MASK)
872 {
873 *intep=ep[i].bEndpointAddress;
874 }
875 }
876 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000877}
878
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000879int open_device (int busn, int devn, short force, PTP_USB *ptp_usb, PTPParams *params, struct usb_device **dev)
880{
881#ifdef DEBUG
Linus Walleijd6a49972006-05-02 08:24:54 +0000882 printf("dev %i\tbus %i\n",devn,busn);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000883#endif
Linus Walleijd6a49972006-05-02 08:24:54 +0000884
885 *dev=find_device(busn,devn,force);
886 if (*dev==NULL) {
887 fprintf(stderr,"could not find any device matching given "
888 "bus/dev numbers\n");
889 exit(-1);
890 }
891 find_endpoints(*dev,&ptp_usb->inep,&ptp_usb->inep_maxpacket,&ptp_usb->outep,&ptp_usb->outep_maxpacket,&ptp_usb->intep);
892
Linus Walleij9eb3d312006-08-04 19:25:59 +0000893 if (init_ptp_usb(params, ptp_usb, *dev) < 0) {
894 return -1;
895 }
Linus Walleijd6a49972006-05-02 08:24:54 +0000896 if (ptp_opensession(params,1)!=PTP_RC_OK) {
897 fprintf(stderr,"ERROR: Could not open session!\n");
898 close_usb(ptp_usb, (*dev)->config->interface->altsetting->bInterfaceNumber);
899 return -1;
900 }
901 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000902}
903
904void close_device (PTP_USB *ptp_usb, PTPParams *params, uint8_t interfaceNumber)
905{
Linus Walleijd6a49972006-05-02 08:24:54 +0000906 if (ptp_closesession(params)!=PTP_RC_OK)
907 fprintf(stderr,"ERROR: Could not close session!\n");
908 close_usb(ptp_usb, interfaceNumber);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000909}
910
Linus Walleijd6a49972006-05-02 08:24:54 +0000911static int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000912{
Linus Walleijd6a49972006-05-02 08:24:54 +0000913
914 return (usb_control_msg(ptp_usb->handle,
915 USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, USB_FEATURE_HALT,
916 ep, NULL, 0, 3000));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000917}
918
Linus Walleijd6a49972006-05-02 08:24:54 +0000919static int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000920{
Linus Walleijd6a49972006-05-02 08:24:54 +0000921 return (usb_control_msg(ptp_usb->handle,
922 USB_DP_DTH|USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS,
923 USB_FEATURE_HALT, ep, (char *)status, 2, 3000));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000924}