blob: a491fda92a09a16009fb471de9ae2f71bb9f75b9 [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)
5 * Modified by Linus Walleij 6/3/2006
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00006 *
7 * This file adds some utils (many copied from ptpcam.c from libptp2) to
8 * use MTP devices. Include mtp-utils.h to use any of the ptp/mtp functions.
9 *
10 */
11#include "ptp.h"
12#include <errno.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <getopt.h>
17#include <unistd.h>
18#include <sys/types.h>
19#include <utime.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22#include <sys/mman.h>
23#include <usb.h>
24
Linus Walleij15e344f2006-03-06 15:15:00 +000025#include "libmtp.h"
26#include "libusb-glue.h"
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000027#include "ptp-pack.h"
28
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
52int ptpcam_usb_timeout = USB_TIMEOUT;
53
54void close_usb(PTP_USB* ptp_usb, uint8_t interfaceNumber);
55struct usb_device* find_device (int busn, int devicen, short force);
56void find_endpoints(struct usb_device *dev, int* inep, int* outep, int* intep);
57void clear_stall(PTP_USB* ptp_usb);
58void init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev);
59static short ptp_write_func (unsigned char *bytes, unsigned int size, void *data);
60static short ptp_read_func (unsigned char *bytes, unsigned int size, void *data);
61static short ptp_check_int (unsigned char *bytes, unsigned int size, void *data);
62int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep);
63int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status);
64
65static short ptp_read_func (unsigned char *bytes, unsigned int size, void *data)
66{
67 int result=-1;
68 PTP_USB *ptp_usb=(PTP_USB *)data;
69 int toread=0;
70 signed long int rbytes=size;
71
72 do {
73 bytes+=toread;
74 if (rbytes>PTPCAM_USB_URB)
75 toread = PTPCAM_USB_URB;
76 else
77 toread = rbytes;
78 result=USB_BULK_READ(ptp_usb->handle, ptp_usb->inep,(char *)bytes, toread,ptpcam_usb_timeout);
79 /* sometimes retry might help */
80 if (result==0)
81 result=USB_BULK_READ(ptp_usb->handle, ptp_usb->inep,(char *)bytes, toread,ptpcam_usb_timeout);
82 if (result < 0)
83 break;
84 rbytes-=PTPCAM_USB_URB;
85 } while (rbytes>0);
86
87 if (result >= 0) {
88 return (PTP_RC_OK);
89 }
90 else
91 {
92 return PTP_ERROR_IO;
93 }
94}
95
96static short ptp_write_func (unsigned char *bytes, unsigned int size, void *data)
97{
98 int result;
99 PTP_USB *ptp_usb=(PTP_USB *)data;
100
101
102 /* only print if size < something */
103 /*int i = 0;
104 if (size < 0xff)
105 {
106 printf("-------------------------\n");
107 printf("Sending data size %d\n", size);
108 for (i = 0; i < size; i += 8)
109 {
110 int j = i;
111 for (; j<size && j<i+8; j++)
112 printf("0x%02x ", bytes[j]);
113 printf("\n");
114 }
115 printf("-------------------------\n");
116 }
117 */
118
119 result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)bytes,size,ptpcam_usb_timeout);
120 if (result >= 0)
121 return (PTP_RC_OK);
122 else
123 {
124 return PTP_ERROR_IO;
125 }
126}
127
128static short ptp_check_int (unsigned char *bytes, unsigned int size, void *data)
129{
130 int result;
131 PTP_USB *ptp_usb=(PTP_USB *)data;
132
133 result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)bytes,size,ptpcam_usb_timeout);
134 if (result==0)
135 result = USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *) bytes, size, ptpcam_usb_timeout);
136 if (result >= 0) {
137 return (PTP_RC_OK);
138 } else {
139 return PTP_ERROR_IO;
140 }
141}
142
143void init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev)
144{
145 usb_dev_handle *device_handle;
146
147 params->write_func=ptp_write_func;
148 params->read_func=ptp_read_func;
149 params->check_int_func=ptp_check_int;
150 params->check_int_fast_func=ptp_check_int;
151 params->error_func=NULL;
152 params->debug_func=NULL;
153 params->sendreq_func=ptp_usb_sendreq;
154 params->senddata_func=ptp_usb_senddata;
155 params->getresp_func=ptp_usb_getresp;
156 params->getdata_func=ptp_usb_getdata;
157 params->data=ptp_usb;
158 params->transaction_id=0;
159 params->byteorder = PTP_DL_LE;
160
161 if ((device_handle=usb_open(dev))){
162 if (!device_handle) {
163 perror("usb_open()");
164 exit(0);
165 }
166 ptp_usb->handle=device_handle;
167 usb_claim_interface(device_handle,
168 dev->config->interface->altsetting->bInterfaceNumber);
169 }
170}
171
172void clear_stall(PTP_USB* ptp_usb)
173{
174 uint16_t status=0;
175 int ret;
176
177 /* check the inep status */
178 ret=usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status);
179 if (ret<0) perror ("inep: usb_get_endpoint_status()");
180 /* and clear the HALT condition if happend */
181 else if (status) {
182 printf("Resetting input pipe!\n");
183 ret=usb_clear_stall_feature(ptp_usb,ptp_usb->inep);
184 /*usb_clear_halt(ptp_usb->handle,ptp_usb->inep); */
185 if (ret<0)perror ("usb_clear_stall_feature()");
186 }
187 status=0;
188
189 /* check the outep status */
190 ret=usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status);
191 if (ret<0) perror ("outep: usb_get_endpoint_status()");
192 /* and clear the HALT condition if happend */
193 else if (status) {
194 printf("Resetting output pipe!\n");
195 ret=usb_clear_stall_feature(ptp_usb,ptp_usb->outep);
196 /*usb_clear_halt(ptp_usb->handle,ptp_usb->outep); */
197 if (ret<0)perror ("usb_clear_stall_feature()");
198 }
199
200 /*usb_clear_halt(ptp_usb->handle,ptp_usb->intep); */
201}
202
203void close_usb(PTP_USB* ptp_usb, uint8_t interfaceNumber)
204{
205 clear_stall(ptp_usb);
206 usb_release_interface(ptp_usb->handle, interfaceNumber);
207 usb_close(ptp_usb->handle);
208}
209
210
211struct usb_bus*
212init_usb()
213{
214 usb_init();
215 usb_find_busses();
216 usb_find_devices();
217 return (usb_get_busses());
218}
219
220/*
221 find_device() returns the pointer to a usb_device structure matching
222 given busn, devicen numbers. If any or both of arguments are 0 then the
223 first matching PTP device structure is returned.
224 */
225struct usb_device* find_device (int busn, int devn, short force)
226{
227 struct usb_bus *bus;
228 struct usb_device *dev;
229
230 bus=init_usb();
231 for (; bus; bus = bus->next)
232 for (dev = bus->devices; dev; dev = dev->next)
233 /* somtimes dev->config is null, not sure why... */
234 if (dev->config != NULL)
235 if (dev->descriptor.bDeviceClass!=USB_CLASS_HUB)
236 {
237 int curbusn, curdevn;
238
239 curbusn=strtol(bus->dirname,NULL,10);
240 curdevn=strtol(dev->filename,NULL,10);
241
242 if (devn==0) {
243 if (busn==0) return dev;
244 if (curbusn==busn) return dev;
245 } else {
246 if ((busn==0)&&(curdevn==devn)) return dev;
247 if ((curbusn==busn)&&(curdevn==devn)) return dev;
248 }
249 }
250 return NULL;
251}
252
253/* this is a temporary function to connect to the first device we can, that has vendor ID CREATIVE_VENDOR_ID */
254
255uint16_t connect_first_device(PTPParams *params, PTP_USB *ptp_usb, uint8_t *interfaceNumber)
256{
257 struct usb_bus *bus;
258 struct usb_device *dev;
259
260 bus=init_usb();
261 for (; bus; bus = bus->next)
262 {
263 for (dev = bus->devices; dev; dev = dev->next)
264 {
265 if (dev->descriptor.bDeviceClass!=USB_CLASS_HUB && dev->descriptor.idVendor==CREATIVE_VENDOR_ID)
266 {
267 uint16_t ret=0;
268 int n;
269 struct usb_endpoint_descriptor *ep;
270 PTPDeviceInfo deviceinfo;
271
272 ep = dev->config->interface->altsetting->endpoint;
273 n=dev->config->interface->altsetting->bNumEndpoints;
274
275 find_endpoints(dev,&(ptp_usb->inep),&(ptp_usb->outep),&(ptp_usb->intep));
276 init_ptp_usb(params, ptp_usb, dev);
277
278 ret = ptp_opensession(params,1);
279 if (ret != PTP_RC_OK)
280 {
281 printf("Could not open session!\n Try to reset the camera.\n");
282 usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber);
283 continue;
284 }
285
286 ret = ptp_getdeviceinfo(params, &deviceinfo);
287 if (ret != PTP_RC_OK)
288 {
289 printf("Could not get device info!\n");
290 usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber);
291 return PTP_CD_RC_ERROR_CONNECTING;
292 }
293
294 /* we're connected, return ok */
295 *interfaceNumber = dev->config->interface->altsetting->bInterfaceNumber;
296
297 return PTP_CD_RC_CONNECTED;
298 }
299 }
300 }
301 /* none found */
302 return PTP_CD_RC_NO_DEVICES;
303}
304
305void find_endpoints(struct usb_device *dev, int* inep, int* outep, int* intep)
306{
307 int i,n;
308 struct usb_endpoint_descriptor *ep;
309
310 ep = dev->config->interface->altsetting->endpoint;
311 n=dev->config->interface->altsetting->bNumEndpoints;
312
313 for (i=0;i<n;i++) {
314 if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_BULK) {
315 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
316 USB_ENDPOINT_DIR_MASK)
317 {
318 *inep=ep[i].bEndpointAddress;
319 }
320 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==0)
321 {
322 *outep=ep[i].bEndpointAddress;
323 }
324 } else if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_INTERRUPT){
325 if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
326 USB_ENDPOINT_DIR_MASK)
327 {
328 *intep=ep[i].bEndpointAddress;
329 }
330 }
331 }
332}
333
334
335int open_device (int busn, int devn, short force, PTP_USB *ptp_usb, PTPParams *params, struct usb_device **dev)
336{
337#ifdef DEBUG
338 printf("dev %i\tbus %i\n",devn,busn);
339#endif
340
341 *dev=find_device(busn,devn,force);
342 if (*dev==NULL) {
343 fprintf(stderr,"could not find any device matching given "
344 "bus/dev numbers\n");
345 exit(-1);
346 }
347 find_endpoints(*dev,&ptp_usb->inep,&ptp_usb->outep,&ptp_usb->intep);
348
349 init_ptp_usb(params, ptp_usb, *dev);
350 if (ptp_opensession(params,1)!=PTP_RC_OK) {
351 fprintf(stderr,"ERROR: Could not open session!\n");
352 close_usb(ptp_usb, (*dev)->config->interface->altsetting->bInterfaceNumber);
353 return -1;
354 }
355 return 0;
356}
357
358void close_device (PTP_USB *ptp_usb, PTPParams *params, uint8_t interfaceNumber)
359{
360 if (ptp_closesession(params)!=PTP_RC_OK)
361 fprintf(stderr,"ERROR: Could not close session!\n");
362 close_usb(ptp_usb, interfaceNumber);
363}
364
365int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep)
366{
367
368 return (usb_control_msg(ptp_usb->handle,
369 USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, USB_FEATURE_HALT,
370 ep, NULL, 0, 3000));
371}
372
373int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status)
374{
375 return (usb_control_msg(ptp_usb->handle,
376 USB_DP_DTH|USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS,
377 USB_FEATURE_HALT, ep, (char *)status, 2, 3000));
378}