blob: 9fc8df3468aeda687682d52edceaccfb197fdf19 [file] [log] [blame]
Brian Silverman395d6252013-09-13 20:58:14 -07001// Copyright 2012 Google Inc. All Rights Reserved.
2
3#include <stddef.h>
4#include <glog/logging.h>
5#include <boost/function.hpp>
6#include <boost/scoped_ptr.hpp>
7#include <libusb.h>
8
9#include "glibusb.h"
10#include "glibusb_device_internal.h"
11#include "glibusb_endpoint.h"
12#include "glibusb_endpoint_internal.h"
13#include "glibusb_internal.h"
14
15namespace glibusb {
16
17namespace {
18VendorProductId GetVendorAndProductIdInternal(
19 struct libusb_device_handle *device_handle) {
20 CHECK_NOTNULL(device_handle);
21 libusb_device_descriptor desc;
22 libusb_device *dev = libusb_get_device(device_handle);
23 libusb_get_device_descriptor(dev, &desc);
24 return VendorProductId(desc.idVendor, desc.idProduct);
25}
26} // namespace
27
28PhysicalUsbDevice::PhysicalUsbDevice(struct libusb_context *context,
29 struct libusb_device_handle *handle)
30 : UsbDevice(GetVendorAndProductIdInternal(handle)),
31 libusb_context_(CHECK_NOTNULL(context)),
32 device_handle_(CHECK_NOTNULL(handle)) {
33 int r = libusb_claim_interface(device_handle_, 0);
34 // TODO(charliehotel): this must not be FATAL.
35 CHECK_GE(r, 0) << ": libusb_claim_interface failed, r=" << std::dec << r;
36
37 struct libusb_device *dev = libusb_get_device(device_handle_);
38 // TODO(charliehotel): this must not be FATAL.
39 CHECK(dev != NULL) << ": libusb_get_device failed";
40
41 struct libusb_device_descriptor desc;
42 r = libusb_get_device_descriptor(dev, &desc);
43 // TODO(charliehotel): this must not be FATAL.
44 CHECK_GE(r, 0) << ": libusb_get_device_descriptor failed";
45
46 VLOG(2) << "vid=0x" << std::hex << desc.idVendor
47 << ", pid=0x" << desc.idProduct;
48 VLOG(2) << " # of configurations = "
49 << static_cast<int>(desc.bNumConfigurations);
50
51 struct libusb_config_descriptor *config;
52 r = libusb_get_active_config_descriptor(dev, &config);
53 // TODO(charliehotel): this must not be FATAL.
54 CHECK_GE(r, 0) << ": libusb_get_active_config_descriptor failed";
55 // TODO(charliehotel): this must not be FATAL.
56 CHECK_NOTNULL(config);
57
58 if (config->bNumInterfaces != 1) {
59 VLOG(2) << "config->bNumInterfaces="
60 << static_cast<int>(config->bNumInterfaces)
61 << ", expected ony one";
62 }
63
64 if (VLOG_IS_ON(2)) {
65 for (int i = 0; i < config->bNumInterfaces; ++i) {
66 const struct libusb_interface *interface = config->interface + i;
67 const struct libusb_interface_descriptor *setting = interface->altsetting;
68
69 VLOG(2) << "bInterfaceNumber="
70 << static_cast<int>(setting->bInterfaceNumber);
71 VLOG(2) << "bAlternateSetting="
72 << static_cast<int>(setting->bAlternateSetting);
73 VLOG(2) << "bNumEndpoints="
74 << static_cast<int>(setting->bNumEndpoints);
75
76 for (int j = 0; j < setting->bNumEndpoints; ++j) {
77 const struct libusb_endpoint_descriptor *endpoint =
78 setting->endpoint + j;
79 switch (endpoint->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
80 case LIBUSB_TRANSFER_TYPE_CONTROL:
81 VLOG(2) << "control";
82 break;
83 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
84 VLOG(2) << "iso";
85 break;
86 case LIBUSB_TRANSFER_TYPE_BULK:
87 VLOG(2) << "bulk";
88 break;
89 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
90 VLOG(2) << "interrupt";
91 break;
92 default:
93 LOG(FATAL) << "unknown transfer type";
94 }
95 if ((endpoint->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) ==
96 LIBUSB_ENDPOINT_IN) {
97 VLOG(2) << " ep: 0x"
98 << std::hex << static_cast<int>(endpoint->bEndpointAddress)
99 << " (in)";
100 } else {
101 VLOG(2) << " ep: 0x"
102 << std::hex << static_cast<int>(endpoint->bEndpointAddress)
103 << " (out)";
104 }
105 VLOG(2) << " packet size="
106 << std::dec << static_cast<int>(endpoint->wMaxPacketSize);
107 VLOG(2) << " interval="
108 << std::dec << static_cast<int>(endpoint->bInterval);
109 }
110 }
111 }
112 libusb_free_config_descriptor(config);
113}
114
115PhysicalUsbDevice::~PhysicalUsbDevice() {
116 CHECK_NOTNULL(device_handle_);
117 libusb_close(device_handle_);
118 device_handle_ = nullptr;
119}
120
121bool PhysicalUsbDevice::DoSetAlternateSetting(int setting) {
122 CHECK_NOTNULL(device_handle_);
123 int r = libusb_set_interface_alt_setting(device_handle_, 0, setting);
124 return r == 0;
125}
126
127template <class UsbEndpointType>
128UsbEndpointType *PhysicalUsbDevice::MatchEndpoint(EndpointMatcher matcher) {
129 CHECK_NOTNULL(device_handle_);
130 struct libusb_config_descriptor *config;
131 libusb_device *dev = libusb_get_device(device_handle_);
132 const int r = libusb_get_active_config_descriptor(dev, &config);
133 // TODO(charliehotel): this must not be FATAL.
134 CHECK_GE(r, 0) << ": libusb_get_active_config_descriptor failed";
135 // TODO(charliehotel): this must not be FATAL.
136 CHECK_NOTNULL(config);
137 const struct libusb_interface *interface = config->interface;
138 const struct libusb_interface_descriptor *setting = interface->altsetting;
139 for (int j = 0; j < setting->bNumEndpoints; ++j) {
140 const struct libusb_endpoint_descriptor *descriptor = setting->endpoint + j;
141 if (matcher(descriptor)) {
142 UsbEndpointType *ans = new UsbEndpointType(
143 libusb_context_, device_handle_, descriptor);
144 libusb_free_config_descriptor(config);
145 return ans;
146 }
147 }
148 libusb_free_config_descriptor(config);
149 return NULL;
150}
151
152namespace {
153
154struct DescriptorHasAddressAndDirection {
155 DescriptorHasAddressAndDirection(int address, UsbEndpoint::DirectionType direction)
156 : address_(address), direction_(direction) {}
157
158 // Returns true if the descriptor provided has an address equal to the number
159 bool operator()(const struct libusb_endpoint_descriptor *descriptor) {
160 return (DescriptorToAddress(descriptor) == address_ &&
161 DescriptorToDirection(descriptor) == direction_);
162 }
163
164 int address_;
165 UsbEndpoint::DirectionType direction_;
166};
167
168// Returns true if the descriptor has a transfer type and direction equal to the
169// provided type and direction.
170struct DescriptorIsOfTypeAndDirection {
171 DescriptorIsOfTypeAndDirection(UsbEndpoint::TransferType transfer_type,
172 UsbEndpoint::DirectionType direction)
173 : transfer_type_(transfer_type), direction_(direction) {}
174
175 bool operator()(const struct libusb_endpoint_descriptor *descriptor) {
176 return (DescriptorToTransfer(descriptor) == transfer_type_ &&
177 DescriptorToDirection(descriptor) == direction_);
178 }
179
180 UsbEndpoint::TransferType transfer_type_;
181 UsbEndpoint::DirectionType direction_;
182};
183
184} // namespace
185
186UsbInEndpoint *PhysicalUsbDevice::DoInEndpoint(int number) {
187 CHECK_EQ(number & LIBUSB_ENDPOINT_ADDRESS_MASK, number)
188 << ": Endpoint out of range.";
189
190 DescriptorHasAddressAndDirection matcher(number, UsbEndpoint::kIn);
191 return MatchEndpoint<PhysicalUsbInEndpoint>(matcher);
192}
193
194UsbOutEndpoint *PhysicalUsbDevice::DoOutEndpoint(int number) {
195 CHECK_EQ(number & LIBUSB_ENDPOINT_ADDRESS_MASK, number)
196 << ": Endpoint out of range.";
197
198 DescriptorHasAddressAndDirection matcher(number, UsbEndpoint::kOut);
199 return MatchEndpoint<PhysicalUsbOutEndpoint>(matcher);
200}
201
202UsbInEndpoint *PhysicalUsbDevice::DoFindInEndpoint(
203 UsbEndpoint::TransferType endpoint) {
204
205 DescriptorIsOfTypeAndDirection matcher(endpoint, UsbEndpoint::kIn);
206 return MatchEndpoint<PhysicalUsbInEndpoint>(matcher);
207}
208
209UsbOutEndpoint *PhysicalUsbDevice::DoFindOutEndpoint(
210 UsbEndpoint::TransferType endpoint) {
211
212 DescriptorIsOfTypeAndDirection matcher(endpoint, UsbEndpoint::kOut);
213 return MatchEndpoint<PhysicalUsbOutEndpoint>(matcher);
214}
215
216struct DeviceLocationAndId PhysicalUsbDevice::DoDeviceLocationAndId() {
217 CHECK_NOTNULL(device_handle_);
218 libusb_device *device = ::libusb_get_device(device_handle_);
219 CHECK_NOTNULL(device);
220 struct DeviceLocationAndId dlid;
221 dlid.location.bus_number = ::libusb_get_bus_number(device);
222 dlid.location.device_address = ::libusb_get_device_address(device);
223 dlid.id = vendor_product_id_;
224 return dlid;
225}
226
227} // namespace glibusb