1/* $FreeBSD: head/lib/libusb/libusb20_ugen20.c 199055 2009-11-08 20:03:52Z thompsa $ */
2/*-
3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/queue.h>
28#include <sys/types.h>
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <string.h>
34#include <poll.h>
35#include <fcntl.h>
36#include <errno.h>
37
38#include "libusb20.h"
39#include "libusb20_desc.h"
40#include "libusb20_int.h"
41
42#include <dev/usb/usb.h>
43#include <dev/usb/usbdi.h>
44#include <dev/usb/usb_ioctl.h>
45
46static libusb20_init_backend_t ugen20_init_backend;
47static libusb20_open_device_t ugen20_open_device;
48static libusb20_close_device_t ugen20_close_device;
49static libusb20_get_backend_name_t ugen20_get_backend_name;
50static libusb20_exit_backend_t ugen20_exit_backend;
51static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
52static libusb20_dev_get_info_t ugen20_dev_get_info;
53static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
54static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
55static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
56static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
57static libusb20_root_set_template_t ugen20_root_set_template;
58static libusb20_root_get_template_t ugen20_root_get_template;
59
60const struct libusb20_backend_methods libusb20_ugen20_backend = {
61 LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
62};
63
64/* USB device specific */
65static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
66static libusb20_get_config_index_t ugen20_get_config_index;
67static libusb20_set_config_index_t ugen20_set_config_index;
68static libusb20_set_alt_index_t ugen20_set_alt_index;
69static libusb20_reset_device_t ugen20_reset_device;
70static libusb20_set_power_mode_t ugen20_set_power_mode;
71static libusb20_get_power_mode_t ugen20_get_power_mode;
72static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
73static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
74static libusb20_do_request_sync_t ugen20_do_request_sync;
75static libusb20_process_t ugen20_process;
76
77/* USB transfer specific */
78static libusb20_tr_open_t ugen20_tr_open;
79static libusb20_tr_close_t ugen20_tr_close;
80static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
81static libusb20_tr_submit_t ugen20_tr_submit;
82static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
83
84static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
85 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
86};
87
88static const char *
89ugen20_get_backend_name(void)
90{
91 return ("FreeBSD UGEN 2.0");
92}
93
94static uint32_t
95ugen20_path_convert_one(const char **pp)
96{
97 const char *ptr;
98 uint32_t temp = 0;
99
100 ptr = *pp;
101
102 while ((*ptr >= '0') && (*ptr <= '9')) {
103 temp *= 10;
104 temp += (*ptr - '0');
105 if (temp >= 1000000) {
106 /* catch overflow early */
107 return (0 - 1);
108 }
109 ptr++;
110 }
111
112 if (*ptr == '.') {
113 /* skip dot */
114 ptr++;
115 }
116 *pp = ptr;
117
118 return (temp);
119}
120
121static int
122ugen20_enumerate(struct libusb20_device *pdev, const char *id)
123{
124 const char *tmp = id;
125 struct usb_device_descriptor ddesc;
126 struct usb_device_info devinfo;
127 uint32_t plugtime;
128 char buf[64];
129 int f;
130 int error;
131
132 pdev->bus_number = ugen20_path_convert_one(&tmp);
133 pdev->device_address = ugen20_path_convert_one(&tmp);
134
135 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
136 pdev->bus_number, pdev->device_address);
137
138 f = open(buf, O_RDWR);
139 if (f < 0) {
140 return (LIBUSB20_ERROR_OTHER);
141 }
142 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
143 error = LIBUSB20_ERROR_OTHER;
144 goto done;
145 }
146 /* store when the device was plugged */
147 pdev->session_data.plugtime = plugtime;
148
149 if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) {
150 error = LIBUSB20_ERROR_OTHER;
151 goto done;
152 }
153 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
154
155 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
156
157 if (pdev->ddesc.bNumConfigurations == 0) {
158 error = LIBUSB20_ERROR_OTHER;
159 goto done;
160 } else if (pdev->ddesc.bNumConfigurations >= 8) {
161 error = LIBUSB20_ERROR_OTHER;
162 goto done;
163 }
164 if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) {
165 error = LIBUSB20_ERROR_OTHER;
166 goto done;
167 }
168 switch (devinfo.udi_mode) {
169 case USB_MODE_DEVICE:
170 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
171 break;
172 default:
173 pdev->usb_mode = LIBUSB20_MODE_HOST;
174 break;
175 }
176
177 switch (devinfo.udi_speed) {
178 case USB_SPEED_LOW:
179 pdev->usb_speed = LIBUSB20_SPEED_LOW;
180 break;
181 case USB_SPEED_FULL:
182 pdev->usb_speed = LIBUSB20_SPEED_FULL;
183 break;
184 case USB_SPEED_HIGH:
185 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
186 break;
187 case USB_SPEED_VARIABLE:
188 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
189 break;
190 case USB_SPEED_SUPER:
191 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
192 break;
193 default:
194 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
195 break;
196 }
197
198 /* generate a nice description for printout */
199
200 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
201 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
202 pdev->device_address, devinfo.udi_product,
203 devinfo.udi_vendor, pdev->bus_number);
204
205 error = 0;
206done:
207 close(f);
208 return (error);
209}
210
211struct ugen20_urd_state {
212 struct usb_read_dir urd;
213 uint32_t nparsed;
214 int f;
215 uint8_t *ptr;
216 const char *src;
217 const char *dst;
218 uint8_t buf[256];
219 uint8_t dummy_zero[1];
220};
221
222static int
223ugen20_readdir(struct ugen20_urd_state *st)
224{
225 ; /* style fix */
226repeat:
227 if (st->ptr == NULL) {
228 st->urd.urd_startentry += st->nparsed;
229 st->urd.urd_data = st->buf;
230 st->urd.urd_maxlen = sizeof(st->buf);
231 st->nparsed = 0;
232
233 if (ioctl(st->f, USB_READ_DIR, &st->urd)) {
234 return (EINVAL);
235 }
236 st->ptr = st->buf;
237 }
238 if (st->ptr[0] == 0) {
239 if (st->nparsed) {
240 st->ptr = NULL;
241 goto repeat;
242 } else {
243 return (ENXIO);
244 }
245 }
246 st->src = (void *)(st->ptr + 1);
247 st->dst = st->src + strlen(st->src) + 1;
248 st->ptr = st->ptr + st->ptr[0];
249 st->nparsed++;
250
251 if ((st->ptr < st->buf) ||
252 (st->ptr > st->dummy_zero)) {
253 /* invalid entry */
254 return (EINVAL);
255 }
256 return (0);
257}
258
259static int
260ugen20_init_backend(struct libusb20_backend *pbe)
261{
262 struct ugen20_urd_state state;
263 struct libusb20_device *pdev;
264
265 memset(&state, 0, sizeof(state));
266
267 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
268 if (state.f < 0)
269 return (LIBUSB20_ERROR_OTHER);
270
271 while (ugen20_readdir(&state) == 0) {
272
273 if ((state.src[0] != 'u') ||
274 (state.src[1] != 'g') ||
275 (state.src[2] != 'e') ||
276 (state.src[3] != 'n')) {
277 continue;
278 }
279 pdev = libusb20_dev_alloc();
280 if (pdev == NULL) {
281 continue;
282 }
283 if (ugen20_enumerate(pdev, state.src + 4)) {
284 libusb20_dev_free(pdev);
285 continue;
286 }
287 /* put the device on the backend list */
288 libusb20_be_enqueue_device(pbe, pdev);
289 }
290 close(state.f);
291 return (0); /* success */
292}
293
294static void
295ugen20_tr_release(struct libusb20_device *pdev)
296{
297 struct usb_fs_uninit fs_uninit;
298
299 if (pdev->nTransfer == 0) {
300 return;
301 }
302 /* release all pending USB transfers */
303 if (pdev->privBeData != NULL) {
304 memset(&fs_uninit, 0, sizeof(fs_uninit));
305 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
306 /* ignore any errors of this kind */
307 }
308 }
309 return;
310}
311
312static int
313ugen20_tr_renew(struct libusb20_device *pdev)
314{
315 struct usb_fs_init fs_init;
316 struct usb_fs_endpoint *pfse;
317 int error;
318 uint32_t size;
319 uint16_t nMaxTransfer;
320
321 nMaxTransfer = pdev->nTransfer;
322 error = 0;
323
324 if (nMaxTransfer == 0) {
325 goto done;
326 }
327 size = nMaxTransfer * sizeof(*pfse);
328
329 if (pdev->privBeData == NULL) {
330 pfse = malloc(size);
331 if (pfse == NULL) {
332 error = LIBUSB20_ERROR_NO_MEM;
333 goto done;
334 }
335 pdev->privBeData = pfse;
336 }
337 /* reset endpoint data */
338 memset(pdev->privBeData, 0, size);
339
340 memset(&fs_init, 0, sizeof(fs_init));
341
342 fs_init.pEndpoints = pdev->privBeData;
343 fs_init.ep_index_max = nMaxTransfer;
344
345 if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) {
346 error = LIBUSB20_ERROR_OTHER;
347 goto done;
348 }
349done:
350 return (error);
351}
352
353static int
354ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
355{
356 uint32_t plugtime;
357 char buf[64];
358 int f;
359 int g;
360 int error;
361
362 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
363 pdev->bus_number, pdev->device_address);
364
365 /*
366 * We need two file handles, one for the control endpoint and one
367 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
368 * kernel locking.
369 */
370 g = open(buf, O_RDWR);
371 if (g < 0) {
372 return (LIBUSB20_ERROR_NO_DEVICE);
373 }
374 f = open(buf, O_RDWR);
375 if (f < 0) {
376 close(g);
377 return (LIBUSB20_ERROR_NO_DEVICE);
378 }
379 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
380 error = LIBUSB20_ERROR_OTHER;
381 goto done;
382 }
383 /* check that the correct device is still plugged */
384 if (pdev->session_data.plugtime != plugtime) {
385 error = LIBUSB20_ERROR_NO_DEVICE;
386 goto done;
387 }
388 /* need to set this before "tr_renew()" */
389 pdev->file = f;
390 pdev->file_ctrl = g;
391
392 /* renew all USB transfers */
393 error = ugen20_tr_renew(pdev);
394 if (error) {
395 goto done;
396 }
397 /* set methods */
398 pdev->methods = &libusb20_ugen20_device_methods;
399
400done:
401 if (error) {
402 if (pdev->privBeData) {
403 /* cleanup after "tr_renew()" */
404 free(pdev->privBeData);
405 pdev->privBeData = NULL;
406 }
407 pdev->file = -1;
408 pdev->file_ctrl = -1;
409 close(f);
410 close(g);
411 }
412 return (error);
413}
414
415static int
416ugen20_close_device(struct libusb20_device *pdev)
417{
418 struct usb_fs_uninit fs_uninit;
419
420 if (pdev->privBeData) {
421 memset(&fs_uninit, 0, sizeof(fs_uninit));
422 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
423 /* ignore this error */
424 }
425 free(pdev->privBeData);
426 }
427 pdev->nTransfer = 0;
428 pdev->privBeData = NULL;
429 close(pdev->file);
430 close(pdev->file_ctrl);
431 pdev->file = -1;
432 pdev->file_ctrl = -1;
433 return (0); /* success */
434}
435
436static void
437ugen20_exit_backend(struct libusb20_backend *pbe)
438{
439 return; /* nothing to do */
440}
441
442static int
443ugen20_get_config_desc_full(struct libusb20_device *pdev,
444 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
445{
446 struct usb_gen_descriptor gen_desc;
447 struct usb_config_descriptor cdesc;
448 uint8_t *ptr;
449 uint16_t len;
450 int error;
451
452 /* make sure memory is initialised */
453 memset(&cdesc, 0, sizeof(cdesc));
454 memset(&gen_desc, 0, sizeof(gen_desc));
455
456 gen_desc.ugd_data = &cdesc;
457 gen_desc.ugd_maxlen = sizeof(cdesc);
458 gen_desc.ugd_config_index = cfg_index;
459
460 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
461 if (error) {
462 return (LIBUSB20_ERROR_OTHER);
463 }
464 len = UGETW(cdesc.wTotalLength);
465 if (len < sizeof(cdesc)) {
466 /* corrupt descriptor */
467 return (LIBUSB20_ERROR_OTHER);
468 }
469 ptr = malloc(len);
470 if (!ptr) {
471 return (LIBUSB20_ERROR_NO_MEM);
472 }
473
474 /* make sure memory is initialised */
475 memset(ptr, 0, len);
476
477 gen_desc.ugd_data = ptr;
478 gen_desc.ugd_maxlen = len;
479
480 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
481 if (error) {
482 free(ptr);
483 return (LIBUSB20_ERROR_OTHER);
484 }
485 /* make sure that the device doesn't fool us */
486 memcpy(ptr, &cdesc, sizeof(cdesc));
487
488 *ppbuf = ptr;
489 *plen = len;
490
491 return (0); /* success */
492}
493
494static int
495ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
496{
497 int temp;
498
499 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) {
500 return (LIBUSB20_ERROR_OTHER);
501 }
502 *pindex = temp;
503
504 return (0);
505}
506
507static int
508ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
509{
510 int temp = cfg_index;
511
512 /* release all active USB transfers */
513 ugen20_tr_release(pdev);
514
515 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) {
516 return (LIBUSB20_ERROR_OTHER);
517 }
518 return (ugen20_tr_renew(pdev));
519}
520
521static int
522ugen20_set_alt_index(struct libusb20_device *pdev,
523 uint8_t iface_index, uint8_t alt_index)
524{
525 struct usb_alt_interface alt_iface;
526
527 memset(&alt_iface, 0, sizeof(alt_iface));
528
529 alt_iface.uai_interface_index = iface_index;
530 alt_iface.uai_alt_index = alt_index;
531
532 /* release all active USB transfers */
533 ugen20_tr_release(pdev);
534
535 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) {
536 return (LIBUSB20_ERROR_OTHER);
537 }
538 return (ugen20_tr_renew(pdev));
539}
540
541static int
542ugen20_reset_device(struct libusb20_device *pdev)
543{
544 int temp = 0;
545
546 /* release all active USB transfers */
547 ugen20_tr_release(pdev);
548
549 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) {
550 return (LIBUSB20_ERROR_OTHER);
551 }
552 return (ugen20_tr_renew(pdev));
553}
554
555static int
556ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
557{
558 int temp;
559
560 switch (power_mode) {
561 case LIBUSB20_POWER_OFF:
562 temp = USB_POWER_MODE_OFF;
563 break;
564 case LIBUSB20_POWER_ON:
565 temp = USB_POWER_MODE_ON;
566 break;
567 case LIBUSB20_POWER_SAVE:
568 temp = USB_POWER_MODE_SAVE;
569 break;
570 case LIBUSB20_POWER_SUSPEND:
571 temp = USB_POWER_MODE_SUSPEND;
572 break;
573 case LIBUSB20_POWER_RESUME:
574 temp = USB_POWER_MODE_RESUME;
575 break;
576 default:
577 return (LIBUSB20_ERROR_INVALID_PARAM);
578 }
579 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) {
580 return (LIBUSB20_ERROR_OTHER);
581 }
582 return (0);
583}
584
585static int
586ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
587{
588 int temp;
589
590 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) {
591 return (LIBUSB20_ERROR_OTHER);
592 }
593 switch (temp) {
594 case USB_POWER_MODE_OFF:
595 temp = LIBUSB20_POWER_OFF;
596 break;
597 case USB_POWER_MODE_ON:
598 temp = LIBUSB20_POWER_ON;
599 break;
600 case USB_POWER_MODE_SAVE:
601 temp = LIBUSB20_POWER_SAVE;
602 break;
603 case USB_POWER_MODE_SUSPEND:
604 temp = LIBUSB20_POWER_SUSPEND;
605 break;
606 case USB_POWER_MODE_RESUME:
607 temp = LIBUSB20_POWER_RESUME;
608 break;
609 default:
610 temp = LIBUSB20_POWER_ON;
611 break;
612 }
613 *power_mode = temp;
614 return (0); /* success */
615}
616
617static int
618ugen20_kernel_driver_active(struct libusb20_device *pdev,
619 uint8_t iface_index)
620{
621 int temp = iface_index;
622
623 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) {
624 return (LIBUSB20_ERROR_OTHER);
625 }
626 return (0); /* kernel driver is active */
627}
628
629static int
630ugen20_detach_kernel_driver(struct libusb20_device *pdev,
631 uint8_t iface_index)
632{
633 int temp = iface_index;
634
635 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) {
636 return (LIBUSB20_ERROR_OTHER);
637 }
638 return (0); /* kernel driver is active */
639}
640
641static int
642ugen20_do_request_sync(struct libusb20_device *pdev,
643 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
644 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
645{
646 struct usb_ctl_request req;
647
648 memset(&req, 0, sizeof(req));
649
650 req.ucr_data = data;
651 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
652 req.ucr_flags |= USB_SHORT_XFER_OK;
653 }
654 if (libusb20_me_encode(&req.ucr_request,
655 sizeof(req.ucr_request), setup)) {
656 /* ignore */
657 }
658 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) {
659 return (LIBUSB20_ERROR_OTHER);
660 }
661 if (pactlen) {
662 /* get actual length */
663 *pactlen = req.ucr_actlen;
664 }
665 return (0); /* kernel driver is active */
666}
667
668static int
669ugen20_process(struct libusb20_device *pdev)
670{
671 struct usb_fs_complete temp;
672 struct usb_fs_endpoint *fsep;
673 struct libusb20_transfer *xfer;
674
675 while (1) {
676
677 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) {
678 if (errno == EBUSY) {
679 break;
680 } else {
681 /* device detached */
682 return (LIBUSB20_ERROR_OTHER);
683 }
684 }
685 fsep = pdev->privBeData;
686 xfer = pdev->pTransfer;
687 fsep += temp.ep_index;
688 xfer += temp.ep_index;
689
690 /* update transfer status */
691
692 if (fsep->status == 0) {
693 xfer->aFrames = fsep->aFrames;
694 xfer->timeComplete = fsep->isoc_time_complete;
695 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
696 } else if (fsep->status == USB_ERR_CANCELLED) {
697 xfer->aFrames = 0;
698 xfer->timeComplete = 0;
699 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
700 } else if (fsep->status == USB_ERR_STALLED) {
701 xfer->aFrames = 0;
702 xfer->timeComplete = 0;
703 xfer->status = LIBUSB20_TRANSFER_STALL;
704 } else if (fsep->status == USB_ERR_TIMEOUT) {
705 xfer->aFrames = 0;
706 xfer->timeComplete = 0;
707 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
708 } else {
709 xfer->aFrames = 0;
710 xfer->timeComplete = 0;
711 xfer->status = LIBUSB20_TRANSFER_ERROR;
712 }
713 libusb20_tr_callback_wrapper(xfer);
714 }
715 return (0); /* done */
716}
717
718static int
719ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
720 uint32_t MaxFrameCount, uint8_t ep_no)
721{
722 struct usb_fs_open temp;
723 struct usb_fs_endpoint *fsep;
724
725 memset(&temp, 0, sizeof(temp));
726
727 fsep = xfer->pdev->privBeData;
728 fsep += xfer->trIndex;
729
730 temp.max_bufsize = MaxBufSize;
731 temp.max_frames = MaxFrameCount;
732 temp.ep_index = xfer->trIndex;
733 temp.ep_no = ep_no;
734
735 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) {
736 return (LIBUSB20_ERROR_INVALID_PARAM);
737 }
738 /* maximums might have changed - update */
739 xfer->maxFrames = temp.max_frames;
740
741 /* "max_bufsize" should be multiple of "max_packet_length" */
742 xfer->maxTotalLength = temp.max_bufsize;
743 xfer->maxPacketLen = temp.max_packet_length;
744
745 /* setup buffer and length lists */
746 fsep->ppBuffer = xfer->ppBuffer;/* zero copy */
747 fsep->pLength = xfer->pLength; /* zero copy */
748
749 return (0); /* success */
750}
751
752static int
753ugen20_tr_close(struct libusb20_transfer *xfer)
754{
755 struct usb_fs_close temp;
756
757 memset(&temp, 0, sizeof(temp));
758
759 temp.ep_index = xfer->trIndex;
760
761 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) {
762 return (LIBUSB20_ERROR_INVALID_PARAM);
763 }
764 return (0); /* success */
765}
766
767static int
768ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
769{
770 struct usb_fs_clear_stall_sync temp;
771
772 memset(&temp, 0, sizeof(temp));
773
774 /* if the transfer is active, an error will be returned */
775
776 temp.ep_index = xfer->trIndex;
777
778 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) {
779 return (LIBUSB20_ERROR_INVALID_PARAM);
780 }
781 return (0); /* success */
782}
783
784static void
785ugen20_tr_submit(struct libusb20_transfer *xfer)
786{
787 struct usb_fs_start temp;
788 struct usb_fs_endpoint *fsep;
789
790 memset(&temp, 0, sizeof(temp));
791
792 fsep = xfer->pdev->privBeData;
793 fsep += xfer->trIndex;
794
795 fsep->nFrames = xfer->nFrames;
796 fsep->flags = 0;
797 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
798 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
799 }
800 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
801 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
802 }
803 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
804 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
805 }
806 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
807 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
808 }
809 /* NOTE: The "fsep->timeout" variable is 16-bit. */
810 if (xfer->timeout > 65535)
811 fsep->timeout = 65535;
812 else
813 fsep->timeout = xfer->timeout;
814
815 temp.ep_index = xfer->trIndex;
816
817 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) {
818 /* ignore any errors - should never happen */
819 }
820 return; /* success */
821}
822
823static void
824ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
825{
826 struct usb_fs_stop temp;
827
828 memset(&temp, 0, sizeof(temp));
829
830 temp.ep_index = xfer->trIndex;
831
832 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) {
833 /* ignore any errors - should never happen */
834 }
835 return;
836}
837
838static int
839ugen20_be_ioctl(uint32_t cmd, void *data)
840{
841 int f;
842 int error;
843
844 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
845 if (f < 0)
846 return (LIBUSB20_ERROR_OTHER);
847 error = ioctl(f, cmd, data);
848 if (error == -1) {
849 if (errno == EPERM) {
850 error = LIBUSB20_ERROR_ACCESS;
851 } else {
852 error = LIBUSB20_ERROR_OTHER;
853 }
854 }
855 close(f);
856 return (error);
857}
858
859static int
860ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
861 uint8_t iface_index, char *buf, uint8_t len)
862{
863 struct usb_gen_descriptor ugd;
864
865 memset(&ugd, 0, sizeof(ugd));
866
867 ugd.ugd_data = buf;
868 ugd.ugd_maxlen = len;
869 ugd.ugd_iface_index = iface_index;
870
871 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) {
872 return (LIBUSB20_ERROR_INVALID_PARAM);
873 }
874 return (0);
875}
876
877static int
878ugen20_dev_get_info(struct libusb20_device *pdev,
879 struct usb_device_info *pinfo)
880{
881 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) {
882 return (LIBUSB20_ERROR_INVALID_PARAM);
883 }
884 return (0);
885}
886
887static int
888ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
889 uint16_t quirk_index, struct libusb20_quirk *pq)
890{
891 struct usb_gen_quirk q;
892 int error;
893
894 memset(&q, 0, sizeof(q));
895
896 q.index = quirk_index;
897
898 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
899
900 if (error) {
901 if (errno == EINVAL) {
902 return (LIBUSB20_ERROR_NOT_FOUND);
903 }
904 } else {
905 pq->vid = q.vid;
906 pq->pid = q.pid;
907 pq->bcdDeviceLow = q.bcdDeviceLow;
908 pq->bcdDeviceHigh = q.bcdDeviceHigh;
909 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
910 }
911 return (error);
912}
913
914static int
915ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
916 struct libusb20_quirk *pq)
917{
918 struct usb_gen_quirk q;
919 int error;
920
921 memset(&q, 0, sizeof(q));
922
923 q.index = quirk_index;
924
925 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
926
927 if (error) {
928 if (errno == EINVAL) {
929 return (LIBUSB20_ERROR_NOT_FOUND);
930 }
931 } else {
932 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
933 }
934 return (error);
935}
936
937static int
938ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
939 struct libusb20_quirk *pq)
940{
941 struct usb_gen_quirk q;
942 int error;
943
944 memset(&q, 0, sizeof(q));
945
946 q.vid = pq->vid;
947 q.pid = pq->pid;
948 q.bcdDeviceLow = pq->bcdDeviceLow;
949 q.bcdDeviceHigh = pq->bcdDeviceHigh;
950 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
951
952 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
953 if (error) {
954 if (errno == ENOMEM) {
955 return (LIBUSB20_ERROR_NO_MEM);
956 }
957 }
958 return (error);
959}
960
961static int
962ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
963 struct libusb20_quirk *pq)
964{
965 struct usb_gen_quirk q;
966 int error;
967
968 memset(&q, 0, sizeof(q));
969
970 q.vid = pq->vid;
971 q.pid = pq->pid;
972 q.bcdDeviceLow = pq->bcdDeviceLow;
973 q.bcdDeviceHigh = pq->bcdDeviceHigh;
974 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
975
976 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
977 if (error) {
978 if (errno == EINVAL) {
979 return (LIBUSB20_ERROR_NOT_FOUND);
980 }
981 }
982 return (error);
983}
984
985static int
986ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
987{
988 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp));
989}
990
991static int
992ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
993{
994 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));
995}
2/*-
3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/queue.h>
28#include <sys/types.h>
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <string.h>
34#include <poll.h>
35#include <fcntl.h>
36#include <errno.h>
37
38#include "libusb20.h"
39#include "libusb20_desc.h"
40#include "libusb20_int.h"
41
42#include <dev/usb/usb.h>
43#include <dev/usb/usbdi.h>
44#include <dev/usb/usb_ioctl.h>
45
46static libusb20_init_backend_t ugen20_init_backend;
47static libusb20_open_device_t ugen20_open_device;
48static libusb20_close_device_t ugen20_close_device;
49static libusb20_get_backend_name_t ugen20_get_backend_name;
50static libusb20_exit_backend_t ugen20_exit_backend;
51static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
52static libusb20_dev_get_info_t ugen20_dev_get_info;
53static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
54static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
55static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
56static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
57static libusb20_root_set_template_t ugen20_root_set_template;
58static libusb20_root_get_template_t ugen20_root_get_template;
59
60const struct libusb20_backend_methods libusb20_ugen20_backend = {
61 LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
62};
63
64/* USB device specific */
65static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
66static libusb20_get_config_index_t ugen20_get_config_index;
67static libusb20_set_config_index_t ugen20_set_config_index;
68static libusb20_set_alt_index_t ugen20_set_alt_index;
69static libusb20_reset_device_t ugen20_reset_device;
70static libusb20_set_power_mode_t ugen20_set_power_mode;
71static libusb20_get_power_mode_t ugen20_get_power_mode;
72static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
73static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
74static libusb20_do_request_sync_t ugen20_do_request_sync;
75static libusb20_process_t ugen20_process;
76
77/* USB transfer specific */
78static libusb20_tr_open_t ugen20_tr_open;
79static libusb20_tr_close_t ugen20_tr_close;
80static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
81static libusb20_tr_submit_t ugen20_tr_submit;
82static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
83
84static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
85 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
86};
87
88static const char *
89ugen20_get_backend_name(void)
90{
91 return ("FreeBSD UGEN 2.0");
92}
93
94static uint32_t
95ugen20_path_convert_one(const char **pp)
96{
97 const char *ptr;
98 uint32_t temp = 0;
99
100 ptr = *pp;
101
102 while ((*ptr >= '0') && (*ptr <= '9')) {
103 temp *= 10;
104 temp += (*ptr - '0');
105 if (temp >= 1000000) {
106 /* catch overflow early */
107 return (0 - 1);
108 }
109 ptr++;
110 }
111
112 if (*ptr == '.') {
113 /* skip dot */
114 ptr++;
115 }
116 *pp = ptr;
117
118 return (temp);
119}
120
121static int
122ugen20_enumerate(struct libusb20_device *pdev, const char *id)
123{
124 const char *tmp = id;
125 struct usb_device_descriptor ddesc;
126 struct usb_device_info devinfo;
127 uint32_t plugtime;
128 char buf[64];
129 int f;
130 int error;
131
132 pdev->bus_number = ugen20_path_convert_one(&tmp);
133 pdev->device_address = ugen20_path_convert_one(&tmp);
134
135 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
136 pdev->bus_number, pdev->device_address);
137
138 f = open(buf, O_RDWR);
139 if (f < 0) {
140 return (LIBUSB20_ERROR_OTHER);
141 }
142 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
143 error = LIBUSB20_ERROR_OTHER;
144 goto done;
145 }
146 /* store when the device was plugged */
147 pdev->session_data.plugtime = plugtime;
148
149 if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) {
150 error = LIBUSB20_ERROR_OTHER;
151 goto done;
152 }
153 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
154
155 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
156
157 if (pdev->ddesc.bNumConfigurations == 0) {
158 error = LIBUSB20_ERROR_OTHER;
159 goto done;
160 } else if (pdev->ddesc.bNumConfigurations >= 8) {
161 error = LIBUSB20_ERROR_OTHER;
162 goto done;
163 }
164 if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) {
165 error = LIBUSB20_ERROR_OTHER;
166 goto done;
167 }
168 switch (devinfo.udi_mode) {
169 case USB_MODE_DEVICE:
170 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
171 break;
172 default:
173 pdev->usb_mode = LIBUSB20_MODE_HOST;
174 break;
175 }
176
177 switch (devinfo.udi_speed) {
178 case USB_SPEED_LOW:
179 pdev->usb_speed = LIBUSB20_SPEED_LOW;
180 break;
181 case USB_SPEED_FULL:
182 pdev->usb_speed = LIBUSB20_SPEED_FULL;
183 break;
184 case USB_SPEED_HIGH:
185 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
186 break;
187 case USB_SPEED_VARIABLE:
188 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
189 break;
190 case USB_SPEED_SUPER:
191 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
192 break;
193 default:
194 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
195 break;
196 }
197
198 /* generate a nice description for printout */
199
200 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
201 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
202 pdev->device_address, devinfo.udi_product,
203 devinfo.udi_vendor, pdev->bus_number);
204
205 error = 0;
206done:
207 close(f);
208 return (error);
209}
210
211struct ugen20_urd_state {
212 struct usb_read_dir urd;
213 uint32_t nparsed;
214 int f;
215 uint8_t *ptr;
216 const char *src;
217 const char *dst;
218 uint8_t buf[256];
219 uint8_t dummy_zero[1];
220};
221
222static int
223ugen20_readdir(struct ugen20_urd_state *st)
224{
225 ; /* style fix */
226repeat:
227 if (st->ptr == NULL) {
228 st->urd.urd_startentry += st->nparsed;
229 st->urd.urd_data = st->buf;
230 st->urd.urd_maxlen = sizeof(st->buf);
231 st->nparsed = 0;
232
233 if (ioctl(st->f, USB_READ_DIR, &st->urd)) {
234 return (EINVAL);
235 }
236 st->ptr = st->buf;
237 }
238 if (st->ptr[0] == 0) {
239 if (st->nparsed) {
240 st->ptr = NULL;
241 goto repeat;
242 } else {
243 return (ENXIO);
244 }
245 }
246 st->src = (void *)(st->ptr + 1);
247 st->dst = st->src + strlen(st->src) + 1;
248 st->ptr = st->ptr + st->ptr[0];
249 st->nparsed++;
250
251 if ((st->ptr < st->buf) ||
252 (st->ptr > st->dummy_zero)) {
253 /* invalid entry */
254 return (EINVAL);
255 }
256 return (0);
257}
258
259static int
260ugen20_init_backend(struct libusb20_backend *pbe)
261{
262 struct ugen20_urd_state state;
263 struct libusb20_device *pdev;
264
265 memset(&state, 0, sizeof(state));
266
267 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
268 if (state.f < 0)
269 return (LIBUSB20_ERROR_OTHER);
270
271 while (ugen20_readdir(&state) == 0) {
272
273 if ((state.src[0] != 'u') ||
274 (state.src[1] != 'g') ||
275 (state.src[2] != 'e') ||
276 (state.src[3] != 'n')) {
277 continue;
278 }
279 pdev = libusb20_dev_alloc();
280 if (pdev == NULL) {
281 continue;
282 }
283 if (ugen20_enumerate(pdev, state.src + 4)) {
284 libusb20_dev_free(pdev);
285 continue;
286 }
287 /* put the device on the backend list */
288 libusb20_be_enqueue_device(pbe, pdev);
289 }
290 close(state.f);
291 return (0); /* success */
292}
293
294static void
295ugen20_tr_release(struct libusb20_device *pdev)
296{
297 struct usb_fs_uninit fs_uninit;
298
299 if (pdev->nTransfer == 0) {
300 return;
301 }
302 /* release all pending USB transfers */
303 if (pdev->privBeData != NULL) {
304 memset(&fs_uninit, 0, sizeof(fs_uninit));
305 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
306 /* ignore any errors of this kind */
307 }
308 }
309 return;
310}
311
312static int
313ugen20_tr_renew(struct libusb20_device *pdev)
314{
315 struct usb_fs_init fs_init;
316 struct usb_fs_endpoint *pfse;
317 int error;
318 uint32_t size;
319 uint16_t nMaxTransfer;
320
321 nMaxTransfer = pdev->nTransfer;
322 error = 0;
323
324 if (nMaxTransfer == 0) {
325 goto done;
326 }
327 size = nMaxTransfer * sizeof(*pfse);
328
329 if (pdev->privBeData == NULL) {
330 pfse = malloc(size);
331 if (pfse == NULL) {
332 error = LIBUSB20_ERROR_NO_MEM;
333 goto done;
334 }
335 pdev->privBeData = pfse;
336 }
337 /* reset endpoint data */
338 memset(pdev->privBeData, 0, size);
339
340 memset(&fs_init, 0, sizeof(fs_init));
341
342 fs_init.pEndpoints = pdev->privBeData;
343 fs_init.ep_index_max = nMaxTransfer;
344
345 if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) {
346 error = LIBUSB20_ERROR_OTHER;
347 goto done;
348 }
349done:
350 return (error);
351}
352
353static int
354ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
355{
356 uint32_t plugtime;
357 char buf[64];
358 int f;
359 int g;
360 int error;
361
362 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
363 pdev->bus_number, pdev->device_address);
364
365 /*
366 * We need two file handles, one for the control endpoint and one
367 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
368 * kernel locking.
369 */
370 g = open(buf, O_RDWR);
371 if (g < 0) {
372 return (LIBUSB20_ERROR_NO_DEVICE);
373 }
374 f = open(buf, O_RDWR);
375 if (f < 0) {
376 close(g);
377 return (LIBUSB20_ERROR_NO_DEVICE);
378 }
379 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
380 error = LIBUSB20_ERROR_OTHER;
381 goto done;
382 }
383 /* check that the correct device is still plugged */
384 if (pdev->session_data.plugtime != plugtime) {
385 error = LIBUSB20_ERROR_NO_DEVICE;
386 goto done;
387 }
388 /* need to set this before "tr_renew()" */
389 pdev->file = f;
390 pdev->file_ctrl = g;
391
392 /* renew all USB transfers */
393 error = ugen20_tr_renew(pdev);
394 if (error) {
395 goto done;
396 }
397 /* set methods */
398 pdev->methods = &libusb20_ugen20_device_methods;
399
400done:
401 if (error) {
402 if (pdev->privBeData) {
403 /* cleanup after "tr_renew()" */
404 free(pdev->privBeData);
405 pdev->privBeData = NULL;
406 }
407 pdev->file = -1;
408 pdev->file_ctrl = -1;
409 close(f);
410 close(g);
411 }
412 return (error);
413}
414
415static int
416ugen20_close_device(struct libusb20_device *pdev)
417{
418 struct usb_fs_uninit fs_uninit;
419
420 if (pdev->privBeData) {
421 memset(&fs_uninit, 0, sizeof(fs_uninit));
422 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
423 /* ignore this error */
424 }
425 free(pdev->privBeData);
426 }
427 pdev->nTransfer = 0;
428 pdev->privBeData = NULL;
429 close(pdev->file);
430 close(pdev->file_ctrl);
431 pdev->file = -1;
432 pdev->file_ctrl = -1;
433 return (0); /* success */
434}
435
436static void
437ugen20_exit_backend(struct libusb20_backend *pbe)
438{
439 return; /* nothing to do */
440}
441
442static int
443ugen20_get_config_desc_full(struct libusb20_device *pdev,
444 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
445{
446 struct usb_gen_descriptor gen_desc;
447 struct usb_config_descriptor cdesc;
448 uint8_t *ptr;
449 uint16_t len;
450 int error;
451
452 /* make sure memory is initialised */
453 memset(&cdesc, 0, sizeof(cdesc));
454 memset(&gen_desc, 0, sizeof(gen_desc));
455
456 gen_desc.ugd_data = &cdesc;
457 gen_desc.ugd_maxlen = sizeof(cdesc);
458 gen_desc.ugd_config_index = cfg_index;
459
460 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
461 if (error) {
462 return (LIBUSB20_ERROR_OTHER);
463 }
464 len = UGETW(cdesc.wTotalLength);
465 if (len < sizeof(cdesc)) {
466 /* corrupt descriptor */
467 return (LIBUSB20_ERROR_OTHER);
468 }
469 ptr = malloc(len);
470 if (!ptr) {
471 return (LIBUSB20_ERROR_NO_MEM);
472 }
473
474 /* make sure memory is initialised */
475 memset(ptr, 0, len);
476
477 gen_desc.ugd_data = ptr;
478 gen_desc.ugd_maxlen = len;
479
480 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
481 if (error) {
482 free(ptr);
483 return (LIBUSB20_ERROR_OTHER);
484 }
485 /* make sure that the device doesn't fool us */
486 memcpy(ptr, &cdesc, sizeof(cdesc));
487
488 *ppbuf = ptr;
489 *plen = len;
490
491 return (0); /* success */
492}
493
494static int
495ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
496{
497 int temp;
498
499 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) {
500 return (LIBUSB20_ERROR_OTHER);
501 }
502 *pindex = temp;
503
504 return (0);
505}
506
507static int
508ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
509{
510 int temp = cfg_index;
511
512 /* release all active USB transfers */
513 ugen20_tr_release(pdev);
514
515 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) {
516 return (LIBUSB20_ERROR_OTHER);
517 }
518 return (ugen20_tr_renew(pdev));
519}
520
521static int
522ugen20_set_alt_index(struct libusb20_device *pdev,
523 uint8_t iface_index, uint8_t alt_index)
524{
525 struct usb_alt_interface alt_iface;
526
527 memset(&alt_iface, 0, sizeof(alt_iface));
528
529 alt_iface.uai_interface_index = iface_index;
530 alt_iface.uai_alt_index = alt_index;
531
532 /* release all active USB transfers */
533 ugen20_tr_release(pdev);
534
535 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) {
536 return (LIBUSB20_ERROR_OTHER);
537 }
538 return (ugen20_tr_renew(pdev));
539}
540
541static int
542ugen20_reset_device(struct libusb20_device *pdev)
543{
544 int temp = 0;
545
546 /* release all active USB transfers */
547 ugen20_tr_release(pdev);
548
549 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) {
550 return (LIBUSB20_ERROR_OTHER);
551 }
552 return (ugen20_tr_renew(pdev));
553}
554
555static int
556ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
557{
558 int temp;
559
560 switch (power_mode) {
561 case LIBUSB20_POWER_OFF:
562 temp = USB_POWER_MODE_OFF;
563 break;
564 case LIBUSB20_POWER_ON:
565 temp = USB_POWER_MODE_ON;
566 break;
567 case LIBUSB20_POWER_SAVE:
568 temp = USB_POWER_MODE_SAVE;
569 break;
570 case LIBUSB20_POWER_SUSPEND:
571 temp = USB_POWER_MODE_SUSPEND;
572 break;
573 case LIBUSB20_POWER_RESUME:
574 temp = USB_POWER_MODE_RESUME;
575 break;
576 default:
577 return (LIBUSB20_ERROR_INVALID_PARAM);
578 }
579 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) {
580 return (LIBUSB20_ERROR_OTHER);
581 }
582 return (0);
583}
584
585static int
586ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
587{
588 int temp;
589
590 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) {
591 return (LIBUSB20_ERROR_OTHER);
592 }
593 switch (temp) {
594 case USB_POWER_MODE_OFF:
595 temp = LIBUSB20_POWER_OFF;
596 break;
597 case USB_POWER_MODE_ON:
598 temp = LIBUSB20_POWER_ON;
599 break;
600 case USB_POWER_MODE_SAVE:
601 temp = LIBUSB20_POWER_SAVE;
602 break;
603 case USB_POWER_MODE_SUSPEND:
604 temp = LIBUSB20_POWER_SUSPEND;
605 break;
606 case USB_POWER_MODE_RESUME:
607 temp = LIBUSB20_POWER_RESUME;
608 break;
609 default:
610 temp = LIBUSB20_POWER_ON;
611 break;
612 }
613 *power_mode = temp;
614 return (0); /* success */
615}
616
617static int
618ugen20_kernel_driver_active(struct libusb20_device *pdev,
619 uint8_t iface_index)
620{
621 int temp = iface_index;
622
623 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) {
624 return (LIBUSB20_ERROR_OTHER);
625 }
626 return (0); /* kernel driver is active */
627}
628
629static int
630ugen20_detach_kernel_driver(struct libusb20_device *pdev,
631 uint8_t iface_index)
632{
633 int temp = iface_index;
634
635 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) {
636 return (LIBUSB20_ERROR_OTHER);
637 }
638 return (0); /* kernel driver is active */
639}
640
641static int
642ugen20_do_request_sync(struct libusb20_device *pdev,
643 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
644 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
645{
646 struct usb_ctl_request req;
647
648 memset(&req, 0, sizeof(req));
649
650 req.ucr_data = data;
651 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
652 req.ucr_flags |= USB_SHORT_XFER_OK;
653 }
654 if (libusb20_me_encode(&req.ucr_request,
655 sizeof(req.ucr_request), setup)) {
656 /* ignore */
657 }
658 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) {
659 return (LIBUSB20_ERROR_OTHER);
660 }
661 if (pactlen) {
662 /* get actual length */
663 *pactlen = req.ucr_actlen;
664 }
665 return (0); /* kernel driver is active */
666}
667
668static int
669ugen20_process(struct libusb20_device *pdev)
670{
671 struct usb_fs_complete temp;
672 struct usb_fs_endpoint *fsep;
673 struct libusb20_transfer *xfer;
674
675 while (1) {
676
677 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) {
678 if (errno == EBUSY) {
679 break;
680 } else {
681 /* device detached */
682 return (LIBUSB20_ERROR_OTHER);
683 }
684 }
685 fsep = pdev->privBeData;
686 xfer = pdev->pTransfer;
687 fsep += temp.ep_index;
688 xfer += temp.ep_index;
689
690 /* update transfer status */
691
692 if (fsep->status == 0) {
693 xfer->aFrames = fsep->aFrames;
694 xfer->timeComplete = fsep->isoc_time_complete;
695 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
696 } else if (fsep->status == USB_ERR_CANCELLED) {
697 xfer->aFrames = 0;
698 xfer->timeComplete = 0;
699 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
700 } else if (fsep->status == USB_ERR_STALLED) {
701 xfer->aFrames = 0;
702 xfer->timeComplete = 0;
703 xfer->status = LIBUSB20_TRANSFER_STALL;
704 } else if (fsep->status == USB_ERR_TIMEOUT) {
705 xfer->aFrames = 0;
706 xfer->timeComplete = 0;
707 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
708 } else {
709 xfer->aFrames = 0;
710 xfer->timeComplete = 0;
711 xfer->status = LIBUSB20_TRANSFER_ERROR;
712 }
713 libusb20_tr_callback_wrapper(xfer);
714 }
715 return (0); /* done */
716}
717
718static int
719ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
720 uint32_t MaxFrameCount, uint8_t ep_no)
721{
722 struct usb_fs_open temp;
723 struct usb_fs_endpoint *fsep;
724
725 memset(&temp, 0, sizeof(temp));
726
727 fsep = xfer->pdev->privBeData;
728 fsep += xfer->trIndex;
729
730 temp.max_bufsize = MaxBufSize;
731 temp.max_frames = MaxFrameCount;
732 temp.ep_index = xfer->trIndex;
733 temp.ep_no = ep_no;
734
735 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) {
736 return (LIBUSB20_ERROR_INVALID_PARAM);
737 }
738 /* maximums might have changed - update */
739 xfer->maxFrames = temp.max_frames;
740
741 /* "max_bufsize" should be multiple of "max_packet_length" */
742 xfer->maxTotalLength = temp.max_bufsize;
743 xfer->maxPacketLen = temp.max_packet_length;
744
745 /* setup buffer and length lists */
746 fsep->ppBuffer = xfer->ppBuffer;/* zero copy */
747 fsep->pLength = xfer->pLength; /* zero copy */
748
749 return (0); /* success */
750}
751
752static int
753ugen20_tr_close(struct libusb20_transfer *xfer)
754{
755 struct usb_fs_close temp;
756
757 memset(&temp, 0, sizeof(temp));
758
759 temp.ep_index = xfer->trIndex;
760
761 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) {
762 return (LIBUSB20_ERROR_INVALID_PARAM);
763 }
764 return (0); /* success */
765}
766
767static int
768ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
769{
770 struct usb_fs_clear_stall_sync temp;
771
772 memset(&temp, 0, sizeof(temp));
773
774 /* if the transfer is active, an error will be returned */
775
776 temp.ep_index = xfer->trIndex;
777
778 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) {
779 return (LIBUSB20_ERROR_INVALID_PARAM);
780 }
781 return (0); /* success */
782}
783
784static void
785ugen20_tr_submit(struct libusb20_transfer *xfer)
786{
787 struct usb_fs_start temp;
788 struct usb_fs_endpoint *fsep;
789
790 memset(&temp, 0, sizeof(temp));
791
792 fsep = xfer->pdev->privBeData;
793 fsep += xfer->trIndex;
794
795 fsep->nFrames = xfer->nFrames;
796 fsep->flags = 0;
797 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
798 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
799 }
800 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
801 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
802 }
803 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
804 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
805 }
806 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
807 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
808 }
809 /* NOTE: The "fsep->timeout" variable is 16-bit. */
810 if (xfer->timeout > 65535)
811 fsep->timeout = 65535;
812 else
813 fsep->timeout = xfer->timeout;
814
815 temp.ep_index = xfer->trIndex;
816
817 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) {
818 /* ignore any errors - should never happen */
819 }
820 return; /* success */
821}
822
823static void
824ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
825{
826 struct usb_fs_stop temp;
827
828 memset(&temp, 0, sizeof(temp));
829
830 temp.ep_index = xfer->trIndex;
831
832 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) {
833 /* ignore any errors - should never happen */
834 }
835 return;
836}
837
838static int
839ugen20_be_ioctl(uint32_t cmd, void *data)
840{
841 int f;
842 int error;
843
844 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
845 if (f < 0)
846 return (LIBUSB20_ERROR_OTHER);
847 error = ioctl(f, cmd, data);
848 if (error == -1) {
849 if (errno == EPERM) {
850 error = LIBUSB20_ERROR_ACCESS;
851 } else {
852 error = LIBUSB20_ERROR_OTHER;
853 }
854 }
855 close(f);
856 return (error);
857}
858
859static int
860ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
861 uint8_t iface_index, char *buf, uint8_t len)
862{
863 struct usb_gen_descriptor ugd;
864
865 memset(&ugd, 0, sizeof(ugd));
866
867 ugd.ugd_data = buf;
868 ugd.ugd_maxlen = len;
869 ugd.ugd_iface_index = iface_index;
870
871 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) {
872 return (LIBUSB20_ERROR_INVALID_PARAM);
873 }
874 return (0);
875}
876
877static int
878ugen20_dev_get_info(struct libusb20_device *pdev,
879 struct usb_device_info *pinfo)
880{
881 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) {
882 return (LIBUSB20_ERROR_INVALID_PARAM);
883 }
884 return (0);
885}
886
887static int
888ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
889 uint16_t quirk_index, struct libusb20_quirk *pq)
890{
891 struct usb_gen_quirk q;
892 int error;
893
894 memset(&q, 0, sizeof(q));
895
896 q.index = quirk_index;
897
898 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
899
900 if (error) {
901 if (errno == EINVAL) {
902 return (LIBUSB20_ERROR_NOT_FOUND);
903 }
904 } else {
905 pq->vid = q.vid;
906 pq->pid = q.pid;
907 pq->bcdDeviceLow = q.bcdDeviceLow;
908 pq->bcdDeviceHigh = q.bcdDeviceHigh;
909 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
910 }
911 return (error);
912}
913
914static int
915ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
916 struct libusb20_quirk *pq)
917{
918 struct usb_gen_quirk q;
919 int error;
920
921 memset(&q, 0, sizeof(q));
922
923 q.index = quirk_index;
924
925 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
926
927 if (error) {
928 if (errno == EINVAL) {
929 return (LIBUSB20_ERROR_NOT_FOUND);
930 }
931 } else {
932 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
933 }
934 return (error);
935}
936
937static int
938ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
939 struct libusb20_quirk *pq)
940{
941 struct usb_gen_quirk q;
942 int error;
943
944 memset(&q, 0, sizeof(q));
945
946 q.vid = pq->vid;
947 q.pid = pq->pid;
948 q.bcdDeviceLow = pq->bcdDeviceLow;
949 q.bcdDeviceHigh = pq->bcdDeviceHigh;
950 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
951
952 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
953 if (error) {
954 if (errno == ENOMEM) {
955 return (LIBUSB20_ERROR_NO_MEM);
956 }
957 }
958 return (error);
959}
960
961static int
962ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
963 struct libusb20_quirk *pq)
964{
965 struct usb_gen_quirk q;
966 int error;
967
968 memset(&q, 0, sizeof(q));
969
970 q.vid = pq->vid;
971 q.pid = pq->pid;
972 q.bcdDeviceLow = pq->bcdDeviceLow;
973 q.bcdDeviceHigh = pq->bcdDeviceHigh;
974 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
975
976 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
977 if (error) {
978 if (errno == EINVAL) {
979 return (LIBUSB20_ERROR_NOT_FOUND);
980 }
981 }
982 return (error);
983}
984
985static int
986ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
987{
988 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp));
989}
990
991static int
992ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
993{
994 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));
995}