Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 1 | // Copyright 2012 Google Inc. All Rights Reserved. |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 2 | // |
| 3 | // Modified by FRC Team 971. |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 4 | |
| 5 | #include <stddef.h> |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 6 | #include <inttypes.h> |
| 7 | #include <libusb-1.0/libusb.h> |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 8 | |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 9 | #include "aos/common/logging/logging.h" |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 10 | #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 | |
| 16 | namespace glibusb { |
| 17 | |
| 18 | namespace { |
| 19 | VendorProductId 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 | |
| 29 | PhysicalUsbDevice::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 Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 35 | 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 Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 40 | |
| 41 | struct libusb_device *dev = libusb_get_device(device_handle_); |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 42 | if (dev == NULL) { |
| 43 | // TODO(charliehotel): this must not be FATAL. |
| 44 | LOG(FATAL, "libusb_get_device failed\n"); |
| 45 | } |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 46 | |
| 47 | struct libusb_device_descriptor desc; |
| 48 | r = libusb_get_device_descriptor(dev, &desc); |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 49 | 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 Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 54 | |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 55 | LOG(DEBUG, "vid=0x%" PRIx16 ", pid=0x%" PRIx16 ", # of configurations = %d\n", |
| 56 | desc.idVendor, desc.idProduct, static_cast<int>(desc.bNumConfigurations)); |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 57 | |
| 58 | struct libusb_config_descriptor *config; |
| 59 | r = libusb_get_active_config_descriptor(dev, &config); |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 60 | 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 Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 65 | // TODO(charliehotel): this must not be FATAL. |
| 66 | CHECK_NOTNULL(config); |
| 67 | |
| 68 | if (config->bNumInterfaces != 1) { |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 69 | LOG(DEBUG, "config->bNumInterfaces=%d, expected only one\n", |
| 70 | static_cast<int>(config->bNumInterfaces)); |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 71 | } |
| 72 | |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 73 | // TODO(brians): Make this enableable through the logging stuff. |
| 74 | if (false) { |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 75 | 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 Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 79 | 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 Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 83 | |
| 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 Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 89 | LOG(DEBUG, "control\n"); |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 90 | break; |
| 91 | case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 92 | LOG(DEBUG, "iso\n"); |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 93 | break; |
| 94 | case LIBUSB_TRANSFER_TYPE_BULK: |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 95 | LOG(DEBUG, "bulk\n"); |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 96 | break; |
| 97 | case LIBUSB_TRANSFER_TYPE_INTERRUPT: |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 98 | LOG(DEBUG, "interrupt\n"); |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 99 | break; |
| 100 | default: |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 101 | LOG(FATAL, "unknown transfer type\n"); |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 102 | } |
| 103 | if ((endpoint->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == |
| 104 | LIBUSB_ENDPOINT_IN) { |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 105 | LOG(DEBUG, " ep: 0x%x (in)\n", |
| 106 | static_cast<int>(endpoint->bEndpointAddress)); |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 107 | } else { |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 108 | LOG(DEBUG, " ep: 0x%x (out)\n", |
| 109 | static_cast<int>(endpoint->bEndpointAddress)); |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 110 | } |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 111 | LOG(DEBUG, " packet size=%d interval=%d\n", |
| 112 | static_cast<int>(endpoint->wMaxPacketSize), |
| 113 | static_cast<int>(endpoint->bInterval)); |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 114 | } |
| 115 | } |
| 116 | } |
| 117 | libusb_free_config_descriptor(config); |
| 118 | } |
| 119 | |
| 120 | PhysicalUsbDevice::~PhysicalUsbDevice() { |
| 121 | CHECK_NOTNULL(device_handle_); |
| 122 | libusb_close(device_handle_); |
| 123 | device_handle_ = nullptr; |
| 124 | } |
| 125 | |
| 126 | bool 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 | |
| 132 | template <class UsbEndpointType> |
| 133 | UsbEndpointType *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 Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 138 | 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 Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 143 | // 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 | |
| 160 | namespace { |
| 161 | |
| 162 | struct 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. |
| 178 | struct 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 | |
| 194 | UsbInEndpoint *PhysicalUsbDevice::DoInEndpoint(int number) { |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 195 | if ((number & LIBUSB_ENDPOINT_ADDRESS_MASK) != number) { |
| 196 | LOG(FATAL, "Endpoint %d out of range.\n", number); |
| 197 | } |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 198 | |
| 199 | DescriptorHasAddressAndDirection matcher(number, UsbEndpoint::kIn); |
| 200 | return MatchEndpoint<PhysicalUsbInEndpoint>(matcher); |
| 201 | } |
| 202 | |
| 203 | UsbOutEndpoint *PhysicalUsbDevice::DoOutEndpoint(int number) { |
Brian Silverman | 7037e87 | 2013-09-14 15:35:45 -0700 | [diff] [blame^] | 204 | if ((number & LIBUSB_ENDPOINT_ADDRESS_MASK) != number) { |
| 205 | LOG(FATAL, "Endpoint %d out of range.\n", number); |
| 206 | } |
Brian Silverman | 395d625 | 2013-09-13 20:58:14 -0700 | [diff] [blame] | 207 | |
| 208 | DescriptorHasAddressAndDirection matcher(number, UsbEndpoint::kOut); |
| 209 | return MatchEndpoint<PhysicalUsbOutEndpoint>(matcher); |
| 210 | } |
| 211 | |
| 212 | UsbInEndpoint *PhysicalUsbDevice::DoFindInEndpoint( |
| 213 | UsbEndpoint::TransferType endpoint) { |
| 214 | |
| 215 | DescriptorIsOfTypeAndDirection matcher(endpoint, UsbEndpoint::kIn); |
| 216 | return MatchEndpoint<PhysicalUsbInEndpoint>(matcher); |
| 217 | } |
| 218 | |
| 219 | UsbOutEndpoint *PhysicalUsbDevice::DoFindOutEndpoint( |
| 220 | UsbEndpoint::TransferType endpoint) { |
| 221 | |
| 222 | DescriptorIsOfTypeAndDirection matcher(endpoint, UsbEndpoint::kOut); |
| 223 | return MatchEndpoint<PhysicalUsbOutEndpoint>(matcher); |
| 224 | } |
| 225 | |
| 226 | struct 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 |