diff options
Diffstat (limited to 'spectro/usbio_ox.c')
-rw-r--r-- | spectro/usbio_ox.c | 220 |
1 files changed, 55 insertions, 165 deletions
diff --git a/spectro/usbio_ox.c b/spectro/usbio_ox.c index c92aed5..312c355 100644 --- a/spectro/usbio_ox.c +++ b/spectro/usbio_ox.c @@ -244,16 +244,6 @@ static void cleanup_device(icoms *p) { if (p->usbd->device != NULL) { /* device is open */ int i; - /* Stop the RunLoop and wait for it */ - if (p->usbd->cfrunloop != NULL) { - - a1logd(p->log, 6, "usb_close_port: waiting for RunLoop thread to exit\n"); - CFRunLoopStop(p->usbd->cfrunloop); - CFRelease(p->usbd->cfrunloop); - if (p->usbd->thread != NULL) - pthread_join(p->usbd->thread, NULL); - } - /* Release all the interfaces */ for (i = 0; i < p->usbd->nifce; i++) { if (p->usbd->interfaces[i] != NULL) { @@ -266,9 +256,6 @@ static void cleanup_device(icoms *p) { (*(p->usbd->device))->USBDeviceClose(p->usbd->device); (*(p->usbd->device))->Release(p->usbd->device); } - pthread_cond_destroy(&p->usbd->cond); - pthread_mutex_destroy(&p->usbd->lock); - memset(p->usbd, 0, sizeof(struct usb_idevice)); } } @@ -336,9 +323,6 @@ char **pnames /* List of process names to try and kill before opening */ return ICOM_NOTS; } - pthread_mutex_init(&p->usbd->lock, NULL); - pthread_cond_init(&p->usbd->cond, NULL); - /* Do open retries */ for (tries = 0; retries >= 0; retries--, tries++) { IOCFPlugInInterface **piif = NULL; @@ -353,6 +337,7 @@ char **pnames /* List of process names to try and kill before opening */ if (tries > 0 && pnames != NULL && kpc == NULL) { if ((kpc = kkill_nprocess(pnames, p->log)) == NULL) { a1logd(p->log, 1, "kkill_nprocess returned error!\n"); + return ICOM_SYS; } } @@ -377,8 +362,11 @@ char **pnames /* List of process names to try and kill before opening */ if ((rv = (*p->usbd->device)->USBDeviceOpenSeize(p->usbd->device)) != kIOReturnSuccess) { a1logd(p->log, 8, "usb_open_port: open '%s' config %d failed (0x%x) (Device being used ?)\n",p->name,config,rv); if (retries <= 0) { - if (kpc != NULL) + if (kpc != NULL) { + if (kpc->th->result < 0) + a1logw(p->log, "usb_open_port: killing competing processes failed\n"); kpc->del(kpc); + } a1loge(p->log, rv, "usb_open_port: open '%s' config %d failed (0x%x) (Device being used ?)\n",p->name, config, rv); (*p->usbd->device)->Release(p->usbd->device); return ICOM_SYS; @@ -508,28 +496,6 @@ char **pnames /* List of process names to try and kill before opening */ IOObjectRelease(ioit); } - { - /* Setup the RunLoop thread */ - a1logd(p->log, 6, "usb_open_port: Starting RunLoop thread\n"); - if ((rv = pthread_create(&p->usbd->thread, NULL, io_runloop, (void*)p)) < 0) { - a1loge(p->log, ICOM_SYS, "usb_open_port: creating RunLoop thread failed with %s\n",rv); - cleanup_device(p); - return ICOM_SYS; - } - - /* Wait for the runloop thread to start and create a cfrunloop */ - pthread_mutex_lock(&p->usbd->lock); - while (p->usbd->cfrunloop == NULL) - pthread_cond_wait(&p->usbd->cond, &p->usbd->lock); - pthread_mutex_unlock(&p->usbd->lock); - if (p->usbd->thrv != kIOReturnSuccess) { /* Thread failed */ - pthread_join(p->usbd->thread, NULL); - cleanup_device(p); - return ICOM_SYS; - } - CFRetain(p->usbd->cfrunloop); - a1logd(p->log, 6, "usb_open_port: RunLoop thread started\n"); - } /* Clear any errors */ /* (Some I/F seem to hang if we do this, some seem to hang if we don't !) */ @@ -562,70 +528,6 @@ char **pnames /* List of process names to try and kill before opening */ /* -------------------------------------------------------------- */ -/* The run loop thread */ -static void *io_runloop(void *context) { - icoms *p = (icoms *)context; - int i; - - /* Register this thread with the Objective-C garbage collector */ -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - objc_registerThreadWithCollector(); -#endif - - a1logd(p->log, 6, "io_runloop: thread started\n"); - - p->usbd->cfrunloop = CFRunLoopGetCurrent(); /* Get this threads RunLoop */ - CFRetain(p->usbd->cfrunloop); - - /* Add a device event source */ - if ((p->usbd->thrv = (*(p->usbd->device))->CreateDeviceAsyncEventSource( - p->usbd->device, &p->usbd->cfsource)) != kIOReturnSuccess) { - a1loge(p->log, p->usbd->thrv, "io_runloop: CreateDeviceAsyncEventSource failed with 0x%x\n",p->usbd->thrv); - } else { - CFRunLoopAddSource(p->usbd->cfrunloop, p->usbd->cfsource, kCFRunLoopDefaultMode); - } - - /* Create an async event source for the interfaces */ - for (i = 0; p->usbd->thrv == kIOReturnSuccess && i < p->usbd->nifce; i++) { - if ((p->usbd->thrv = (*(p->usbd->interfaces[i]))->CreateInterfaceAsyncEventSource( - p->usbd->interfaces[i], &p->usbd->cfsources[i])) != kIOReturnSuccess) { - a1loge(p->log, p->usbd->thrv, "io_runloop: CreateInterfaceAsyncEventSource failed with 0x%x\n",p->usbd->thrv); - } else { - /* Add it to the RunLoop */ - CFRunLoopAddSource(p->usbd->cfrunloop, p->usbd->cfsources[i], kCFRunLoopDefaultMode); - } - } - - /* Signal main thread that we've started */ - pthread_mutex_lock(&p->usbd->lock); - pthread_cond_signal(&p->usbd->cond); - pthread_mutex_unlock(&p->usbd->lock); - - /* Run the loop, or exit on error */ - if (p->usbd->thrv == kIOReturnSuccess) { - CFRunLoopRun(); /* Run the loop and deliver events */ - } - - /* Delete the interfaces async event sources */ - for (i = 0; i < p->usbd->nifce; i++) { - if (p->usbd->cfsources[i] != NULL) { - CFRunLoopRemoveSource(p->usbd->cfrunloop, p->usbd->cfsources[i], kCFRunLoopDefaultMode); - CFRelease(p->usbd->cfsources[i]); - } - } - - /* Delete the devices event sources */ - if (p->usbd->cfsource != NULL) { - CFRunLoopRemoveSource(p->usbd->cfrunloop, p->usbd->cfsource, kCFRunLoopDefaultMode); - CFRelease(p->usbd->cfsource); - } - - CFRelease(p->usbd->cfrunloop); - - a1logd(p->log, 6, "io_runloop: thread done\n"); - return NULL; -} - /* I/O structures */ typedef struct _usbio_req { @@ -633,14 +535,12 @@ typedef struct _usbio_req { int iix; /* Interface index */ UInt8 pno; /* pipe index */ volatile int done; /* Done flag */ - pthread_mutex_t lock; /* Protect req & callback access */ - pthread_cond_t cond; /* Signal to thread waiting on req */ int xlength; /* Bytes transferred */ IOReturn result; /* Result of transaction */ + CFRunLoopRef rlr; /* RunLoop of calling thread */ } usbio_req; - -/* Async completion callback - called by RunLoop thread */ +/* Async completion callback - called by RunLoop */ static void io_callback(void *refcon, IOReturn result, void *arg0) { usbio_req *req = (usbio_req *)refcon; @@ -649,9 +549,8 @@ static void io_callback(void *refcon, IOReturn result, void *arg0) { req->xlength = (int)(long)arg0; req->result = result; req->done = 1; - pthread_mutex_lock(&req->lock); - pthread_cond_signal(&req->cond); - pthread_mutex_unlock(&req->lock); + + CFRunLoopStop(req->rlr); /* We're done */ } /* Our universal USB transfer function */ @@ -669,6 +568,7 @@ static int icoms_usb_transaction( int dirw = (endpoint & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT ? 1 : 0; usbio_req req; IOReturn result; + CFRunLoopSourceRef cfsource; /* Device event sources */ int iix = p->EPINFO(endpoint).interface; UInt8 pno = (UInt8)p->EPINFO(endpoint).pipe; @@ -687,16 +587,30 @@ static int icoms_usb_transaction( req.pno = pno; req.xlength = 0; req.done = 0; - pthread_mutex_init(&req.lock, NULL); - pthread_cond_init(&req.cond, NULL); + + req.rlr = CFRunLoopGetCurrent(); /* Get this threads RunLoop */ + CFRetain(req.rlr); + + /* Create an async event source for the interface */ + if ((result = (*(p->usbd->interfaces[iix]))->CreateInterfaceAsyncEventSource( + p->usbd->interfaces[iix], &cfsource)) != kIOReturnSuccess) { + a1logw(p->log, "icoms_usb_transaction: CreateInterfaceAsyncEventSource failed with 0x%x\n",result); + CFRelease(req.rlr); + return ICOM_SYS; + } + CFRetain(cfsource); + + /* Add it to the RunLoop */ + CFRunLoopAddSource(req.rlr, cfsource, kCFRunLoopDefaultMode); if (dirw) result = (*p->usbd->interfaces[iix])->WritePipeAsync(p->usbd->interfaces[iix], pno, buffer, length, io_callback, &req); - else + else result = (*p->usbd->interfaces[iix])->ReadPipeAsync(p->usbd->interfaces[iix], pno, buffer, length, io_callback, &req); + if (result != kIOReturnSuccess) { a1loge(p->log, ICOM_SYS, "icoms_usb_transaction: %sPipeAsync failed with 0x%x\n",dirw ? "Write" : "Read", result); reqrv = ICOM_SYS; @@ -707,66 +621,46 @@ static int icoms_usb_transaction( amutex_lock(cancelt->cmtx); cancelt->hcancel = (void *)&req; cancelt->state = 1; - amutex_unlock(cancelt->cond); /* Signal any thread waiting for IO start */ + amutex_unlock(cancelt->condx); /* Signal any thread waiting for IO start */ amutex_unlock(cancelt->cmtx); } - /* Wait for the callback to complete */ - pthread_mutex_lock(&req.lock); - if (!req.done) { - struct timeval tv; - struct timespec ts; - - // this is unduly complicated... - gettimeofday(&tv, NULL); - ts.tv_sec = tv.tv_sec + timeout/1000; - ts.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000) * 1000L; - if (ts.tv_nsec > 1000000000L) { - ts.tv_nsec -= 1000000000L; - ts.tv_sec++; - } - - for(;;) { /* Ignore spurious wakeups */ - if ((rv = pthread_cond_timedwait(&req.cond, &req.lock, &ts)) != 0) { - if (rv != ETIMEDOUT) { - a1logd(p->log, 1, "coms_usb_transaction: pthread_cond_timedwait failed with %d\n",rv); - (*p->usbd->interfaces[iix])->AbortPipe(p->usbd->interfaces[iix], pno); - req.result = kIOReturnAborted; - reqrv = ICOM_SYS; - break; - } - - /* Timed out */ - a1logd(p->log, 8, "coms_usb_transaction: time out - aborting io\n"); - (*p->usbd->interfaces[iix])->AbortPipe(p->usbd->interfaces[iix], pno); - reqrv = ICOM_TO; - /* Wait for the cancelled io to be signalled */ - if ((rv = pthread_cond_wait(&req.cond, &req.lock)) != 0) { - pthread_mutex_unlock(&req.lock); - a1logd(p->log, 1, "coms_usb_transaction: pthread_cond_wait failed with %d\n",rv); - req.result = kIOReturnAborted; - reqrv = ICOM_SYS; - break; - } - break; - } - if (req.done) /* Ignore spurious wakeups */ - break; - } + /* Wait for the callback to complete or for a timeout */ + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout / 1000.0, false); + + // kCFRunLoopRunFinished = 1 + // kCFRunLoopRunStopped = 2 + // kCFRunLoopRunTimedOut = 3 + // kCFRunLoopRunHandledSource = 4 + + if (result == kCFRunLoopRunTimedOut) { + /* Timed out - so abort i/o */ + a1logd(p->log, 8, "coms_usb_transaction: time out - aborting io\n"); + (*p->usbd->interfaces[iix])->AbortPipe(p->usbd->interfaces[iix], pno); + CFRunLoopRun(); /* Wait for abort */ + reqrv = ICOM_TO; + } else if (result != kCFRunLoopRunStopped) { + a1logd(p->log, 8, "coms_usb_transaction: unexpected result 0x%x\n",result); + reqrv = ICOM_USBR; } - pthread_mutex_unlock(&req.lock); + + done:; + CFRunLoopRemoveSource(req.rlr, cfsource, kCFRunLoopDefaultMode); + CFRelease(cfsource); + CFRelease(req.rlr); a1logd(p->log, 8, "coms_usb_transaction: completed with reqrv 0x%x and xlength %d\n",req.result,req.xlength); /* If io was aborted, ClearPipeStall */ if (req.result == kIOReturnAborted) { + a1logd(p->log, 8, "coms_usb_transaction: io was aborted\n"); #if (InterfaceVersion > 182) (*p->usbd->interfaces[iix])->ClearPipeStallBothEnds(p->usbd->interfaces[iix], pno); #else (*p->usbd->interfaces[iix])->ClearPipeStall(p->usbd->interfaces[iix], pno); - icoms_usb_control_msg(p, NULL, IUSB_REQ_HOST_TO_DEV | IUSB_REQ_TYPE_STANDARD - | IUSB_REQ_RECIP_ENDPOINT, IUSB_REQ_CLEAR_FEATURE, - IUSB_FEATURE_EP_HALT, endpoint, NULL, 0, 200); +// icoms_usb_control_msg(p, NULL, IUSB_REQ_HOST_TO_DEV | IUSB_REQ_TYPE_STANDARD +// | IUSB_REQ_RECIP_ENDPOINT, IUSB_REQ_CLEAR_FEATURE, +// IUSB_FEATURE_EP_HALT, endpoint, NULL, 0, 200); #endif if (reqrv == ICOM_OK) /* If not aborted for a known reason, must be cancelled */ reqrv = ICOM_CANC; @@ -788,19 +682,15 @@ static int icoms_usb_transaction( if (transferred != NULL) *transferred = req.xlength; -done:; if (cancelt != NULL) { amutex_lock(cancelt->cmtx); cancelt->hcancel = (void *)NULL; if (cancelt->state == 0) - amutex_unlock(cancelt->cond); + amutex_unlock(cancelt->condx); cancelt->state = 2; amutex_unlock(cancelt->cmtx); } - pthread_cond_destroy(&req.cond); - pthread_mutex_destroy(&req.lock); - if (in_usb_rw < 0) exit(0); |