blob: 0026ef3aa6c8a514d1bbe9922a11155d299fb47a [file] [log] [blame]
Austin Schuh9b360e92013-03-27 04:47:04 +00001#include "libusb_wrap.h"
2
Brian Silverman4bde0172013-10-25 15:53:25 -07003#include <string.h>
4
Brian Silverman798c7782013-03-28 16:48:02 -07005#include <iostream>
6
7#include "aos/common/logging/logging.h"
8
Austin Schuh9b360e92013-03-27 04:47:04 +00009LibUSB::LibUSB() {
Brian Silverman798c7782013-03-28 16:48:02 -070010 if (libusb_init(&ctx_) < 0) {
11 LOG(FATAL, "libusb_init(%p) failed\n", &ctx_);
12 }
Austin Schuh9b360e92013-03-27 04:47:04 +000013 libusb_set_debug(ctx_, 3);
14}
15
16LibUSBDeviceHandle *LibUSB::FindDeviceWithVIDPID(int vid, int pid) {
17 int r;
18 libusb_device **devs;
19 libusb_device_handle *dev_handle;
20
21 ssize_t cnt;
22 cnt = libusb_get_device_list(ctx_, &devs);
Brian Silverman798c7782013-03-28 16:48:02 -070023 if (cnt < 0) {
24 LOG(ERROR, "Get Device Error\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000025 return NULL;
26 }
Brian Silverman798c7782013-03-28 16:48:02 -070027 LOG(INFO, "%d Devices in list.\n", cnt);
Austin Schuh9b360e92013-03-27 04:47:04 +000028 bool found = false;
29 for (int i = 0; i < cnt; ++i) {
30 struct libusb_device_descriptor desc;
31 r = libusb_get_device_descriptor(devs[i], &desc);
Brian Silverman798c7782013-03-28 16:48:02 -070032 if (r < 0) {
33 LOG(FATAL, "lib_usb_get_device_descriptor(%p, %p) failed\n",
34 devs[i], &desc);
35 }
Austin Schuh9b360e92013-03-27 04:47:04 +000036 if (desc.idVendor == vid && desc.idProduct == pid) {
Brian Silverman798c7782013-03-28 16:48:02 -070037 LOG(INFO, "Device %d:%d matches\n",
38 (int)libusb_get_bus_number(devs[i]),
39 (int)libusb_get_device_address(devs[i]));
Austin Schuh9b360e92013-03-27 04:47:04 +000040 r = libusb_open(devs[i], &dev_handle);
41 if (libusb_kernel_driver_active(dev_handle, 0) == 1) {
Brian Silvermana4f9ef22013-03-30 14:31:16 -070042 LOG(INFO, "Device already in use, trying next one.\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000043 continue;
44 }
45 if (r < 0) {
Brian Silvermana4f9ef22013-03-30 14:31:16 -070046 LOG(WARNING, "Failed to open device.\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000047 } else {
48 found = true;
49 break;
50 }
51 }
52 }
53 libusb_free_device_list(devs, 1);
54 if (!found) {
Brian Silvermana4f9ef22013-03-30 14:31:16 -070055 LOG(ERROR, "Couldn't open device.\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000056 return NULL;
57 }
58
59 if (libusb_kernel_driver_active(dev_handle, 0) == 1) {
Brian Silvermana4f9ef22013-03-30 14:31:16 -070060 LOG(INFO, "Kernel Driver Active\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000061 if (libusb_detach_kernel_driver(dev_handle, 0) == 0) {
Brian Silvermana4f9ef22013-03-30 14:31:16 -070062 LOG(INFO, "Kernel Driver Detached!\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000063 } else {
Brian Silvermana4f9ef22013-03-30 14:31:16 -070064 LOG(ERROR, "Couldn't detach kernel driver.\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000065 return NULL;
66 }
67 }
68
69 r = libusb_claim_interface(dev_handle, 0);
70 if (r < 0) {
Brian Silvermana4f9ef22013-03-30 14:31:16 -070071 LOG(ERROR, "Cannot Claim Interface\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000072 return 0;
73 }
Brian Silvermana4f9ef22013-03-30 14:31:16 -070074 LOG(INFO, "Claimed Interface\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000075 return new LibUSBDeviceHandle(dev_handle);
76}
77
78LibUSB::~LibUSB() {
79 libusb_exit(ctx_);
80}
81
Brian Silverman4ad17832013-03-31 01:26:08 -070082void LibUSB::HandleEvents() {
83 int ret = libusb_handle_events(ctx_);
84 if (ret != 0) {
85 LOG(FATAL, "libusb_handle_events(%p) returned %d\n", ctx_, ret);
86 }
87}
88
Austin Schuh9b360e92013-03-27 04:47:04 +000089LibUSBDeviceHandle::LibUSBDeviceHandle(
90 libusb_device_handle *dev_handle) : dev_handle_(dev_handle) { }
91
92LibUSBDeviceHandle::~LibUSBDeviceHandle() {
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070093 int r = libusb_release_interface(dev_handle_, 0);
Austin Schuh9b360e92013-03-27 04:47:04 +000094 if (r != 0) {
Brian Silvermana4f9ef22013-03-30 14:31:16 -070095 LOG(FATAL, "Cannot Release Interface\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000096 }
Brian Silvermana4f9ef22013-03-30 14:31:16 -070097 LOG(INFO, "Released Interface\n");
Austin Schuh9b360e92013-03-27 04:47:04 +000098
99 libusb_close(dev_handle_);
100}
101
102int LibUSBDeviceHandle::interrupt_transfer(
103 unsigned char endpoint, unsigned char *data, int length,
104 int *transferred, unsigned int timeout) {
105 return libusb_interrupt_transfer(dev_handle_, endpoint, data, length,
106 transferred, timeout);
107}
108
109int LibUSBDeviceHandle::bulk_transfer(
110 unsigned char endpoint, unsigned char *data,
111 int length, int *transferred, unsigned int timeout) {
112 return libusb_bulk_transfer(dev_handle_, endpoint, data, length,
113 transferred, timeout);
114}
Brian Silverman4ad17832013-03-31 01:26:08 -0700115
116namespace libusb {
117
118Transfer::Transfer(size_t data_length,
119 void (*callback)(Transfer *, void *),
Brian Silverman4bde0172013-10-25 15:53:25 -0700120 void *user_data,
121 int num_iso_packets)
122 : transfer_(libusb_alloc_transfer(num_iso_packets)),
Brian Silverman4ad17832013-03-31 01:26:08 -0700123 data_(new uint8_t[data_length]),
124 data_length_(data_length),
125 callback_(callback),
126 user_data_(user_data) {
127}
128Transfer::~Transfer() {
129 libusb_free_transfer(transfer_);
130 delete data_;
131}
132
133void Transfer::FillInterrupt(LibUSBDeviceHandle *device,
134 unsigned char endpoint,
135 unsigned int timeout) {
136 libusb_fill_interrupt_transfer(transfer_,
137 device->dev_handle_,
138 endpoint,
139 data_,
140 data_length_,
141 StaticTransferCallback,
142 this,
143 timeout);
144}
145
146void Transfer::Submit() {
147 int ret = libusb_submit_transfer(transfer_);
148 if (ret != 0) {
149 if (ret == LIBUSB_ERROR_BUSY) {
150 LOG(FATAL, "transfer %p already submitted\n", this);
151 }
Brian Silverman4bde0172013-10-25 15:53:25 -0700152 LOG(FATAL, "libusb error %d submitting transfer %p. errno %d: %s\n",
153 ret, this, errno, strerror(errno));
Brian Silverman4ad17832013-03-31 01:26:08 -0700154 }
155}
156
157void Transfer::Cancel() {
158 int ret = libusb_cancel_transfer(transfer_);
159 if (ret != 0) {
Brian Silverman4bde0172013-10-25 15:53:25 -0700160 LOG(FATAL, "libusb error %d cancelling transfer %p. errno %d: %s\n",
161 ret, this, errno, strerror(errno));
Brian Silverman4ad17832013-03-31 01:26:08 -0700162 }
163}
164
165void Transfer::TransferCallback() {
166 callback_(this, user_data_);
167}
168
Brian Silvermanc554a8f2013-03-31 19:07:49 -0700169IsochronousTransfer::IsochronousTransfer(size_t packet_length,
170 int num_packets,
171 void (*callback)(Transfer *, void *),
172 void *user_data)
Brian Silverman4bde0172013-10-25 15:53:25 -0700173 : Transfer(packet_length * num_packets, callback, user_data, num_packets),
Brian Silvermanc554a8f2013-03-31 19:07:49 -0700174 num_packets_(num_packets) {
175}
176
177void IsochronousTransfer::FillIsochronous(LibUSBDeviceHandle *device,
178 unsigned char endpoint,
Brian Silverman4bde0172013-10-25 15:53:25 -0700179 const ::aos::time::Time &timeout) {
180 libusb_fill_iso_transfer(transfer_,
Brian Silvermanc554a8f2013-03-31 19:07:49 -0700181 device->dev_handle_,
182 endpoint,
183 data_,
184 data_length_,
185 num_packets_,
186 StaticTransferCallback,
187 this,
Brian Silverman4bde0172013-10-25 15:53:25 -0700188 timeout.ToMSec());
189 transfer_->iso_packet_desc[0].length = data_length_;
Brian Silvermanc554a8f2013-03-31 19:07:49 -0700190}
191
Brian Silverman4ad17832013-03-31 01:26:08 -0700192} // namespace libusb