blob: b77cddf48b40331b785e7e57b8795b7a2edb5488 [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 Walleijd6a49972006-05-02 08:24:54 +0000401// Based on same function on library.c in libgphoto2
Richard Low43fdb882006-09-06 16:19:05 +0000402#define CONTEXT_BLOCK_SIZE 0x100000
Linus Walleijb02a0662006-04-25 08:05:09 +0000403static short
Linus Walleij784ac3f2006-12-29 10:36:51 +0000404ptp_read_func (
405 unsigned long size, PTPDataHandler *handler,void *data,
406 unsigned long *readbytes
407) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000408 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000409 unsigned long toread = 0;
Linus Walleijd6a49972006-05-02 08:24:54 +0000410 int result = 0;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000411 unsigned long curread = 0, written;
412 unsigned char *bytes;
Linus Walleijd6a49972006-05-02 08:24:54 +0000413 /* Split into small blocks. Too large blocks (>1x MB) would
414 * timeout.
415 */
Linus Walleij784ac3f2006-12-29 10:36:51 +0000416 bytes = malloc(CONTEXT_BLOCK_SIZE);
Linus Walleijd6a49972006-05-02 08:24:54 +0000417 while (curread < size) {
418 toread = size - curread;
Richard Low43fdb882006-09-06 16:19:05 +0000419 if (toread > CONTEXT_BLOCK_SIZE)
420 toread = CONTEXT_BLOCK_SIZE;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000421
422 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, (char*)bytes, toread, ptpcam_usb_timeout);
Linus Walleijd6a49972006-05-02 08:24:54 +0000423 if (result == 0) {
Linus Walleij784ac3f2006-12-29 10:36:51 +0000424 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep, (char*)bytes, toread, ptpcam_usb_timeout);
Linus Walleijd6a49972006-05-02 08:24:54 +0000425 }
426 if (result < 0)
Richard Low43fdb882006-09-06 16:19:05 +0000427 return PTP_ERROR_IO;
Linus Walleije78de6d2006-10-31 14:46:36 +0000428#ifdef ENABLE_USB_BULK_DEBUG
429 printf("<==USB IN\n");
Linus Walleij784ac3f2006-12-29 10:36:51 +0000430 data_dump_ascii (stdout,bytes,result,16);
Linus Walleije78de6d2006-10-31 14:46:36 +0000431#endif
Linus Walleij784ac3f2006-12-29 10:36:51 +0000432 handler->putfunc (NULL, handler->private, result, bytes, &written);
Linus Walleijd6a49972006-05-02 08:24:54 +0000433 curread += result;
434 if (result < toread) /* short reads are common */
435 break;
436 }
Linus Walleij784ac3f2006-12-29 10:36:51 +0000437 if (readbytes) *readbytes = curread;
438 free (bytes);
Linus Walleijee73ef22006-08-27 19:56:00 +0000439
440 // Increase counters, call callback
441 if (ptp_usb->callback_active) {
442 ptp_usb->current_transfer_complete += curread;
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000443 if (ptp_usb->current_transfer_complete > ptp_usb->current_transfer_total) {
444 // Fishy... but some commands have unpredictable lengths.
445 // send last update and disable callback.
446 ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total;
447 ptp_usb->callback_active = 0;
448 }
Linus Walleijee73ef22006-08-27 19:56:00 +0000449 if (ptp_usb->current_transfer_callback != NULL) {
450 (void) ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete,
451 ptp_usb->current_transfer_total,
452 ptp_usb->current_transfer_callback_data);
453 }
454 }
455
Linus Walleijd6a49972006-05-02 08:24:54 +0000456 if (result > 0) {
Linus Walleijd6a49972006-05-02 08:24:54 +0000457 return (PTP_RC_OK);
458 } else {
459 return PTP_ERROR_IO;
460 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000461}
462
Linus Walleijd6a49972006-05-02 08:24:54 +0000463// Based on same function on library.c in libgphoto2
Linus Walleijb02a0662006-04-25 08:05:09 +0000464static short
Linus Walleij784ac3f2006-12-29 10:36:51 +0000465ptp_write_func (
466 unsigned long size,
467 PTPDataHandler *handler,
468 void *data,
469 unsigned long *written
470) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000471 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000472 unsigned long towrite = 0;
Linus Walleijd6a49972006-05-02 08:24:54 +0000473 int result = 0;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000474 unsigned long curwrite = 0;
475 unsigned char *bytes;
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000476
Linus Walleij784ac3f2006-12-29 10:36:51 +0000477 bytes = malloc(CONTEXT_BLOCK_SIZE);
478 if (!bytes) return PTP_ERROR_IO;
Linus Walleijd6a49972006-05-02 08:24:54 +0000479 /*
480 * gp_port_write returns (in case of success) the number of bytes
Linus Walleijd214b9b2006-08-26 22:08:37 +0000481 * written. Too large blocks (>5x MB) could timeout.
Linus Walleijd6a49972006-05-02 08:24:54 +0000482 */
483 while (curwrite < size) {
484 towrite = size-curwrite;
Richard Low43fdb882006-09-06 16:19:05 +0000485 if (towrite > CONTEXT_BLOCK_SIZE)
486 towrite = CONTEXT_BLOCK_SIZE;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000487 handler->getfunc (NULL, handler->private,towrite,bytes,&towrite);
488 result = USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char*)bytes,towrite,ptpcam_usb_timeout);
Linus Walleije78de6d2006-10-31 14:46:36 +0000489#ifdef ENABLE_USB_BULK_DEBUG
490 printf("USB OUT==>\n");
Richard Lowedd61832006-12-30 12:38:18 +0000491 data_dump_ascii (stdout,bytes,towrite,16);
Linus Walleije78de6d2006-10-31 14:46:36 +0000492#endif
Linus Walleijd6a49972006-05-02 08:24:54 +0000493 if (result < 0)
Richard Low43fdb882006-09-06 16:19:05 +0000494 return PTP_ERROR_IO;
Linus Walleijd6a49972006-05-02 08:24:54 +0000495 curwrite += result;
496 if (result < towrite) /* short writes happen */
497 break;
498 }
Linus Walleij784ac3f2006-12-29 10:36:51 +0000499 free (bytes);
500 if (written) *written = curwrite;
Linus Walleijd214b9b2006-08-26 22:08:37 +0000501
502 // Increase counters, call callback
503 if (ptp_usb->callback_active) {
Linus Walleij4af6fbe2006-08-27 09:33:52 +0000504 ptp_usb->current_transfer_complete += curwrite;
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000505 if (ptp_usb->current_transfer_complete > ptp_usb->current_transfer_total) {
506 // Fishy... but some commands have unpredictable lengths.
507 // send last update and disable callback.
508 ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total;
509 ptp_usb->callback_active = 0;
510 }
Linus Walleijd214b9b2006-08-26 22:08:37 +0000511 if (ptp_usb->current_transfer_callback != NULL) {
512 (void) ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete,
513 ptp_usb->current_transfer_total,
514 ptp_usb->current_transfer_callback_data);
515 }
Linus Walleij80d134a2006-08-22 21:41:37 +0000516 }
Linus Walleijd214b9b2006-08-26 22:08:37 +0000517
518 // If this is the last transfer (callbacks only active if this function called repeatedly with
519 // new data, otherwise this is a single large transaction which ends here).
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000520 // a request and the bulk send header.
521 if (!ptp_usb->callback_active) {
Linus Walleijd214b9b2006-08-26 22:08:37 +0000522 // Then terminate an even packet boundary write with a zero length packet
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000523 if ((size % ptp_usb->outep_maxpacket) == 0) {
Linus Walleijd214b9b2006-08-26 22:08:37 +0000524 result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)"x",0,ptpcam_usb_timeout);
525 }
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000526 } else if (ptp_usb->current_transfer_complete == ptp_usb->current_transfer_total) {
527 // This is the amount actually transfered in this large transaction.
528 uint64_t actual_xfer_size = ptp_usb->current_transfer_total - 2*PTP_USB_BULK_HDR_LEN;
529
530 if ((actual_xfer_size % ptp_usb->outep_maxpacket) == 0) {
531 result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)"x",0,ptpcam_usb_timeout);
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000532 }
533 // Set as complete and disable callback, just as good.
534 // This also blocks callbacks from the following response command.
535 if (ptp_usb->current_transfer_callback != NULL) {
536 (void) ptp_usb->current_transfer_callback(ptp_usb->current_transfer_total, // Both total = 100%
537 ptp_usb->current_transfer_total, // Both total = 100%
538 ptp_usb->current_transfer_callback_data);
539 }
540 ptp_usb->callback_active = 0;
Linus Walleijd214b9b2006-08-26 22:08:37 +0000541 }
542
Linus Walleijd6a49972006-05-02 08:24:54 +0000543 if (result < 0)
544 return PTP_ERROR_IO;
545 return PTP_RC_OK;
Linus Walleijb02a0662006-04-25 08:05:09 +0000546}
547
Linus Walleijd6a49972006-05-02 08:24:54 +0000548// This is a bit hackish at the moment. I wonder if it even works.
Linus Walleij784ac3f2006-12-29 10:36:51 +0000549static short ptp_check_int (
550 unsigned long size, PTPDataHandler *handler,void *data,
551 unsigned long *readbytes
552) {
Linus Walleijd6a49972006-05-02 08:24:54 +0000553 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleijb02a0662006-04-25 08:05:09 +0000554 int result;
Linus Walleij784ac3f2006-12-29 10:36:51 +0000555 unsigned char bytes[64];
556
557 if (size>64) return PTP_ERROR_IO;
Linus Walleijb02a0662006-04-25 08:05:09 +0000558
559 result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)bytes,size,ptpcam_usb_timeout);
560 if (result==0)
561 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *) bytes, size, ptpcam_usb_timeout);
562 if (result >= 0) {
Linus Walleij784ac3f2006-12-29 10:36:51 +0000563 handler->putfunc (NULL, handler->private, result, bytes, readbytes);
Linus Walleijb02a0662006-04-25 08:05:09 +0000564 return (PTP_RC_OK);
565 } else {
566 return PTP_ERROR_IO;
567 }
568}
569
Linus Walleij9eb3d312006-08-04 19:25:59 +0000570static int init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000571{
Linus Walleijd6a49972006-05-02 08:24:54 +0000572 usb_dev_handle *device_handle;
573
574 params->write_func=ptp_write_func;
575 params->read_func=ptp_read_func;
576 params->check_int_func=ptp_check_int;
577 params->check_int_fast_func=ptp_check_int;
578 params->error_func=NULL;
579 params->debug_func=NULL;
580 params->sendreq_func=ptp_usb_sendreq;
581 params->senddata_func=ptp_usb_senddata;
582 params->getresp_func=ptp_usb_getresp;
583 params->getdata_func=ptp_usb_getdata;
584 params->data=ptp_usb;
585 params->transaction_id=0;
586 params->byteorder = PTP_DL_LE;
587
Linus Walleij0ed2a9f2006-05-04 05:31:34 +0000588 if ((device_handle = usb_open(dev))){
Linus Walleijd6a49972006-05-02 08:24:54 +0000589 if (!device_handle) {
590 perror("usb_open()");
Linus Walleij9eb3d312006-08-04 19:25:59 +0000591 return -1;
Linus Walleijd6a49972006-05-02 08:24:54 +0000592 }
Linus Walleij0ed2a9f2006-05-04 05:31:34 +0000593 ptp_usb->handle = device_handle;
Linus Walleij501ba4d2006-10-16 06:17:04 +0000594#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
595 /*
596 * If this device is known to be wrongfully claimed by other kernel
597 * drivers (such as mass storage), then try to unload it to make it
598 * accessible from user space.
599 */
600 if (ptp_usb->device_flags & DEVICE_FLAG_UNLOAD_DRIVER) {
601 if (usb_detach_kernel_driver_np(device_handle, dev->config->interface->altsetting->bInterfaceNumber)) {
Linus Walleij7beba572006-11-29 08:56:12 +0000602 // Totally ignore this error!
603 // perror("usb_detach_kernel_driver_np()");
Linus Walleij501ba4d2006-10-16 06:17:04 +0000604 }
605 }
606#endif
Linus Walleijeac1e002006-11-30 22:06:02 +0000607#ifdef __WIN32__
608 // Only needed on Windows
Linus Walleij7beba572006-11-29 08:56:12 +0000609 if (usb_set_configuration(device_handle, dev->config->bConfigurationValue)) {
610 perror("usb_set_configuration()");
611 return -1;
612 }
Linus Walleijeac1e002006-11-30 22:06:02 +0000613#endif
Linus Walleijef5cca92006-05-05 07:19:08 +0000614 if (usb_claim_interface(device_handle, dev->config->interface->altsetting->bInterfaceNumber)) {
Linus Walleij0ed2a9f2006-05-04 05:31:34 +0000615 perror("usb_claim_interface()");
Linus Walleij9eb3d312006-08-04 19:25:59 +0000616 return -1;
Linus Walleij0ed2a9f2006-05-04 05:31:34 +0000617 }
Linus Walleijc6210fb2006-05-08 11:11:41 +0000618 ptp_usb->interface = dev->config->interface->altsetting->bInterfaceNumber;
Linus Walleijd6a49972006-05-02 08:24:54 +0000619 }
Linus Walleij9eb3d312006-08-04 19:25:59 +0000620 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000621}
622
Linus Walleijd6a49972006-05-02 08:24:54 +0000623static void clear_stall(PTP_USB* ptp_usb)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000624{
Linus Walleijd6a49972006-05-02 08:24:54 +0000625 uint16_t status=0;
626 int ret;
627
628 /* check the inep status */
Linus Walleij1fd2d272006-05-08 09:22:01 +0000629 ret = usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status);
Linus Walleijd6a49972006-05-02 08:24:54 +0000630 if (ret<0) perror ("inep: usb_get_endpoint_status()");
631 /* and clear the HALT condition if happend */
632 else if (status) {
633 printf("Resetting input pipe!\n");
634 ret=usb_clear_stall_feature(ptp_usb,ptp_usb->inep);
635 /*usb_clear_halt(ptp_usb->handle,ptp_usb->inep); */
636 if (ret<0)perror ("usb_clear_stall_feature()");
637 }
638 status=0;
639
640 /* check the outep status */
641 ret=usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status);
642 if (ret<0) perror ("outep: usb_get_endpoint_status()");
643 /* and clear the HALT condition if happend */
644 else if (status) {
645 printf("Resetting output pipe!\n");
646 ret=usb_clear_stall_feature(ptp_usb,ptp_usb->outep);
647 /*usb_clear_halt(ptp_usb->handle,ptp_usb->outep); */
648 if (ret<0)perror ("usb_clear_stall_feature()");
649 }
650
651 /*usb_clear_halt(ptp_usb->handle,ptp_usb->intep); */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000652}
653
Linus Walleijd6a49972006-05-02 08:24:54 +0000654static void close_usb(PTP_USB* ptp_usb, uint8_t interfaceNumber)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000655{
Linus Walleijd6a49972006-05-02 08:24:54 +0000656 clear_stall(ptp_usb);
657 // Added to clear some stuff on the OUT endpoint
658 // TODO: is this good on the Mac too?
659 usb_resetep(ptp_usb->handle, ptp_usb->outep);
660 usb_release_interface(ptp_usb->handle, interfaceNumber);
661 // Brutally reset device
662 // TODO: is this good on the Mac too?
663 usb_reset(ptp_usb->handle);
664 usb_close(ptp_usb->handle);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000665}
666
667
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000668/*
669 find_device() returns the pointer to a usb_device structure matching
670 given busn, devicen numbers. If any or both of arguments are 0 then the
671 first matching PTP device structure is returned.
672 */
Linus Walleijd6a49972006-05-02 08:24:54 +0000673static struct usb_device* find_device (int busn, int devn, short force)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000674{
Linus Walleijd6a49972006-05-02 08:24:54 +0000675 struct usb_bus *bus;
676 struct usb_device *dev;
677
678 bus=init_usb();
679 for (; bus; bus = bus->next)
680 for (dev = bus->devices; dev; dev = dev->next)
681 /* somtimes dev->config is null, not sure why... */
682 if (dev->config != NULL)
683 if (dev->descriptor.bDeviceClass!=USB_CLASS_HUB)
684 {
685 int curbusn, curdevn;
686
687 curbusn=strtol(bus->dirname,NULL,10);
688 curdevn=strtol(dev->filename,NULL,10);
689
690 if (devn==0) {
691 if (busn==0) return dev;
692 if (curbusn==busn) return dev;
693 } else {
694 if ((busn==0)&&(curdevn==devn)) return dev;
695 if ((curbusn==busn)&&(curdevn==devn)) return dev;
696 }
697 }
698 return NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000699}
700
Linus Walleij6946ac52006-03-21 06:51:22 +0000701/**
702 * This function scans through the device list to see if there are
703 * some devices to connect to. The table at the top of this file is
704 * used to identify potential devices.
705 */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000706uint16_t connect_first_device(PTPParams *params, PTP_USB *ptp_usb, uint8_t *interfaceNumber)
707{
Linus Walleij6946ac52006-03-21 06:51:22 +0000708 struct usb_bus *bus;
709 struct usb_device *dev;
Linus Walleij1fd2d272006-05-08 09:22:01 +0000710 struct usb_endpoint_descriptor *ep;
711 PTPDeviceInfo deviceinfo;
712 uint16_t ret=0;
713 int n;
Linus Walleij6946ac52006-03-21 06:51:22 +0000714
Linus Walleij0558ac52006-09-07 06:55:03 +0000715 // Reset device flags
716 ptp_usb->device_flags = DEVICE_FLAG_NONE;
Linus Walleij1fd2d272006-05-08 09:22:01 +0000717 // First try to locate the device using the extended
718 // device descriptor.
719 dev = probe_usb_bus_for_mtp_devices();
720
721 if (dev != NULL) {
722 int i;
723
724 // See if we can find the name of this beast
725 for (i = 0; i < mtp_device_table_size; i++) {
726 LIBMTP_device_entry_t const *mtp_device = &mtp_device_table[i];
727 if (dev->descriptor.idVendor == mtp_device->vendor_id &&
728 dev->descriptor.idProduct == mtp_device->product_id ) {
729 printf("Autodetected device \"%s\" (VID=%04x,PID=%04x) is known.\n",
730 mtp_device->name, dev->descriptor.idVendor, dev->descriptor.idProduct);
Linus Walleij0558ac52006-09-07 06:55:03 +0000731 ptp_usb->device_flags = mtp_device->device_flags;
Linus Walleij1fd2d272006-05-08 09:22:01 +0000732 break;
733 }
734 }
735 if (i == mtp_device_table_size) {
736 printf("Autodetected device with VID=%04x and PID=%04x is UNKNOWN.\n",
737 dev->descriptor.idVendor, dev->descriptor.idProduct);
738 printf("Please report this VID/PID and the device model name etc to the\n");
739 printf("libmtp development team!\n");
740 }
741 }
742
743 // If autodetection fails, scan the bus for well known devices.
744 if (dev == NULL) {
745 bus = init_usb();
746 for (; bus; bus = bus->next) {
747 for (dev = bus->devices; dev; dev = dev->next) {
748 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000749
Linus Walleij1fd2d272006-05-08 09:22:01 +0000750 // Loop over the list of supported devices
751 for (i = 0; i < mtp_device_table_size; i++) {
752 LIBMTP_device_entry_t const *mtp_device = &mtp_device_table[i];
Linus Walleij6946ac52006-03-21 06:51:22 +0000753
Linus Walleij1fd2d272006-05-08 09:22:01 +0000754 if (dev->descriptor.bDeviceClass != USB_CLASS_HUB &&
755 dev->descriptor.idVendor == mtp_device->vendor_id &&
756 dev->descriptor.idProduct == mtp_device->product_id ) {
757
758 printf("Found non-autodetected device \"%s\" on USB bus...\n", mtp_device->name);
Linus Walleij0558ac52006-09-07 06:55:03 +0000759 ptp_usb->device_flags = mtp_device->device_flags;
Linus Walleijd3fdd972006-05-30 15:51:37 +0000760 goto next_step;
Linus Walleij1fd2d272006-05-08 09:22:01 +0000761
Linus Walleijb02a0662006-04-25 08:05:09 +0000762 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000763 }
Linus Walleij6946ac52006-03-21 06:51:22 +0000764 }
765 }
766 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000767
Linus Walleijd3fdd972006-05-30 15:51:37 +0000768next_step:
Linus Walleij1fd2d272006-05-08 09:22:01 +0000769 // Still not found any?
770 if (dev == NULL) {
771 return PTP_CD_RC_NO_DEVICES;
772 }
773
Linus Walleij0558ac52006-09-07 06:55:03 +0000774 // Found a device, then assign endpoints to ptp_usb...
Linus Walleij1fd2d272006-05-08 09:22:01 +0000775 ep = dev->config->interface->altsetting->endpoint;
776 n = dev->config->interface->altsetting->bNumEndpoints;
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000777 find_endpoints(dev, &ptp_usb->inep, &ptp_usb->inep_maxpacket,
778 &ptp_usb->outep, &ptp_usb->outep_maxpacket, &ptp_usb->intep);
Linus Walleij1fd2d272006-05-08 09:22:01 +0000779
780 // printf("Init PTP USB...\n");
Linus Walleij9eb3d312006-08-04 19:25:59 +0000781 if (init_ptp_usb(params, ptp_usb, dev) < 0) {
782 return PTP_CD_RC_ERROR_CONNECTING;
783 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000784
785 ret = ptp_opensession(params,1);
Linus Walleij48a2d462006-11-19 14:07:59 +0000786
787 // This works in situations where previous bad applications have not used LIBMTP_Release_Device on exit
788 if (ret == PTP_ERROR_IO) {
789 printf("%s\n","PTP ERROR IO: Trying again after resetting USB");
790 // printf("%s\n","Closing USB interface...");
791 close_usb(ptp_usb,dev->config->interface->altsetting->bInterfaceNumber);
792 // printf("%s\n","Init PTP USB...");
793 if (init_ptp_usb(params, ptp_usb, dev) < 0) {
794 return PTP_CD_RC_ERROR_CONNECTING;
795 }
796
797 ret = ptp_opensession(params,1);
798 }
799
Linus Walleij1fd2d272006-05-08 09:22:01 +0000800 // printf("Session open (%d)...\n", ret);
801 if (ret == PTP_RC_InvalidTransactionID) {
802 params->transaction_id += 10;
803 ret = ptp_opensession(params,1);
804 }
805 if (ret != PTP_RC_SessionAlreadyOpened && ret != PTP_RC_OK) {
806 printf("Could not open session! (Return code %d)\n Try to reset the device.\n", ret);
807 usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber);
808 }
809
810 // It is actually permissible to call this before opening the session
811 ret = ptp_getdeviceinfo(params, &deviceinfo);
812 if (ret != PTP_RC_OK) {
813 printf("Could not get device info!\n");
814 usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber);
815 return PTP_CD_RC_ERROR_CONNECTING;
816 }
817
818 // we're connected, return OK
819 *interfaceNumber = dev->config->interface->altsetting->bInterfaceNumber;
820 return PTP_CD_RC_CONNECTED;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000821}
822
Linus Walleijd6a49972006-05-02 08:24:54 +0000823static 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 +0000824{
Linus Walleijd6a49972006-05-02 08:24:54 +0000825 int i,n;
826 struct usb_endpoint_descriptor *ep;
827
828 ep = dev->config->interface->altsetting->endpoint;
829 n=dev->config->interface->altsetting->bNumEndpoints;
830
831 for (i=0;i<n;i++) {
832 if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_BULK) {
833 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
834 USB_ENDPOINT_DIR_MASK)
835 {
836 *inep=ep[i].bEndpointAddress;
837 *inep_maxpacket=ep[i].wMaxPacketSize;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000838 }
Linus Walleijd6a49972006-05-02 08:24:54 +0000839 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==0)
840 {
841 *outep=ep[i].bEndpointAddress;
Linus Walleij7f0c72e2006-09-06 13:01:58 +0000842 *outep_maxpacket=ep[i].wMaxPacketSize;
Linus Walleijd6a49972006-05-02 08:24:54 +0000843 }
844 } else if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_INTERRUPT){
845 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
846 USB_ENDPOINT_DIR_MASK)
847 {
848 *intep=ep[i].bEndpointAddress;
849 }
850 }
851 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000852}
853
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000854int open_device (int busn, int devn, short force, PTP_USB *ptp_usb, PTPParams *params, struct usb_device **dev)
855{
856#ifdef DEBUG
Linus Walleijd6a49972006-05-02 08:24:54 +0000857 printf("dev %i\tbus %i\n",devn,busn);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000858#endif
Linus Walleijd6a49972006-05-02 08:24:54 +0000859
860 *dev=find_device(busn,devn,force);
861 if (*dev==NULL) {
862 fprintf(stderr,"could not find any device matching given "
863 "bus/dev numbers\n");
864 exit(-1);
865 }
866 find_endpoints(*dev,&ptp_usb->inep,&ptp_usb->inep_maxpacket,&ptp_usb->outep,&ptp_usb->outep_maxpacket,&ptp_usb->intep);
867
Linus Walleij9eb3d312006-08-04 19:25:59 +0000868 if (init_ptp_usb(params, ptp_usb, *dev) < 0) {
869 return -1;
870 }
Linus Walleijd6a49972006-05-02 08:24:54 +0000871 if (ptp_opensession(params,1)!=PTP_RC_OK) {
872 fprintf(stderr,"ERROR: Could not open session!\n");
873 close_usb(ptp_usb, (*dev)->config->interface->altsetting->bInterfaceNumber);
874 return -1;
875 }
876 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000877}
878
879void close_device (PTP_USB *ptp_usb, PTPParams *params, uint8_t interfaceNumber)
880{
Linus Walleijd6a49972006-05-02 08:24:54 +0000881 if (ptp_closesession(params)!=PTP_RC_OK)
882 fprintf(stderr,"ERROR: Could not close session!\n");
883 close_usb(ptp_usb, interfaceNumber);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000884}
885
Linus Walleijd6a49972006-05-02 08:24:54 +0000886static int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000887{
Linus Walleijd6a49972006-05-02 08:24:54 +0000888
889 return (usb_control_msg(ptp_usb->handle,
890 USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, USB_FEATURE_HALT,
891 ep, NULL, 0, 3000));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000892}
893
Linus Walleijd6a49972006-05-02 08:24:54 +0000894static int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000895{
Linus Walleijd6a49972006-05-02 08:24:54 +0000896 return (usb_control_msg(ptp_usb->handle,
897 USB_DP_DTH|USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS,
898 USB_FEATURE_HALT, ep, (char *)status, 2, 3000));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000899}