From 830c8ddc4c5e085368161257245fbcd43995ddc6 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Kollasch" Date: Fri, 1 Feb 2019 21:10:02 -0600 Subject: [PATCH] argyllcms: improve WIP patch for NetBSD ugen(4) --- argyllcms/wip-patch-spectro_usbio__bsd.c | 442 +++++++++++++++++++++-- 1 file changed, 404 insertions(+), 38 deletions(-) diff --git a/argyllcms/wip-patch-spectro_usbio__bsd.c b/argyllcms/wip-patch-spectro_usbio__bsd.c index 2bd21b3fc8..fcb2130e72 100644 --- a/argyllcms/wip-patch-spectro_usbio__bsd.c +++ b/argyllcms/wip-patch-spectro_usbio__bsd.c @@ -32,18 +32,7 @@ Attempt to make actually function with NetBSD ugen(4). int rv, found = 0; if (paths[j] == NULL) -@@ -112,6 +117,10 @@ icompaths *p - - vid = di.udi_vendorNo; - pid = di.udi_productNo; -+#if 1 -+ vid = 0x0971; -+ pid = 0x2005; -+#endif - - a1logd(p->log, 6, "usb_get_paths: checking vid 0x%04x, pid 0x%04x\n",vid,pid); - -@@ -121,12 +130,8 @@ icompaths *p +@@ -121,12 +126,8 @@ icompaths *p continue; } @@ -58,7 +47,7 @@ Attempt to make actually function with NetBSD ugen(4). /* Allocate an idevice so that we can fill in the end point information */ if ((usbd = (struct usb_idevice *) calloc(sizeof(struct usb_idevice), 1)) == NULL) { -@@ -136,8 +141,56 @@ icompaths *p +@@ -136,8 +137,56 @@ icompaths *p return ICOM_SYS; } @@ -97,7 +86,7 @@ Attempt to make actually function with NetBSD ugen(4). + ued.ued_interface_index = 0; + ued.ued_alt_index = USB_CURRENT_ALT_INDEX; + ued.ued_endpoint_index = epix; -+ if (ioctl(fd, USB_GET_ENDPOINT_DESC, ued) < 0) { ++ if (ioctl(fd, USB_GET_ENDPOINT_DESC, &ued) < 0) { + break; + } + @@ -116,7 +105,62 @@ Attempt to make actually function with NetBSD ugen(4). /* Found a known instrument ? */ if ((itype = inst_usb_match(vid, pid, nep)) != instUnknown) { char pname[400], *cp; -@@ -309,7 +362,6 @@ char **pnames /* List of process names +@@ -245,52 +294,18 @@ void usb_close_port(icoms *p) { + + a1logd(p->log, 6, "usb_close_port: called\n"); + +-#ifdef NEVER // ~~99 + if (p->is_open && p->usbd != NULL) { +- struct usbdevfs_urb urb; +- unsigned char buf[8+IUSB_DESC_TYPE_DEVICE_SIZE]; +- int iface, rv; +- +- /* Release all the interfaces */ +- for (iface = 0; iface < p->nifce; iface++) +- ioctl(p->usbd->fd, USBDEVFS_RELEASEINTERFACE, &iface); +- +- /* Workaround for some bugs - reset device on close */ +- if (p->uflags & icomuf_reset_before_close) { +- if ((rv = ioctl(p->usbd->fd, USBDEVFS_RESET, NULL)) != 0) { +- a1logd(p->log, 1, "usb_close_port: reset returned %d\n",rv); +- } +- } +- +- if (p->usbd->running) { /* If reaper is still running */ +- unsigned char buf[1] = { 0 }; +- +- a1logd(p->log, 6, "usb_close_port: waking reaper thread to trigger exit\n"); +- p->usbd->shutdown = 1; +- +- if (write(p->usbd->sd_pipe[1], buf, 1) < 1) { +- a1logd(p->log, 1, "usb_close_port: writing to sd_pipe failed with '%s'\n", strerror(errno)); +- /* Hmm. We could be in trouble ? */ +- } ++ for (int i = 15; i >= 0; i--) { ++ close(p->ep[i].fd); + } +- a1logd(p->log, 6, "usb_close_port: waiting for reaper thread\n"); +- pthread_join(p->usbd->thread, NULL); /* Wait for urb reaper thread to exit */ +- close(p->usbd->fd); +- pthread_mutex_destroy(&p->usbd->lock); +- close(p->usbd->sd_pipe[0]); +- close(p->usbd->sd_pipe[1]); +- + a1logd(p->log, 6, "usb_close_port: usb port has been released and closed\n"); + } + p->is_open = 0; +-#endif // ~~99 + + /* Find it and delete it from our static cleanup list */ + usb_delete_from_cleanup_list(p); + } + +-static void *urb_reaper(void *context); /* Declare */ +- + /* Open a USB port for all our uses. */ + /* This always re-opens the port */ + /* return icom error */ +@@ -309,7 +324,6 @@ char **pnames /* List of process names if (p->is_open) p->close_port(p); @@ -124,7 +168,7 @@ Attempt to make actually function with NetBSD ugen(4). /* Make sure the port is open */ if (!p->is_open) { int rv, i, iface; -@@ -344,12 +396,16 @@ char **pnames /* List of process names +@@ -344,12 +358,16 @@ char **pnames /* List of process names p->cconfig = 1; if (p->cconfig != config) { @@ -141,7 +185,7 @@ Attempt to make actually function with NetBSD ugen(4). } /* We're done */ -@@ -362,6 +418,7 @@ char **pnames /* List of process names +@@ -362,6 +380,7 @@ char **pnames /* List of process names /* Claim all the interfaces */ for (iface = 0; iface < p->nifce; iface++) { @@ -149,16 +193,21 @@ Attempt to make actually function with NetBSD ugen(4). if ((rv = ioctl(p->usbd->fd, USBDEVFS_CLAIMINTERFACE, &iface)) < 0) { struct usbdevfs_getdriver getd; getd.interface = iface; -@@ -386,6 +443,30 @@ char **pnames /* List of process names +@@ -386,6 +405,30 @@ char **pnames /* List of process names return ICOM_SYS; } } +#endif + } + -+ for (int i = 0; i < 16 ; i++) { ++ char epdpath[33]; ++ snprintf(epdpath, sizeof(epdpath), "%s.%02d", p->usbd->dpath, 0); ++ int fd; ++ fd = open(epdpath, O_RDWR); ++ p->ep[0].fd = fd; ++ ++ for (int i = 1; i < 16; i++) { + int flg; -+ char epdpath[33]; + if (p->ep[i].valid && p->ep[i+16].valid) + flg = O_RDWR; + else if (p->ep[i].valid) @@ -168,32 +217,31 @@ Attempt to make actually function with NetBSD ugen(4). + else + continue; + -+ snprintf(epdpath, sizeof(epdpath), "%s.%02d", i); ++ snprintf(epdpath, sizeof(epdpath), "%s.%02d", p->usbd->dpath, i); + int fd = open(epdpath, flg); + -+ if (p->ep[i].valid && p->ep[i+16].valid) -+ p->ep[i].fd = p->ep[i+16].fd = fd; -+ else if (p->ep[i].valid) -+ p->ep[i].fd = fd; -+ else if (p->ep[i+16].valid) -+ p->ep[i+16].fd = fd; ++ p->ep[i].fd = p->ep[i+16].fd = fd; } /* Clear any errors. */ -@@ -407,6 +488,7 @@ char **pnames /* List of process names +@@ -407,25 +450,10 @@ char **pnames /* List of process names p->rd_qa = 8; a1logd(p->log, 8, "usb_open_port: 'serial' read quanta = packet size = %d\n",p->rd_qa); -+#if 0 - /* Start the reaper thread to handle URB completions */ - if ((rv = pipe(p->usbd->sd_pipe)) < 0) { - a1loge(p->log, ICOM_SYS, "usb_open_port: creat pipe failed with %d\n",rv); -@@ -420,12 +502,12 @@ char **pnames /* List of process names - a1loge(p->log, ICOM_SYS, "usb_open_port: creating urb reaper thread failed with %s\n",rv); - return ICOM_SYS; - } -+#endif - +- /* Start the reaper thread to handle URB completions */ +- if ((rv = pipe(p->usbd->sd_pipe)) < 0) { +- a1loge(p->log, ICOM_SYS, "usb_open_port: creat pipe failed with %d\n",rv); +- return ICOM_SYS; +- } +- pthread_mutex_init(&p->usbd->lock, NULL); +- +- p->usbd->running = 1; +- if ((rv = pthread_create(&p->usbd->thread, NULL, urb_reaper, (void*)p)) < 0) { +- p->usbd->running = 0; +- a1loge(p->log, ICOM_SYS, "usb_open_port: creating urb reaper thread failed with %s\n",rv); +- return ICOM_SYS; +- } +- p->is_open = 1; a1logd(p->log, 8, "usb_open_port: USB port is now open\n"); } @@ -202,3 +250,321 @@ Attempt to make actually function with NetBSD ugen(4). /* Install the cleanup signal handlers, and add to our cleanup list */ usb_install_signal_handlers(p); +@@ -444,88 +472,23 @@ static int icoms_usb_transaction( + int length, + unsigned int timeout /* In msec */ + ) { +- int type; + int remlen; + unsigned char *bp; +- int xlength = 0; ++ ssize_t xlength = 0; + int i; + int reqrv = ICOM_OK; + +-#ifdef NEVER // ~~99 + in_usb_rw++; + a1logd(p->log, 8, "icoms_usb_transaction: req type 0x%x ep 0x%x size %d\n",ttype,endpoint,length); + +- if (!p->usbd->running) { +- in_usb_rw--; +- a1logv(p->log, 1, "icoms_usb_transaction: reaper thread is not running\n"); +- return ICOM_SYS; +- } ++ /* XXX USB_SET_TIMEOUT */ + +- /* Translate icoms transfer type of Linux */ +- switch (ttype) { +- case icom_usb_trantype_command: +- type = USBDEVFS_URB_TYPE_CONTROL; +- break; +- case icom_usb_trantype_interrutpt: +- type = USBDEVFS_URB_TYPE_INTERRUPT; +- break; +- case icom_usb_trantype_bulk: +- type = USBDEVFS_URB_TYPE_BULK; +- break; +- } +- +- /* Setup the icom req and urbs */ +- req.urbs = NULL; +- pthread_mutex_init(&req.lock, NULL); +- pthread_cond_init(&req.cond, NULL); +- +- /* Linux historically only copes with 16384 length urbs, */ +- /* so break up longer requests into multiple urbs */ +- +- req.cancelled = 0; +- req.nourbs = req.nurbs = (length + (1 << 14)-1) >> 14; +- if ((req.urbs = (usbio_urb *)calloc(sizeof(usbio_urb), req.nourbs)) == NULL) { +- in_usb_rw--; +- a1loge(p->log, ICOM_SYS, "icoms_usb_transaction: control transfer too big! (%d)\n",length); +- return ICOM_SYS; +- } ++ if ((endpoint & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT) ++ xlength = write(p->ep[endpoint&0xf].fd, buffer, length); ++ else ++ xlength = read(p->ep[endpoint&0xf].fd, buffer, length); + +- bp = buffer; +- remlen = length; +- for (i = 0; i < req.nurbs; i++) { +- req.urbs[i].req = &req; +- req.urbs[i].urbno = i; +- /* Setup Linux URB */ +- req.urbs[i].urb.usercontext = &req.urbs[i]; +- req.urbs[i].urb.type = type; +- if (type != USBDEVFS_URB_TYPE_CONTROL) +- req.urbs[i].urb.endpoint = endpoint; +- if (remlen > 16384) +- req.urbs[i].urb.buffer_length = 16384; +- else +- req.urbs[i].urb.buffer_length = remlen; +- req.urbs[i].urb.buffer = (void *)bp; +- remlen -= req.urbs[i].urb.buffer_length; +- bp += req.urbs[i].urb.buffer_length; +- req.urbs[i].urb.status = -EINPROGRESS; +- } +-a1logd(p->log, 8, "icoms_usb_transaction: reset req %p nourbs to %d\n",&req,req.nourbs); +- +- /* Add our request to the req list so that it can be cancelled on reap failure */ +- pthread_mutex_lock(&p->usbd->lock); +- req.next = p->usbd->reqs; +- p->usbd->reqs = &req; +- pthread_mutex_unlock(&p->usbd->lock); +- +- /* submit the URBs */ +- for (i = 0; i < req.nurbs; i++) { +- if ((rv = ioctl(p->usbd->fd, USBDEVFS_SUBMITURB, &req.urbs[i].urb)) < 0) { +- a1logd(p->log, 1, "coms_usb_transaction: Submitting urb to fd %d failed with %d\n",p->usbd->fd, rv); +- req.urbs[i].urb.status = ICOM_SYS; /* Mark it as failed to submit */ +- req.nourbs--; +- } +- } +- ++#if 0 + if (cancelt != NULL) { + amutex_lock(cancelt->cmtx); + cancelt->hcancel = (void *)&req; +@@ -533,85 +496,7 @@ a1logd(p->log, 8, "icoms_usb_transaction + amutex_unlock(cancelt->cond); /* Signal any thread waiting for IO start */ + amutex_unlock(cancelt->cmtx); + } +- +- /* Wait for the reaper to wake us, or for a timeout, */ +- /* or for the reaper to die. */ +- pthread_mutex_lock(&req.lock); +- if (req.nourbs > 0) { +- 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) { +- pthread_mutex_unlock(&req.lock); +- a1logd(p->log, 1, "coms_usb_transaction: pthread_cond_timedwait failed with %d\n",rv); +- rv = ICOM_SYS; +- goto done; +- } +- +- /* Timed out - cancel the remaining URB's */ +- a1logd(p->log, 8, "coms_usb_transaction: time out - cancel remaining URB's\n"); +- reqrv = ICOM_TO; +- if (!req.cancelled && (rv = cancel_req(p, &req, -1)) != ICOM_OK) { +- pthread_mutex_unlock(&req.lock); +- reqrv = ICOM_SYS; +- /* Since cancelling failed, we can't wait for them to be reaped */ +- goto done; +- } +- +- /* Wait for the cancelled URB's to be reaped */ +- for (;req.nourbs > 0;) { /* Ignore spurious wakeups */ +- 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); +- reqrv = ICOM_SYS; +- /* Waiting for reap failed, so give up */ +- goto done; +- } +- } +- } else { +- a1logd(p->log, 8, "coms_usb_transaction: reap - %d left\n",req.nourbs); +- } +- if (req.nourbs <= 0) +- break; /* All urbs's are done */ +- } +- } +- pthread_mutex_unlock(&req.lock); +- +- /* Compute the overall result by going through the urbs. */ +- for (i = 0; i < req.nurbs; i++) { +- int stat = req.urbs[i].urb.status; +- xlength += req.urbs[i].urb.actual_length; +- +- if (stat == ICOM_SYS) { /* Submit or cancel failed */ +- reqrv = ICOM_SYS; +- } else if (reqrv == ICOM_OK && stat < 0 && stat != -ECONNRESET) { /* Error result */ +- if ((endpoint & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT) +- reqrv = ICOM_USBW; +- else +- reqrv = ICOM_USBR; +- } else if (reqrv == ICOM_OK && stat == -ECONNRESET) { /* Cancelled */ +- reqrv = ICOM_CANC; +- } else if (reqrv == ICOM_OK +- && req.urbs[i].urb.actual_length < req.urbs[i].urb.buffer_length) { +- /* Disregard any following urb's status - they are probably cancelled */ +- break; +- } +- /* reqrv == ICOM_TO will ignore urb status */ +- } +- +- if (ttype == icom_usb_trantype_command) +- xlength += IUSB_REQ_HEADER_SIZE; /* Account for header - linux doesn't */ ++#endif + + /* requested size wasn't transferred ? */ + if (reqrv == ICOM_OK && xlength != length) +@@ -620,6 +505,7 @@ a1logd(p->log, 8, "icoms_usb_transaction + if (transferred != NULL) + *transferred = xlength; + ++#if 0 + done:; + if (cancelt != NULL) { + amutex_lock(cancelt->cmtx); +@@ -629,20 +515,7 @@ done:; + cancelt->state = 2; + amutex_unlock(cancelt->cmtx); + } +- +- /* Remove our request from the list */ +- pthread_mutex_lock(&p->usbd->lock); +- preq = &p->usbd->reqs; +- while (*preq != &req && *preq != NULL) /* Find it */ +- preq = &((*preq)->next); +- if (*preq != NULL) +- *preq = (*preq)->next; +- pthread_mutex_unlock(&p->usbd->lock); +- +- if (req.urbs != NULL) +- free(req.urbs); +- pthread_cond_destroy(&req.cond); +- pthread_mutex_destroy(&req.lock); ++#endif + + if (in_usb_rw < 0) + exit(0); +@@ -650,7 +523,6 @@ done:; + in_usb_rw--; + + a1logd(p->log, 8, "coms_usb_transaction: returning err 0x%x and %d bytes\n",reqrv, xlength); +-#endif // ~~99 + + return reqrv; + } +@@ -665,51 +537,34 @@ int value, int index, unsigned char *byt + int timeout) { + int reqrv = ICOM_OK; + int dirw = (requesttype & IUSB_REQ_DIR_MASK) == IUSB_REQ_HOST_TO_DEV ? 1 : 0; +- unsigned char *buf; ++ struct usb_ctl_request ucr; + + a1logd(p->log, 8, "icoms_usb_control_msg: type 0x%x req 0x%x size %d\n",requesttype,request,size); + +-#ifdef NEVER // ~~99 +- /* Allocate a buffer for the ctrl header + payload */ +- if ((buf = calloc(1, IUSB_REQ_HEADER_SIZE + size)) == NULL) { +- a1loge(p->log, ICOM_SYS, "icoms_usb_control_msg: calloc failed\n"); +- return ICOM_SYS; +- } +- ++ ucr.ucr_addr = 0; + /* Setup the control header */ +- buf[0] = requesttype; +- buf[1] = request; +- short2buf(buf + 2, value); +- short2buf(buf + 4, index); +- short2buf(buf + 6, size); +- +- /* If it's a write, copy the write data into the buffer */ +- if (dirw) +- memcpy(buf + IUSB_REQ_HEADER_SIZE, bytes, size); +- +- reqrv = icoms_usb_transaction(p, NULL, transferred, icom_usb_trantype_command, +- dirw ? 0x80 : 0x00, buf, IUSB_REQ_HEADER_SIZE + size, timeout); +- +- /* If read, copy the data back */ +- if (!dirw) +- memcpy(bytes, buf + IUSB_REQ_HEADER_SIZE, size); ++ ucr.ucr_request.bmRequestType = requesttype; ++ ucr.ucr_request.bRequest = request; ++ USETW(ucr.ucr_request.wValue, value); ++ USETW(ucr.ucr_request.wIndex, index); ++ USETW(ucr.ucr_request.wLength, size); ++ ucr.ucr_data = bytes; ++ ucr.ucr_flags = USBD_SHORT_XFER_OK; ++ ucr.ucr_actlen = 0; + +- if (transferred != NULL) /* Adjust for header size requested */ +- *transferred -= IUSB_REQ_HEADER_SIZE; ++ /* XXX USB_SET_TIMEOUT */ + +- free(buf); ++ if (ioctl(p->ep[0].fd, USB_DO_REQUEST, &ucr) < 0) ++ return ICOM_SYS; /* XXX */ ++ ++ if (transferred != NULL) ++ *transferred = ucr.ucr_actlen; + +-#endif // ~~99 + a1logd(p->log, 8, "icoms_usb_control_msg: returning err 0x%x and %d bytes\n",reqrv, *transferred); + return reqrv; + } + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +-/* Time out error return value */ +- +-#define USBIO_ERROR_TIMEOUT -ETIMEDOUT +- +-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /* Cancel i/o in another thread */ + int icoms_usb_cancel_io( +@@ -717,8 +572,9 @@ int icoms_usb_cancel_io( + usb_cancelt *cancelt + ) { + int rv = ICOM_OK; +-#ifdef NEVER // ~~99 ++ + a1logd(p->log, 8, "icoms_usb_cancel_io called\n"); ++#ifdef NEVER // ~~99 + usb_lock_cancel(cancelt); + if (cancelt->hcancel != NULL) + rv = cancel_req(p, (usbio_req *)cancelt->hcancel, -1); +@@ -739,6 +595,8 @@ int icoms_usb_resetep( + ) { + int rv = ICOM_OK; + ++ a1logd(p->log, 1, "icoms_usb_resetep unimplemented with %d\n",rv); ++ + #ifdef NEVER // ~~99 + if ((rv = ioctl(p->usbd->fd, USBDEVFS_RESETEP, &ep)) != 0) { + a1logd(p->log, 1, "icoms_usb_resetep failed with %d\n",rv); +@@ -756,6 +614,8 @@ int icoms_usb_clearhalt( + ) { + int rv = ICOM_OK; + ++ a1logd(p->log, 1, "icoms_usb_clearhalt unimplemented with %d\n",rv); ++ + #ifdef NEVER // ~~99 + if ((rv = ioctl(p->usbd->fd, USBDEVFS_CLEAR_HALT, &ep)) != 0) { + a1logd(p->log, 1, "icoms_usb_clearhalt failed with %d\n",rv);