blob: 4b2c922cf8f825d0b8d9f2e87e09c1c459e313c7 [file] [log] [blame]
Brian Silverman395d6252013-09-13 20:58:14 -07001// Copyright 2012 Google Inc. All Rights Reserved.
Brian Silverman7037e872013-09-14 15:35:45 -07002//
3// Modified by FRC Team 971.
Brian Silverman395d6252013-09-13 20:58:14 -07004
5#include <stddef.h>
Brian Silverman7037e872013-09-14 15:35:45 -07006#include <inttypes.h>
7#include <libusb-1.0/libusb.h>
Brian Silverman395d6252013-09-13 20:58:14 -07008
Brian Silverman7037e872013-09-14 15:35:45 -07009#include "aos/common/logging/logging.h"
Brian Silverman395d6252013-09-13 20:58:14 -070010#include "glibusb.h"
11#include "glibusb_device_internal.h"
12#include "glibusb_endpoint.h"
13#include "glibusb_endpoint_internal.h"
14#include "glibusb_internal.h"
15
16namespace glibusb {
17
18namespace {
19VendorProductId GetVendorAndProductIdInternal(
20 struct libusb_device_handle *device_handle) {
21 CHECK_NOTNULL(device_handle);
22 libusb_device_descriptor desc;
23 libusb_device *dev = libusb_get_device(device_handle);
24 libusb_get_device_descriptor(dev, &desc);
25 return VendorProductId(desc.idVendor, desc.idProduct);
26}
27} // namespace
28
29PhysicalUsbDevice::PhysicalUsbDevice(struct libusb_context *context,
30 struct libusb_device_handle *handle)
31 : UsbDevice(GetVendorAndProductIdInternal(handle)),
32 libusb_context_(CHECK_NOTNULL(context)),
33 device_handle_(CHECK_NOTNULL(handle)) {
34 int r = libusb_claim_interface(device_handle_, 0);
Brian Silverman7037e872013-09-14 15:35:45 -070035 if (r < 0) {
36 // TODO(charliehotel): this must not be FATAL.
37 LOG(FATAL, "libusb_claim_interface failed with %d: %s\n",
38 r, libusb_error_name(r));
39 }
Brian Silverman395d6252013-09-13 20:58:14 -070040
41 struct libusb_device *dev = libusb_get_device(device_handle_);
Brian Silverman7037e872013-09-14 15:35:45 -070042 if (dev == NULL) {
43 // TODO(charliehotel): this must not be FATAL.
44 LOG(FATAL, "libusb_get_device failed\n");
45 }
Brian Silverman395d6252013-09-13 20:58:14 -070046
47 struct libusb_device_descriptor desc;
48 r = libusb_get_device_descriptor(dev, &desc);
Brian Silverman7037e872013-09-14 15:35:45 -070049 if (r < 0) {
50 // TODO(charliehotel): this must not be FATAL.
51 LOG(FATAL, "libusb_get_device_descriptor failed with %d: %s\n",
52 r, libusb_error_name(r));
53 }
Brian Silverman395d6252013-09-13 20:58:14 -070054
Brian Silverman7037e872013-09-14 15:35:45 -070055 LOG(DEBUG, "vid=0x%" PRIx16 ", pid=0x%" PRIx16 ", # of configurations = %d\n",
56 desc.idVendor, desc.idProduct, static_cast<int>(desc.bNumConfigurations));
Brian Silverman395d6252013-09-13 20:58:14 -070057
58 struct libusb_config_descriptor *config;
59 r = libusb_get_active_config_descriptor(dev, &config);
Brian Silverman7037e872013-09-14 15:35:45 -070060 if (r < 0) {
61 // TODO(charliehotel): this must not be FATAL.
62 LOG(FATAL, "libusb_get_active_config_descriptor failed with %d: %s\n",
63 r, libusb_error_name(r));
64 }
Brian Silverman395d6252013-09-13 20:58:14 -070065 // TODO(charliehotel): this must not be FATAL.
66 CHECK_NOTNULL(config);
67
68 if (config->bNumInterfaces != 1) {
Brian Silverman7037e872013-09-14 15:35:45 -070069 LOG(DEBUG, "config->bNumInterfaces=%d, expected only one\n",
70 static_cast<int>(config->bNumInterfaces));
Brian Silverman395d6252013-09-13 20:58:14 -070071 }
72
Brian Silverman7037e872013-09-14 15:35:45 -070073 // TODO(brians): Make this enableable through the logging stuff.
74 if (false) {
Brian Silverman395d6252013-09-13 20:58:14 -070075 for (int i = 0; i < config->bNumInterfaces; ++i) {
76 const struct libusb_interface *interface = config->interface + i;
77 const struct libusb_interface_descriptor *setting = interface->altsetting;
78
Brian Silverman7037e872013-09-14 15:35:45 -070079 LOG(DEBUG, "bInterfaceNumber=%d bAlternateSetting=%d bNumEndpoints=%d\n",
80 static_cast<int>(setting->bInterfaceNumber),
81 static_cast<int>(setting->bAlternateSetting),
82 static_cast<int>(setting->bNumEndpoints));
Brian Silverman395d6252013-09-13 20:58:14 -070083
84 for (int j = 0; j < setting->bNumEndpoints; ++j) {
85 const struct libusb_endpoint_descriptor *endpoint =
86 setting->endpoint + j;
87 switch (endpoint->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
88 case LIBUSB_TRANSFER_TYPE_CONTROL:
Brian Silverman7037e872013-09-14 15:35:45 -070089 LOG(DEBUG, "control\n");
Brian Silverman395d6252013-09-13 20:58:14 -070090 break;
91 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
Brian Silverman7037e872013-09-14 15:35:45 -070092 LOG(DEBUG, "iso\n");
Brian Silverman395d6252013-09-13 20:58:14 -070093 break;
94 case LIBUSB_TRANSFER_TYPE_BULK:
Brian Silverman7037e872013-09-14 15:35:45 -070095 LOG(DEBUG, "bulk\n");
Brian Silverman395d6252013-09-13 20:58:14 -070096 break;
97 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
Brian Silverman7037e872013-09-14 15:35:45 -070098 LOG(DEBUG, "interrupt\n");
Brian Silverman395d6252013-09-13 20:58:14 -070099 break;
100 default:
Brian Silverman7037e872013-09-14 15:35:45 -0700101 LOG(FATAL, "unknown transfer type\n");
Brian Silverman395d6252013-09-13 20:58:14 -0700102 }
103 if ((endpoint->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) ==
104 LIBUSB_ENDPOINT_IN) {
Brian Silverman7037e872013-09-14 15:35:45 -0700105 LOG(DEBUG, " ep: 0x%x (in)\n",
106 static_cast<int>(endpoint->bEndpointAddress));
Brian Silverman395d6252013-09-13 20:58:14 -0700107 } else {
Brian Silverman7037e872013-09-14 15:35:45 -0700108 LOG(DEBUG, " ep: 0x%x (out)\n",
109 static_cast<int>(endpoint->bEndpointAddress));
Brian Silverman395d6252013-09-13 20:58:14 -0700110 }
Brian Silverman7037e872013-09-14 15:35:45 -0700111 LOG(DEBUG, " packet size=%d interval=%d\n",
112 static_cast<int>(endpoint->wMaxPacketSize),
113 static_cast<int>(endpoint->bInterval));
Brian Silverman395d6252013-09-13 20:58:14 -0700114 }
115 }
116 }
117 libusb_free_config_descriptor(config);
118}
119
120PhysicalUsbDevice::~PhysicalUsbDevice() {
121 CHECK_NOTNULL(device_handle_);
122 libusb_close(device_handle_);
123 device_handle_ = nullptr;
124}
125
126bool PhysicalUsbDevice::DoSetAlternateSetting(int setting) {
127 CHECK_NOTNULL(device_handle_);
128 int r = libusb_set_interface_alt_setting(device_handle_, 0, setting);
129 return r == 0;
130}
131
132template <class UsbEndpointType>
133UsbEndpointType *PhysicalUsbDevice::MatchEndpoint(EndpointMatcher matcher) {
134 CHECK_NOTNULL(device_handle_);
135 struct libusb_config_descriptor *config;
136 libusb_device *dev = libusb_get_device(device_handle_);
137 const int r = libusb_get_active_config_descriptor(dev, &config);
Brian Silverman7037e872013-09-14 15:35:45 -0700138 if (r < 0) {
139 // TODO(charliehotel): this must not be FATAL.
140 LOG(FATAL, "libusb_get_active_config_descriptor failed with %d: %s\n",
141 r, libusb_error_name(r));
142 }
Brian Silverman395d6252013-09-13 20:58:14 -0700143 // TODO(charliehotel): this must not be FATAL.
144 CHECK_NOTNULL(config);
145 const struct libusb_interface *interface = config->interface;
146 const struct libusb_interface_descriptor *setting = interface->altsetting;
147 for (int j = 0; j < setting->bNumEndpoints; ++j) {
148 const struct libusb_endpoint_descriptor *descriptor = setting->endpoint + j;
149 if (matcher(descriptor)) {
150 UsbEndpointType *ans = new UsbEndpointType(
151 libusb_context_, device_handle_, descriptor);
152 libusb_free_config_descriptor(config);
153 return ans;
154 }
155 }
156 libusb_free_config_descriptor(config);
157 return NULL;
158}
159
160namespace {
161
162struct DescriptorHasAddressAndDirection {
163 DescriptorHasAddressAndDirection(int address, UsbEndpoint::DirectionType direction)
164 : address_(address), direction_(direction) {}
165
166 // Returns true if the descriptor provided has an address equal to the number
167 bool operator()(const struct libusb_endpoint_descriptor *descriptor) {
168 return (DescriptorToAddress(descriptor) == address_ &&
169 DescriptorToDirection(descriptor) == direction_);
170 }
171
172 int address_;
173 UsbEndpoint::DirectionType direction_;
174};
175
176// Returns true if the descriptor has a transfer type and direction equal to the
177// provided type and direction.
178struct DescriptorIsOfTypeAndDirection {
179 DescriptorIsOfTypeAndDirection(UsbEndpoint::TransferType transfer_type,
180 UsbEndpoint::DirectionType direction)
181 : transfer_type_(transfer_type), direction_(direction) {}
182
183 bool operator()(const struct libusb_endpoint_descriptor *descriptor) {
184 return (DescriptorToTransfer(descriptor) == transfer_type_ &&
185 DescriptorToDirection(descriptor) == direction_);
186 }
187
188 UsbEndpoint::TransferType transfer_type_;
189 UsbEndpoint::DirectionType direction_;
190};
191
192} // namespace
193
194UsbInEndpoint *PhysicalUsbDevice::DoInEndpoint(int number) {
Brian Silverman7037e872013-09-14 15:35:45 -0700195 if ((number & LIBUSB_ENDPOINT_ADDRESS_MASK) != number) {
196 LOG(FATAL, "Endpoint %d out of range.\n", number);
197 }
Brian Silverman395d6252013-09-13 20:58:14 -0700198
199 DescriptorHasAddressAndDirection matcher(number, UsbEndpoint::kIn);
200 return MatchEndpoint<PhysicalUsbInEndpoint>(matcher);
201}
202
203UsbOutEndpoint *PhysicalUsbDevice::DoOutEndpoint(int number) {
Brian Silverman7037e872013-09-14 15:35:45 -0700204 if ((number & LIBUSB_ENDPOINT_ADDRESS_MASK) != number) {
205 LOG(FATAL, "Endpoint %d out of range.\n", number);
206 }
Brian Silverman395d6252013-09-13 20:58:14 -0700207
208 DescriptorHasAddressAndDirection matcher(number, UsbEndpoint::kOut);
209 return MatchEndpoint<PhysicalUsbOutEndpoint>(matcher);
210}
211
212UsbInEndpoint *PhysicalUsbDevice::DoFindInEndpoint(
213 UsbEndpoint::TransferType endpoint) {
214
215 DescriptorIsOfTypeAndDirection matcher(endpoint, UsbEndpoint::kIn);
216 return MatchEndpoint<PhysicalUsbInEndpoint>(matcher);
217}
218
219UsbOutEndpoint *PhysicalUsbDevice::DoFindOutEndpoint(
220 UsbEndpoint::TransferType endpoint) {
221
222 DescriptorIsOfTypeAndDirection matcher(endpoint, UsbEndpoint::kOut);
223 return MatchEndpoint<PhysicalUsbOutEndpoint>(matcher);
224}
225
226struct DeviceLocationAndId PhysicalUsbDevice::DoDeviceLocationAndId() {
227 CHECK_NOTNULL(device_handle_);
228 libusb_device *device = ::libusb_get_device(device_handle_);
229 CHECK_NOTNULL(device);
230 struct DeviceLocationAndId dlid;
231 dlid.location.bus_number = ::libusb_get_bus_number(device);
232 dlid.location.device_address = ::libusb_get_device_address(device);
233 dlid.id = vendor_product_id_;
234 return dlid;
235}
236
237} // namespace glibusb