blob: 95a62229076487ef727f6fc240713420e6dbcf74 [file] [log] [blame]
Brian Silverman395d6252013-09-13 20:58:14 -07001// Copyright 2012 Google Inc. All Rights Reserved.
2//
Brian Silverman7037e872013-09-14 15:35:45 -07003// Modified by FRC Team 971.
4//
Brian Silverman395d6252013-09-13 20:58:14 -07005// Alternative libusb call to do transfers that quits when
6// a notification is notified.
7//
8// This code was originally from third_party/libusb/libusb1/sync.c
9// and has been slightly modified to poll the notification.
10
11#include "glibusb_transfer.h"
12
13#include <stddef.h>
14#include <stdint.h>
15#include <stdio.h>
16#include <sys/time.h>
Brian Silverman7037e872013-09-14 15:35:45 -070017#include <libusb-1.0/libusb.h>
Brian Silverman395d6252013-09-13 20:58:14 -070018
Brian Silverman7037e872013-09-14 15:35:45 -070019#include "aos/common/logging/logging.h"
Brian Silverman395d6252013-09-13 20:58:14 -070020#include "glibusb_endpoint.h"
21
Brian Silverman395d6252013-09-13 20:58:14 -070022namespace glibusb {
23
24namespace {
Brian Silverman14a7b1a2013-10-11 21:34:03 -070025
Brian Silverman395d6252013-09-13 20:58:14 -070026// Static code from libusb1/sync.c
Brian Silverman14a7b1a2013-10-11 21:34:03 -070027void transfer_cb(struct libusb_transfer *transfer) {
Brian Silverman395d6252013-09-13 20:58:14 -070028 int *completed = static_cast<int*>(transfer->user_data);
29 *completed = 1;
Brian Silverman7037e872013-09-14 15:35:45 -070030 LOG(DEBUG, "actual_length=%d\n", transfer->actual_length);
Brian Silverman395d6252013-09-13 20:58:14 -070031 /* caller interprets results and frees transfer */
32}
Brian Silverman14a7b1a2013-10-11 21:34:03 -070033
34// How many isochronous packets we're going to deal with.
35// TODO(brians): Make this settable per endpoint instead of a constant.
36const int kNumIsoPackets = 1;
37
Brian Silverman395d6252013-09-13 20:58:14 -070038} // namespace
39
Brian Silverman14a7b1a2013-10-11 21:34:03 -070040int do_sync_transfer(
Brian Silverman395d6252013-09-13 20:58:14 -070041 struct libusb_context *context,
42 struct libusb_device_handle *dev_handle,
43 unsigned char endpoint, unsigned char *buffer, int length,
44 int *transferred, unsigned int timeout, unsigned char type,
45 Notification *quit) {
Brian Silverman14a7b1a2013-10-11 21:34:03 -070046 bool isochronous = type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
47 struct libusb_transfer *transfer =
48 libusb_alloc_transfer(isochronous ? kNumIsoPackets : 0);
Brian Silverman395d6252013-09-13 20:58:14 -070049 int completed = 0;
50 int r;
51
52 if (!transfer)
53 return LIBUSB_ERROR_NO_MEM;
54
Brian Silverman14a7b1a2013-10-11 21:34:03 -070055 switch (type) {
56 case LIBUSB_TRANSFER_TYPE_BULK:
57 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
58 libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
59 transfer_cb, &completed, timeout);
60 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
61 libusb_fill_iso_transfer(transfer, dev_handle, endpoint, buffer, length,
62 kNumIsoPackets, transfer_cb, &completed,
63 timeout);
64 transfer->iso_packet_desc[0].length = length;
65 default:
66 LOG(FATAL, "unhandled transfer type %hhd\n", type);
67 }
Brian Silverman395d6252013-09-13 20:58:14 -070068
69 r = libusb_submit_transfer(transfer);
70 if (r < 0) {
71 libusb_free_transfer(transfer);
72 return r;
73 }
74
75 while (!completed) {
76 struct timeval tv;
77 tv.tv_sec = 1;
78 tv.tv_usec = 0;
79 r = libusb_handle_events_timeout_completed(context, &tv, &completed);
80 if (quit != NULL && quit->HasBeenNotified()) {
Brian Silverman7037e872013-09-14 15:35:45 -070081 LOG(WARNING, "Caught quit notification. Canceling transfer.\n");
Brian Silverman395d6252013-09-13 20:58:14 -070082 r = LIBUSB_ERROR_TIMEOUT;
83 }
84 if (r < 0) {
85 if (r == LIBUSB_ERROR_INTERRUPTED) {
86 continue;
87 }
88 libusb_cancel_transfer(transfer);
89 while (!completed) {
90 struct timeval cancel_tv;
Brian Silverman7037e872013-09-14 15:35:45 -070091 cancel_tv.tv_sec = 60;
Brian Silverman395d6252013-09-13 20:58:14 -070092 cancel_tv.tv_usec = 0;
93 if (libusb_handle_events_timeout_completed(context, &cancel_tv,
94 &completed) < 0) {
95 break;
96 }
97 }
98 libusb_free_transfer(transfer);
99 return r;
100 }
101 }
102
Brian Silverman14a7b1a2013-10-11 21:34:03 -0700103 *transferred = isochronous ? transfer->iso_packet_desc[0].actual_length :
104 transfer->actual_length;
Brian Silverman395d6252013-09-13 20:58:14 -0700105 switch (transfer->status) {
106 case LIBUSB_TRANSFER_COMPLETED:
107 r = 0;
108 break;
109 case LIBUSB_TRANSFER_TIMED_OUT:
110 r = LIBUSB_ERROR_TIMEOUT;
111 break;
112 case LIBUSB_TRANSFER_STALL:
113 r = LIBUSB_ERROR_PIPE;
114 break;
115 case LIBUSB_TRANSFER_OVERFLOW:
116 r = LIBUSB_ERROR_OVERFLOW;
117 break;
118 case LIBUSB_TRANSFER_NO_DEVICE:
119 r = LIBUSB_ERROR_NO_DEVICE;
120 break;
121 case LIBUSB_TRANSFER_ERROR:
122 case LIBUSB_TRANSFER_CANCELLED:
123 r = LIBUSB_ERROR_IO;
124 break;
125 default:
Brian Silverman7037e872013-09-14 15:35:45 -0700126 LOG(WARNING, "unrecognised status code %d\n",
127 static_cast<int>(transfer->status));
Brian Silverman395d6252013-09-13 20:58:14 -0700128 r = LIBUSB_ERROR_OTHER;
129 }
130
131 libusb_free_transfer(transfer);
132 return r;
133}
134
135} // namespace glibusb