blob: ec4cd2c87f5e815bab301608b558b23286aef08a [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 {
25// Static code from libusb1/sync.c
26void bulk_transfer_cb(struct libusb_transfer *transfer) {
27 int *completed = static_cast<int*>(transfer->user_data);
28 *completed = 1;
Brian Silverman7037e872013-09-14 15:35:45 -070029 LOG(DEBUG, "actual_length=%d\n", transfer->actual_length);
Brian Silverman395d6252013-09-13 20:58:14 -070030 /* caller interprets results and frees transfer */
31}
32} // namespace
33
34int do_sync_bulk_transfer(
35 struct libusb_context *context,
36 struct libusb_device_handle *dev_handle,
37 unsigned char endpoint, unsigned char *buffer, int length,
38 int *transferred, unsigned int timeout, unsigned char type,
39 Notification *quit) {
40 struct libusb_transfer *transfer = libusb_alloc_transfer(0);
41 int completed = 0;
42 int r;
43
44 if (!transfer)
45 return LIBUSB_ERROR_NO_MEM;
46
47 libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
48 bulk_transfer_cb, &completed, timeout);
49 transfer->type = type;
50
51 r = libusb_submit_transfer(transfer);
52 if (r < 0) {
53 libusb_free_transfer(transfer);
54 return r;
55 }
56
57 while (!completed) {
58 struct timeval tv;
59 tv.tv_sec = 1;
60 tv.tv_usec = 0;
61 r = libusb_handle_events_timeout_completed(context, &tv, &completed);
62 if (quit != NULL && quit->HasBeenNotified()) {
Brian Silverman7037e872013-09-14 15:35:45 -070063 LOG(WARNING, "Caught quit notification. Canceling transfer.\n");
Brian Silverman395d6252013-09-13 20:58:14 -070064 r = LIBUSB_ERROR_TIMEOUT;
65 }
66 if (r < 0) {
67 if (r == LIBUSB_ERROR_INTERRUPTED) {
68 continue;
69 }
70 libusb_cancel_transfer(transfer);
71 while (!completed) {
72 struct timeval cancel_tv;
Brian Silverman7037e872013-09-14 15:35:45 -070073 cancel_tv.tv_sec = 60;
Brian Silverman395d6252013-09-13 20:58:14 -070074 cancel_tv.tv_usec = 0;
75 if (libusb_handle_events_timeout_completed(context, &cancel_tv,
76 &completed) < 0) {
77 break;
78 }
79 }
80 libusb_free_transfer(transfer);
81 return r;
82 }
83 }
84
85 *transferred = transfer->actual_length;
86 switch (transfer->status) {
87 case LIBUSB_TRANSFER_COMPLETED:
88 r = 0;
89 break;
90 case LIBUSB_TRANSFER_TIMED_OUT:
91 r = LIBUSB_ERROR_TIMEOUT;
92 break;
93 case LIBUSB_TRANSFER_STALL:
94 r = LIBUSB_ERROR_PIPE;
95 break;
96 case LIBUSB_TRANSFER_OVERFLOW:
97 r = LIBUSB_ERROR_OVERFLOW;
98 break;
99 case LIBUSB_TRANSFER_NO_DEVICE:
100 r = LIBUSB_ERROR_NO_DEVICE;
101 break;
102 case LIBUSB_TRANSFER_ERROR:
103 case LIBUSB_TRANSFER_CANCELLED:
104 r = LIBUSB_ERROR_IO;
105 break;
106 default:
Brian Silverman7037e872013-09-14 15:35:45 -0700107 LOG(WARNING, "unrecognised status code %d\n",
108 static_cast<int>(transfer->status));
Brian Silverman395d6252013-09-13 20:58:14 -0700109 r = LIBUSB_ERROR_OTHER;
110 }
111
112 libusb_free_transfer(transfer);
113 return r;
114}
115
116} // namespace glibusb