libusb 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +8 -0
- data/.travis.yml +10 -0
- data/.yardopts +6 -1
- data/Gemfile +16 -0
- data/{History.txt → History.md} +28 -16
- data/README.md +144 -0
- data/Rakefile +28 -24
- data/ext/extconf.rb +33 -0
- data/ext/libusbx-1.0.14/AUTHORS +50 -0
- data/ext/libusbx-1.0.14/COPYING +504 -0
- data/ext/libusbx-1.0.14/ChangeLog +139 -0
- data/ext/libusbx-1.0.14/INSTALL +234 -0
- data/ext/libusbx-1.0.14/Makefile.am +23 -0
- data/ext/libusbx-1.0.14/Makefile.in +803 -0
- data/ext/libusbx-1.0.14/NEWS +2 -0
- data/ext/libusbx-1.0.14/PORTING +94 -0
- data/ext/libusbx-1.0.14/README +28 -0
- data/ext/libusbx-1.0.14/THANKS +7 -0
- data/ext/libusbx-1.0.14/TODO +2 -0
- data/ext/libusbx-1.0.14/aclocal.m4 +9480 -0
- data/ext/libusbx-1.0.14/compile +143 -0
- data/ext/libusbx-1.0.14/config.guess +1501 -0
- data/ext/libusbx-1.0.14/config.h.in +116 -0
- data/ext/libusbx-1.0.14/config.sub +1705 -0
- data/ext/libusbx-1.0.14/configure +14818 -0
- data/ext/libusbx-1.0.14/configure.ac +230 -0
- data/ext/libusbx-1.0.14/depcomp +630 -0
- data/ext/libusbx-1.0.14/doc/Makefile.am +9 -0
- data/ext/libusbx-1.0.14/doc/Makefile.in +380 -0
- data/ext/libusbx-1.0.14/doc/doxygen.cfg.in +1288 -0
- data/ext/libusbx-1.0.14/examples/Makefile.am +18 -0
- data/ext/libusbx-1.0.14/examples/Makefile.in +596 -0
- data/ext/libusbx-1.0.14/examples/dpfp.c +506 -0
- data/ext/libusbx-1.0.14/examples/dpfp_threaded.c +544 -0
- data/ext/libusbx-1.0.14/examples/ezusb.c +616 -0
- data/ext/libusbx-1.0.14/examples/ezusb.h +107 -0
- data/ext/libusbx-1.0.14/examples/fxload.c +261 -0
- data/ext/libusbx-1.0.14/examples/getopt/getopt.c +1060 -0
- data/ext/libusbx-1.0.14/examples/getopt/getopt.h +180 -0
- data/ext/libusbx-1.0.14/examples/getopt/getopt1.c +188 -0
- data/ext/libusbx-1.0.14/examples/listdevs.c +63 -0
- data/ext/libusbx-1.0.14/examples/xusb.c +1036 -0
- data/ext/libusbx-1.0.14/install-sh +520 -0
- data/ext/libusbx-1.0.14/libusb-1.0.pc.in +11 -0
- data/ext/libusbx-1.0.14/libusb/Makefile.am +56 -0
- data/ext/libusbx-1.0.14/libusb/Makefile.in +721 -0
- data/ext/libusbx-1.0.14/libusb/core.c +1951 -0
- data/ext/libusbx-1.0.14/libusb/descriptor.c +731 -0
- data/ext/libusbx-1.0.14/libusb/io.c +2450 -0
- data/ext/libusbx-1.0.14/libusb/libusb-1.0.def +126 -0
- data/ext/libusbx-1.0.14/libusb/libusb-1.0.rc +59 -0
- data/ext/libusbx-1.0.14/libusb/libusb.h +1506 -0
- data/ext/libusbx-1.0.14/libusb/libusbi.h +910 -0
- data/ext/libusbx-1.0.14/libusb/os/darwin_usb.c +1807 -0
- data/ext/libusbx-1.0.14/libusb/os/darwin_usb.h +169 -0
- data/ext/libusbx-1.0.14/libusb/os/linux_usbfs.c +2569 -0
- data/ext/libusbx-1.0.14/libusb/os/linux_usbfs.h +149 -0
- data/ext/libusbx-1.0.14/libusb/os/openbsd_usb.c +727 -0
- data/ext/libusbx-1.0.14/libusb/os/poll_posix.h +10 -0
- data/ext/libusbx-1.0.14/libusb/os/poll_windows.c +747 -0
- data/ext/libusbx-1.0.14/libusb/os/poll_windows.h +114 -0
- data/ext/libusbx-1.0.14/libusb/os/threads_posix.c +80 -0
- data/ext/libusbx-1.0.14/libusb/os/threads_posix.h +50 -0
- data/ext/libusbx-1.0.14/libusb/os/threads_windows.c +211 -0
- data/ext/libusbx-1.0.14/libusb/os/threads_windows.h +87 -0
- data/ext/libusbx-1.0.14/libusb/os/windows_usb.c +4369 -0
- data/ext/libusbx-1.0.14/libusb/os/windows_usb.h +979 -0
- data/ext/libusbx-1.0.14/libusb/sync.c +321 -0
- data/ext/libusbx-1.0.14/libusb/version.h +18 -0
- data/ext/libusbx-1.0.14/libusb/version_nano.h +1 -0
- data/ext/libusbx-1.0.14/ltmain.sh +9636 -0
- data/ext/libusbx-1.0.14/missing +376 -0
- data/lib/libusb.rb +2 -3
- data/lib/libusb/call.rb +49 -7
- data/lib/libusb/compat.rb +15 -9
- data/lib/libusb/configuration.rb +15 -3
- data/lib/libusb/constants.rb +19 -6
- data/lib/libusb/context.rb +181 -3
- data/lib/libusb/dev_handle.rb +91 -40
- data/lib/libusb/endpoint.rb +41 -14
- data/lib/libusb/eventmachine.rb +183 -0
- data/lib/libusb/transfer.rb +21 -8
- data/lib/libusb/version_gem.rb +19 -0
- data/lib/libusb/{version.rb → version_struct.rb} +0 -0
- data/libusb.gemspec +31 -0
- data/test/test_libusb_compat.rb +1 -1
- data/test/test_libusb_compat_mass_storage.rb +2 -2
- data/test/test_libusb_descriptors.rb +1 -1
- data/test/test_libusb_event_machine.rb +118 -0
- data/test/test_libusb_iso_transfer.rb +6 -1
- data/test/test_libusb_mass_storage.rb +9 -3
- data/test/test_libusb_mass_storage2.rb +1 -1
- data/test/test_libusb_structs.rb +45 -0
- data/test/test_libusb_threads.rb +89 -0
- data/test/test_libusb_version.rb +4 -0
- metadata +109 -44
- data/.autotest +0 -23
- data/.gemtest +0 -0
- data/Manifest.txt +0 -3
- data/README.rdoc +0 -115
- data/test/test_libusb_keyboard.rb +0 -50
|
@@ -0,0 +1,1807 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* darwin backend for libusbx 1.0
|
|
3
|
+
* Copyright © 2008-2011 Nathan Hjelm <hjelmn@users.sourceforge.net>
|
|
4
|
+
*
|
|
5
|
+
* This library is free software; you can redistribute it and/or
|
|
6
|
+
* modify it under the terms of the GNU Lesser General Public
|
|
7
|
+
* License as published by the Free Software Foundation; either
|
|
8
|
+
* version 2.1 of the License, or (at your option) any later version.
|
|
9
|
+
*
|
|
10
|
+
* This library is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13
|
+
* Lesser General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Lesser General Public
|
|
16
|
+
* License along with this library; if not, write to the Free Software
|
|
17
|
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
#include <config.h>
|
|
21
|
+
#include <ctype.h>
|
|
22
|
+
#include <dirent.h>
|
|
23
|
+
#include <errno.h>
|
|
24
|
+
#include <fcntl.h>
|
|
25
|
+
#include <pthread.h>
|
|
26
|
+
#include <stdio.h>
|
|
27
|
+
#include <stdlib.h>
|
|
28
|
+
#include <string.h>
|
|
29
|
+
#include <sys/ioctl.h>
|
|
30
|
+
#include <sys/stat.h>
|
|
31
|
+
#include <sys/types.h>
|
|
32
|
+
#include <unistd.h>
|
|
33
|
+
#include <libkern/OSAtomic.h>
|
|
34
|
+
|
|
35
|
+
#include <mach/clock.h>
|
|
36
|
+
#include <mach/clock_types.h>
|
|
37
|
+
#include <mach/mach_host.h>
|
|
38
|
+
#include <mach/mach_port.h>
|
|
39
|
+
|
|
40
|
+
#include <AvailabilityMacros.h>
|
|
41
|
+
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
|
42
|
+
#include <objc/objc-auto.h>
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
#include <IOKit/IOCFBundle.h>
|
|
46
|
+
#include <IOKit/usb/IOUSBLib.h>
|
|
47
|
+
#include <IOKit/IOCFPlugIn.h>
|
|
48
|
+
|
|
49
|
+
#include "darwin_usb.h"
|
|
50
|
+
|
|
51
|
+
/* async event thread */
|
|
52
|
+
static pthread_mutex_t libusb_darwin_at_mutex;
|
|
53
|
+
static pthread_cond_t libusb_darwin_at_cond;
|
|
54
|
+
|
|
55
|
+
static clock_serv_t clock_realtime;
|
|
56
|
+
static clock_serv_t clock_monotonic;
|
|
57
|
+
|
|
58
|
+
static CFRunLoopRef libusb_darwin_acfl = NULL; /* async cf loop */
|
|
59
|
+
static volatile int32_t initCount = 0;
|
|
60
|
+
|
|
61
|
+
/* async event thread */
|
|
62
|
+
static pthread_t libusb_darwin_at;
|
|
63
|
+
|
|
64
|
+
static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian);
|
|
65
|
+
static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface);
|
|
66
|
+
static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface);
|
|
67
|
+
static int darwin_reset_device(struct libusb_device_handle *dev_handle);
|
|
68
|
+
static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0);
|
|
69
|
+
|
|
70
|
+
#ifdef ENABLE_LOGGING
|
|
71
|
+
static const char *darwin_error_str (int result) {
|
|
72
|
+
switch (result) {
|
|
73
|
+
case kIOReturnSuccess:
|
|
74
|
+
return "no error";
|
|
75
|
+
case kIOReturnNotOpen:
|
|
76
|
+
return "device not opened for exclusive access";
|
|
77
|
+
case kIOReturnNoDevice:
|
|
78
|
+
return "no connection to an IOService";
|
|
79
|
+
case kIOUSBNoAsyncPortErr:
|
|
80
|
+
return "no async port has been opened for interface";
|
|
81
|
+
case kIOReturnExclusiveAccess:
|
|
82
|
+
return "another process has device opened for exclusive access";
|
|
83
|
+
case kIOUSBPipeStalled:
|
|
84
|
+
return "pipe is stalled";
|
|
85
|
+
case kIOReturnError:
|
|
86
|
+
return "could not establish a connection to the Darwin kernel";
|
|
87
|
+
case kIOUSBTransactionTimeout:
|
|
88
|
+
return "transaction timed out";
|
|
89
|
+
case kIOReturnBadArgument:
|
|
90
|
+
return "invalid argument";
|
|
91
|
+
case kIOReturnAborted:
|
|
92
|
+
return "transaction aborted";
|
|
93
|
+
case kIOReturnNotResponding:
|
|
94
|
+
return "device not responding";
|
|
95
|
+
case kIOReturnOverrun:
|
|
96
|
+
return "data overrun";
|
|
97
|
+
case kIOReturnCannotWire:
|
|
98
|
+
return "physical memory can not be wired down";
|
|
99
|
+
default:
|
|
100
|
+
return "unknown error";
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
#endif
|
|
104
|
+
|
|
105
|
+
static int darwin_to_libusb (int result) {
|
|
106
|
+
switch (result) {
|
|
107
|
+
case kIOReturnUnderrun:
|
|
108
|
+
case kIOReturnSuccess:
|
|
109
|
+
return LIBUSB_SUCCESS;
|
|
110
|
+
case kIOReturnNotOpen:
|
|
111
|
+
case kIOReturnNoDevice:
|
|
112
|
+
return LIBUSB_ERROR_NO_DEVICE;
|
|
113
|
+
case kIOReturnExclusiveAccess:
|
|
114
|
+
return LIBUSB_ERROR_ACCESS;
|
|
115
|
+
case kIOUSBPipeStalled:
|
|
116
|
+
return LIBUSB_ERROR_PIPE;
|
|
117
|
+
case kIOReturnBadArgument:
|
|
118
|
+
return LIBUSB_ERROR_INVALID_PARAM;
|
|
119
|
+
case kIOUSBTransactionTimeout:
|
|
120
|
+
return LIBUSB_ERROR_TIMEOUT;
|
|
121
|
+
case kIOReturnNotResponding:
|
|
122
|
+
case kIOReturnAborted:
|
|
123
|
+
case kIOReturnError:
|
|
124
|
+
case kIOUSBNoAsyncPortErr:
|
|
125
|
+
default:
|
|
126
|
+
return LIBUSB_ERROR_OTHER;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp) {
|
|
132
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
|
|
133
|
+
|
|
134
|
+
/* current interface */
|
|
135
|
+
struct darwin_interface *cInterface;
|
|
136
|
+
|
|
137
|
+
int8_t i, iface;
|
|
138
|
+
|
|
139
|
+
usbi_dbg ("converting ep address 0x%02x to pipeRef and interface", ep);
|
|
140
|
+
|
|
141
|
+
for (iface = 0 ; iface < USB_MAXINTERFACES ; iface++) {
|
|
142
|
+
cInterface = &priv->interfaces[iface];
|
|
143
|
+
|
|
144
|
+
if (dev_handle->claimed_interfaces & (1 << iface)) {
|
|
145
|
+
for (i = 0 ; i < cInterface->num_endpoints ; i++) {
|
|
146
|
+
if (cInterface->endpoint_addrs[i] == ep) {
|
|
147
|
+
*pipep = i + 1;
|
|
148
|
+
*ifcp = iface;
|
|
149
|
+
usbi_dbg ("pipe %d on interface %d matches", *pipep, *ifcp);
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* No pipe found with the correct endpoint address */
|
|
157
|
+
usbi_warn (HANDLE_CTX(dev_handle), "no pipeRef found with endpoint address 0x%02x.", ep);
|
|
158
|
+
|
|
159
|
+
return -1;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
static int usb_setup_device_iterator (io_iterator_t *deviceIterator, long location) {
|
|
163
|
+
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
|
|
164
|
+
|
|
165
|
+
if (!matchingDict)
|
|
166
|
+
return kIOReturnError;
|
|
167
|
+
|
|
168
|
+
if (location) {
|
|
169
|
+
CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
|
170
|
+
&kCFTypeDictionaryKeyCallBacks,
|
|
171
|
+
&kCFTypeDictionaryValueCallBacks);
|
|
172
|
+
|
|
173
|
+
if (propertyMatchDict) {
|
|
174
|
+
CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberLongType, &location);
|
|
175
|
+
|
|
176
|
+
CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBDevicePropertyLocationID), locationCF);
|
|
177
|
+
/* release our reference to the CFNumber (CFDictionarySetValue retains it) */
|
|
178
|
+
CFRelease (locationCF);
|
|
179
|
+
|
|
180
|
+
CFDictionarySetValue (matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
|
|
181
|
+
/* release out reference to the CFMutableDictionaryRef (CFDictionarySetValue retains it) */
|
|
182
|
+
CFRelease (propertyMatchDict);
|
|
183
|
+
}
|
|
184
|
+
/* else we can still proceed as long as the caller accounts for the possibility of other devices in the iterator */
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, deviceIterator);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
static int get_ioregistry_value_number (io_service_t service, CFStringRef property, CFNumberType type, void *p) {
|
|
191
|
+
CFTypeRef cfNumber = IORegistryEntryCreateCFProperty (service, property, kCFAllocatorDefault, 0);
|
|
192
|
+
int ret = 0;
|
|
193
|
+
|
|
194
|
+
if (cfNumber) {
|
|
195
|
+
if (CFGetTypeID(cfNumber) == CFNumberGetTypeID()) {
|
|
196
|
+
ret = CFNumberGetValue(cfNumber, type, p);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
CFRelease (cfNumber);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return ret;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp, UInt8 *portp, UInt32 *parent_locationp) {
|
|
206
|
+
io_cf_plugin_ref_t *plugInInterface = NULL;
|
|
207
|
+
usb_device_t **device;
|
|
208
|
+
io_service_t usbDevice, parent;
|
|
209
|
+
kern_return_t result;
|
|
210
|
+
SInt32 score;
|
|
211
|
+
|
|
212
|
+
if (!IOIteratorIsValid (deviceIterator))
|
|
213
|
+
return NULL;
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
while ((usbDevice = IOIteratorNext(deviceIterator))) {
|
|
217
|
+
result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID,
|
|
218
|
+
kIOCFPlugInInterfaceID, &plugInInterface,
|
|
219
|
+
&score);
|
|
220
|
+
|
|
221
|
+
/* we are done with the usb_device_t */
|
|
222
|
+
(void)IOObjectRelease(usbDevice);
|
|
223
|
+
|
|
224
|
+
if (portp) {
|
|
225
|
+
*portp = 0;
|
|
226
|
+
(void) get_ioregistry_value_number (usbDevice, CFSTR("PortNum"), kCFNumberSInt8Type, portp);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (parent_locationp) {
|
|
230
|
+
*parent_locationp = 0;
|
|
231
|
+
|
|
232
|
+
result = IORegistryEntryGetParentEntry (usbDevice, kIOUSBPlane, &parent);
|
|
233
|
+
|
|
234
|
+
if (kIOReturnSuccess == result) {
|
|
235
|
+
(void) get_ioregistry_value_number (parent, CFSTR("locationID"), kCFNumberLongType, parent_locationp);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (kIOReturnSuccess == result && plugInInterface)
|
|
240
|
+
break;
|
|
241
|
+
|
|
242
|
+
usbi_dbg ("libusb/darwin.c usb_get_next_device: could not set up plugin for service: %s\n", darwin_error_str (result));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!usbDevice)
|
|
246
|
+
return NULL;
|
|
247
|
+
|
|
248
|
+
(void)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
|
|
249
|
+
(LPVOID)&device);
|
|
250
|
+
|
|
251
|
+
(*plugInInterface)->Stop(plugInInterface);
|
|
252
|
+
IODestroyPlugInInterface (plugInInterface);
|
|
253
|
+
|
|
254
|
+
/* get the location from the device */
|
|
255
|
+
if (locationp)
|
|
256
|
+
(*(device))->GetLocationID(device, locationp);
|
|
257
|
+
|
|
258
|
+
return device;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
static kern_return_t darwin_get_device (uint32_t dev_location, usb_device_t ***darwin_device) {
|
|
262
|
+
kern_return_t kresult;
|
|
263
|
+
UInt32 location;
|
|
264
|
+
io_iterator_t deviceIterator;
|
|
265
|
+
|
|
266
|
+
kresult = usb_setup_device_iterator (&deviceIterator, dev_location);
|
|
267
|
+
if (kresult)
|
|
268
|
+
return kresult;
|
|
269
|
+
|
|
270
|
+
/* This port of libusb uses locations to keep track of devices. */
|
|
271
|
+
while ((*darwin_device = usb_get_next_device (deviceIterator, &location, NULL, NULL)) != NULL) {
|
|
272
|
+
if (location == dev_location)
|
|
273
|
+
break;
|
|
274
|
+
|
|
275
|
+
(**darwin_device)->Release(*darwin_device);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
IOObjectRelease (deviceIterator);
|
|
279
|
+
|
|
280
|
+
if (!(*darwin_device))
|
|
281
|
+
return kIOReturnNoDevice;
|
|
282
|
+
|
|
283
|
+
return kIOReturnSuccess;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
|
|
289
|
+
struct libusb_context *ctx = (struct libusb_context *)ptr;
|
|
290
|
+
struct libusb_device_handle *handle;
|
|
291
|
+
struct darwin_device_priv *dpriv;
|
|
292
|
+
struct darwin_device_handle_priv *priv;
|
|
293
|
+
|
|
294
|
+
io_service_t device;
|
|
295
|
+
long location;
|
|
296
|
+
bool locationValid;
|
|
297
|
+
CFTypeRef locationCF;
|
|
298
|
+
UInt32 message;
|
|
299
|
+
|
|
300
|
+
usbi_dbg ("a device has been detached");
|
|
301
|
+
|
|
302
|
+
while ((device = IOIteratorNext (rem_devices)) != 0) {
|
|
303
|
+
/* get the location from the i/o registry */
|
|
304
|
+
locationCF = IORegistryEntryCreateCFProperty (device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0);
|
|
305
|
+
|
|
306
|
+
IOObjectRelease (device);
|
|
307
|
+
|
|
308
|
+
if (!locationCF)
|
|
309
|
+
continue;
|
|
310
|
+
|
|
311
|
+
locationValid = CFGetTypeID(locationCF) == CFNumberGetTypeID() &&
|
|
312
|
+
CFNumberGetValue(locationCF, kCFNumberLongType, &location);
|
|
313
|
+
|
|
314
|
+
CFRelease (locationCF);
|
|
315
|
+
|
|
316
|
+
if (!locationValid)
|
|
317
|
+
continue;
|
|
318
|
+
|
|
319
|
+
usbi_mutex_lock(&ctx->open_devs_lock);
|
|
320
|
+
list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
|
|
321
|
+
dpriv = (struct darwin_device_priv *)handle->dev->os_priv;
|
|
322
|
+
|
|
323
|
+
/* the device may have been opened several times. write to each handle's event descriptor */
|
|
324
|
+
if (dpriv->location == location && handle->os_priv) {
|
|
325
|
+
priv = (struct darwin_device_handle_priv *)handle->os_priv;
|
|
326
|
+
|
|
327
|
+
message = MESSAGE_DEVICE_GONE;
|
|
328
|
+
write (priv->fds[1], &message, sizeof (message));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
usbi_mutex_unlock(&ctx->open_devs_lock);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
static void darwin_clear_iterator (io_iterator_t iter) {
|
|
337
|
+
io_service_t device;
|
|
338
|
+
|
|
339
|
+
while ((device = IOIteratorNext (iter)) != 0)
|
|
340
|
+
IOObjectRelease (device);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
static void *event_thread_main (void *arg0) {
|
|
344
|
+
IOReturn kresult;
|
|
345
|
+
struct libusb_context *ctx = (struct libusb_context *)arg0;
|
|
346
|
+
CFRunLoopRef runloop;
|
|
347
|
+
|
|
348
|
+
/* Set this thread's name, so it can be seen in the debugger
|
|
349
|
+
and crash reports. */
|
|
350
|
+
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
|
351
|
+
pthread_setname_np ("org.libusb.device-detach");
|
|
352
|
+
#endif
|
|
353
|
+
|
|
354
|
+
/* Tell the Objective-C garbage collector about this thread.
|
|
355
|
+
This is required because, unlike NSThreads, pthreads are
|
|
356
|
+
not automatically registered. Although we don't use
|
|
357
|
+
Objective-C, we use CoreFoundation, which does. */
|
|
358
|
+
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
|
359
|
+
objc_registerThreadWithCollector();
|
|
360
|
+
#endif
|
|
361
|
+
|
|
362
|
+
/* hotplug (device removal) source */
|
|
363
|
+
CFRunLoopSourceRef libusb_notification_cfsource;
|
|
364
|
+
io_notification_port_t libusb_notification_port;
|
|
365
|
+
io_iterator_t libusb_rem_device_iterator;
|
|
366
|
+
|
|
367
|
+
usbi_dbg ("creating hotplug event source");
|
|
368
|
+
|
|
369
|
+
runloop = CFRunLoopGetCurrent ();
|
|
370
|
+
CFRetain (runloop);
|
|
371
|
+
|
|
372
|
+
/* add the notification port to the run loop */
|
|
373
|
+
libusb_notification_port = IONotificationPortCreate (kIOMasterPortDefault);
|
|
374
|
+
libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port);
|
|
375
|
+
CFRunLoopAddSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
|
|
376
|
+
|
|
377
|
+
/* create notifications for removed devices */
|
|
378
|
+
kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification,
|
|
379
|
+
IOServiceMatching(kIOUSBDeviceClassName),
|
|
380
|
+
(IOServiceMatchingCallback)darwin_devices_detached,
|
|
381
|
+
(void *)ctx, &libusb_rem_device_iterator);
|
|
382
|
+
|
|
383
|
+
if (kresult != kIOReturnSuccess) {
|
|
384
|
+
usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult));
|
|
385
|
+
|
|
386
|
+
pthread_exit (NULL);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* arm notifiers */
|
|
390
|
+
darwin_clear_iterator (libusb_rem_device_iterator);
|
|
391
|
+
|
|
392
|
+
usbi_dbg ("thread ready to receive events");
|
|
393
|
+
|
|
394
|
+
/* signal the main thread that the async runloop has been created. */
|
|
395
|
+
pthread_mutex_lock (&libusb_darwin_at_mutex);
|
|
396
|
+
libusb_darwin_acfl = runloop;
|
|
397
|
+
pthread_cond_signal (&libusb_darwin_at_cond);
|
|
398
|
+
pthread_mutex_unlock (&libusb_darwin_at_mutex);
|
|
399
|
+
|
|
400
|
+
/* run the runloop */
|
|
401
|
+
CFRunLoopRun();
|
|
402
|
+
|
|
403
|
+
usbi_dbg ("thread exiting");
|
|
404
|
+
|
|
405
|
+
/* delete notification port */
|
|
406
|
+
IONotificationPortDestroy (libusb_notification_port);
|
|
407
|
+
IOObjectRelease (libusb_rem_device_iterator);
|
|
408
|
+
|
|
409
|
+
CFRelease (runloop);
|
|
410
|
+
|
|
411
|
+
libusb_darwin_acfl = NULL;
|
|
412
|
+
|
|
413
|
+
pthread_exit (NULL);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
static int darwin_init(struct libusb_context *ctx) {
|
|
417
|
+
host_name_port_t host_self;
|
|
418
|
+
|
|
419
|
+
if (OSAtomicIncrement32Barrier(&initCount) == 1) {
|
|
420
|
+
/* create the clocks that will be used */
|
|
421
|
+
|
|
422
|
+
host_self = mach_host_self();
|
|
423
|
+
host_get_clock_service(host_self, CALENDAR_CLOCK, &clock_realtime);
|
|
424
|
+
host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic);
|
|
425
|
+
mach_port_deallocate(mach_task_self(), host_self);
|
|
426
|
+
|
|
427
|
+
pthread_mutex_init (&libusb_darwin_at_mutex, NULL);
|
|
428
|
+
pthread_cond_init (&libusb_darwin_at_cond, NULL);
|
|
429
|
+
|
|
430
|
+
pthread_create (&libusb_darwin_at, NULL, event_thread_main, (void *)ctx);
|
|
431
|
+
|
|
432
|
+
pthread_mutex_lock (&libusb_darwin_at_mutex);
|
|
433
|
+
while (!libusb_darwin_acfl)
|
|
434
|
+
pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
|
|
435
|
+
pthread_mutex_unlock (&libusb_darwin_at_mutex);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return 0;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
static void darwin_exit (void) {
|
|
442
|
+
if (OSAtomicDecrement32Barrier(&initCount) == 0) {
|
|
443
|
+
mach_port_deallocate(mach_task_self(), clock_realtime);
|
|
444
|
+
mach_port_deallocate(mach_task_self(), clock_monotonic);
|
|
445
|
+
|
|
446
|
+
/* stop the async runloop and wait for the thread to terminate. */
|
|
447
|
+
CFRunLoopStop (libusb_darwin_acfl);
|
|
448
|
+
pthread_join (libusb_darwin_at, NULL);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
static int darwin_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) {
|
|
453
|
+
struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
|
|
454
|
+
|
|
455
|
+
/* return cached copy */
|
|
456
|
+
memmove (buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH);
|
|
457
|
+
|
|
458
|
+
*host_endian = 0;
|
|
459
|
+
|
|
460
|
+
return 0;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
static int get_configuration_index (struct libusb_device *dev, int config_value) {
|
|
464
|
+
struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
|
|
465
|
+
UInt8 i, numConfig;
|
|
466
|
+
IOUSBConfigurationDescriptorPtr desc;
|
|
467
|
+
IOReturn kresult;
|
|
468
|
+
|
|
469
|
+
/* is there a simpler way to determine the index? */
|
|
470
|
+
kresult = (*(priv->device))->GetNumberOfConfigurations (priv->device, &numConfig);
|
|
471
|
+
if (kresult != kIOReturnSuccess)
|
|
472
|
+
return darwin_to_libusb (kresult);
|
|
473
|
+
|
|
474
|
+
for (i = 0 ; i < numConfig ; i++) {
|
|
475
|
+
(*(priv->device))->GetConfigurationDescriptorPtr (priv->device, i, &desc);
|
|
476
|
+
|
|
477
|
+
if (desc->bConfigurationValue == config_value)
|
|
478
|
+
return i;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/* configuration not found */
|
|
482
|
+
return LIBUSB_ERROR_OTHER;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
static int darwin_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) {
|
|
486
|
+
struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
|
|
487
|
+
int config_index;
|
|
488
|
+
|
|
489
|
+
if (0 == priv->active_config)
|
|
490
|
+
return LIBUSB_ERROR_INVALID_PARAM;
|
|
491
|
+
|
|
492
|
+
config_index = get_configuration_index (dev, priv->active_config);
|
|
493
|
+
if (config_index < 0)
|
|
494
|
+
return config_index;
|
|
495
|
+
|
|
496
|
+
return darwin_get_config_descriptor (dev, config_index, buffer, len, host_endian);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) {
|
|
500
|
+
struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
|
|
501
|
+
IOUSBConfigurationDescriptorPtr desc;
|
|
502
|
+
IOReturn kresult;
|
|
503
|
+
usb_device_t **device = NULL;
|
|
504
|
+
|
|
505
|
+
if (!priv)
|
|
506
|
+
return LIBUSB_ERROR_OTHER;
|
|
507
|
+
|
|
508
|
+
if (!priv->device) {
|
|
509
|
+
kresult = darwin_get_device (priv->location, &device);
|
|
510
|
+
if (kresult || !device) {
|
|
511
|
+
usbi_err (DEVICE_CTX (dev), "could not find device: %s", darwin_error_str (kresult));
|
|
512
|
+
|
|
513
|
+
return darwin_to_libusb (kresult);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/* don't have to open the device to get a config descriptor */
|
|
517
|
+
} else
|
|
518
|
+
device = priv->device;
|
|
519
|
+
|
|
520
|
+
kresult = (*device)->GetConfigurationDescriptorPtr (device, config_index, &desc);
|
|
521
|
+
if (kresult == kIOReturnSuccess) {
|
|
522
|
+
/* copy descriptor */
|
|
523
|
+
if (libusb_le16_to_cpu(desc->wTotalLength) < len)
|
|
524
|
+
len = libusb_le16_to_cpu(desc->wTotalLength);
|
|
525
|
+
|
|
526
|
+
memmove (buffer, desc, len);
|
|
527
|
+
|
|
528
|
+
/* GetConfigurationDescriptorPtr returns the descriptor in USB bus order */
|
|
529
|
+
*host_endian = 0;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (!priv->device)
|
|
533
|
+
(*device)->Release (device);
|
|
534
|
+
|
|
535
|
+
return darwin_to_libusb (kresult);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/* check whether the os has configured the device */
|
|
539
|
+
static int darwin_check_configuration (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **darwin_device) {
|
|
540
|
+
struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
|
|
541
|
+
|
|
542
|
+
IOUSBConfigurationDescriptorPtr configDesc;
|
|
543
|
+
IOUSBFindInterfaceRequest request;
|
|
544
|
+
kern_return_t kresult;
|
|
545
|
+
io_iterator_t interface_iterator;
|
|
546
|
+
io_service_t firstInterface;
|
|
547
|
+
|
|
548
|
+
if (priv->dev_descriptor.bNumConfigurations < 1) {
|
|
549
|
+
usbi_err (ctx, "device has no configurations");
|
|
550
|
+
return LIBUSB_ERROR_OTHER; /* no configurations at this speed so we can't use it */
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/* find the first configuration */
|
|
554
|
+
kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc);
|
|
555
|
+
priv->first_config = (kIOReturnSuccess == kresult) ? configDesc->bConfigurationValue : 1;
|
|
556
|
+
|
|
557
|
+
/* check if the device is already configured. there is probably a better way than iterating over the
|
|
558
|
+
to accomplish this (the trick is we need to avoid a call to GetConfigurations since buggy devices
|
|
559
|
+
might lock up on the device request) */
|
|
560
|
+
|
|
561
|
+
/* Setup the Interface Request */
|
|
562
|
+
request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
|
|
563
|
+
request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
|
|
564
|
+
request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
|
|
565
|
+
request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
|
|
566
|
+
|
|
567
|
+
kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator);
|
|
568
|
+
if (kresult)
|
|
569
|
+
return darwin_to_libusb (kresult);
|
|
570
|
+
|
|
571
|
+
/* iterate once */
|
|
572
|
+
firstInterface = IOIteratorNext(interface_iterator);
|
|
573
|
+
|
|
574
|
+
/* done with the interface iterator */
|
|
575
|
+
IOObjectRelease(interface_iterator);
|
|
576
|
+
|
|
577
|
+
if (firstInterface) {
|
|
578
|
+
IOObjectRelease (firstInterface);
|
|
579
|
+
|
|
580
|
+
/* device is configured */
|
|
581
|
+
if (priv->dev_descriptor.bNumConfigurations == 1)
|
|
582
|
+
/* to avoid problems with some devices get the configurations value from the configuration descriptor */
|
|
583
|
+
priv->active_config = priv->first_config;
|
|
584
|
+
else
|
|
585
|
+
/* devices with more than one configuration should work with GetConfiguration */
|
|
586
|
+
(*darwin_device)->GetConfiguration (darwin_device, &priv->active_config);
|
|
587
|
+
} else
|
|
588
|
+
/* not configured */
|
|
589
|
+
priv->active_config = 0;
|
|
590
|
+
|
|
591
|
+
usbi_dbg ("active config: %u, first config: %u", priv->active_config, priv->first_config);
|
|
592
|
+
|
|
593
|
+
return 0;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **device) {
|
|
597
|
+
struct darwin_device_priv *priv;
|
|
598
|
+
int retries = 5, delay = 30000;
|
|
599
|
+
int unsuspended = 0, try_unsuspend = 1, try_reconfigure = 1;
|
|
600
|
+
int is_open = 0;
|
|
601
|
+
int ret = 0, ret2;
|
|
602
|
+
IOUSBDevRequest req;
|
|
603
|
+
UInt8 bDeviceClass;
|
|
604
|
+
UInt16 idProduct, idVendor;
|
|
605
|
+
|
|
606
|
+
(*device)->GetDeviceClass (device, &bDeviceClass);
|
|
607
|
+
(*device)->GetDeviceProduct (device, &idProduct);
|
|
608
|
+
(*device)->GetDeviceVendor (device, &idVendor);
|
|
609
|
+
|
|
610
|
+
priv = (struct darwin_device_priv *)dev->os_priv;
|
|
611
|
+
|
|
612
|
+
/* try to open the device (we can usually continue even if this fails) */
|
|
613
|
+
is_open = ((*device)->USBDeviceOpenSeize(device) == kIOReturnSuccess);
|
|
614
|
+
|
|
615
|
+
/**** retrieve device descriptor ****/
|
|
616
|
+
do {
|
|
617
|
+
/* Set up request for device descriptor */
|
|
618
|
+
memset (&(priv->dev_descriptor), 0, sizeof(IOUSBDeviceDescriptor));
|
|
619
|
+
req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
|
|
620
|
+
req.bRequest = kUSBRqGetDescriptor;
|
|
621
|
+
req.wValue = kUSBDeviceDesc << 8;
|
|
622
|
+
req.wIndex = 0;
|
|
623
|
+
req.wLength = sizeof(priv->dev_descriptor);
|
|
624
|
+
req.pData = &(priv->dev_descriptor);
|
|
625
|
+
|
|
626
|
+
/* according to Apple's documentation the device must be open for DeviceRequest but we may not be able to open some
|
|
627
|
+
* devices and Apple's USB Prober doesn't bother to open the device before issuing a descriptor request. Still,
|
|
628
|
+
* to follow the spec as closely as possible, try opening the device */
|
|
629
|
+
|
|
630
|
+
ret = (*(device))->DeviceRequest (device, &req);
|
|
631
|
+
|
|
632
|
+
if (kIOReturnOverrun == ret && kUSBDeviceDesc == priv->dev_descriptor.bDescriptorType)
|
|
633
|
+
/* received an overrun error but we still received a device descriptor */
|
|
634
|
+
ret = kIOReturnSuccess;
|
|
635
|
+
|
|
636
|
+
if (kIOReturnSuccess == ret && (0 == priv->dev_descriptor.bNumConfigurations ||
|
|
637
|
+
0 == priv->dev_descriptor.bcdUSB)) {
|
|
638
|
+
/* work around for incorrectly configured devices */
|
|
639
|
+
if (try_reconfigure && is_open) {
|
|
640
|
+
usbi_dbg("descriptor appears to be invalid. resetting configuration before trying again...");
|
|
641
|
+
|
|
642
|
+
/* set the first configuration */
|
|
643
|
+
(*device)->SetConfiguration(device, 1);
|
|
644
|
+
|
|
645
|
+
/* don't try to reconfigure again */
|
|
646
|
+
try_reconfigure = 0;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
ret = kIOUSBPipeStalled;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
if (kIOReturnSuccess != ret && is_open && try_unsuspend) {
|
|
653
|
+
/* device may be suspended. unsuspend it and try again */
|
|
654
|
+
#if DeviceVersion >= 320
|
|
655
|
+
UInt32 info;
|
|
656
|
+
|
|
657
|
+
/* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */
|
|
658
|
+
(void)(*device)->GetUSBDeviceInformation (device, &info);
|
|
659
|
+
|
|
660
|
+
try_unsuspend = info & (1 << kUSBInformationDeviceIsSuspendedBit);
|
|
661
|
+
#endif
|
|
662
|
+
|
|
663
|
+
if (try_unsuspend) {
|
|
664
|
+
/* resume the device */
|
|
665
|
+
ret2 = (*device)->USBDeviceSuspend (device, 0);
|
|
666
|
+
if (kIOReturnSuccess != ret2) {
|
|
667
|
+
/* prevent log spew from poorly behaving devices. this indicates the
|
|
668
|
+
os actually had trouble communicating with the device */
|
|
669
|
+
usbi_dbg("could not retrieve device descriptor. failed to unsuspend: %s",darwin_error_str(ret2));
|
|
670
|
+
} else
|
|
671
|
+
unsuspended = 1;
|
|
672
|
+
|
|
673
|
+
try_unsuspend = 0;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if (kIOReturnSuccess != ret) {
|
|
678
|
+
usbi_dbg("kernel responded with code: 0x%08x. sleeping for %d ms before trying again", ret, delay/1000);
|
|
679
|
+
/* sleep for a little while before trying again */
|
|
680
|
+
usleep (delay);
|
|
681
|
+
}
|
|
682
|
+
} while (kIOReturnSuccess != ret && retries--);
|
|
683
|
+
|
|
684
|
+
if (unsuspended)
|
|
685
|
+
/* resuspend the device */
|
|
686
|
+
(void)(*device)->USBDeviceSuspend (device, 1);
|
|
687
|
+
|
|
688
|
+
if (is_open)
|
|
689
|
+
(void) (*device)->USBDeviceClose (device);
|
|
690
|
+
|
|
691
|
+
if (ret != kIOReturnSuccess) {
|
|
692
|
+
/* a debug message was already printed out for this error */
|
|
693
|
+
if (LIBUSB_CLASS_HUB == bDeviceClass)
|
|
694
|
+
usbi_dbg ("could not retrieve device descriptor %.4x:%.4x: %s. skipping device", idVendor, idProduct, darwin_error_str (ret));
|
|
695
|
+
else
|
|
696
|
+
usbi_warn (ctx, "could not retrieve device descriptor %.4x:%.4x: %s. skipping device", idVendor, idProduct, darwin_error_str (ret));
|
|
697
|
+
|
|
698
|
+
return -1;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
usbi_dbg ("device descriptor:");
|
|
702
|
+
usbi_dbg (" bDescriptorType: 0x%02x", priv->dev_descriptor.bDescriptorType);
|
|
703
|
+
usbi_dbg (" bcdUSB: 0x%04x", priv->dev_descriptor.bcdUSB);
|
|
704
|
+
usbi_dbg (" bDeviceClass: 0x%02x", priv->dev_descriptor.bDeviceClass);
|
|
705
|
+
usbi_dbg (" bDeviceSubClass: 0x%02x", priv->dev_descriptor.bDeviceSubClass);
|
|
706
|
+
usbi_dbg (" bDeviceProtocol: 0x%02x", priv->dev_descriptor.bDeviceProtocol);
|
|
707
|
+
usbi_dbg (" bMaxPacketSize0: 0x%02x", priv->dev_descriptor.bMaxPacketSize0);
|
|
708
|
+
usbi_dbg (" idVendor: 0x%04x", priv->dev_descriptor.idVendor);
|
|
709
|
+
usbi_dbg (" idProduct: 0x%04x", priv->dev_descriptor.idProduct);
|
|
710
|
+
usbi_dbg (" bcdDevice: 0x%04x", priv->dev_descriptor.bcdDevice);
|
|
711
|
+
usbi_dbg (" iManufacturer: 0x%02x", priv->dev_descriptor.iManufacturer);
|
|
712
|
+
usbi_dbg (" iProduct: 0x%02x", priv->dev_descriptor.iProduct);
|
|
713
|
+
usbi_dbg (" iSerialNumber: 0x%02x", priv->dev_descriptor.iSerialNumber);
|
|
714
|
+
usbi_dbg (" bNumConfigurations: 0x%02x", priv->dev_descriptor.bNumConfigurations);
|
|
715
|
+
|
|
716
|
+
/* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */
|
|
717
|
+
if (libusb_le16_to_cpu (priv->dev_descriptor.idProduct) != idProduct) {
|
|
718
|
+
/* not a valid device */
|
|
719
|
+
usbi_warn (ctx, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device",
|
|
720
|
+
idProduct, libusb_le16_to_cpu (priv->dev_descriptor.idProduct));
|
|
721
|
+
return -1;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
return 0;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
static int process_new_device (struct libusb_context *ctx, usb_device_t **device, UInt32 locationID,
|
|
728
|
+
UInt32 parent_location, UInt8 port, struct discovered_devs **_discdevs,
|
|
729
|
+
struct libusb_device **last_dev) {
|
|
730
|
+
struct darwin_device_priv *priv;
|
|
731
|
+
struct libusb_device *dev, *parent = NULL;
|
|
732
|
+
struct discovered_devs *discdevs;
|
|
733
|
+
UInt16 address;
|
|
734
|
+
UInt8 devSpeed;
|
|
735
|
+
int ret = 0, need_unref = 0;
|
|
736
|
+
|
|
737
|
+
do {
|
|
738
|
+
dev = usbi_get_device_by_session_id(ctx, locationID);
|
|
739
|
+
if (!dev) {
|
|
740
|
+
usbi_dbg ("allocating new device for location 0x%08x", locationID);
|
|
741
|
+
dev = usbi_alloc_device(ctx, locationID);
|
|
742
|
+
need_unref = 1;
|
|
743
|
+
} else
|
|
744
|
+
usbi_dbg ("using existing device for location 0x%08x", locationID);
|
|
745
|
+
|
|
746
|
+
if (!dev) {
|
|
747
|
+
ret = LIBUSB_ERROR_NO_MEM;
|
|
748
|
+
break;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
priv = (struct darwin_device_priv *)dev->os_priv;
|
|
752
|
+
|
|
753
|
+
(*device)->GetDeviceAddress (device, (USBDeviceAddress *)&address);
|
|
754
|
+
|
|
755
|
+
ret = darwin_cache_device_descriptor (ctx, dev, device);
|
|
756
|
+
if (ret < 0)
|
|
757
|
+
break;
|
|
758
|
+
|
|
759
|
+
/* check current active configuration (and cache the first configuration value-- which may be used by claim_interface) */
|
|
760
|
+
ret = darwin_check_configuration (ctx, dev, device);
|
|
761
|
+
if (ret < 0)
|
|
762
|
+
break;
|
|
763
|
+
|
|
764
|
+
/* the device iterator provides devices in increasing order of location. given this property
|
|
765
|
+
* we can use the last device to find the parent. */
|
|
766
|
+
for (parent = *last_dev ; parent ; parent = parent->parent_dev) {
|
|
767
|
+
struct darwin_device_priv *parent_priv = (struct darwin_device_priv *) parent->os_priv;
|
|
768
|
+
|
|
769
|
+
if (parent_priv->location == parent_location) {
|
|
770
|
+
break;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
dev->parent_dev = parent;
|
|
775
|
+
|
|
776
|
+
dev->port_number = port;
|
|
777
|
+
dev->bus_number = locationID >> 24;
|
|
778
|
+
dev->device_address = address;
|
|
779
|
+
|
|
780
|
+
(*device)->GetDeviceSpeed (device, &devSpeed);
|
|
781
|
+
|
|
782
|
+
switch (devSpeed) {
|
|
783
|
+
case kUSBDeviceSpeedLow: dev->speed = LIBUSB_SPEED_LOW; break;
|
|
784
|
+
case kUSBDeviceSpeedFull: dev->speed = LIBUSB_SPEED_FULL; break;
|
|
785
|
+
case kUSBDeviceSpeedHigh: dev->speed = LIBUSB_SPEED_HIGH; break;
|
|
786
|
+
default:
|
|
787
|
+
usbi_warn (ctx, "Got unknown device speed %d", devSpeed);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/* save our location, we'll need this later */
|
|
791
|
+
priv->location = locationID;
|
|
792
|
+
snprintf(priv->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", address, priv->dev_descriptor.idVendor, priv->dev_descriptor.idProduct,
|
|
793
|
+
priv->dev_descriptor.bDeviceClass, priv->dev_descriptor.bDeviceSubClass);
|
|
794
|
+
|
|
795
|
+
ret = usbi_sanitize_device (dev);
|
|
796
|
+
if (ret < 0)
|
|
797
|
+
break;
|
|
798
|
+
|
|
799
|
+
/* append the device to the list of discovered devices */
|
|
800
|
+
discdevs = discovered_devs_append(*_discdevs, dev);
|
|
801
|
+
if (!discdevs) {
|
|
802
|
+
ret = LIBUSB_ERROR_NO_MEM;
|
|
803
|
+
break;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
*_discdevs = discdevs;
|
|
807
|
+
*last_dev = dev;
|
|
808
|
+
|
|
809
|
+
usbi_dbg ("found device with address %d port = %d parent = %p at %p", dev->device_address,
|
|
810
|
+
dev->port_number, priv->sys_path, (void *) parent);
|
|
811
|
+
} while (0);
|
|
812
|
+
|
|
813
|
+
if (need_unref)
|
|
814
|
+
libusb_unref_device(dev);
|
|
815
|
+
|
|
816
|
+
return ret;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
static int darwin_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) {
|
|
820
|
+
io_iterator_t deviceIterator;
|
|
821
|
+
usb_device_t **device;
|
|
822
|
+
kern_return_t kresult;
|
|
823
|
+
UInt32 location, parent_location;
|
|
824
|
+
UInt8 port;
|
|
825
|
+
struct libusb_device *last_dev = NULL;
|
|
826
|
+
|
|
827
|
+
kresult = usb_setup_device_iterator (&deviceIterator, 0);
|
|
828
|
+
if (kresult != kIOReturnSuccess)
|
|
829
|
+
return darwin_to_libusb (kresult);
|
|
830
|
+
|
|
831
|
+
while ((device = usb_get_next_device (deviceIterator, &location, &port, &parent_location)) != NULL) {
|
|
832
|
+
(void) process_new_device (ctx, device, location, parent_location, port, _discdevs, &last_dev);
|
|
833
|
+
|
|
834
|
+
(*(device))->Release(device);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
IOObjectRelease(deviceIterator);
|
|
838
|
+
|
|
839
|
+
return 0;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
static int darwin_open (struct libusb_device_handle *dev_handle) {
|
|
843
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
|
|
844
|
+
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
|
|
845
|
+
usb_device_t **darwin_device;
|
|
846
|
+
IOReturn kresult;
|
|
847
|
+
|
|
848
|
+
if (0 == dpriv->open_count) {
|
|
849
|
+
kresult = darwin_get_device (dpriv->location, &darwin_device);
|
|
850
|
+
if (kresult) {
|
|
851
|
+
usbi_err (HANDLE_CTX (dev_handle), "could not find device: %s", darwin_error_str (kresult));
|
|
852
|
+
return darwin_to_libusb (kresult);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
dpriv->device = darwin_device;
|
|
856
|
+
|
|
857
|
+
/* try to open the device */
|
|
858
|
+
kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device);
|
|
859
|
+
|
|
860
|
+
if (kresult != kIOReturnSuccess) {
|
|
861
|
+
usbi_warn (HANDLE_CTX (dev_handle), "USBDeviceOpen: %s", darwin_error_str(kresult));
|
|
862
|
+
|
|
863
|
+
switch (kresult) {
|
|
864
|
+
case kIOReturnExclusiveAccess:
|
|
865
|
+
/* it is possible to perform some actions on a device that is not open so do not return an error */
|
|
866
|
+
priv->is_open = 0;
|
|
867
|
+
|
|
868
|
+
break;
|
|
869
|
+
default:
|
|
870
|
+
(*(dpriv->device))->Release (dpriv->device);
|
|
871
|
+
dpriv->device = NULL;
|
|
872
|
+
return darwin_to_libusb (kresult);
|
|
873
|
+
}
|
|
874
|
+
} else {
|
|
875
|
+
/* create async event source */
|
|
876
|
+
kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource);
|
|
877
|
+
if (kresult != kIOReturnSuccess) {
|
|
878
|
+
usbi_err (HANDLE_CTX (dev_handle), "CreateDeviceAsyncEventSource: %s", darwin_error_str(kresult));
|
|
879
|
+
|
|
880
|
+
(*(dpriv->device))->USBDeviceClose (dpriv->device);
|
|
881
|
+
(*(dpriv->device))->Release (dpriv->device);
|
|
882
|
+
|
|
883
|
+
dpriv->device = NULL;
|
|
884
|
+
return darwin_to_libusb (kresult);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
priv->is_open = 1;
|
|
888
|
+
|
|
889
|
+
CFRetain (libusb_darwin_acfl);
|
|
890
|
+
|
|
891
|
+
/* add the cfSource to the aync run loop */
|
|
892
|
+
CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/* device opened successfully */
|
|
897
|
+
dpriv->open_count++;
|
|
898
|
+
|
|
899
|
+
/* create a file descriptor for notifications */
|
|
900
|
+
pipe (priv->fds);
|
|
901
|
+
|
|
902
|
+
/* set the pipe to be non-blocking */
|
|
903
|
+
fcntl (priv->fds[1], F_SETFD, O_NONBLOCK);
|
|
904
|
+
|
|
905
|
+
usbi_add_pollfd(HANDLE_CTX(dev_handle), priv->fds[0], POLLIN);
|
|
906
|
+
|
|
907
|
+
usbi_dbg ("device open for access");
|
|
908
|
+
|
|
909
|
+
return 0;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
static void darwin_close (struct libusb_device_handle *dev_handle) {
|
|
913
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
|
|
914
|
+
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
|
|
915
|
+
IOReturn kresult;
|
|
916
|
+
int i;
|
|
917
|
+
|
|
918
|
+
if (dpriv->open_count == 0) {
|
|
919
|
+
/* something is probably very wrong if this is the case */
|
|
920
|
+
usbi_err (HANDLE_CTX (dev_handle), "Close called on a device that was not open!\n");
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
dpriv->open_count--;
|
|
925
|
+
|
|
926
|
+
/* make sure all interfaces are released */
|
|
927
|
+
for (i = 0 ; i < USB_MAXINTERFACES ; i++)
|
|
928
|
+
if (dev_handle->claimed_interfaces & (1 << i))
|
|
929
|
+
libusb_release_interface (dev_handle, i);
|
|
930
|
+
|
|
931
|
+
if (0 == dpriv->open_count) {
|
|
932
|
+
if (priv->is_open) {
|
|
933
|
+
/* delete the device's async event source */
|
|
934
|
+
if (priv->cfSource) {
|
|
935
|
+
CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode);
|
|
936
|
+
CFRelease (priv->cfSource);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/* close the device */
|
|
940
|
+
kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device);
|
|
941
|
+
if (kresult) {
|
|
942
|
+
/* Log the fact that we had a problem closing the file, however failing a
|
|
943
|
+
* close isn't really an error, so return success anyway */
|
|
944
|
+
usbi_warn (HANDLE_CTX (dev_handle), "USBDeviceClose: %s", darwin_error_str(kresult));
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
kresult = (*(dpriv->device))->Release(dpriv->device);
|
|
949
|
+
if (kresult) {
|
|
950
|
+
/* Log the fact that we had a problem closing the file, however failing a
|
|
951
|
+
* close isn't really an error, so return success anyway */
|
|
952
|
+
usbi_warn (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult));
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
dpriv->device = NULL;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/* file descriptors are maintained per-instance */
|
|
959
|
+
usbi_remove_pollfd (HANDLE_CTX (dev_handle), priv->fds[0]);
|
|
960
|
+
close (priv->fds[1]);
|
|
961
|
+
close (priv->fds[0]);
|
|
962
|
+
|
|
963
|
+
priv->fds[0] = priv->fds[1] = -1;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) {
|
|
967
|
+
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
|
|
968
|
+
|
|
969
|
+
*config = (int) dpriv->active_config;
|
|
970
|
+
|
|
971
|
+
return 0;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
static int darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) {
|
|
975
|
+
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
|
|
976
|
+
IOReturn kresult;
|
|
977
|
+
int i;
|
|
978
|
+
|
|
979
|
+
/* Setting configuration will invalidate the interface, so we need
|
|
980
|
+
to reclaim it. First, dispose of existing interfaces, if any. */
|
|
981
|
+
for (i = 0 ; i < USB_MAXINTERFACES ; i++)
|
|
982
|
+
if (dev_handle->claimed_interfaces & (1 << i))
|
|
983
|
+
darwin_release_interface (dev_handle, i);
|
|
984
|
+
|
|
985
|
+
kresult = (*(dpriv->device))->SetConfiguration (dpriv->device, config);
|
|
986
|
+
if (kresult != kIOReturnSuccess)
|
|
987
|
+
return darwin_to_libusb (kresult);
|
|
988
|
+
|
|
989
|
+
/* Reclaim any interfaces. */
|
|
990
|
+
for (i = 0 ; i < USB_MAXINTERFACES ; i++)
|
|
991
|
+
if (dev_handle->claimed_interfaces & (1 << i))
|
|
992
|
+
darwin_claim_interface (dev_handle, i);
|
|
993
|
+
|
|
994
|
+
dpriv->active_config = config;
|
|
995
|
+
|
|
996
|
+
return 0;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
static int darwin_get_interface (usb_device_t **darwin_device, uint8_t ifc, io_service_t *usbInterfacep) {
|
|
1000
|
+
IOUSBFindInterfaceRequest request;
|
|
1001
|
+
uint8_t current_interface;
|
|
1002
|
+
kern_return_t kresult;
|
|
1003
|
+
io_iterator_t interface_iterator;
|
|
1004
|
+
|
|
1005
|
+
*usbInterfacep = IO_OBJECT_NULL;
|
|
1006
|
+
|
|
1007
|
+
/* Setup the Interface Request */
|
|
1008
|
+
request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
|
|
1009
|
+
request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
|
|
1010
|
+
request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
|
|
1011
|
+
request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
|
|
1012
|
+
|
|
1013
|
+
kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator);
|
|
1014
|
+
if (kresult)
|
|
1015
|
+
return kresult;
|
|
1016
|
+
|
|
1017
|
+
for ( current_interface = 0 ; current_interface <= ifc ; current_interface++ ) {
|
|
1018
|
+
*usbInterfacep = IOIteratorNext(interface_iterator);
|
|
1019
|
+
if (current_interface != ifc)
|
|
1020
|
+
(void) IOObjectRelease (*usbInterfacep);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/* done with the interface iterator */
|
|
1024
|
+
IOObjectRelease(interface_iterator);
|
|
1025
|
+
|
|
1026
|
+
return 0;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) {
|
|
1030
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
|
|
1031
|
+
|
|
1032
|
+
/* current interface */
|
|
1033
|
+
struct darwin_interface *cInterface = &priv->interfaces[iface];
|
|
1034
|
+
|
|
1035
|
+
kern_return_t kresult;
|
|
1036
|
+
|
|
1037
|
+
u_int8_t numep, direction, number;
|
|
1038
|
+
u_int8_t dont_care1, dont_care3;
|
|
1039
|
+
u_int16_t dont_care2;
|
|
1040
|
+
int i;
|
|
1041
|
+
|
|
1042
|
+
usbi_dbg ("building table of endpoints.");
|
|
1043
|
+
|
|
1044
|
+
/* retrieve the total number of endpoints on this interface */
|
|
1045
|
+
kresult = (*(cInterface->interface))->GetNumEndpoints(cInterface->interface, &numep);
|
|
1046
|
+
if (kresult) {
|
|
1047
|
+
usbi_err (HANDLE_CTX (dev_handle), "can't get number of endpoints for interface: %s", darwin_error_str(kresult));
|
|
1048
|
+
return darwin_to_libusb (kresult);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
/* iterate through pipe references */
|
|
1052
|
+
for (i = 1 ; i <= numep ; i++) {
|
|
1053
|
+
kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1,
|
|
1054
|
+
&dont_care2, &dont_care3);
|
|
1055
|
+
|
|
1056
|
+
if (kresult != kIOReturnSuccess) {
|
|
1057
|
+
usbi_err (HANDLE_CTX (dev_handle), "error getting pipe information for pipe %d: %s", i, darwin_error_str(kresult));
|
|
1058
|
+
|
|
1059
|
+
return darwin_to_libusb (kresult);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
usbi_dbg ("interface: %i pipe %i: dir: %i number: %i", iface, i, direction, number);
|
|
1063
|
+
|
|
1064
|
+
cInterface->endpoint_addrs[i - 1] = ((direction << 7 & LIBUSB_ENDPOINT_DIR_MASK) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK));
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
cInterface->num_endpoints = numep;
|
|
1068
|
+
|
|
1069
|
+
return 0;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface) {
|
|
1073
|
+
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
|
|
1074
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
|
|
1075
|
+
io_service_t usbInterface = IO_OBJECT_NULL;
|
|
1076
|
+
IOReturn kresult;
|
|
1077
|
+
IOCFPlugInInterface **plugInInterface = NULL;
|
|
1078
|
+
SInt32 score;
|
|
1079
|
+
|
|
1080
|
+
/* current interface */
|
|
1081
|
+
struct darwin_interface *cInterface = &priv->interfaces[iface];
|
|
1082
|
+
|
|
1083
|
+
kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
|
|
1084
|
+
if (kresult != kIOReturnSuccess)
|
|
1085
|
+
return darwin_to_libusb (kresult);
|
|
1086
|
+
|
|
1087
|
+
/* make sure we have an interface */
|
|
1088
|
+
if (!usbInterface && dpriv->first_config != 0) {
|
|
1089
|
+
usbi_info (HANDLE_CTX (dev_handle), "no interface found; setting configuration: %d", dpriv->first_config);
|
|
1090
|
+
|
|
1091
|
+
/* set the configuration */
|
|
1092
|
+
kresult = darwin_set_configuration (dev_handle, dpriv->first_config);
|
|
1093
|
+
if (kresult != LIBUSB_SUCCESS) {
|
|
1094
|
+
usbi_err (HANDLE_CTX (dev_handle), "could not set configuration");
|
|
1095
|
+
return kresult;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
|
|
1099
|
+
if (kresult) {
|
|
1100
|
+
usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult));
|
|
1101
|
+
return darwin_to_libusb (kresult);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
if (!usbInterface) {
|
|
1106
|
+
usbi_err (HANDLE_CTX (dev_handle), "interface not found");
|
|
1107
|
+
return LIBUSB_ERROR_NOT_FOUND;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
/* get an interface to the device's interface */
|
|
1111
|
+
kresult = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID,
|
|
1112
|
+
kIOCFPlugInInterfaceID, &plugInInterface, &score);
|
|
1113
|
+
|
|
1114
|
+
/* ignore release error */
|
|
1115
|
+
(void)IOObjectRelease (usbInterface);
|
|
1116
|
+
|
|
1117
|
+
if (kresult) {
|
|
1118
|
+
usbi_err (HANDLE_CTX (dev_handle), "IOCreatePlugInInterfaceForService: %s", darwin_error_str(kresult));
|
|
1119
|
+
return darwin_to_libusb (kresult);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
if (!plugInInterface) {
|
|
1123
|
+
usbi_err (HANDLE_CTX (dev_handle), "plugin interface not found");
|
|
1124
|
+
return LIBUSB_ERROR_NOT_FOUND;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
/* Do the actual claim */
|
|
1128
|
+
kresult = (*plugInInterface)->QueryInterface(plugInInterface,
|
|
1129
|
+
CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
|
|
1130
|
+
(LPVOID)&cInterface->interface);
|
|
1131
|
+
/* We no longer need the intermediate plug-in */
|
|
1132
|
+
IODestroyPlugInInterface (plugInInterface);
|
|
1133
|
+
if (kresult || !cInterface->interface) {
|
|
1134
|
+
usbi_err (HANDLE_CTX (dev_handle), "QueryInterface: %s", darwin_error_str(kresult));
|
|
1135
|
+
return darwin_to_libusb (kresult);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/* claim the interface */
|
|
1139
|
+
kresult = (*(cInterface->interface))->USBInterfaceOpen(cInterface->interface);
|
|
1140
|
+
if (kresult) {
|
|
1141
|
+
usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceOpen: %s", darwin_error_str(kresult));
|
|
1142
|
+
return darwin_to_libusb (kresult);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/* update list of endpoints */
|
|
1146
|
+
kresult = get_endpoints (dev_handle, iface);
|
|
1147
|
+
if (kresult) {
|
|
1148
|
+
/* this should not happen */
|
|
1149
|
+
darwin_release_interface (dev_handle, iface);
|
|
1150
|
+
usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table");
|
|
1151
|
+
return kresult;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
cInterface->cfSource = NULL;
|
|
1155
|
+
|
|
1156
|
+
/* create async event source */
|
|
1157
|
+
kresult = (*(cInterface->interface))->CreateInterfaceAsyncEventSource (cInterface->interface, &cInterface->cfSource);
|
|
1158
|
+
if (kresult != kIOReturnSuccess) {
|
|
1159
|
+
usbi_err (HANDLE_CTX (dev_handle), "could not create async event source");
|
|
1160
|
+
|
|
1161
|
+
/* can't continue without an async event source */
|
|
1162
|
+
(void)darwin_release_interface (dev_handle, iface);
|
|
1163
|
+
|
|
1164
|
+
return darwin_to_libusb (kresult);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
/* add the cfSource to the async thread's run loop */
|
|
1168
|
+
CFRunLoopAddSource(libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode);
|
|
1169
|
+
|
|
1170
|
+
usbi_dbg ("interface opened");
|
|
1171
|
+
|
|
1172
|
+
return 0;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface) {
|
|
1176
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
|
|
1177
|
+
IOReturn kresult;
|
|
1178
|
+
|
|
1179
|
+
/* current interface */
|
|
1180
|
+
struct darwin_interface *cInterface = &priv->interfaces[iface];
|
|
1181
|
+
|
|
1182
|
+
/* Check to see if an interface is open */
|
|
1183
|
+
if (!cInterface->interface)
|
|
1184
|
+
return LIBUSB_SUCCESS;
|
|
1185
|
+
|
|
1186
|
+
/* clean up endpoint data */
|
|
1187
|
+
cInterface->num_endpoints = 0;
|
|
1188
|
+
|
|
1189
|
+
/* delete the interface's async event source */
|
|
1190
|
+
if (cInterface->cfSource) {
|
|
1191
|
+
CFRunLoopRemoveSource (libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode);
|
|
1192
|
+
CFRelease (cInterface->cfSource);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
kresult = (*(cInterface->interface))->USBInterfaceClose(cInterface->interface);
|
|
1196
|
+
if (kresult)
|
|
1197
|
+
usbi_warn (HANDLE_CTX (dev_handle), "USBInterfaceClose: %s", darwin_error_str(kresult));
|
|
1198
|
+
|
|
1199
|
+
kresult = (*(cInterface->interface))->Release(cInterface->interface);
|
|
1200
|
+
if (kresult != kIOReturnSuccess)
|
|
1201
|
+
usbi_warn (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult));
|
|
1202
|
+
|
|
1203
|
+
cInterface->interface = IO_OBJECT_NULL;
|
|
1204
|
+
|
|
1205
|
+
return darwin_to_libusb (kresult);
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) {
|
|
1209
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
|
|
1210
|
+
IOReturn kresult;
|
|
1211
|
+
|
|
1212
|
+
/* current interface */
|
|
1213
|
+
struct darwin_interface *cInterface = &priv->interfaces[iface];
|
|
1214
|
+
|
|
1215
|
+
if (!cInterface->interface)
|
|
1216
|
+
return LIBUSB_ERROR_NO_DEVICE;
|
|
1217
|
+
|
|
1218
|
+
kresult = (*(cInterface->interface))->SetAlternateInterface (cInterface->interface, altsetting);
|
|
1219
|
+
if (kresult != kIOReturnSuccess)
|
|
1220
|
+
darwin_reset_device (dev_handle);
|
|
1221
|
+
|
|
1222
|
+
/* update list of endpoints */
|
|
1223
|
+
kresult = get_endpoints (dev_handle, iface);
|
|
1224
|
+
if (kresult) {
|
|
1225
|
+
/* this should not happen */
|
|
1226
|
+
darwin_release_interface (dev_handle, iface);
|
|
1227
|
+
usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table");
|
|
1228
|
+
return kresult;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
return darwin_to_libusb (kresult);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) {
|
|
1235
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
|
|
1236
|
+
|
|
1237
|
+
/* current interface */
|
|
1238
|
+
struct darwin_interface *cInterface;
|
|
1239
|
+
uint8_t pipeRef, iface;
|
|
1240
|
+
IOReturn kresult;
|
|
1241
|
+
|
|
1242
|
+
/* determine the interface/endpoint to use */
|
|
1243
|
+
if (ep_to_pipeRef (dev_handle, endpoint, &pipeRef, &iface) != 0) {
|
|
1244
|
+
usbi_err (HANDLE_CTX (dev_handle), "endpoint not found on any open interface");
|
|
1245
|
+
|
|
1246
|
+
return LIBUSB_ERROR_NOT_FOUND;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
cInterface = &priv->interfaces[iface];
|
|
1250
|
+
|
|
1251
|
+
#if (InterfaceVersion < 190)
|
|
1252
|
+
kresult = (*(cInterface->interface))->ClearPipeStall(cInterface->interface, pipeRef);
|
|
1253
|
+
#else
|
|
1254
|
+
/* newer versions of darwin support clearing additional bits on the device's endpoint */
|
|
1255
|
+
kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef);
|
|
1256
|
+
#endif
|
|
1257
|
+
if (kresult)
|
|
1258
|
+
usbi_warn (HANDLE_CTX (dev_handle), "ClearPipeStall: %s", darwin_error_str (kresult));
|
|
1259
|
+
|
|
1260
|
+
return darwin_to_libusb (kresult);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
static int darwin_reset_device(struct libusb_device_handle *dev_handle) {
|
|
1264
|
+
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
|
|
1265
|
+
IOReturn kresult;
|
|
1266
|
+
|
|
1267
|
+
kresult = (*(dpriv->device))->ResetDevice (dpriv->device);
|
|
1268
|
+
if (kresult)
|
|
1269
|
+
usbi_err (HANDLE_CTX (dev_handle), "ResetDevice: %s", darwin_error_str (kresult));
|
|
1270
|
+
|
|
1271
|
+
return darwin_to_libusb (kresult);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, int interface) {
|
|
1275
|
+
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
|
|
1276
|
+
io_service_t usbInterface;
|
|
1277
|
+
CFTypeRef driver;
|
|
1278
|
+
IOReturn kresult;
|
|
1279
|
+
|
|
1280
|
+
kresult = darwin_get_interface (dpriv->device, interface, &usbInterface);
|
|
1281
|
+
if (kresult) {
|
|
1282
|
+
usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult));
|
|
1283
|
+
|
|
1284
|
+
return darwin_to_libusb (kresult);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
driver = IORegistryEntryCreateCFProperty (usbInterface, kIOBundleIdentifierKey, kCFAllocatorDefault, 0);
|
|
1288
|
+
IOObjectRelease (usbInterface);
|
|
1289
|
+
|
|
1290
|
+
if (driver) {
|
|
1291
|
+
CFRelease (driver);
|
|
1292
|
+
|
|
1293
|
+
return 1;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
/* no driver */
|
|
1297
|
+
return 0;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
/* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */
|
|
1301
|
+
static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
|
|
1302
|
+
(void)dev_handle;
|
|
1303
|
+
(void)interface;
|
|
1304
|
+
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
|
|
1308
|
+
(void)dev_handle;
|
|
1309
|
+
(void)interface;
|
|
1310
|
+
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
static void darwin_destroy_device(struct libusb_device *dev) {
|
|
1314
|
+
(void)dev;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
|
|
1318
|
+
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
1319
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
|
|
1320
|
+
|
|
1321
|
+
IOReturn ret;
|
|
1322
|
+
uint8_t transferType;
|
|
1323
|
+
/* None of the values below are used in libusbx for bulk transfers */
|
|
1324
|
+
uint8_t direction, number, interval, pipeRef, iface;
|
|
1325
|
+
uint16_t maxPacketSize;
|
|
1326
|
+
|
|
1327
|
+
struct darwin_interface *cInterface;
|
|
1328
|
+
|
|
1329
|
+
if (IS_XFEROUT(transfer) && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)
|
|
1330
|
+
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
1331
|
+
|
|
1332
|
+
if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
|
|
1333
|
+
usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
|
|
1334
|
+
|
|
1335
|
+
return LIBUSB_ERROR_NOT_FOUND;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
cInterface = &priv->interfaces[iface];
|
|
1339
|
+
|
|
1340
|
+
(*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
|
|
1341
|
+
&transferType, &maxPacketSize, &interval);
|
|
1342
|
+
|
|
1343
|
+
/* submit the request */
|
|
1344
|
+
/* timeouts are unavailable on interrupt endpoints */
|
|
1345
|
+
if (transferType == kUSBInterrupt) {
|
|
1346
|
+
if (IS_XFERIN(transfer))
|
|
1347
|
+
ret = (*(cInterface->interface))->ReadPipeAsync(cInterface->interface, pipeRef, transfer->buffer,
|
|
1348
|
+
transfer->length, darwin_async_io_callback, itransfer);
|
|
1349
|
+
else
|
|
1350
|
+
ret = (*(cInterface->interface))->WritePipeAsync(cInterface->interface, pipeRef, transfer->buffer,
|
|
1351
|
+
transfer->length, darwin_async_io_callback, itransfer);
|
|
1352
|
+
} else {
|
|
1353
|
+
itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
|
|
1354
|
+
|
|
1355
|
+
if (IS_XFERIN(transfer))
|
|
1356
|
+
ret = (*(cInterface->interface))->ReadPipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer,
|
|
1357
|
+
transfer->length, transfer->timeout, transfer->timeout,
|
|
1358
|
+
darwin_async_io_callback, (void *)itransfer);
|
|
1359
|
+
else
|
|
1360
|
+
ret = (*(cInterface->interface))->WritePipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer,
|
|
1361
|
+
transfer->length, transfer->timeout, transfer->timeout,
|
|
1362
|
+
darwin_async_io_callback, (void *)itransfer);
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
if (ret)
|
|
1366
|
+
usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out",
|
|
1367
|
+
darwin_error_str(ret), ret);
|
|
1368
|
+
|
|
1369
|
+
return darwin_to_libusb (ret);
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
static int submit_iso_transfer(struct usbi_transfer *itransfer) {
|
|
1373
|
+
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
1374
|
+
struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
|
|
1375
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
|
|
1376
|
+
|
|
1377
|
+
IOReturn kresult;
|
|
1378
|
+
uint8_t pipeRef, iface;
|
|
1379
|
+
UInt64 frame;
|
|
1380
|
+
AbsoluteTime atTime;
|
|
1381
|
+
int i;
|
|
1382
|
+
|
|
1383
|
+
struct darwin_interface *cInterface;
|
|
1384
|
+
|
|
1385
|
+
/* construct an array of IOUSBIsocFrames, reuse the old one if possible */
|
|
1386
|
+
if (tpriv->isoc_framelist && tpriv->num_iso_packets != transfer->num_iso_packets) {
|
|
1387
|
+
free(tpriv->isoc_framelist);
|
|
1388
|
+
tpriv->isoc_framelist = NULL;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
if (!tpriv->isoc_framelist) {
|
|
1392
|
+
tpriv->num_iso_packets = transfer->num_iso_packets;
|
|
1393
|
+
tpriv->isoc_framelist = (IOUSBIsocFrame*) calloc (transfer->num_iso_packets, sizeof(IOUSBIsocFrame));
|
|
1394
|
+
if (!tpriv->isoc_framelist)
|
|
1395
|
+
return LIBUSB_ERROR_NO_MEM;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
/* copy the frame list from the libusbx descriptor (the structures differ only is member order) */
|
|
1399
|
+
for (i = 0 ; i < transfer->num_iso_packets ; i++)
|
|
1400
|
+
tpriv->isoc_framelist[i].frReqCount = transfer->iso_packet_desc[i].length;
|
|
1401
|
+
|
|
1402
|
+
/* determine the interface/endpoint to use */
|
|
1403
|
+
if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
|
|
1404
|
+
usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
|
|
1405
|
+
|
|
1406
|
+
return LIBUSB_ERROR_NOT_FOUND;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
cInterface = &priv->interfaces[iface];
|
|
1410
|
+
|
|
1411
|
+
/* Last but not least we need the bus frame number */
|
|
1412
|
+
kresult = (*(cInterface->interface))->GetBusFrameNumber(cInterface->interface, &frame, &atTime);
|
|
1413
|
+
if (kresult) {
|
|
1414
|
+
usbi_err (TRANSFER_CTX (transfer), "failed to get bus frame number: %d", kresult);
|
|
1415
|
+
free(tpriv->isoc_framelist);
|
|
1416
|
+
tpriv->isoc_framelist = NULL;
|
|
1417
|
+
|
|
1418
|
+
return darwin_to_libusb (kresult);
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
/* schedule for a frame a little in the future */
|
|
1422
|
+
frame += 4;
|
|
1423
|
+
|
|
1424
|
+
if (cInterface->frames[transfer->endpoint] && frame < cInterface->frames[transfer->endpoint])
|
|
1425
|
+
frame = cInterface->frames[transfer->endpoint];
|
|
1426
|
+
|
|
1427
|
+
/* submit the request */
|
|
1428
|
+
if (IS_XFERIN(transfer))
|
|
1429
|
+
kresult = (*(cInterface->interface))->ReadIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame,
|
|
1430
|
+
transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback,
|
|
1431
|
+
itransfer);
|
|
1432
|
+
else
|
|
1433
|
+
kresult = (*(cInterface->interface))->WriteIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame,
|
|
1434
|
+
transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback,
|
|
1435
|
+
itransfer);
|
|
1436
|
+
|
|
1437
|
+
cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets / 8;
|
|
1438
|
+
|
|
1439
|
+
if (kresult != kIOReturnSuccess) {
|
|
1440
|
+
usbi_err (TRANSFER_CTX (transfer), "isochronous transfer failed (dir: %s): %s", IS_XFERIN(transfer) ? "In" : "Out",
|
|
1441
|
+
darwin_error_str(kresult));
|
|
1442
|
+
free (tpriv->isoc_framelist);
|
|
1443
|
+
tpriv->isoc_framelist = NULL;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
return darwin_to_libusb (kresult);
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
static int submit_control_transfer(struct usbi_transfer *itransfer) {
|
|
1450
|
+
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
1451
|
+
struct libusb_control_setup *setup = (struct libusb_control_setup *) transfer->buffer;
|
|
1452
|
+
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv;
|
|
1453
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
|
|
1454
|
+
struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
|
|
1455
|
+
|
|
1456
|
+
IOReturn kresult;
|
|
1457
|
+
|
|
1458
|
+
bzero(&tpriv->req, sizeof(tpriv->req));
|
|
1459
|
+
|
|
1460
|
+
/* IOUSBDeviceInterface expects the request in cpu endianess */
|
|
1461
|
+
tpriv->req.bmRequestType = setup->bmRequestType;
|
|
1462
|
+
tpriv->req.bRequest = setup->bRequest;
|
|
1463
|
+
/* these values should be in bus order from libusb_fill_control_setup */
|
|
1464
|
+
tpriv->req.wValue = OSSwapLittleToHostInt16 (setup->wValue);
|
|
1465
|
+
tpriv->req.wIndex = OSSwapLittleToHostInt16 (setup->wIndex);
|
|
1466
|
+
tpriv->req.wLength = OSSwapLittleToHostInt16 (setup->wLength);
|
|
1467
|
+
/* data is stored after the libusbx control block */
|
|
1468
|
+
tpriv->req.pData = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
|
|
1469
|
+
tpriv->req.completionTimeout = transfer->timeout;
|
|
1470
|
+
tpriv->req.noDataTimeout = transfer->timeout;
|
|
1471
|
+
|
|
1472
|
+
itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
|
|
1473
|
+
|
|
1474
|
+
/* all transfers in libusb-1.0 are async */
|
|
1475
|
+
|
|
1476
|
+
if (transfer->endpoint) {
|
|
1477
|
+
struct darwin_interface *cInterface;
|
|
1478
|
+
uint8_t pipeRef, iface;
|
|
1479
|
+
|
|
1480
|
+
if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
|
|
1481
|
+
usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
|
|
1482
|
+
|
|
1483
|
+
return LIBUSB_ERROR_NOT_FOUND;
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
cInterface = &priv->interfaces[iface];
|
|
1487
|
+
|
|
1488
|
+
kresult = (*(cInterface->interface))->ControlRequestAsyncTO (cInterface->interface, pipeRef, &(tpriv->req), darwin_async_io_callback, itransfer);
|
|
1489
|
+
} else
|
|
1490
|
+
/* control request on endpoint 0 */
|
|
1491
|
+
kresult = (*(dpriv->device))->DeviceRequestAsyncTO(dpriv->device, &(tpriv->req), darwin_async_io_callback, itransfer);
|
|
1492
|
+
|
|
1493
|
+
if (kresult != kIOReturnSuccess)
|
|
1494
|
+
usbi_err (TRANSFER_CTX (transfer), "control request failed: %s", darwin_error_str(kresult));
|
|
1495
|
+
|
|
1496
|
+
return darwin_to_libusb (kresult);
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
static int darwin_submit_transfer(struct usbi_transfer *itransfer) {
|
|
1500
|
+
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
1501
|
+
|
|
1502
|
+
switch (transfer->type) {
|
|
1503
|
+
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
|
1504
|
+
return submit_control_transfer(itransfer);
|
|
1505
|
+
case LIBUSB_TRANSFER_TYPE_BULK:
|
|
1506
|
+
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
|
1507
|
+
return submit_bulk_transfer(itransfer);
|
|
1508
|
+
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
|
1509
|
+
return submit_iso_transfer(itransfer);
|
|
1510
|
+
default:
|
|
1511
|
+
usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
|
|
1512
|
+
return LIBUSB_ERROR_INVALID_PARAM;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
static int cancel_control_transfer(struct usbi_transfer *itransfer) {
|
|
1517
|
+
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
1518
|
+
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv;
|
|
1519
|
+
IOReturn kresult;
|
|
1520
|
+
|
|
1521
|
+
usbi_warn (ITRANSFER_CTX (itransfer), "aborting all transactions control pipe");
|
|
1522
|
+
|
|
1523
|
+
if (!dpriv->device)
|
|
1524
|
+
return LIBUSB_ERROR_NO_DEVICE;
|
|
1525
|
+
|
|
1526
|
+
kresult = (*(dpriv->device))->USBDeviceAbortPipeZero (dpriv->device);
|
|
1527
|
+
|
|
1528
|
+
return darwin_to_libusb (kresult);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
static int darwin_abort_transfers (struct usbi_transfer *itransfer) {
|
|
1532
|
+
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
1533
|
+
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv;
|
|
1534
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
|
|
1535
|
+
struct darwin_interface *cInterface;
|
|
1536
|
+
uint8_t pipeRef, iface;
|
|
1537
|
+
IOReturn kresult;
|
|
1538
|
+
|
|
1539
|
+
if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
|
|
1540
|
+
usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
|
|
1541
|
+
|
|
1542
|
+
return LIBUSB_ERROR_NOT_FOUND;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
cInterface = &priv->interfaces[iface];
|
|
1546
|
+
|
|
1547
|
+
if (!dpriv->device)
|
|
1548
|
+
return LIBUSB_ERROR_NO_DEVICE;
|
|
1549
|
+
|
|
1550
|
+
usbi_warn (ITRANSFER_CTX (itransfer), "aborting all transactions on interface %d pipe %d", iface, pipeRef);
|
|
1551
|
+
|
|
1552
|
+
/* abort transactions */
|
|
1553
|
+
(*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef);
|
|
1554
|
+
|
|
1555
|
+
usbi_dbg ("calling clear pipe stall to clear the data toggle bit");
|
|
1556
|
+
|
|
1557
|
+
/* clear the data toggle bit */
|
|
1558
|
+
#if (InterfaceVersion < 190)
|
|
1559
|
+
kresult = (*(cInterface->interface))->ClearPipeStall(cInterface->interface, pipeRef);
|
|
1560
|
+
#else
|
|
1561
|
+
/* newer versions of darwin support clearing additional bits on the device's endpoint */
|
|
1562
|
+
kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef);
|
|
1563
|
+
#endif
|
|
1564
|
+
|
|
1565
|
+
return darwin_to_libusb (kresult);
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
static int darwin_cancel_transfer(struct usbi_transfer *itransfer) {
|
|
1569
|
+
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
1570
|
+
|
|
1571
|
+
switch (transfer->type) {
|
|
1572
|
+
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
|
1573
|
+
return cancel_control_transfer(itransfer);
|
|
1574
|
+
case LIBUSB_TRANSFER_TYPE_BULK:
|
|
1575
|
+
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
|
1576
|
+
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
|
1577
|
+
return darwin_abort_transfers (itransfer);
|
|
1578
|
+
default:
|
|
1579
|
+
usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
|
|
1580
|
+
return LIBUSB_ERROR_INVALID_PARAM;
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
static void darwin_clear_transfer_priv (struct usbi_transfer *itransfer) {
|
|
1585
|
+
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
1586
|
+
struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
|
|
1587
|
+
|
|
1588
|
+
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && tpriv->isoc_framelist) {
|
|
1589
|
+
free (tpriv->isoc_framelist);
|
|
1590
|
+
tpriv->isoc_framelist = NULL;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0) {
|
|
1595
|
+
struct usbi_transfer *itransfer = (struct usbi_transfer *)refcon;
|
|
1596
|
+
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
1597
|
+
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
|
|
1598
|
+
UInt32 message, size;
|
|
1599
|
+
|
|
1600
|
+
usbi_dbg ("an async io operation has completed");
|
|
1601
|
+
|
|
1602
|
+
/* The size should never be larger than 4 GB - Also see libusb bug #117 */
|
|
1603
|
+
if ((intptr_t) arg0 > UINT32_MAX)
|
|
1604
|
+
usbi_err (ITRANSFER_CTX (itransfer),
|
|
1605
|
+
"async size truncation detected - please report this error");
|
|
1606
|
+
size = (UInt32) (intptr_t) arg0;
|
|
1607
|
+
|
|
1608
|
+
/* send a completion message to the device's file descriptor */
|
|
1609
|
+
message = MESSAGE_ASYNC_IO_COMPLETE;
|
|
1610
|
+
write (priv->fds[1], &message, sizeof (message));
|
|
1611
|
+
write (priv->fds[1], &itransfer, sizeof (itransfer));
|
|
1612
|
+
write (priv->fds[1], &result, sizeof (IOReturn));
|
|
1613
|
+
write (priv->fds[1], &size, sizeof (size));
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) {
|
|
1617
|
+
if (itransfer->flags & USBI_TRANSFER_TIMED_OUT)
|
|
1618
|
+
result = kIOUSBTransactionTimeout;
|
|
1619
|
+
|
|
1620
|
+
switch (result) {
|
|
1621
|
+
case kIOReturnUnderrun:
|
|
1622
|
+
case kIOReturnSuccess:
|
|
1623
|
+
return LIBUSB_TRANSFER_COMPLETED;
|
|
1624
|
+
case kIOReturnAborted:
|
|
1625
|
+
return LIBUSB_TRANSFER_CANCELLED;
|
|
1626
|
+
case kIOUSBPipeStalled:
|
|
1627
|
+
usbi_dbg ("transfer error: pipe is stalled");
|
|
1628
|
+
return LIBUSB_TRANSFER_STALL;
|
|
1629
|
+
case kIOReturnOverrun:
|
|
1630
|
+
usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: data overrun");
|
|
1631
|
+
return LIBUSB_TRANSFER_OVERFLOW;
|
|
1632
|
+
case kIOUSBTransactionTimeout:
|
|
1633
|
+
usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: timed out");
|
|
1634
|
+
itransfer->flags |= USBI_TRANSFER_TIMED_OUT;
|
|
1635
|
+
return LIBUSB_TRANSFER_TIMED_OUT;
|
|
1636
|
+
default:
|
|
1637
|
+
usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result);
|
|
1638
|
+
return LIBUSB_TRANSFER_ERROR;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
static void darwin_handle_callback (struct usbi_transfer *itransfer, kern_return_t result, UInt32 io_size) {
|
|
1643
|
+
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
1644
|
+
struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
|
|
1645
|
+
int isIsoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type;
|
|
1646
|
+
int isBulk = LIBUSB_TRANSFER_TYPE_BULK == transfer->type;
|
|
1647
|
+
int isControl = LIBUSB_TRANSFER_TYPE_CONTROL == transfer->type;
|
|
1648
|
+
int isInterrupt = LIBUSB_TRANSFER_TYPE_INTERRUPT == transfer->type;
|
|
1649
|
+
int i;
|
|
1650
|
+
|
|
1651
|
+
if (!isIsoc && !isBulk && !isControl && !isInterrupt) {
|
|
1652
|
+
usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
|
|
1653
|
+
return;
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
usbi_dbg ("handling %s completion with kernel status %d",
|
|
1657
|
+
isControl ? "control" : isBulk ? "bulk" : isIsoc ? "isoc" : "interrupt", result);
|
|
1658
|
+
|
|
1659
|
+
if (kIOReturnSuccess == result || kIOReturnUnderrun == result) {
|
|
1660
|
+
if (isIsoc && tpriv->isoc_framelist) {
|
|
1661
|
+
/* copy isochronous results back */
|
|
1662
|
+
|
|
1663
|
+
for (i = 0; i < transfer->num_iso_packets ; i++) {
|
|
1664
|
+
struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
|
|
1665
|
+
lib_desc->status = darwin_to_libusb (tpriv->isoc_framelist[i].frStatus);
|
|
1666
|
+
lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount;
|
|
1667
|
+
}
|
|
1668
|
+
} else if (!isIsoc)
|
|
1669
|
+
itransfer->transferred += io_size;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
/* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */
|
|
1673
|
+
usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, result));
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
static int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready) {
|
|
1677
|
+
struct usbi_transfer *itransfer;
|
|
1678
|
+
UInt32 io_size;
|
|
1679
|
+
IOReturn kresult;
|
|
1680
|
+
POLL_NFDS_TYPE i = 0;
|
|
1681
|
+
ssize_t ret;
|
|
1682
|
+
UInt32 message;
|
|
1683
|
+
|
|
1684
|
+
usbi_mutex_lock(&ctx->open_devs_lock);
|
|
1685
|
+
for (i = 0; i < nfds && num_ready > 0; i++) {
|
|
1686
|
+
struct pollfd *pollfd = &fds[i];
|
|
1687
|
+
struct libusb_device_handle *handle;
|
|
1688
|
+
struct darwin_device_handle_priv *hpriv = NULL;
|
|
1689
|
+
|
|
1690
|
+
usbi_dbg ("checking fd %i with revents = %x", fds[i], pollfd->revents);
|
|
1691
|
+
|
|
1692
|
+
if (!pollfd->revents)
|
|
1693
|
+
continue;
|
|
1694
|
+
|
|
1695
|
+
num_ready--;
|
|
1696
|
+
list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
|
|
1697
|
+
hpriv = (struct darwin_device_handle_priv *)handle->os_priv;
|
|
1698
|
+
if (hpriv->fds[0] == pollfd->fd)
|
|
1699
|
+
break;
|
|
1700
|
+
}
|
|
1701
|
+
if (!hpriv)
|
|
1702
|
+
continue;
|
|
1703
|
+
|
|
1704
|
+
if (!(pollfd->revents & POLLERR)) {
|
|
1705
|
+
ret = read (hpriv->fds[0], &message, sizeof (message));
|
|
1706
|
+
if (ret < (ssize_t)sizeof (message))
|
|
1707
|
+
continue;
|
|
1708
|
+
} else
|
|
1709
|
+
/* could not poll the device-- response is to delete the device (this seems a little heavy-handed) */
|
|
1710
|
+
message = MESSAGE_DEVICE_GONE;
|
|
1711
|
+
|
|
1712
|
+
switch (message) {
|
|
1713
|
+
case MESSAGE_DEVICE_GONE:
|
|
1714
|
+
/* remove the device's async port from the runloop */
|
|
1715
|
+
if (hpriv->cfSource) {
|
|
1716
|
+
if (libusb_darwin_acfl)
|
|
1717
|
+
CFRunLoopRemoveSource (libusb_darwin_acfl, hpriv->cfSource, kCFRunLoopDefaultMode);
|
|
1718
|
+
CFRelease (hpriv->cfSource);
|
|
1719
|
+
hpriv->cfSource = NULL;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fds[0]);
|
|
1723
|
+
usbi_handle_disconnect(handle);
|
|
1724
|
+
|
|
1725
|
+
/* done with this device */
|
|
1726
|
+
continue;
|
|
1727
|
+
case MESSAGE_ASYNC_IO_COMPLETE:
|
|
1728
|
+
read (hpriv->fds[0], &itransfer, sizeof (itransfer));
|
|
1729
|
+
read (hpriv->fds[0], &kresult, sizeof (IOReturn));
|
|
1730
|
+
read (hpriv->fds[0], &io_size, sizeof (UInt32));
|
|
1731
|
+
|
|
1732
|
+
darwin_handle_callback (itransfer, kresult, io_size);
|
|
1733
|
+
break;
|
|
1734
|
+
default:
|
|
1735
|
+
usbi_warn (ctx, "unknown message received from device pipe");
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
usbi_mutex_unlock(&ctx->open_devs_lock);
|
|
1740
|
+
|
|
1741
|
+
return 0;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
static int darwin_clock_gettime(int clk_id, struct timespec *tp) {
|
|
1745
|
+
mach_timespec_t sys_time;
|
|
1746
|
+
clock_serv_t clock_ref;
|
|
1747
|
+
|
|
1748
|
+
switch (clk_id) {
|
|
1749
|
+
case USBI_CLOCK_REALTIME:
|
|
1750
|
+
/* CLOCK_REALTIME represents time since the epoch */
|
|
1751
|
+
clock_ref = clock_realtime;
|
|
1752
|
+
break;
|
|
1753
|
+
case USBI_CLOCK_MONOTONIC:
|
|
1754
|
+
/* use system boot time as reference for the monotonic clock */
|
|
1755
|
+
clock_ref = clock_monotonic;
|
|
1756
|
+
break;
|
|
1757
|
+
default:
|
|
1758
|
+
return LIBUSB_ERROR_INVALID_PARAM;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
clock_get_time (clock_ref, &sys_time);
|
|
1762
|
+
|
|
1763
|
+
tp->tv_sec = sys_time.tv_sec;
|
|
1764
|
+
tp->tv_nsec = sys_time.tv_nsec;
|
|
1765
|
+
|
|
1766
|
+
return 0;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
const struct usbi_os_backend darwin_backend = {
|
|
1770
|
+
.name = "Darwin",
|
|
1771
|
+
.init = darwin_init,
|
|
1772
|
+
.exit = darwin_exit,
|
|
1773
|
+
.get_device_list = darwin_get_device_list,
|
|
1774
|
+
.get_device_descriptor = darwin_get_device_descriptor,
|
|
1775
|
+
.get_active_config_descriptor = darwin_get_active_config_descriptor,
|
|
1776
|
+
.get_config_descriptor = darwin_get_config_descriptor,
|
|
1777
|
+
|
|
1778
|
+
.open = darwin_open,
|
|
1779
|
+
.close = darwin_close,
|
|
1780
|
+
.get_configuration = darwin_get_configuration,
|
|
1781
|
+
.set_configuration = darwin_set_configuration,
|
|
1782
|
+
.claim_interface = darwin_claim_interface,
|
|
1783
|
+
.release_interface = darwin_release_interface,
|
|
1784
|
+
|
|
1785
|
+
.set_interface_altsetting = darwin_set_interface_altsetting,
|
|
1786
|
+
.clear_halt = darwin_clear_halt,
|
|
1787
|
+
.reset_device = darwin_reset_device,
|
|
1788
|
+
|
|
1789
|
+
.kernel_driver_active = darwin_kernel_driver_active,
|
|
1790
|
+
.detach_kernel_driver = darwin_detach_kernel_driver,
|
|
1791
|
+
.attach_kernel_driver = darwin_attach_kernel_driver,
|
|
1792
|
+
|
|
1793
|
+
.destroy_device = darwin_destroy_device,
|
|
1794
|
+
|
|
1795
|
+
.submit_transfer = darwin_submit_transfer,
|
|
1796
|
+
.cancel_transfer = darwin_cancel_transfer,
|
|
1797
|
+
.clear_transfer_priv = darwin_clear_transfer_priv,
|
|
1798
|
+
|
|
1799
|
+
.handle_events = op_handle_events,
|
|
1800
|
+
|
|
1801
|
+
.clock_gettime = darwin_clock_gettime,
|
|
1802
|
+
|
|
1803
|
+
.device_priv_size = sizeof(struct darwin_device_priv),
|
|
1804
|
+
.device_handle_priv_size = sizeof(struct darwin_device_handle_priv),
|
|
1805
|
+
.transfer_priv_size = sizeof(struct darwin_transfer_priv),
|
|
1806
|
+
.add_iso_packet_size = 0,
|
|
1807
|
+
};
|