2
/* General USB I/O support, OS X native implementation. */
3
/* This file is conditionaly #included into usbio.c */
6
* Argyll Color Correction System
8
* Author: Graeme W. Gill
11
* Copyright 2006 - 2013 Graeme W. Gill
12
* All rights reserved.
14
* This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
15
* see the License2.txt file for licencing details.
20
#include <CoreFoundation/CoreFoundation.h>
21
#include <IOKit/IOTypes.h>
22
#include <IOKit/IOKitLib.h>
23
#include <IOKit/usb/IOUSBLib.h>
24
#include <IOKit/IOCFPlugIn.h>
25
//#include <IOKit/IOCFBundle.h>
26
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
27
# include <objc/objc-auto.h>
30
/* Add paths to USB connected instruments */
31
/* Return an icom error */
36
CFMutableDictionaryRef sdict; /* USB Device dictionary */
37
io_iterator_t mit; /* Matching itterator */
39
struct usb_idevice *usbd = NULL;
41
a1logd(p->log, 6, "usb_get_paths: about to look through devices:\n");
43
/* Get dictionary of USB devices */
44
if ((sdict = IOServiceMatching(kIOUSBDeviceClassName)) == NULL) {
45
a1loge(p->log, ICOM_SYS, "usb_get_paths() IOServiceMatching returned a NULL dictionary\n");
49
/* Init itterator to find matching types. Consumes sdict reference */
50
if ((kstat = IOServiceGetMatchingServices(kIOMasterPortDefault, sdict, &mit))
52
a1loge(p->log, ICOM_SYS, "usb_get_paths() IOServiceGetMatchingServices returned %d\n", kstat);
56
/* Find all the matching USB devices */
58
io_object_t ioob; /* USB object found */
59
io_iterator_t it1; /* Child level 1 */
60
CFMutableDictionaryRef usbprops = 0; /* USB Device properties */
61
CFNumberRef vref, pref; /* USB Vendor and Product ID propeties */
62
CFNumberRef nconfref; /* No configurations */
63
CFNumberRef nepref, lidpref; /* No ep's, Location ID properties */
64
unsigned int vid = 0, pid = 0, nep, tnep, nconfig = 0, lid = 0;
67
if ((ioob = IOIteratorNext(mit)) == 0)
70
/* Get the two properies we need. */
71
if ((vref = IORegistryEntryCreateCFProperty(ioob, CFSTR(kUSBVendorID),
72
kCFAllocatorDefault,kNilOptions)) != 0) {
73
CFNumberGetValue(vref, kCFNumberIntType, &vid);
76
if ((pref = IORegistryEntryCreateCFProperty(ioob, CFSTR(kUSBProductID),
77
kCFAllocatorDefault,kNilOptions)) != 0) {
78
CFNumberGetValue(pref, kCFNumberIntType, &pid);
82
if ((nconfref = IORegistryEntryCreateCFProperty(ioob, CFSTR("bNumConfigurations"),
83
kCFAllocatorDefault,kNilOptions)) != 0) {
84
CFNumberGetValue(nconfref, kCFNumberIntType, &nconfig);
88
if ((lidpref = IORegistryEntryCreateCFProperty(ioob, CFSTR("locationID"),
89
kCFAllocatorDefault,kNilOptions)) != 0) {
90
CFNumberGetValue(lidpref, kCFNumberIntType, &lid);
94
a1logd(p->log, 6, "usb_check_and_add: checking vid 0x%04x, pid 0x%04x, lid 0x%x\n",vid,pid,lid);
96
/* Do a preliminary match */
97
if ((itype = inst_usb_match(vid, pid, 0)) == instUnknown) {
98
a1logd(p->log, 6 , "usb_check_and_add: 0x%04x 0x%04x not reconized\n",vid,pid);
99
IOObjectRelease(ioob); /* Release found object */
103
/* Allocate an idevice so that we can fill in the end point information */
104
if ((usbd = (struct usb_idevice *) calloc(sizeof(struct usb_idevice), 1)) == NULL) {
105
a1loge(p->log, ICOM_SYS, "icoms: calloc failed!\n");
109
usbd->nconfig = nconfig;
110
usbd->config = 1; /* We are only interested in config 1 */
112
/* Go through all the Interfaces, adding up the number of end points */
114
if ((kstat = IORegistryEntryCreateIterator(ioob, kIOServicePlane,
115
kIORegistryIterateRecursively, &it1)) != KERN_SUCCESS) {
116
IOObjectRelease(ioob);
117
IOObjectRelease(mit);
118
a1loge(p->log, kstat, "usb_check_and_add: IORegistryEntryCreateIterator() with %d\n",kstat);
123
io_object_t ch1; /* Child object 1 */
124
if ((ch1 = IOIteratorNext(it1)) == 0)
126
if (IOObjectConformsTo(ch1, "IOUSBInterface")) {
127
unsigned int config = 0;
129
/* Get the configuration number */
130
if ((nconfref = IORegistryEntryCreateCFProperty(ch1, CFSTR(kUSBNumEndpoints),
131
kCFAllocatorDefault,kNilOptions)) != 0) {
132
CFNumberGetValue(nconfref, kCFNumberIntType, &config);
141
/* Get the number of end points */
142
if ((nepref = IORegistryEntryCreateCFProperty(ch1, CFSTR(kUSBNumEndpoints),
143
kCFAllocatorDefault,kNilOptions)) != 0) {
144
CFNumberGetValue(nepref, kCFNumberIntType, &nep);
148
IOObjectRelease(ch1);
151
IOObjectRelease(it1);
153
if ((itype = inst_usb_match(vid, pid, tnep)) != instUnknown) {
158
/* If this device is HID, it will have already added to the paths list, */
159
/* so check for this and skip this device if it is already there. */
160
for (i = 0; i < p->npaths; i++) {
161
if (p->paths[i]->vid == vid
162
&& p->paths[i]->pid == pid
163
&& p->paths[i]->hidd != NULL
164
&& p->paths[i]->hidd->lid == lid) {
165
a1logd(p->log, 1, "usb_check_and_add: Ignoring device because it is already in list as HID\n");
170
IOObjectRelease(ioob); /* Release found object */
175
a1logd(p->log, 1, "usb_check_and_add: found instrument vid 0x%04x, pid 0x%04x\n",vid,pid);
179
/* Create a path/identification */
180
sprintf(pname,"usb%d: (%s)", lid >> 20, inst_name(itype));
182
/* Add the path and ep info to the list */
183
if ((rv = p->add_usb(p, pname, vid, pid, tnep, usbd, itype)) != ICOM_OK) {
184
IOObjectRelease(ioob); /* Release found object */
186
IOObjectRelease(mit); /* Release the itterator */
191
IOObjectRelease(ioob); /* Release found object */
195
IOObjectRelease(mit); /* Release the itterator */
197
a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
201
/* Copy usb_idevice contents from icompaths to icom */
202
/* return icom error */
203
int usb_copy_usb_idevice(icoms *d, icompath *s) {
205
if (s->usbd == NULL) {
209
if ((d->usbd = calloc(sizeof(struct usb_idevice), 1)) == NULL) {
210
a1loge(d->log, ICOM_SYS, "usb_copy_usb_idevice: malloc\n");
213
d->nconfig = s->usbd->nconfig;
214
d->config = s->usbd->config;
215
d->nifce = s->usbd->nifce;
216
d->usbd->ioob = s->usbd->ioob;
217
IOObjectRetain(d->usbd->ioob);
221
/* Cleanup and then free a usb dev entry */
222
void usb_del_usb_idevice(struct usb_idevice *usbd) {
228
IOObjectRelease(usbd->ioob);
233
/* Cleanup any USB specific icoms state */
234
void usb_del_usb(icoms *p) {
236
usb_del_usb_idevice(p->usbd);
239
/* Clean up anything allocated/created in p->usbd, but don't free p->usbd itself */
240
static void cleanup_device(icoms *p) {
242
if (p->usbd != NULL) {
243
if (p->usbd->device != NULL) { /* device is open */
246
/* Stop the RunLoop and wait for it */
247
if (p->usbd->cfrunloop != NULL) {
249
a1logd(p->log, 6, "usb_close_port: waiting for RunLoop thread to exit\n");
250
CFRunLoopStop(p->usbd->cfrunloop);
251
CFRelease(p->usbd->cfrunloop);
252
if (p->usbd->thread != NULL)
253
pthread_join(p->usbd->thread, NULL);
256
/* Release all the interfaces */
257
for (i = 0; i < p->usbd->nifce; i++) {
258
if (p->usbd->interfaces[i] != NULL) {
259
(*p->usbd->interfaces[i])->USBInterfaceClose(p->usbd->interfaces[i]);
260
(*p->usbd->interfaces[i])->Release(p->usbd->interfaces[i]);
264
/* Close the device */
265
(*(p->usbd->device))->USBDeviceClose(p->usbd->device);
266
(*(p->usbd->device))->Release(p->usbd->device);
268
pthread_cond_destroy(&p->usbd->cond);
269
pthread_mutex_destroy(&p->usbd->lock);
271
memset(p->usbd, 0, sizeof(struct usb_idevice));
275
/* Close an open USB port */
276
/* If we don't do this, the port and/or the device may be left in an unusable state. */
277
void usb_close_port(icoms *p) {
279
a1logd(p->log, 6, "usb_close_port: called\n");
281
if (p->is_open && p->usbd != NULL) {
283
/* Workaround for some bugs - reset device on close */
284
if (p->uflags & icomuf_reset_before_close) {
286
if ((rv = (*(p->usbd->device))->ResetDevice(p->usbd->device)) != kIOReturnSuccess) {
287
a1logd(p->log, 1, "usb_close_port: ResetDevice failed with 0x%x\n",rv);
291
/* Close down and free everything in p->usbd */
293
if (p->usbd != NULL) {
297
a1logd(p->log, 6, "usb_close_port: usb port has been released and closed\n");
301
/* Find it and delete it from our static cleanup list */
302
usb_delete_from_cleanup_list(p);
305
static int icoms_usb_control_msg(icoms *p, int *transferred, int requesttype, int request,
306
int value, int index, unsigned char *bytes, int size, int timeout);
307
static void *io_runloop(void *context);
309
/* Open a USB port for all our uses. */
310
/* This always re-opens the port */
311
/* return icom error */
312
static int usb_open_port(
314
int config, /* Configuration number, (1 based) */
315
int wr_ep, /* Write end point */
316
int rd_ep, /* Read end point */
317
icomuflags usbflags,/* Any special handling flags */
318
int retries, /* > 0 if we should retry set_configuration (100msec) */
319
char **pnames /* List of process names to try and kill before opening */
323
a1logd(p->log, 8, "usb_open_port: Make sure USB port is open, tries %d\n",retries);
328
/* Make sure the port is open */
330
kkill_nproc_ctx *kpc = NULL;
333
/* Nothing currently needs it, so we haven't implemented it yet... */
334
a1loge(p->log, ICOM_NOTS, "usb_open_port: native driver cant handle config %d\n",config);
338
pthread_mutex_init(&p->usbd->lock, NULL);
339
pthread_cond_init(&p->usbd->cond, NULL);
341
/* Do open retries */
342
for (tries = 0; retries >= 0; retries--, tries++) {
343
IOCFPlugInInterface **piif = NULL;
346
a1logd(p->log, 8, "usb_open_port: About to open USB port '%s'\n",p->name);
349
//msec_sleep(i_rand(50,100));
352
if (tries > 0 && pnames != NULL && kpc == NULL) {
353
if ((kpc = kkill_nprocess(pnames, p->log)) == NULL) {
354
a1logd(p->log, 1, "kkill_nprocess returned error!\n");
358
if ((rv = IOCreatePlugInInterfaceForService(p->usbd->ioob,
359
kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
360
&piif, &score)) != kIOReturnSuccess || piif == NULL) {
361
a1loge(p->log, rv, "usb_open_port: Failed to get piif for "
362
"USB device '%s', result 0x%x, piif 0x%x\n",p->name,rv,piif);
366
p->usbd->device = NULL;
367
if ((rv = (*piif)->QueryInterface(piif,
368
CFUUIDGetUUIDBytes(DeviceInterfaceID), (void *)&p->usbd->device))
369
!= kIOReturnSuccess || p->usbd->device == NULL) {
370
a1loge(p->log, rv, "usb_open_port: QueryInterface '%s' failed with 0%x\n",p->name, rv);
371
(*piif)->Release(piif);
374
(*piif)->Release(piif); /* delete intermediate object */
376
if ((rv = (*p->usbd->device)->USBDeviceOpenSeize(p->usbd->device)) != kIOReturnSuccess) {
377
a1logd(p->log, 8, "usb_open_port: open '%s' config %d failed (0x%x) (Device being used ?)\n",p->name,config,rv);
381
a1loge(p->log, rv, "usb_open_port: open '%s' config %d failed (0x%x) (Device being used ?)\n",p->name, config, rv);
382
(*p->usbd->device)->Release(p->usbd->device);
387
a1logd(p->log, 1, "usb_open_port: open port '%s' succeeded\n",p->name);
389
p->uflags = usbflags;
391
/* We're done retries */
398
/* We should only do a set configuration if the device has more than one */
399
/* possible configuration and it is currently not the desired configuration, */
400
/* but we should avoid doing a set configuration if the OS has already */
401
/* selected the configuration we want, since two set configs seem to */
402
/* mess up the Spyder2, BUT we can't do a get config because this */
403
/* messes up the i1pro-D. */
405
/* OS X doesn't do a set_configuration() by default */
408
if (p->cconfig != config) {
409
if ((rv = (*(p->usbd->device))->SetConfiguration(
410
p->usbd->device, config)) != kIOReturnSuccess) {
411
a1loge(p->log, rv, "usb_open_port: SetConfiguration failed with 0x%x\n",rv);
416
a1logd(p->log, 6, "usb_open_port: SetConfiguration %d OK\n",config);
422
IOUSBFindInterfaceRequest req;
425
IOCFPlugInInterface **pluginref = NULL;
428
req.bInterfaceClass =
429
req.bInterfaceSubClass =
430
req.bInterfaceProtocol =
431
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
433
if ((rv = (*(p->usbd->device))->CreateInterfaceIterator(
434
p->usbd->device, &req, &ioit)) != kIOReturnSuccess) {
435
a1loge(p->log, rv, "usb_open_port: CreateInterfaceIterator failed with 0x%x\n",rv);
439
iface = IOIteratorNext(ioit);
440
for (i = 0; iface != 0; i++, iface = IOIteratorNext(ioit)) {
443
if ((rv = IOCreatePlugInInterfaceForService(iface,
444
kIOUSBInterfaceUserClientTypeID,
445
kIOCFPlugInInterfaceID,
446
&pluginref, &score)) != kIOReturnSuccess) {
447
a1loge(p->log, rv, "usb_open_port: IOCreatePlugInInterfaceForService failed with 0x%x\n",rv);
448
IOObjectRelease(iface);
449
IOObjectRelease(ioit);
453
IOObjectRelease(iface);
454
if ((rv = (*pluginref)->QueryInterface(pluginref,
455
CFUUIDGetUUIDBytes(InterfaceInterfaceID),
456
(void *)&p->usbd->interfaces[i])) != kIOReturnSuccess) {
457
a1loge(p->log, rv, "usb_open_port: QueryInterface failed with 0x%x\n",rv);
458
(*pluginref)->Stop(pluginref);
459
IODestroyPlugInInterface(pluginref);
460
IOObjectRelease(ioit);
464
(*pluginref)->Stop(pluginref);
465
IODestroyPlugInInterface(pluginref);
467
if ((rv = (*(p->usbd->interfaces[i]))->USBInterfaceOpen(
468
p->usbd->interfaces[i])) != kIOReturnSuccess) {
469
a1loge(p->log, rv, "usb_open_port: USBInterfaceOpen failed with 0x%x\n",rv);
470
IOObjectRelease(ioit);
475
/* Get the end point details, and set reference to pipe no and interfece ix */
476
if ((rv = (*(p->usbd->interfaces[i]))->GetNumEndpoints(
477
p->usbd->interfaces[i], &nep)) != kIOReturnSuccess) {
478
a1loge(p->log, rv, "usb_open_port: GetNumEndpoints failed with 0x%x\n",rv);
479
IOObjectRelease(ioit);
483
for (j = 0; j < nep; j++) {
484
UInt8 direction, pnumber, transferType, interval;
485
UInt16 maxPacketSize;
487
if ((rv = (*(p->usbd->interfaces[i]))->GetPipeProperties(
488
p->usbd->interfaces[i], (UInt8)(j+1), &direction, &pnumber,
489
&transferType, &maxPacketSize, &interval)) != kIOReturnSuccess) {
490
a1loge(p->log, rv, "usb_open_port: GetPipeProperties failed with 0x%x\n",rv);
491
IOObjectRelease(ioit);
495
ad = ((direction << IUSB_ENDPOINT_DIR_SHIFT) & IUSB_ENDPOINT_DIR_MASK)
496
| (pnumber & IUSB_ENDPOINT_NUM_MASK);
497
p->EPINFO(ad).valid = 1;
498
p->EPINFO(ad).addr = ad;
499
p->EPINFO(ad).packetsize = maxPacketSize;
500
p->EPINFO(ad).type = transferType & IUSB_ENDPOINT_TYPE_MASK;
501
p->EPINFO(ad).interface = i;
502
p->EPINFO(ad).pipe = j+1;
503
a1logd(p->log, 6, "set ep ad 0x%x packetsize %d type %d, if %d, pipe %d\n",ad,maxPacketSize,transferType & IUSB_ENDPOINT_TYPE_MASK,i,j);
506
p->usbd->nifce = i; /* Just in case.. */
508
IOObjectRelease(ioit);
511
/* Setup the RunLoop thread */
512
a1logd(p->log, 6, "usb_open_port: Starting RunLoop thread\n");
513
if ((rv = pthread_create(&p->usbd->thread, NULL, io_runloop, (void*)p)) < 0) {
514
a1loge(p->log, ICOM_SYS, "usb_open_port: creating RunLoop thread failed with %s\n",rv);
519
/* Wait for the runloop thread to start and create a cfrunloop */
520
pthread_mutex_lock(&p->usbd->lock);
521
while (p->usbd->cfrunloop == NULL)
522
pthread_cond_wait(&p->usbd->cond, &p->usbd->lock);
523
pthread_mutex_unlock(&p->usbd->lock);
524
if (p->usbd->thrv != kIOReturnSuccess) { /* Thread failed */
525
pthread_join(p->usbd->thread, NULL);
529
CFRetain(p->usbd->cfrunloop);
530
a1logd(p->log, 6, "usb_open_port: RunLoop thread started\n");
533
/* Clear any errors */
534
/* (Some I/F seem to hang if we do this, some seem to hang if we don't !) */
535
if (!(p->uflags & icomuf_no_open_clear)) {
537
for (i = 0; i < 32; i++) {
540
p->usb_clearhalt(p, p->ep[i].addr);
544
/* Set "serial" coms values */
547
p->rd_qa = p->EPINFO(rd_ep).packetsize;
550
a1logd(p->log, 8, "usb_open_port: 'serial' read quanta = packet size = %d\n",p->rd_qa);
553
a1logd(p->log, 8, "usb_open_port: USB port is now open\n");
556
/* Install the cleanup signal handlers, and add to our cleanup list */
557
usb_install_signal_handlers(p);
562
/* -------------------------------------------------------------- */
564
/* The run loop thread */
565
static void *io_runloop(void *context) {
566
icoms *p = (icoms *)context;
569
/* Register this thread with the Objective-C garbage collector */
570
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
571
objc_registerThreadWithCollector();
574
a1logd(p->log, 6, "io_runloop: thread started\n");
576
p->usbd->cfrunloop = CFRunLoopGetCurrent(); /* Get this threads RunLoop */
577
CFRetain(p->usbd->cfrunloop);
579
/* Add a device event source */
580
if ((p->usbd->thrv = (*(p->usbd->device))->CreateDeviceAsyncEventSource(
581
p->usbd->device, &p->usbd->cfsource)) != kIOReturnSuccess) {
582
a1loge(p->log, p->usbd->thrv, "io_runloop: CreateDeviceAsyncEventSource failed with 0x%x\n",p->usbd->thrv);
584
CFRunLoopAddSource(p->usbd->cfrunloop, p->usbd->cfsource, kCFRunLoopDefaultMode);
587
/* Create an async event source for the interfaces */
588
for (i = 0; p->usbd->thrv == kIOReturnSuccess && i < p->usbd->nifce; i++) {
589
if ((p->usbd->thrv = (*(p->usbd->interfaces[i]))->CreateInterfaceAsyncEventSource(
590
p->usbd->interfaces[i], &p->usbd->cfsources[i])) != kIOReturnSuccess) {
591
a1loge(p->log, p->usbd->thrv, "io_runloop: CreateInterfaceAsyncEventSource failed with 0x%x\n",p->usbd->thrv);
593
/* Add it to the RunLoop */
594
CFRunLoopAddSource(p->usbd->cfrunloop, p->usbd->cfsources[i], kCFRunLoopDefaultMode);
598
/* Signal main thread that we've started */
599
pthread_mutex_lock(&p->usbd->lock);
600
pthread_cond_signal(&p->usbd->cond);
601
pthread_mutex_unlock(&p->usbd->lock);
603
/* Run the loop, or exit on error */
604
if (p->usbd->thrv == kIOReturnSuccess) {
605
CFRunLoopRun(); /* Run the loop and deliver events */
608
/* Delete the interfaces async event sources */
609
for (i = 0; i < p->usbd->nifce; i++) {
610
if (p->usbd->cfsources[i] != NULL) {
611
CFRunLoopRemoveSource(p->usbd->cfrunloop, p->usbd->cfsources[i], kCFRunLoopDefaultMode);
612
CFRelease(p->usbd->cfsources[i]);
616
/* Delete the devices event sources */
617
if (p->usbd->cfsource != NULL) {
618
CFRunLoopRemoveSource(p->usbd->cfrunloop, p->usbd->cfsource, kCFRunLoopDefaultMode);
619
CFRelease(p->usbd->cfsource);
622
CFRelease(p->usbd->cfrunloop);
624
a1logd(p->log, 6, "io_runloop: thread done\n");
630
typedef struct _usbio_req {
632
int iix; /* Interface index */
633
UInt8 pno; /* pipe index */
634
volatile int done; /* Done flag */
635
pthread_mutex_t lock; /* Protect req & callback access */
636
pthread_cond_t cond; /* Signal to thread waiting on req */
637
int xlength; /* Bytes transferred */
638
IOReturn result; /* Result of transaction */
642
/* Async completion callback - called by RunLoop thread */
643
static void io_callback(void *refcon, IOReturn result, void *arg0) {
644
usbio_req *req = (usbio_req *)refcon;
646
a1logd(req->p->log, 1, "io_callback: result 0x%x, length %d\n",result,(int)(long)arg0);
648
req->xlength = (int)(long)arg0;
649
req->result = result;
651
pthread_mutex_lock(&req->lock);
652
pthread_cond_signal(&req->cond);
653
pthread_mutex_unlock(&req->lock);
656
/* Our universal USB transfer function */
657
static int icoms_usb_transaction(
659
usb_cancelt *cancelt,
661
icom_usb_trantype ttype, /* transfer type */
662
unsigned char endpoint, /* 0x80 for control write, 0x00 for control read */
663
unsigned char *buffer,
665
unsigned int timeout /* In msec */
667
int reqrv = ICOM_OK, rv = 0;
668
int dirw = (endpoint & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT ? 1 : 0;
671
int iix = p->EPINFO(endpoint).interface;
672
UInt8 pno = (UInt8)p->EPINFO(endpoint).pipe;
676
a1logd(p->log, 8, "icoms_usb_transaction: req type 0x%x ep 0x%x size %d\n",ttype,endpoint,length);
678
if (ttype != icom_usb_trantype_interrutpt
679
&& ttype != icom_usb_trantype_bulk) {
680
/* We only handle interrupt & bulk, not control */
689
pthread_mutex_init(&req.lock, NULL);
690
pthread_cond_init(&req.cond, NULL);
693
result = (*p->usbd->interfaces[iix])->WritePipeAsync(p->usbd->interfaces[iix],
694
pno, buffer, length, io_callback, &req);
696
result = (*p->usbd->interfaces[iix])->ReadPipeAsync(p->usbd->interfaces[iix],
697
pno, buffer, length, io_callback, &req);
699
if (result != kIOReturnSuccess) {
700
a1loge(p->log, ICOM_SYS, "icoms_usb_transaction: %sPipeAsync failed with 0x%x\n",dirw ? "Write" : "Read", result);
705
if (cancelt != NULL) {
706
usb_lock_cancel(cancelt);
707
cancelt->hcancel = (void *)&req;
708
usb_unlock_cancel(cancelt);
711
/* Wait for the callback to complete */
712
pthread_mutex_lock(&req.lock);
717
// this is unduly complicated...
718
gettimeofday(&tv, NULL);
719
ts.tv_sec = tv.tv_sec + timeout/1000;
720
ts.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000) * 1000L;
721
if (ts.tv_nsec > 1000000000L) {
722
ts.tv_nsec -= 1000000000L;
726
for(;;) { /* Ignore spurious wakeups */
727
if ((rv = pthread_cond_timedwait(&req.cond, &req.lock, &ts)) != 0) {
728
if (rv != ETIMEDOUT) {
729
a1logd(p->log, 1, "coms_usb_transaction: pthread_cond_timedwait failed with %d\n",rv);
730
(*p->usbd->interfaces[iix])->AbortPipe(p->usbd->interfaces[iix], pno);
731
req.result = kIOReturnAborted;
737
a1logd(p->log, 8, "coms_usb_transaction: time out - aborting io\n");
738
(*p->usbd->interfaces[iix])->AbortPipe(p->usbd->interfaces[iix], pno);
740
/* Wait for the cancelled io to be signalled */
741
if ((rv = pthread_cond_wait(&req.cond, &req.lock)) != 0) {
742
pthread_mutex_unlock(&req.lock);
743
a1logd(p->log, 1, "coms_usb_transaction: pthread_cond_wait failed with %d\n",rv);
744
req.result = kIOReturnAborted;
750
if (req.done) /* Ignore spurious wakeups */
754
pthread_mutex_unlock(&req.lock);
756
a1logd(p->log, 8, "coms_usb_transaction: completed with reqrv 0x%x and xlength %d\n",req.result,req.xlength);
758
/* If io was aborted, ClearPipeStall */
759
if (req.result == kIOReturnAborted) {
760
#if defined(NEVER) && (InterfaceVersion > 182)
761
(*p->usbd->interfaces[iix])->ClearPipeStallBothEnds(p->usbd->interfaces[iix], pno);
763
(*p->usbd->interfaces[iix])->ClearPipeStall(p->usbd->interfaces[iix], pno);
764
icoms_usb_control_msg(p, NULL, IUSB_REQ_HOST_TO_DEV | IUSB_REQ_TYPE_STANDARD
765
| IUSB_REQ_RECIP_ENDPOINT, IUSB_REQ_CLEAR_FEATURE,
766
IUSB_FEATURE_EP_HALT, endpoint, NULL, 0, 200);
768
if (reqrv == ICOM_OK) /* If not aborted for a known reason, must be cancelled */
772
/* If normal completion - not timed out or aborted */
773
if (reqrv == ICOM_OK) { /* Completed OK */
774
if (req.result == kIOReturnSuccess) {
775
if (req.xlength != length)
785
if (transferred != NULL)
786
*transferred = req.xlength;
789
if (cancelt != NULL) {
790
usb_lock_cancel(cancelt);
791
cancelt->hcancel = (void *)NULL;
792
usb_unlock_cancel(cancelt);
795
pthread_cond_destroy(&req.cond);
796
pthread_mutex_destroy(&req.lock);
803
a1logd(p->log, 8, "coms_usb_transaction: returning err 0x%x and %d bytes\n",reqrv, req.xlength);
809
/* Our control message routine */
810
/* Return error icom error code */
811
static int icoms_usb_control_msg(
814
int requesttype, int request,
815
int value, int index, unsigned char *bytes, int size,
818
int dirw = (requesttype & IUSB_REQ_DIR_MASK) == IUSB_REQ_HOST_TO_DEV ? 1 : 0;
820
IOUSBDevRequestTO req;
822
a1logd(p->log, 8, "icoms_usb_control_msg: type 0x%x req 0x%x size %d\n",requesttype,request,size);
823
bzero(&req, sizeof(req));
824
req.bmRequestType = requesttype;
825
req.bRequest = request;
830
req.completionTimeout = timeout;
831
req.noDataTimeout = timeout;
833
if (transferred != NULL)
836
if ((rv = (*(p->usbd->device))->DeviceRequestTO(p->usbd->device, &req)) != kIOReturnSuccess) {
837
if (rv == kIOUSBTransactionTimeout) {
846
if (transferred != NULL)
847
*transferred = req.wLenDone;
850
a1logd(p->log, 8, "icoms_usb_control_msg: returning err 0x%x and %d bytes\n",reqrv, transferred != NULL ? *transferred : -1);
854
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
855
/* Time out error return value */
857
//#define USBIO_ERROR_TIMEOUT -ETIMEDOUT
859
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
861
/* Cancel i/o in another thread */
862
int icoms_usb_cancel_io(
868
usb_lock_cancel(cancelt);
869
usbio_req *req = (usbio_req *)cancelt->hcancel;
873
if ((rv = (*p->usbd->interfaces[req->iix])->AbortPipe(
874
p->usbd->interfaces[req->iix], req->pno)) != kIOReturnSuccess) {
878
usb_unlock_cancel(cancelt);
883
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
884
/* Reset and end point data toggle to 0 */
885
int icoms_usb_resetep(
887
int ep /* End point address */
890
int iix = p->EPINFO(ep).interface;
891
UInt8 pno = (UInt8)p->EPINFO(ep).pipe;
894
if ((rv = (*p->usbd->interfaces[iix])->ResetPipe(
895
p->usbd->interfaces[iix], pno)) != kIOReturnSuccess) {
896
a1logd(p->log, 1, "icoms_usb_resetep failed with 0x%x\n",rv);
902
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
903
/* Clear a halt on an end point */
904
int icoms_usb_clearhalt(
906
int ep /* End point address */
909
int iix = p->EPINFO(ep).interface;
910
UInt8 pno = (UInt8)p->EPINFO(ep).pipe;
914
#if defined(NEVER) && (InterfaceVersion > 182)
915
if ((rv = (*p->usbd->interfaces[iix])->ClearPipeStallBothEnds(
916
p->usbd->interfaces[iix], pno)) != kIOReturnSuccess) {
917
a1logd(p->log, 1, "icoms_usb_clearhalt failed with 0x%x\n",rv);
921
if ((rv = (*p->usbd->interfaces[iix])->ClearPipeStall(
922
p->usbd->interfaces[iix], pno)) != kIOReturnSuccess) {
923
a1logd(p->log, 1, "icoms_usb_clearhalt failed with 0x%x\n",rv);
926
if ((irv = icoms_usb_control_msg(p, NULL, IUSB_REQ_HOST_TO_DEV | IUSB_REQ_TYPE_STANDARD
927
| IUSB_REQ_RECIP_ENDPOINT, IUSB_REQ_CLEAR_FEATURE,
928
IUSB_FEATURE_EP_HALT, ep, NULL, 0, 200)) != ICOM_OK) {
929
a1logd(p->log, 1, "icoms_usb_clearhalt far end failed with 0x%x\n",irv);
936
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
940
IOUSBFindInterfaceRequest req;
943
/* See if we can find any interfaces */
944
req.bInterfaceClass =
945
req.bInterfaceSubClass =
946
req.bInterfaceProtocol =
947
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
949
if ((rv = (*(p->usbd->device))->CreateInterfaceIterator(
950
p->usbd->device, &req, &ioit)) != kIOReturnSuccess) {
951
a1loge(p->log, rv, "usb_open_port: CreateInterfaceIterator failed with 0x%x\n",rv);
955
if (IOIteratorNext(ioit) == 0) { /* Configure the device */
956
IOUSBConfigurationDescriptorPtr confdesc;
958
if ((rv = (*(p->usbd->device))->GetConfigurationDescriptorPtr(
959
p->usbd->device, config-1, &confdesc)) != kIOReturnSuccess) {
960
a1loge(p->log, rv, "usb_open_port: GetConfigurationDescriptorPtr failed with 0x%x\n",rv);
961
IOObjectRelease(ioit);
965
if ((rv = (*(p->usbd->device))->SetConfiguration(
966
p->usbd->device, confdesc->bConfigurationValue)) != kIOReturnSuccess) {
967
a1loge(p->log, rv, "usb_open_port: SetConfiguration failed with 0x%x\n",rv);
968
IOObjectRelease(ioit);
972
a1logd(p->log, 6, "usb_open_port: SetConfiguration %d OK\n",confdesc->bConfigurationValue);
974
} else { /* Some diagnostics */
976
if ((rv = (*(p->usbd->device))->GetConfiguration(
977
p->usbd->device, &confno)) != kIOReturnSuccess) {
978
a1logd(p->log, 6, "usb_open_port: GetConfiguration failed with 0x%x\n",rv);
980
a1logd(p->log, 6, "usb_open_port: Device didn't need configuring - currently %d\n",confno);
983
IOObjectRelease(ioit);