blob: a700cf24abb7797428a87b06ca3fa32c829f3a07 [file] [log] [blame]
Brian Silverman395d6252013-09-13 20:58:14 -07001// Copyright 2012 Google Inc. All Rights Reserved.
2//
3// Alternative libusb call to do transfers that quits when
4// a notification is notified.
5//
6// This code was originally from third_party/libusb/libusb1/sync.c
7// and has been slightly modified to poll the notification.
8
9#include "glibusb_transfer.h"
10
11#include <stddef.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <sys/time.h>
15#include <gflags/gflags.h>
16#include <glog/logging.h>
17#include <libusb.h>
18
19#include "glibusb_endpoint.h"
20
21
22DEFINE_int32(notification_poll,
23 60,
24 "Time in seconds to wait between checking the quit notification "
25 "when waiting for USB messages.");
26
27namespace {
28
29static bool GEQZero(const char* flagname, int32_t value) {
30 if (value < 0) {
31 printf("Invalid value for --%s: %d\n", flagname, value);
32 return false;
33 }
34 return true;
35}
36
37static const bool notification_poll_dummy = google::RegisterFlagValidator(
38 &FLAGS_notification_poll, &GEQZero);
39
40} // namespace
41
42
43namespace glibusb {
44
45namespace {
46// Static code from libusb1/sync.c
47void bulk_transfer_cb(struct libusb_transfer *transfer) {
48 int *completed = static_cast<int*>(transfer->user_data);
49 *completed = 1;
50 VLOG(3) << "actual_length=" << transfer->actual_length;
51 /* caller interprets results and frees transfer */
52}
53} // namespace
54
55int do_sync_bulk_transfer(
56 struct libusb_context *context,
57 struct libusb_device_handle *dev_handle,
58 unsigned char endpoint, unsigned char *buffer, int length,
59 int *transferred, unsigned int timeout, unsigned char type,
60 Notification *quit) {
61 struct libusb_transfer *transfer = libusb_alloc_transfer(0);
62 int completed = 0;
63 int r;
64
65 if (!transfer)
66 return LIBUSB_ERROR_NO_MEM;
67
68 libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
69 bulk_transfer_cb, &completed, timeout);
70 transfer->type = type;
71
72 r = libusb_submit_transfer(transfer);
73 if (r < 0) {
74 libusb_free_transfer(transfer);
75 return r;
76 }
77
78 while (!completed) {
79 struct timeval tv;
80 tv.tv_sec = 1;
81 tv.tv_usec = 0;
82 r = libusb_handle_events_timeout_completed(context, &tv, &completed);
83 if (quit != NULL && quit->HasBeenNotified()) {
84 LOG(WARNING) << "Caught quit notification. Canceling transfer.";
85 r = LIBUSB_ERROR_TIMEOUT;
86 }
87 if (r < 0) {
88 if (r == LIBUSB_ERROR_INTERRUPTED) {
89 continue;
90 }
91 libusb_cancel_transfer(transfer);
92 while (!completed) {
93 struct timeval cancel_tv;
94 cancel_tv.tv_sec = (quit == NULL ? FLAGS_notification_poll : 60);
95 cancel_tv.tv_usec = 0;
96 if (libusb_handle_events_timeout_completed(context, &cancel_tv,
97 &completed) < 0) {
98 break;
99 }
100 }
101 libusb_free_transfer(transfer);
102 return r;
103 }
104 }
105
106 *transferred = transfer->actual_length;
107 switch (transfer->status) {
108 case LIBUSB_TRANSFER_COMPLETED:
109 r = 0;
110 break;
111 case LIBUSB_TRANSFER_TIMED_OUT:
112 r = LIBUSB_ERROR_TIMEOUT;
113 break;
114 case LIBUSB_TRANSFER_STALL:
115 r = LIBUSB_ERROR_PIPE;
116 break;
117 case LIBUSB_TRANSFER_OVERFLOW:
118 r = LIBUSB_ERROR_OVERFLOW;
119 break;
120 case LIBUSB_TRANSFER_NO_DEVICE:
121 r = LIBUSB_ERROR_NO_DEVICE;
122 break;
123 case LIBUSB_TRANSFER_ERROR:
124 case LIBUSB_TRANSFER_CANCELLED:
125 r = LIBUSB_ERROR_IO;
126 break;
127 default:
128 LOG(WARNING) << "unrecognised status code " << transfer->status;
129 r = LIBUSB_ERROR_OTHER;
130 }
131
132 libusb_free_transfer(transfer);
133 return r;
134}
135
136} // namespace glibusb