blob: 7eb5a3f97654175d79d1e39ad7c3d289ec470747 [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 */
12#include "ptp.h"
13#include <errno.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <getopt.h>
18#include <unistd.h>
19#include <sys/types.h>
20#include <utime.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <sys/mman.h>
24#include <usb.h>
25
Linus Walleij15e344f2006-03-06 15:15:00 +000026#include "libmtp.h"
27#include "libusb-glue.h"
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000028
29/* OUR APPLICATION USB URB (2MB) ;) */
30#define PTPCAM_USB_URB 2097152
31
32/* this must not be too short - the original 4000 was not long
33 enough for big file transfers. I imagine the player spends a
34 bit of time gearing up to receiving lots of data. This also makes
35 connecting/disconnecting more reliable */
36#define USB_TIMEOUT 10000
37#define USB_CAPTURE_TIMEOUT 20000
38
39/* USB control message data phase direction */
40#ifndef USB_DP_HTD
41#define USB_DP_HTD (0x00 << 7) /* host to device */
42#endif
43#ifndef USB_DP_DTH
44#define USB_DP_DTH (0x01 << 7) /* device to host */
45#endif
46
47/* USB Feature selector HALT */
48#ifndef USB_FEATURE_HALT
49#define USB_FEATURE_HALT 0x00
50#endif
51
Linus Walleija5483642006-03-09 09:20:38 +000052/*
Linus Walleije8c54642006-03-28 09:45:00 +000053 * MTP device list, trying real bad to get all devices into
54 * this list by stealing from everyone I know.
Linus Walleija5483642006-03-09 09:20:38 +000055 */
Linus Walleij6fd2f082006-03-28 07:19:22 +000056static const LIBMTP_device_entry_t mtp_device_table[] = {
Linus Walleije8c54642006-03-28 09:45:00 +000057 /* Creative devices */
Linus Walleij6fd2f082006-03-28 07:19:22 +000058 { "Creative Zen Vision", 0x041e, 0x411f, NULL },
59 { "Creative Portable Media Center", 0x041e, 0x4123, NULL },
60 { "Creative Zen Xtra (MTP mode)", 0x041e, 0x4128, NULL },
61 { "Second generation Dell DJ", 0x041e, 0x412f, NULL },
62 { "Creative Zen Micro (MTP mode)", 0x041e, 0x4130, NULL },
63 { "Creative Zen Touch (MTP mode)", 0x041e, 0x4131, NULL },
64 { "Creative Zen Sleek (MTP mode)", 0x041e, 0x4137, NULL },
65 { "Creative Zen MicroPhoto", 0x041e, 0x413c, NULL },
66 { "Creative Zen Sleek Photo", 0x041e, 0x413d, NULL },
67 { "Creative Zen Vision:M", 0x041e, 0x413e, NULL },
Linus Walleijea08c2b2006-04-21 08:26:06 +000068 /* Contributed by anonymous person on SourceForge */
Linus Walleija06a2792006-04-21 07:52:26 +000069 { "Samsung YP-T7J", 0x04e8, 0x5047, NULL },
Linus Walleijf46ce4f2006-04-30 22:09:09 +000070 /* From Mark Veinot */
71 { "JVC Alneo XA-HD500", 0x04f1, 0x6105, NULL },
Linus Walleije8c54642006-03-28 09:45:00 +000072 /*
73 * Copied in from libgphoto2's libptp2 adaption "library.c"
74 * carefully trying to pick only the MTP devices.
75 * Greetings to Marcus Meissner! (we should merge our
76 * projects some day...)
77 */
Linus Walleija06a2792006-04-21 07:52:26 +000078 { "Philipps HDD6320", 0x0471, 0x01eb, NULL},
Linus Walleij6fd2f082006-03-28 07:19:22 +000079 { "iRiver T10", 0x4102, 0x1113, NULL },
Linus Walleije8c54642006-03-28 09:45:00 +000080 { "iRiver U10", 0x4102, 0x1116, NULL },
Linus Walleij6fd2f082006-03-28 07:19:22 +000081 { "iRiver T10", 0x4102, 0x1117, NULL },
Linus Walleije8c54642006-03-28 09:45:00 +000082 { "iRiver T20", 0x4102, 0x1118, NULL },
83 { "iRiver T30", 0x4102, 0x1119, NULL },
Linus Walleija06a2792006-04-21 07:52:26 +000084 { "iRiver H10", 0x4102, 0x2102, NULL },
85 { "Dell DJ Itty", 0x413c, 0x4500, NULL},
Linus Walleije8c54642006-03-28 09:45:00 +000086 { "Toshiba Gigabeat", 0x0930, 0x000c, NULL}
Linus Walleija5483642006-03-09 09:20:38 +000087};
Linus Walleij6fd2f082006-03-28 07:19:22 +000088static const int mtp_device_table_size = sizeof(mtp_device_table) / sizeof(LIBMTP_device_entry_t);
Linus Walleija5483642006-03-09 09:20:38 +000089
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000090int ptpcam_usb_timeout = USB_TIMEOUT;
91
Linus Walleijd6a49972006-05-02 08:24:54 +000092// Local functions
93static void close_usb(PTP_USB* ptp_usb, uint8_t interfaceNumber);
94static struct usb_device* find_device (int busn, int devicen, short force);
95static void find_endpoints(struct usb_device *dev, int* inep, int* inep_maxpacket, int* outep, int* outep_maxpacket, int* intep);
96static void clear_stall(PTP_USB* ptp_usb);
97static void init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000098static short ptp_write_func (unsigned char *bytes, unsigned int size, void *data);
Linus Walleijb02a0662006-04-25 08:05:09 +000099static short ptp_read_func (unsigned char *bytes, unsigned int size, void *data, unsigned int *readbytes);
100static short ptp_check_int (unsigned char *bytes, unsigned int size, void *data, unsigned int *rlen);
Linus Walleijd6a49972006-05-02 08:24:54 +0000101static int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep);
102static int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status);
103static struct usb_bus* init_usb();
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000104
Linus Walleij6fd2f082006-03-28 07:19:22 +0000105int get_device_list(LIBMTP_device_entry_t ** const devices, int * const numdevs)
106{
107 *devices = (LIBMTP_device_entry_t *) &mtp_device_table;
108 *numdevs = mtp_device_table_size;
109 return 0;
110}
111
Linus Walleijd6a49972006-05-02 08:24:54 +0000112// Based on same function on library.c in libgphoto2
Linus Walleijb02a0662006-04-25 08:05:09 +0000113#define CONTEXT_BLOCK_SIZE 100000
114static short
115ptp_read_func (unsigned char *bytes, unsigned int size, void *data, unsigned int *readbytes)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000116{
Linus Walleijb02a0662006-04-25 08:05:09 +0000117 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleijd6a49972006-05-02 08:24:54 +0000118 int toread = 0;
119 int result = 0;
120 int curread = 0;
121 /* Split into small blocks. Too large blocks (>1x MB) would
122 * timeout.
123 */
124 while (curread < size) {
125 toread = size - curread;
126 if (toread > 4096)
127 toread = 4096;
128
129 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep,(char *)(bytes+curread), toread, ptpcam_usb_timeout);
130 if (result == 0) {
131 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->inep,(char *)(bytes+curread), toread, ptpcam_usb_timeout);
132 }
133 if (result < 0)
134 break;
135 curread += result;
136 if (result < toread) /* short reads are common */
137 break;
138 }
139 if (result > 0) {
140 *readbytes = curread;
141 return (PTP_RC_OK);
142 } else {
143 return PTP_ERROR_IO;
144 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000145}
146
Linus Walleijd6a49972006-05-02 08:24:54 +0000147// Based on same function on library.c in libgphoto2
Linus Walleijb02a0662006-04-25 08:05:09 +0000148static short
149ptp_write_func (unsigned char *bytes, unsigned int size, void *data)
150{
151 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleijd6a49972006-05-02 08:24:54 +0000152 int towrite = 0;
153 int result = 0;
154 int curwrite = 0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000155
Linus Walleijd6a49972006-05-02 08:24:54 +0000156 /*
157 * gp_port_write returns (in case of success) the number of bytes
158 * write. Too large blocks (>5x MB) could timeout.
159 */
160 while (curwrite < size) {
161 towrite = size-curwrite;
162 if (towrite > 4096)
163 towrite = 4096;
164 result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)(bytes+curwrite),towrite,ptpcam_usb_timeout);
165 if (result < 0)
166 break;
167 curwrite += result;
168 if (result < towrite) /* short writes happen */
169 break;
170 }
171 // Should load wMaxPacketsize from endpoint first. But works fine for all EPs.
172 if ((size % 512) == 0)
173 result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)"x",0,ptpcam_usb_timeout);
174 if (result < 0)
175 return PTP_ERROR_IO;
176 return PTP_RC_OK;
Linus Walleijb02a0662006-04-25 08:05:09 +0000177}
178
Linus Walleijd6a49972006-05-02 08:24:54 +0000179// This is a bit hackish at the moment. I wonder if it even works.
Linus Walleijb02a0662006-04-25 08:05:09 +0000180static short ptp_check_int (unsigned char *bytes, unsigned int size, void *data, unsigned int *rlen)
181{
Linus Walleijd6a49972006-05-02 08:24:54 +0000182 PTP_USB *ptp_usb = (PTP_USB *)data;
Linus Walleijb02a0662006-04-25 08:05:09 +0000183 int result;
Linus Walleijb02a0662006-04-25 08:05:09 +0000184
185 result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)bytes,size,ptpcam_usb_timeout);
186 if (result==0)
187 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *) bytes, size, ptpcam_usb_timeout);
188 if (result >= 0) {
189 *rlen = result;
190 return (PTP_RC_OK);
191 } else {
192 return PTP_ERROR_IO;
193 }
194}
195
Linus Walleijd6a49972006-05-02 08:24:54 +0000196static void init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000197{
Linus Walleijd6a49972006-05-02 08:24:54 +0000198 usb_dev_handle *device_handle;
199
200 params->write_func=ptp_write_func;
201 params->read_func=ptp_read_func;
202 params->check_int_func=ptp_check_int;
203 params->check_int_fast_func=ptp_check_int;
204 params->error_func=NULL;
205 params->debug_func=NULL;
206 params->sendreq_func=ptp_usb_sendreq;
207 params->senddata_func=ptp_usb_senddata;
208 params->getresp_func=ptp_usb_getresp;
209 params->getdata_func=ptp_usb_getdata;
210 params->data=ptp_usb;
211 params->transaction_id=0;
212 params->byteorder = PTP_DL_LE;
213
214 if ((device_handle=usb_open(dev))){
215 if (!device_handle) {
216 perror("usb_open()");
217 exit(0);
218 }
219 ptp_usb->handle=device_handle;
220 usb_claim_interface(device_handle,
221 dev->config->interface->altsetting->bInterfaceNumber);
222 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000223}
224
Linus Walleijd6a49972006-05-02 08:24:54 +0000225static void clear_stall(PTP_USB* ptp_usb)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000226{
Linus Walleijd6a49972006-05-02 08:24:54 +0000227 uint16_t status=0;
228 int ret;
229
230 /* check the inep status */
231 ret=usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status);
232 if (ret<0) perror ("inep: usb_get_endpoint_status()");
233 /* and clear the HALT condition if happend */
234 else if (status) {
235 printf("Resetting input pipe!\n");
236 ret=usb_clear_stall_feature(ptp_usb,ptp_usb->inep);
237 /*usb_clear_halt(ptp_usb->handle,ptp_usb->inep); */
238 if (ret<0)perror ("usb_clear_stall_feature()");
239 }
240 status=0;
241
242 /* check the outep status */
243 ret=usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status);
244 if (ret<0) perror ("outep: usb_get_endpoint_status()");
245 /* and clear the HALT condition if happend */
246 else if (status) {
247 printf("Resetting output pipe!\n");
248 ret=usb_clear_stall_feature(ptp_usb,ptp_usb->outep);
249 /*usb_clear_halt(ptp_usb->handle,ptp_usb->outep); */
250 if (ret<0)perror ("usb_clear_stall_feature()");
251 }
252
253 /*usb_clear_halt(ptp_usb->handle,ptp_usb->intep); */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000254}
255
Linus Walleijd6a49972006-05-02 08:24:54 +0000256static void close_usb(PTP_USB* ptp_usb, uint8_t interfaceNumber)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000257{
Linus Walleijd6a49972006-05-02 08:24:54 +0000258 clear_stall(ptp_usb);
259 // Added to clear some stuff on the OUT endpoint
260 // TODO: is this good on the Mac too?
261 usb_resetep(ptp_usb->handle, ptp_usb->outep);
262 usb_release_interface(ptp_usb->handle, interfaceNumber);
263 // Brutally reset device
264 // TODO: is this good on the Mac too?
265 usb_reset(ptp_usb->handle);
266 usb_close(ptp_usb->handle);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000267}
268
269
Linus Walleijd6a49972006-05-02 08:24:54 +0000270static struct usb_bus* init_usb()
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000271{
Linus Walleijd6a49972006-05-02 08:24:54 +0000272 usb_init();
273 usb_find_busses();
274 usb_find_devices();
275 return (usb_get_busses());
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000276}
277
278/*
279 find_device() returns the pointer to a usb_device structure matching
280 given busn, devicen numbers. If any or both of arguments are 0 then the
281 first matching PTP device structure is returned.
282 */
Linus Walleijd6a49972006-05-02 08:24:54 +0000283static struct usb_device* find_device (int busn, int devn, short force)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000284{
Linus Walleijd6a49972006-05-02 08:24:54 +0000285 struct usb_bus *bus;
286 struct usb_device *dev;
287
288 bus=init_usb();
289 for (; bus; bus = bus->next)
290 for (dev = bus->devices; dev; dev = dev->next)
291 /* somtimes dev->config is null, not sure why... */
292 if (dev->config != NULL)
293 if (dev->descriptor.bDeviceClass!=USB_CLASS_HUB)
294 {
295 int curbusn, curdevn;
296
297 curbusn=strtol(bus->dirname,NULL,10);
298 curdevn=strtol(dev->filename,NULL,10);
299
300 if (devn==0) {
301 if (busn==0) return dev;
302 if (curbusn==busn) return dev;
303 } else {
304 if ((busn==0)&&(curdevn==devn)) return dev;
305 if ((curbusn==busn)&&(curdevn==devn)) return dev;
306 }
307 }
308 return NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000309}
310
Linus Walleij6946ac52006-03-21 06:51:22 +0000311/**
312 * This function scans through the device list to see if there are
313 * some devices to connect to. The table at the top of this file is
314 * used to identify potential devices.
315 */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000316uint16_t connect_first_device(PTPParams *params, PTP_USB *ptp_usb, uint8_t *interfaceNumber)
317{
Linus Walleij6946ac52006-03-21 06:51:22 +0000318 struct usb_bus *bus;
319 struct usb_device *dev;
320
321 bus = init_usb();
322 for (; bus; bus = bus->next) {
323 for (dev = bus->devices; dev; dev = dev->next) {
324 int i;
325
326 // Loop over the list of supported devices
327 for (i = 0; i < mtp_device_table_size; i++) {
Linus Walleij6fd2f082006-03-28 07:19:22 +0000328 LIBMTP_device_entry_t const *mtp_device = &mtp_device_table[i];
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000329
Linus Walleij6946ac52006-03-21 06:51:22 +0000330 if (dev->descriptor.bDeviceClass != USB_CLASS_HUB &&
331 dev->descriptor.idVendor == mtp_device->vendor_id &&
332 dev->descriptor.idProduct == mtp_device->product_id ) {
333 uint16_t ret=0;
334 int n;
335 struct usb_endpoint_descriptor *ep;
336 PTPDeviceInfo deviceinfo;
337
338 printf("Found device \"%s\" on USB bus...\n", mtp_device->name);
339 ep = dev->config->interface->altsetting->endpoint;
340 n=dev->config->interface->altsetting->bNumEndpoints;
341
Linus Walleije8c54642006-03-28 09:45:00 +0000342 find_endpoints(dev,&(ptp_usb->inep),&(ptp_usb->inep_maxpacket),&(ptp_usb->outep),&(ptp_usb->outep_maxpacket),&(ptp_usb->intep));
Linus Walleijb02a0662006-04-25 08:05:09 +0000343 printf("Init PTP USB...\n");
Linus Walleij6946ac52006-03-21 06:51:22 +0000344 init_ptp_usb(params, ptp_usb, dev);
345
346 ret = ptp_opensession(params,1);
Linus Walleijb02a0662006-04-25 08:05:09 +0000347 printf("Session open (%d)...\n", ret);
348 if (ret == PTP_RC_InvalidTransactionID) {
349 params->transaction_id += 10;
350 ret = ptp_opensession(params,1);
351 }
352 if (ret != PTP_RC_SessionAlreadyOpened && ret != PTP_RC_OK) {
353 printf("Could not open session! (Return code %d)\n Try to reset the device.\n", ret);
Linus Walleij6946ac52006-03-21 06:51:22 +0000354 usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber);
355 continue;
356 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000357 /* It is actually permissible to call this before opening the session */
Linus Walleij6946ac52006-03-21 06:51:22 +0000358 ret = ptp_getdeviceinfo(params, &deviceinfo);
359 if (ret != PTP_RC_OK) {
360 printf("Could not get device info!\n");
361 usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber);
362 return PTP_CD_RC_ERROR_CONNECTING;
363 }
364
365 /* we're connected, return ok */
366 *interfaceNumber = dev->config->interface->altsetting->bInterfaceNumber;
367
368 return PTP_CD_RC_CONNECTED;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000369 }
Linus Walleij6946ac52006-03-21 06:51:22 +0000370 }
371 }
372 }
373 /* none found */
374 return PTP_CD_RC_NO_DEVICES;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000375}
376
Linus Walleijd6a49972006-05-02 08:24:54 +0000377static 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 +0000378{
Linus Walleijd6a49972006-05-02 08:24:54 +0000379 int i,n;
380 struct usb_endpoint_descriptor *ep;
381
382 ep = dev->config->interface->altsetting->endpoint;
383 n=dev->config->interface->altsetting->bNumEndpoints;
384
385 for (i=0;i<n;i++) {
386 if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_BULK) {
387 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
388 USB_ENDPOINT_DIR_MASK)
389 {
390 *inep=ep[i].bEndpointAddress;
391 *inep_maxpacket=ep[i].wMaxPacketSize;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000392 }
Linus Walleijd6a49972006-05-02 08:24:54 +0000393 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==0)
394 {
395 *outep=ep[i].bEndpointAddress;
396 *inep_maxpacket=ep[i].wMaxPacketSize;
397 }
398 } else if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_INTERRUPT){
399 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
400 USB_ENDPOINT_DIR_MASK)
401 {
402 *intep=ep[i].bEndpointAddress;
403 }
404 }
405 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000406}
407
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000408int open_device (int busn, int devn, short force, PTP_USB *ptp_usb, PTPParams *params, struct usb_device **dev)
409{
410#ifdef DEBUG
Linus Walleijd6a49972006-05-02 08:24:54 +0000411 printf("dev %i\tbus %i\n",devn,busn);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000412#endif
Linus Walleijd6a49972006-05-02 08:24:54 +0000413
414 *dev=find_device(busn,devn,force);
415 if (*dev==NULL) {
416 fprintf(stderr,"could not find any device matching given "
417 "bus/dev numbers\n");
418 exit(-1);
419 }
420 find_endpoints(*dev,&ptp_usb->inep,&ptp_usb->inep_maxpacket,&ptp_usb->outep,&ptp_usb->outep_maxpacket,&ptp_usb->intep);
421
422 init_ptp_usb(params, ptp_usb, *dev);
423 if (ptp_opensession(params,1)!=PTP_RC_OK) {
424 fprintf(stderr,"ERROR: Could not open session!\n");
425 close_usb(ptp_usb, (*dev)->config->interface->altsetting->bInterfaceNumber);
426 return -1;
427 }
428 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000429}
430
431void close_device (PTP_USB *ptp_usb, PTPParams *params, uint8_t interfaceNumber)
432{
Linus Walleijd6a49972006-05-02 08:24:54 +0000433 if (ptp_closesession(params)!=PTP_RC_OK)
434 fprintf(stderr,"ERROR: Could not close session!\n");
435 close_usb(ptp_usb, interfaceNumber);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000436}
437
Linus Walleijd6a49972006-05-02 08:24:54 +0000438static int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000439{
Linus Walleijd6a49972006-05-02 08:24:54 +0000440
441 return (usb_control_msg(ptp_usb->handle,
442 USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, USB_FEATURE_HALT,
443 ep, NULL, 0, 3000));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000444}
445
Linus Walleijd6a49972006-05-02 08:24:54 +0000446static int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000447{
Linus Walleijd6a49972006-05-02 08:24:54 +0000448 return (usb_control_msg(ptp_usb->handle,
449 USB_DP_DTH|USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS,
450 USB_FEATURE_HALT, ep, (char *)status, 2, 3000));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000451}