~ubuntu-branches/ubuntu/trusty/argyll/trusty-proposed

« back to all changes in this revision

Viewing changes to spectro/usbio_nt.c

  • Committer: Package Import Robot
  • Author(s): Artur Rona
  • Date: 2014-02-12 00:35:39 UTC
  • mfrom: (13.1.24 sid)
  • Revision ID: package-import@ubuntu.com-20140212003539-24tautzlitsiz61w
Tags: 1.5.1-5ubuntu1
* Merge from Debian unstable. (LP: #1275572) Remaining changes:
  - debian/control:
    + Build-depend on libtiff-dev rather than libtiff4-dev.
  - debian/control, debian/patches/06_fix_udev_rule.patch:
    + Fix udev rules to actually work; ENV{ACL_MANAGE} has
      stopped working ages ago, and with logind it's now the
      "uaccess" tag. Dropping also consolekit from Recommends.
  - debian/patches/drop-usb-db.patch:
    + Use hwdb builtin, instead of the obsolete usb-db
      in the udev rules.
* debian/patches/05_ftbfs-underlinkage.diff:
  - Dropped change, no needed anymore.
* Refresh the patches.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/* General USB I/O support, MSWin native libusb0.sys implementation. */
 
3
/* This file is conditionaly #included into usbio.c */
 
4
 
 
5
/* 
 
6
 * Argyll Color Correction System
 
7
 *
 
8
 * Author: Graeme W. Gill
 
9
 * Date:   2006/22/4
 
10
 *
 
11
 * Copyright 2006 - 2013 Graeme W. Gill
 
12
 * All rights reserved.
 
13
 *
 
14
 * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
 
15
 * see the License2.txt file for licencing details.
 
16
 */
 
17
 
 
18
#include <stdlib.h>
 
19
#include <string.h>
 
20
#include <stdio.h>
 
21
#include <errno.h>
 
22
#include <ctype.h>
 
23
#include <windows.h>
 
24
#include <winioctl.h>
 
25
#include <setupapi.h>
 
26
#include <driver_api.h>
 
27
 
 
28
#define DEBUG           /* Turn on debug messages */
 
29
 
 
30
#define LIBUSBW1_MAX_DEVICES 255
 
31
#define LIBUSBW1_PATH_MAX 512
 
32
#define LIBUSBW1_DEFAULT_TIMEOUT 5000
 
33
 
 
34
/* USB descriptors are little endian */
 
35
 
 
36
/* Take a word sized return buffer, and convert it to an unsigned int */
 
37
static unsigned int buf2uint(unsigned char *buf) {
 
38
        unsigned int val;
 
39
        val = buf[3];
 
40
        val = ((val << 8) + (0xff & buf[2]));
 
41
        val = ((val << 8) + (0xff & buf[1]));
 
42
        val = ((val << 8) + (0xff & buf[0]));
 
43
        return val;
 
44
}
 
45
 
 
46
/* Take a short sized return buffer, and convert it to an int */
 
47
static unsigned int buf2ushort(unsigned char *buf) {
 
48
        unsigned int val;
 
49
        val = buf[1];
 
50
        val = ((val << 8) + (0xff & buf[0]));
 
51
        return val;
 
52
}
 
53
 
 
54
/* Take an int, and convert it into a byte buffer */
 
55
static void int2buf(unsigned char *buf, int inv) {
 
56
        buf[0] = (inv >> 0) & 0xff;
 
57
        buf[1] = (inv >> 8) & 0xff;
 
58
        buf[2] = (inv >> 16) & 0xff;
 
59
        buf[3] = (inv >> 24) & 0xff;
 
60
}
 
61
 
 
62
/* Take a short, and convert it into a byte buffer */
 
63
static void short2buf(unsigned char *buf, int inv) {
 
64
        buf[0] = (inv >> 0) & 0xff;
 
65
        buf[1] = (inv >> 8) & 0xff;
 
66
}
 
67
 
 
68
/* Do a synchronous request. Return an ICOM error */
 
69
static int do_sync_io(
 
70
HANDLE handle,
 
71
unsigned int ioctl,
 
72
void *out, int outsz,
 
73
void *in, int insz,
 
74
int *retsz) {
 
75
        OVERLAPPED olaps;
 
76
        DWORD xlength;
 
77
 
 
78
        memset(&olaps, 0, sizeof(OVERLAPPED));  
 
79
        if (retsz != NULL)
 
80
                *retsz = 0;
 
81
 
 
82
        if ((olaps.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
 
83
                return ICOM_SYS;
 
84
        
 
85
        if (!DeviceIoControl(handle, ioctl, out, outsz, in, insz, &xlength, &olaps)) {
 
86
                if (GetLastError() != ERROR_IO_PENDING) {
 
87
                        CloseHandle(olaps.hEvent);
 
88
                        return ICOM_USBW;
 
89
                }
 
90
                if (!GetOverlappedResult(handle, &olaps, &xlength, TRUE)) {
 
91
                        CloseHandle(olaps.hEvent);
 
92
                        return ICOM_USBR;
 
93
                }
 
94
        }
 
95
        CloseHandle(olaps.hEvent);
 
96
        if (retsz != NULL)
 
97
                *retsz = (int)xlength;
 
98
 
 
99
        return ICOM_OK;
 
100
}
 
101
 
 
102
/* Add paths to USB connected instruments */
 
103
/* Return an icom error */
 
104
int usb_get_paths(
 
105
icompaths *p 
 
106
) {
 
107
        unsigned int vid, pid, nep10 = 0xffff;
 
108
        unsigned int configix, nconfig, nifce;
 
109
        instType itype;
 
110
        struct usb_idevice *usbd = NULL;
 
111
        int rv, retsz, i;
 
112
 
 
113
        for (i = 0; i < LIBUSBW1_MAX_DEVICES; i++) {
 
114
                libusb_request req;
 
115
                char dpath[LIBUSBW1_PATH_MAX];
 
116
                HANDLE handle;
 
117
                unsigned char buf[IUSB_DESC_TYPE_DEVICE_SIZE];
 
118
 
 
119
                _snprintf(dpath, LIBUSBW1_PATH_MAX - 1,"\\\\.\\libusb0-%04d", i+1);
 
120
                a1logd(p->log, 6, "usb_get_paths opening device '%s'\n",dpath);
 
121
 
 
122
                if ((handle = CreateFile(dpath, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
 
123
                                                                    NULL)) == INVALID_HANDLE_VALUE) {
 
124
#ifdef DEBUG
 
125
                        a1logd(p->log, 8, "usb_get_paths failed to open device '%s'\n",dpath);
 
126
#endif
 
127
                        continue;
 
128
                }
 
129
 
 
130
                /* Set kernel message debug */
 
131
                if (p->log->debug >= 6) {
 
132
                        req.debug.level = LIBUSB_DEBUG_MAX;
 
133
                        req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
134
                        if (do_sync_io(handle, LIBUSB_IOCTL_SET_DEBUG_LEVEL,
 
135
                                &req, sizeof(libusb_request), NULL, 0, NULL)) {
 
136
                                a1logd(p->log, 1, "usb_get_paths: failed to set driver log leve\n");
 
137
                        } else {
 
138
                                a1logd(p->log, 1, "usb_get_paths: turned on kernel debug messages\n");
 
139
                        }
 
140
                }
 
141
 
 
142
                /* Read the device descriptor */
 
143
                req.descriptor.type        = IUSB_DESC_TYPE_DEVICE;
 
144
                req.descriptor.recipient   = IUSB_REQ_RECIP_DEVICE;
 
145
                req.descriptor.index       = 0;
 
146
                req.descriptor.language_id = 0;
 
147
                req.timeout                = LIBUSBW1_DEFAULT_TIMEOUT;
 
148
                
 
149
                if (do_sync_io(handle, LIBUSB_IOCTL_GET_DESCRIPTOR, 
 
150
                                        &req, sizeof(libusb_request), 
 
151
                                        buf, IUSB_DESC_TYPE_DEVICE_SIZE, &retsz) != ICOM_OK
 
152
                                                             || retsz != IUSB_DESC_TYPE_DEVICE_SIZE) {
 
153
                        a1logd(p->log, 1, "usb_get_paths: failed to read device descriptor '%s'\n",dpath);
 
154
                        CloseHandle(handle);
 
155
                        continue;
 
156
                }
 
157
 
 
158
                /* Extract the vid and pid */   
 
159
                vid = buf2ushort(buf + 8);
 
160
                pid = buf2ushort(buf + 10);
 
161
                nconfig = buf[17];
 
162
                
 
163
                a1logd(p->log, 6, "usb_get_paths: checking vid 0x%04x, pid 0x%04x\n",vid,pid);
 
164
 
 
165
                /* Do a preliminary match */
 
166
                if ((itype = inst_usb_match(vid, pid, 0)) == instUnknown) {
 
167
                        a1logd(p->log, 6 , "usb_get_paths: instrument not reconized\n");
 
168
                        CloseHandle(handle);
 
169
                        continue;
 
170
                }
 
171
 
 
172
                /* Allocate an idevice so that we can fill in the end point information */
 
173
                if ((usbd = (struct usb_idevice *) calloc(sizeof(struct usb_idevice), 1)) == NULL) {
 
174
                        a1loge(p->log, ICOM_SYS, "usb_get_paths: calloc failed!\n");
 
175
                        CloseHandle(handle);
 
176
                        return ICOM_SYS;
 
177
                }
 
178
 
 
179
                usbd->nconfig = nconfig;
 
180
                
 
181
                /* Read the configuration descriptors looking for the first configuration, first interface, */
 
182
                /* and extract the number of end points for each configuration */
 
183
                for (configix = 0; configix < nconfig; configix++) {
 
184
                        int configno, totlen;
 
185
                        unsigned char *buf2, *bp, *zp;
 
186
                        unsigned int ninfaces, inface, nep;
 
187
 
 
188
                        /* Read the configuration descriptor */
 
189
                        req.descriptor.type        = IUSB_DESC_TYPE_CONFIG;
 
190
                        req.descriptor.recipient   = IUSB_REQ_RECIP_DEVICE;
 
191
                        req.descriptor.index       = configix;
 
192
                        req.descriptor.language_id = 0;
 
193
                        req.timeout                = LIBUSBW1_DEFAULT_TIMEOUT;
 
194
                        
 
195
                        if ((rv = do_sync_io(handle, LIBUSB_IOCTL_GET_DESCRIPTOR, 
 
196
                                                &req, sizeof(libusb_request), 
 
197
                                                buf, IUSB_DESC_TYPE_CONFIG_SIZE, &retsz)) != ICOM_OK
 
198
                                                                     || retsz != IUSB_DESC_TYPE_CONFIG_SIZE) {
 
199
                                a1logd(p->log, 1, "usb_get_paths: failed to read configix  %d descriptor\n",configix);
 
200
                                free(usbd);
 
201
                                CloseHandle(handle);
 
202
                                break;
 
203
                        }
 
204
                        nifce = buf[4];         /* number of interfaces */
 
205
                        configno = buf[5];              /* Configuration number */
 
206
 
 
207
                        if (configno != 1)
 
208
                                continue;
 
209
 
 
210
                        if ((totlen = buf2ushort(buf + 2)) < 6) {
 
211
                                a1logd(p->log, 1, "usb_get_paths: '%s' config desc size strange\n",dpath);
 
212
                                free(usbd);
 
213
                                CloseHandle(handle);
 
214
                                break;
 
215
                        }
 
216
                        if ((buf2 = calloc(1, totlen)) == NULL) {
 
217
                                a1loge(p->log, ICOM_SYS, "usb_get_paths: calloc of descriptor failed!\n");
 
218
                                free(usbd);
 
219
                                CloseHandle(handle);
 
220
                                return ICOM_SYS;
 
221
                        }
 
222
                        
 
223
                        /* Read the whole configuration descriptor */
 
224
                        req.descriptor.type        = IUSB_DESC_TYPE_CONFIG;
 
225
                        req.descriptor.recipient   = IUSB_REQ_RECIP_DEVICE;
 
226
                        req.descriptor.index       = configix;
 
227
                        req.descriptor.language_id = 0;
 
228
                        req.timeout                = LIBUSBW1_DEFAULT_TIMEOUT;
 
229
                        
 
230
                        if (do_sync_io(handle, LIBUSB_IOCTL_GET_DESCRIPTOR, 
 
231
                                                &req, sizeof(libusb_request), 
 
232
                                                buf2, totlen, &retsz) != ICOM_OK
 
233
                                                                     || retsz != totlen) {
 
234
                                a1logd(p->log, 1, "usb_get_paths: failed to read all configix %d descriptor\n",configix);
 
235
                                free(buf2);
 
236
                                free(usbd);
 
237
                                CloseHandle(handle);
 
238
                                break;
 
239
                        }
 
240
 
 
241
                        bp = buf2 + buf2[0];    /* Skip coniguration tag */
 
242
                        zp = buf2 + totlen;             /* Past last bytes */
 
243
 
 
244
                        /* We are at the first configuration. */
 
245
                        /* Just read tags and keep track of where we are */
 
246
                        ninfaces = 0;
 
247
                        nep = 0;
 
248
                        usbd->nifce = buf2[4];                          /* number of interfaces */
 
249
                        usbd->config = configno = buf2[5];      /* this configuration */
 
250
                        for (;bp < zp; bp += bp[0]) {
 
251
                                int ifaceno;
 
252
                                if ((bp + 1) >= zp)
 
253
                                        break;                  /* Hmm - bodgy, give up */
 
254
                                if (bp[1] == IUSB_DESC_TYPE_INTERFACE) {
 
255
                                        ninfaces++;
 
256
                                        if ((bp + 2) >= zp)
 
257
                                                break;                  /* Hmm - bodgy, give up */
 
258
                                        ifaceno = bp[2];        /* Get bInterfaceNumber */
 
259
                                } else if (bp[1] == IUSB_DESC_TYPE_ENDPOINT) {
 
260
                                        nep++;
 
261
                                        if ((bp + 5) >= zp)
 
262
                                                break;                  /* Hmm - bodgy */
 
263
                                        /* At first config - */
 
264
                                        /* record current nep and end point details */
 
265
                                        if (configno == 1) {
 
266
                                                int ad = bp[2];
 
267
                                                nep10 = nep;
 
268
                                                usbd->EPINFO(ad).valid = 1;
 
269
                                                usbd->EPINFO(ad).addr = ad;
 
270
                                                usbd->EPINFO(ad).packetsize = buf2ushort(bp + 4);
 
271
                                                usbd->EPINFO(ad).type = bp[3] & IUSB_ENDPOINT_TYPE_MASK;
 
272
                                                usbd->EPINFO(ad).interface = ifaceno;
 
273
                                                a1logd(p->log, 6, "set ep ad 0x%x packetsize %d type %d\n",ad,usbd->EPINFO(ad).packetsize,usbd->EPINFO(ad).type);
 
274
                                        }
 
275
                                }
 
276
                                /* Ignore other tags */
 
277
                        }
 
278
                        free(buf2);
 
279
                }
 
280
                if (nep10 == 0xffff) {                  /* Hmm. Failed to find number of end points */
 
281
                        a1logd(p->log, 1, "usb_get_paths: failed to find number of end points\n");
 
282
                        free(usbd);
 
283
                        CloseHandle(handle);
 
284
                        continue;
 
285
                }
 
286
 
 
287
                /* Check that we have an up to date kernel driver */
 
288
                req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
289
                if (do_sync_io(handle, LIBUSB_IOCTL_GET_VERSION, 
 
290
                                        &req, sizeof(libusb_request), 
 
291
                                        &req, sizeof(libusb_request), &retsz) != ICOM_OK
 
292
                                                             || retsz != sizeof(libusb_request)) {
 
293
                        a1logd(p->log, 1, "usb_get_paths: failed to read driver version info\n");
 
294
                        free(usbd);
 
295
                        CloseHandle(handle);
 
296
                        continue;
 
297
                }
 
298
                if (req.version.major < 1
 
299
                 || req.version.major == 1 && (req.version.minor < 2
 
300
         || req.version.minor == 2 && req.version.micro < 6)) {
 
301
                        a1loge(p->log, ICOM_VER, "usb_get_paths: Must update %s System Driver to latest version!\n",inst_name(itype));
 
302
                        free(usbd);
 
303
                        CloseHandle(handle);
 
304
                        return ICOM_VER;
 
305
                }
 
306
                CloseHandle(handle);
 
307
 
 
308
                /* Found a known instrument ? */
 
309
                if ((itype = inst_usb_match(vid, pid, nep10)) != instUnknown) {
 
310
                        char pname[400];
 
311
 
 
312
                        a1logd(p->log, 1, "usb_get_paths: found instrument vid 0x%04x, pid 0x%04x\n",vid,pid);
 
313
 
 
314
                        /* Create a path/identification */
 
315
                        sprintf(pname,"%s (%s)", dpath + 4, inst_name(itype));
 
316
 
 
317
                        if ((usbd->dpath = strdup(dpath)) == NULL) {
 
318
                                a1loge(p->log, ICOM_SYS, "usb_check_and_add: strdup path failed!\n");
 
319
                                free(usbd);
 
320
                                return ICOM_SYS;
 
321
                        }
 
322
 
 
323
                        /* Add the path and ep info to the list */
 
324
                        if ((rv = p->add_usb(p, pname, vid, pid, nep10, usbd, itype)) != ICOM_OK)
 
325
                                return rv;
 
326
                } else {
 
327
                        free(usbd);
 
328
                }
 
329
        }
 
330
 
 
331
        return ICOM_OK;
 
332
}
 
333
 
 
334
 
 
335
/* Copy usb_idevice contents from icompaths to icom */
 
336
/* return icom error */
 
337
int usb_copy_usb_idevice(icoms *d, icompath *s) {
 
338
        int i;
 
339
        if (s->usbd == NULL) { 
 
340
                d->usbd = NULL;
 
341
                return ICOM_OK;
 
342
        }
 
343
        if ((d->usbd = calloc(sizeof(struct usb_idevice), 1)) == NULL) {
 
344
                a1loge(d->log, ICOM_SYS, "usb_copy_usb_idevice: malloc\n");
 
345
                return ICOM_SYS;
 
346
        }
 
347
        if ((d->usbd->dpath = strdup(s->usbd->dpath)) == NULL) {
 
348
                a1loge(d->log, ICOM_SYS, "usb_copy_usb_idevice: malloc\n");
 
349
                return ICOM_SYS;
 
350
        }
 
351
        /* Copy the current state & ep info */
 
352
        d->nconfig = s->usbd->nconfig;
 
353
        d->config = s->usbd->config;
 
354
        d->nifce = s->usbd->nifce;
 
355
        for (i = 0; i < 32; i++)
 
356
                d->ep[i] = s->usbd->ep[i];              /* Struct copy */
 
357
        return ICOM_OK;
 
358
}
 
359
 
 
360
/* Cleanup and then free a usb dev entry */
 
361
void usb_del_usb_idevice(struct usb_idevice *usbd) {
 
362
 
 
363
        if (usbd == NULL)
 
364
                return;
 
365
 
 
366
        if (usbd->dpath != NULL)
 
367
                free(usbd->dpath);
 
368
        free(usbd);
 
369
}
 
370
 
 
371
/* Cleanup any USB specific icoms state */
 
372
void usb_del_usb(icoms *p) {
 
373
 
 
374
        usb_del_usb_idevice(p->usbd);
 
375
}
 
376
 
 
377
/* Close an open USB port */
 
378
/* If we don't do this, the port and/or the device may be left in an unusable state. */
 
379
void usb_close_port(icoms *p) {
 
380
 
 
381
        a1logd(p->log, 6, "usb_close_port: called\n");
 
382
 
 
383
        if (p->is_open && p->usbd != NULL) {
 
384
                int iface, rv;
 
385
 
 
386
                /* Release all the interfaces */
 
387
                for (iface = 0; iface < p->nifce; iface++) {
 
388
                        libusb_request req;
 
389
 
 
390
                        memset(&req, 0, sizeof(req));
 
391
                        req.intf.interface_number = iface;
 
392
                        req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
393
                
 
394
                        do_sync_io(p->usbd->handle, LIBUSB_IOCTL_RELEASE_INTERFACE, 
 
395
                                             &req, sizeof(libusb_request), NULL, 0, NULL);
 
396
                }
 
397
 
 
398
                /* Workaround for some bugs - reset device on close */
 
399
                if (p->uflags & icomuf_reset_before_close) {
 
400
                        libusb_request req;
 
401
 
 
402
                        memset(&req, 0, sizeof(req));
 
403
                        req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
404
                
 
405
                        if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_RESET_DEVICE, 
 
406
                                             &req, sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
 
407
                                a1logd(p->log, 1, "usb_close_port: reset returned %d\n",rv);
 
408
                        }
 
409
                }
 
410
                CloseHandle(p->usbd->handle);
 
411
 
 
412
                free(p->usbd->dpath);
 
413
                free(p->usbd);
 
414
                p->usbd = NULL;
 
415
 
 
416
                a1logd(p->log, 6, "usb_close_port: usb port has been released and closed\n");
 
417
        }
 
418
        p->is_open = 0;
 
419
 
 
420
        /* Find it and delete it from our static cleanup list */
 
421
        usb_delete_from_cleanup_list(p);
 
422
}
 
423
 
 
424
static void *urb_reaper(void *context);         /* Declare */
 
425
 
 
426
/* Open a USB port for all our uses. */
 
427
/* This always re-opens the port */
 
428
/* return icom error */
 
429
static int usb_open_port(
 
430
icoms *p,
 
431
int    config,          /* Configuration number */
 
432
int    wr_ep,           /* Write end point */
 
433
int    rd_ep,           /* Read end point */
 
434
icomuflags usbflags,/* Any special handling flags */
 
435
int retries,            /* > 0 if we should retry set_configuration (100msec) */ 
 
436
char **pnames           /* List of process names to try and kill before opening */
 
437
) {
 
438
        int rv, tries = 0;
 
439
        a1logd(p->log, 8, "usb_open_port: Make sure USB port is open, tries %d\n",retries);
 
440
 
 
441
        if (p->is_open)
 
442
                p->close_port(p);
 
443
 
 
444
        /* Make sure the port is open */
 
445
        if (!p->is_open) {
 
446
                int rv, i, iface;
 
447
                kkill_nproc_ctx *kpc = NULL;
 
448
                OSVERSIONINFO osver;
 
449
 
 
450
                if (config != 1) {
 
451
                        /* Nothing currently needs it, so we haven't implemented it yet... */
 
452
                        a1loge(p->log, ICOM_NOTS, "usb_open_port: native driver cant handle config %d\n",config);
 
453
                        return ICOM_NOTS;
 
454
                }
 
455
 
 
456
                /* Do open retries */
 
457
                for (tries = 0; retries >= 0; retries--, tries++) {
 
458
 
 
459
                        a1logd(p->log, 8, "usb_open_port: About to open USB port '%s'\n",p->usbd->dpath);
 
460
 
 
461
                        if (tries > 0) {
 
462
                                //msec_sleep(i_rand(50,100));
 
463
                                msec_sleep(77);
 
464
                        }
 
465
 
 
466
                        if ((p->usbd->handle = CreateFile(p->usbd->dpath, 0, 0, NULL, OPEN_EXISTING,
 
467
                                             FILE_FLAG_OVERLAPPED, NULL)) == INVALID_HANDLE_VALUE) {
 
468
                                a1logd(p->log, 8, "usb_open_port: open '%s' config %d failed (%d) (Device being used ?)\n",p->usbd->dpath,config,GetLastError());
 
469
                                if (retries <= 0) {
 
470
                                        if (kpc != NULL)
 
471
                                                kpc->del(kpc); 
 
472
                                        a1loge(p->log, ICOM_SYS, "usb_open_port: open '%s' config %d failed (%d) (Device being used ?)\n",p->usbd->dpath,config,GetLastError());
 
473
                                        return ICOM_SYS;
 
474
                                }
 
475
                                continue;
 
476
                        } else if (p->debug)
 
477
                                a1logd(p->log, 2, "usb_open_port: open port '%s' succeeded\n",p->usbd->dpath);
 
478
 
 
479
                        p->uflags = usbflags;
 
480
 
 
481
                        /* We're done */
 
482
                        break;
 
483
                }
 
484
 
 
485
                if (kpc != NULL)
 
486
                        kpc->del(kpc); 
 
487
 
 
488
                /* We should only do a set configuration if the device has more than one */
 
489
                /* possible configuration and it is currently not the desired configuration, */
 
490
                /* but we should avoid doing a set configuration if the OS has already */
 
491
                /* selected the configuration we want, since two set configs seem to */
 
492
                /* mess up the Spyder2, BUT we can't do a get config because this */
 
493
                /* messes up the i1pro-D. */
 
494
 
 
495
                osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 
496
                osver.dwMajorVersion = 5;
 
497
                GetVersionEx(&osver);
 
498
                if (osver.dwMajorVersion >= 6 && osver.dwMinorVersion >= 2) {
 
499
                        p->cconfig = 0;         /* Need to do set_congfig(1) on Win8 */
 
500
                } else {
 
501
                        p->cconfig = 1;         /* Set by default to config 1 */
 
502
                }
 
503
 
 
504
                if (p->cconfig != config) {
 
505
                        libusb_request req;
 
506
 
 
507
                        memset(&req, 0, sizeof(libusb_request));
 
508
                        req.configuration.configuration = config;
 
509
                        req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
510
                
 
511
                        if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_SET_CONFIGURATION, 
 
512
                                             &req, sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
 
513
                
 
514
                                a1loge(p->log, rv, "usb_open_port: Setting port '%s' to config %d failed with %d\n",p->usbd->dpath,config,rv);
 
515
                                return ICOM_SYS;
 
516
                        }
 
517
                        p->cconfig = config;
 
518
                        a1logd(p->log, 6, "usb_open_port: set config %d OK\n",config);
 
519
                }
 
520
 
 
521
                /* Claim all the interfaces */
 
522
                for (iface = 0; iface < p->nifce; iface++) {
 
523
                        libusb_request req;
 
524
 
 
525
                        memset(&req, 0, sizeof(libusb_request));
 
526
                        req.intf.interface_number = iface;
 
527
                        req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
528
                
 
529
                        if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_CLAIM_INTERFACE, 
 
530
                                             &req, sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
 
531
                
 
532
                                a1loge(p->log, rv, "usb_open_port: Claiming USB port '%s' interface %d failed with %d\n",p->usbd->dpath,iface,rv);
 
533
                                return ICOM_SYS;
 
534
                        }
 
535
                }
 
536
 
 
537
                /* Clear any errors */
 
538
                /* (Some I/F seem to hang if we do this, some seem to hang if we don't !) */
 
539
                if (!(p->uflags & icomuf_no_open_clear)) {
 
540
                        for (i = 0; i < 32; i++) {
 
541
                                if (!p->ep[i].valid)
 
542
                                        continue;
 
543
                                p->usb_clearhalt(p, p->ep[i].addr); 
 
544
                        }
 
545
                }
 
546
 
 
547
                /* Set "serial" coms values */
 
548
                p->wr_ep = wr_ep;
 
549
                p->rd_ep = rd_ep;
 
550
                p->rd_qa = p->EPINFO(rd_ep).packetsize;
 
551
                if (p->rd_qa == 0)
 
552
                        p->rd_qa = 8;
 
553
                a1logd(p->log, 8, "usb_open_port: 'serial' read quanta = packet size = %d\n",p->rd_qa);
 
554
 
 
555
                p->is_open = 1;
 
556
                a1logd(p->log, 8, "usb_open_port: USB port is now open\n");
 
557
        }
 
558
 
 
559
        /* Install the cleanup signal handlers, and add to our cleanup list */
 
560
        usb_install_signal_handlers(p);
 
561
 
 
562
        return ICOM_OK;
 
563
}
 
564
 
 
565
/*  -------------------------------------------------------------- */
 
566
 
 
567
/* Our universal USB transfer function */
 
568
static int icoms_usb_transaction(
 
569
        icoms *p,
 
570
        usb_cancelt *cancelt,
 
571
        int *transferred,
 
572
        icom_usb_trantype ttype,        /* transfer type */
 
573
        unsigned char endpoint,         /* 0x80 for control write, 0x00 for control read */
 
574
        unsigned char *buffer,
 
575
        int length,
 
576
        unsigned int timeout            /* In msec */
 
577
) {
 
578
        int rv = ICOM_OK;
 
579
        int dirw = (endpoint & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT ? 1 : 0;
 
580
    libusb_request req;
 
581
        OVERLAPPED olaps;
 
582
        DWORD xlength = 0;
 
583
 
 
584
        in_usb_rw++;
 
585
 
 
586
        a1logd(p->log, 8, "icoms_usb_transaction: req type 0x%x ep 0x%x size %d\n",ttype,endpoint,length);
 
587
 
 
588
        if (ttype != icom_usb_trantype_interrutpt
 
589
         && ttype != icom_usb_trantype_bulk) {
 
590
                /* We only handle interrupt & bulk, not control */
 
591
                return ICOM_SYS;
 
592
        }
 
593
 
 
594
        memset(&olaps, 0, sizeof(olaps));       
 
595
 
 
596
        if ((olaps.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
 
597
                return ICOM_SYS;
 
598
        
 
599
        if (cancelt != NULL) {
 
600
                usb_lock_cancel(cancelt);
 
601
                cancelt->hcancel = (void *)&endpoint;
 
602
                usb_unlock_cancel(cancelt);
 
603
        }
 
604
 
 
605
        memset(&req, 0, sizeof(libusb_request));
 
606
        req.endpoint.endpoint = endpoint;
 
607
 
 
608
        if (!DeviceIoControl(p->usbd->handle, 
 
609
                              dirw ? LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE
 
610
                              : LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ,
 
611
                              &req, sizeof(libusb_request), 
 
612
                              buffer,
 
613
                              length, &xlength, &olaps)) {
 
614
                if (GetLastError() != ERROR_IO_PENDING) {
 
615
                        rv = dirw ? ICOM_USBW : ICOM_USBR;
 
616
                        goto done;
 
617
                }
 
618
 
 
619
                if (WaitForSingleObject(olaps.hEvent, timeout) == WAIT_TIMEOUT) {
 
620
 
 
621
                        /* Cancel the operation */
 
622
                        memset(&req, 0, sizeof(libusb_request));
 
623
                        req.endpoint.endpoint = endpoint;
 
624
                        req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
625
                        do_sync_io(p->usbd->handle, LIBUSB_IOCTL_ABORT_ENDPOINT, 
 
626
                                                   &req, sizeof(libusb_request), NULL, 0, NULL);
 
627
                        rv = ICOM_TO;
 
628
                }
 
629
 
 
630
                if (!GetOverlappedResult(p->usbd->handle, &olaps, &xlength, TRUE)) {
 
631
                        if (rv == ICOM_OK) {
 
632
                                if (GetLastError() == ERROR_OPERATION_ABORTED)
 
633
                                        rv = ICOM_CANC;
 
634
                                else
 
635
                                        rv = dirw ? ICOM_USBW : ICOM_USBR;
 
636
                        }
 
637
                }
 
638
        }
 
639
done:;
 
640
        if (cancelt != NULL) {
 
641
                usb_lock_cancel(cancelt);
 
642
                cancelt->hcancel = (void *)NULL;
 
643
                usb_unlock_cancel(cancelt);
 
644
        }
 
645
 
 
646
        CloseHandle(olaps.hEvent);
 
647
 
 
648
        if (transferred != NULL)
 
649
                *transferred = (int)xlength;
 
650
 
 
651
        /* The requested size wasn't transferred */
 
652
        if (rv == ICOM_OK  && xlength != length)
 
653
                rv = ICOM_SHORT;
 
654
 
 
655
        if (in_usb_rw < 0)
 
656
                exit(0);
 
657
 
 
658
        in_usb_rw--;
 
659
 
 
660
        a1logd(p->log, 8, "coms_usb_transaction: returning err 0x%x and %d bytes\n",rv, xlength);
 
661
 
 
662
        return rv;
 
663
}
 
664
 
 
665
 
 
666
/* Our control message routine */
 
667
/* Return error icom error code */
 
668
static int icoms_usb_control_msg(
 
669
icoms *p,
 
670
int *transferred,
 
671
int requesttype, int request,
 
672
int value, int index, unsigned char *bytes, int size, 
 
673
int timeout) {
 
674
        int rv = ICOM_OK;
 
675
        int dirw = (requesttype & IUSB_REQ_DIR_MASK) == IUSB_REQ_HOST_TO_DEV ? 1 : 0;
 
676
    libusb_request req;
 
677
        unsigned char *obuf = (unsigned char *)&req;
 
678
        int osize = sizeof(libusb_request);
 
679
        unsigned char *ibuf = bytes;
 
680
        int isize = size;
 
681
    int ioctl = 0;
 
682
        int retsz = 0;
 
683
 
 
684
        a1logd(p->log, 8, "icoms_usb_control_msg: type 0x%x req 0x%x size %d\n",requesttype,request,size);
 
685
 
 
686
        memset(&req, 0, sizeof(libusb_request));
 
687
    req.timeout = timeout;
 
688
 
 
689
        /* We need to treat each request type as a different IOCTL */
 
690
        switch (requesttype & IUSB_REQ_TYPE_MASK) {
 
691
 
 
692
                case IUSB_REQ_TYPE_STANDARD:
 
693
 
 
694
                        switch (request) {
 
695
                                case IUSB_REQ_GET_STATUS:
 
696
                                        req.status.recipient = requesttype & IUSB_REQ_RECIP_MASK;
 
697
                                        req.status.index = index;
 
698
                                        ioctl = LIBUSB_IOCTL_GET_STATUS;
 
699
                                        break;
 
700
 
 
701
                                case IUSB_REQ_CLEAR_FEATURE:
 
702
                                        req.feature.recipient = requesttype & IUSB_REQ_RECIP_MASK;
 
703
                                        req.feature.feature = value;
 
704
                                        req.feature.index = index;
 
705
                                        ioctl = LIBUSB_IOCTL_CLEAR_FEATURE;
 
706
                                        break;
 
707
 
 
708
                                case IUSB_REQ_SET_FEATURE:
 
709
                                        req.feature.recipient = requesttype & IUSB_REQ_RECIP_MASK;
 
710
                                        req.feature.feature = value;
 
711
                                        req.feature.index = index;
 
712
                                        ioctl = LIBUSB_IOCTL_SET_FEATURE;
 
713
                                        break;
 
714
 
 
715
                                case IUSB_REQ_GET_DESCRIPTOR:
 
716
                                        req.descriptor.recipient = requesttype & IUSB_REQ_RECIP_MASK;
 
717
                                        req.descriptor.type = (value >> 8) & 0xFF;
 
718
                                        req.descriptor.index = value & 0xFF;
 
719
                                        req.descriptor.language_id = index;
 
720
                                        ioctl = LIBUSB_IOCTL_GET_DESCRIPTOR;
 
721
                                        break;
 
722
 
 
723
                                case IUSB_REQ_SET_DESCRIPTOR:
 
724
                                        req.descriptor.recipient = requesttype & IUSB_REQ_RECIP_MASK;
 
725
                                        req.descriptor.type = (value >> 8) & 0xFF;
 
726
                                        req.descriptor.index = value & 0xFF;
 
727
                                        req.descriptor.language_id = index;
 
728
                                        ioctl = LIBUSB_IOCTL_SET_DESCRIPTOR;
 
729
                                        break;
 
730
 
 
731
                                case IUSB_REQ_GET_CONFIGURATION:
 
732
                                        ioctl = LIBUSB_IOCTL_GET_CONFIGURATION;
 
733
                                        break;
 
734
 
 
735
                                case IUSB_REQ_SET_CONFIGURATION:
 
736
                                        req.configuration.configuration = value;
 
737
                                        ioctl = LIBUSB_IOCTL_SET_CONFIGURATION;
 
738
                                        break;
 
739
 
 
740
                                case IUSB_REQ_GET_INTERFACE:
 
741
                                        req.intf.interface_number = index;
 
742
                                        ioctl = LIBUSB_IOCTL_GET_INTERFACE;
 
743
                                        break;
 
744
 
 
745
                                case IUSB_REQ_SET_INTERFACE:
 
746
                                        req.intf.interface_number = index;
 
747
                                        req.intf.altsetting_number = value;
 
748
                                        ioctl = LIBUSB_IOCTL_SET_INTERFACE;
 
749
                                        break;
 
750
 
 
751
                                default:
 
752
                                        return ICOM_SYS; 
 
753
                        }
 
754
                        break;
 
755
 
 
756
                case IUSB_REQ_TYPE_VENDOR:
 
757
                case IUSB_REQ_TYPE_CLASS:
 
758
 
 
759
                        req.vendor.type = (requesttype & IUSB_REQ_TYPE_MASK) >> IUSB_REQ_TYPE_SHIFT;
 
760
                        req.vendor.recipient = requesttype & IUSB_REQ_RECIP_MASK;
 
761
                        req.vendor.request = request;
 
762
                        req.vendor.value = value;
 
763
                        req.vendor.index = index;
 
764
 
 
765
                        if (dirw)
 
766
                                ioctl = LIBUSB_IOCTL_VENDOR_WRITE;
 
767
                        else
 
768
                                ioctl = LIBUSB_IOCTL_VENDOR_READ;
 
769
                        break;
 
770
 
 
771
                case IUSB_REQ_TYPE_RESERVED:
 
772
                default:
 
773
                        return ICOM_SYS;
 
774
        }
 
775
 
 
776
        /* If we're writing the data, append it to the req */
 
777
    if (dirw) {
 
778
        osize = sizeof(libusb_request) + size;
 
779
                if ((obuf = calloc(1, osize)) == NULL) {
 
780
                        a1loge(p->log, ICOM_SYS, "icoms_usb_control_msg: calloc failed\n");
 
781
                        return ICOM_SYS;
 
782
                }
 
783
 
 
784
        memcpy(obuf, &req, sizeof(libusb_request));
 
785
        memcpy(obuf + sizeof(libusb_request), bytes, size);
 
786
        ibuf = NULL;
 
787
        isize = 0;
 
788
    }
 
789
 
 
790
    if ((rv = do_sync_io(p->usbd->handle, ioctl, obuf, osize, ibuf, isize, &retsz))
 
791
                                                                                     != ICOM_OK) {
 
792
                if (dirw)
 
793
                        free(obuf);
 
794
                return rv;
 
795
    }
 
796
 
 
797
        if (dirw) {
 
798
                free(obuf);
 
799
                retsz = size;
 
800
        }
 
801
 
 
802
        if (transferred != NULL)        /* Adjust for header size requested */
 
803
                *transferred = retsz;
 
804
 
 
805
        a1logd(p->log, 8, "icoms_usb_control_msg: returning err 0x%x and %d bytes\n",rv, *transferred);
 
806
        return rv;
 
807
}
 
808
 
 
809
/* Cancel i/o operation in another thread. */
 
810
/* Only Vista has CancelIoEx that can cancel a single operation, */
 
811
/* so we cancel the io to the end point, which will */
 
812
/* acheive what we want. */
 
813
int icoms_usb_cancel_io(
 
814
        icoms *p,
 
815
        usb_cancelt *cancelt
 
816
) {
 
817
        int rv = ICOM_OK;
 
818
        usb_lock_cancel(cancelt);
 
819
        if (cancelt->hcancel != NULL) {
 
820
                libusb_request req;
 
821
 
 
822
                memset(&req, 0, sizeof(libusb_request));
 
823
                req.endpoint.endpoint = *((unsigned char *)cancelt->hcancel);
 
824
                req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
825
 
 
826
                if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_ABORT_ENDPOINT, 
 
827
                                                   &req, sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
 
828
                        a1logd(p->log, 1, "icoms_usb_cancel_io: failed with 0x%x\n",rv);
 
829
                }
 
830
        }
 
831
        usb_unlock_cancel(cancelt);
 
832
 
 
833
        return rv;
 
834
}
 
835
 
 
836
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
 
837
/* Reset and end point data toggle to 0 */
 
838
int icoms_usb_resetep(
 
839
        icoms *p,
 
840
        int ep                                  /* End point address */
 
841
) {
 
842
        libusb_request req;
 
843
        int rv = ICOM_OK;
 
844
 
 
845
        memset(&req, 0, sizeof(libusb_request));
 
846
        req.endpoint.endpoint = ep;
 
847
        req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
848
 
 
849
        if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_RESET_ENDPOINT, &req, 
 
850
                            sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
 
851
                a1logd(p->log, 1, "icoms_usb_resetep failed with %d\n",rv);
 
852
                return rv;
 
853
        }
 
854
        return rv;
 
855
}
 
856
 
 
857
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
 
858
/* Clear a halt on an end point */
 
859
/* (Actually does a resetep) */
 
860
int icoms_usb_clearhalt(
 
861
        icoms *p,
 
862
        int ep                                  /* End point address */
 
863
) {
 
864
        libusb_request req;
 
865
        int rv = ICOM_OK;
 
866
 
 
867
        memset(&req, 0, sizeof(libusb_request));
 
868
        req.endpoint.endpoint = ep;
 
869
        req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
870
 
 
871
        if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_RESET_ENDPOINT, &req, 
 
872
                            sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
 
873
                a1logd(p->log, 1, "icoms_usb_resetep failed with %d\n",rv);
 
874
                return rv;
 
875
        }
 
876
        return rv;
 
877
}
 
878
 
 
879
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
 
880
 
 
881
#ifdef NEVER
 
882
                        libusb_request req;
 
883
                        unsigned char buf[1] = { 0xff };
 
884
 
 
885
                        memset(&req, 0, sizeof(libusb_request));
 
886
                        req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
 
887
                
 
888
                        if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_GET_CONFIGURATION, 
 
889
                                             &req, sizeof(libusb_request), buf, 1, NULL)) != ICOM_OK) {
 
890
                
 
891
                                a1logd(p->log, 1, "usb_open_port: Getting port '%s' configuration failed with %d\n",p->usbd->dpath,rv);
 
892
                                /* Ignore error */
 
893
                        } else {
 
894
                                a1logd(p->log, 1, "usb_open_port: current config = %d\n",(int)buf[0]);
 
895
                        }
 
896
                        config = buf[0];
 
897
#endif // NEVER
 
898