summaryrefslogtreecommitdiff
path: root/security/trezord/files/usb.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'security/trezord/files/usb.hpp')
-rw-r--r--security/trezord/files/usb.hpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/security/trezord/files/usb.hpp b/security/trezord/files/usb.hpp
new file mode 100644
index 000000000000..b0d4adb8405c
--- /dev/null
+++ b/security/trezord/files/usb.hpp
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the TREZOR project.
+ *
+ * Copyright (C) 2014 SatoshiLabs
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <libusb.h>
+
+namespace trezord
+{
+namespace usb
+{
+
+static std::unique_ptr< utils::async_executor > usb_executor;
+
+struct usb_device_info {
+ char path[10];
+ uint16_t vendor_id;
+ uint16_t product_id;
+
+ usb_device_info *next;
+};
+
+// Init/exit
+
+void
+init()
+{
+ libusb_init(NULL);
+ usb_executor.reset(new utils::async_executor());
+}
+
+void
+exit()
+{
+ libusb_exit(NULL);
+ usb_executor.reset();
+}
+
+// Enumeration
+
+usb_device_info *
+enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+ return usb_executor->await([=] {
+ libusb_device **devs = NULL;
+ libusb_device *dev = NULL;
+ struct usb_device_info *root = NULL; /* return object */
+ struct usb_device_info *cur_dev = NULL;
+ int i = 0;
+
+ libusb_get_device_list(NULL, &devs);
+ while ((dev = devs[i++]) != NULL) {
+ struct libusb_device_descriptor desc;
+ libusb_get_device_descriptor(dev, &desc);
+ if ((vendor_id == 0 || vendor_id == desc.idVendor) && (product_id == 0 || product_id == desc.idProduct)) {
+ struct usb_device_info *tmp;
+ tmp = (struct usb_device_info *) calloc(1, sizeof(struct usb_device_info));
+ if (cur_dev) {
+ cur_dev->next = tmp;
+ } else {
+ root = tmp;
+ }
+ cur_dev = tmp;
+
+ cur_dev->next = NULL;
+ snprintf(cur_dev->path, sizeof(cur_dev->path), "%04x:%04x",
+ libusb_get_bus_number(dev),
+ libusb_get_device_address(dev));
+
+ cur_dev->vendor_id = desc.idVendor;
+ cur_dev->product_id = desc.idProduct;
+ }
+ }
+ libusb_free_device_list(devs, 1);
+ return root;
+ });
+}
+
+void
+free_enumeration(usb_device_info *devs)
+{
+ return usb_executor->await([=] {
+ struct usb_device_info *d = devs;
+ while (d) {
+ struct usb_device_info *next = d->next;
+ free(d);
+ d = next;
+ }
+ });
+}
+
+// Open/close
+
+libusb_device_handle *
+open_path(char const *path)
+{
+ return usb_executor->await([=] {
+ libusb_device **devs = NULL;
+ libusb_device *dev = NULL;
+ libusb_device_handle *handle = NULL;
+ int i = 0;
+
+ libusb_get_device_list(NULL, &devs);
+ while ((dev = devs[i++]) != NULL) {
+ char devpath[10];
+ snprintf(devpath, sizeof(devpath), "%04x:%04x",
+ libusb_get_bus_number(dev),
+ libusb_get_device_address(dev));
+ if (strncmp(devpath, path, sizeof(devpath)) == 0) {
+ if (libusb_open(dev, &handle) == 0) {
+ libusb_set_auto_detach_kernel_driver(handle, 1);
+ if (libusb_claim_interface(handle, 0)) {
+ libusb_close(handle);
+ handle = NULL;
+ }
+ }
+ break;
+ }
+ }
+ libusb_free_device_list(devs, 1);
+ return handle;
+ });
+}
+
+void
+close(libusb_device_handle *device)
+{
+ return usb_executor->await([=] {
+ libusb_release_interface(device, 0);
+ libusb_close(device);
+ });
+}
+
+// Communication
+
+int
+write(libusb_device_handle *device, unsigned char *data, size_t length)
+{
+ return usb_executor->await([=] {
+ int xfer = -1;
+ libusb_interrupt_transfer(device, 0x01, data, length, &xfer, 0);
+ return xfer;
+ });
+}
+
+int
+read(libusb_device_handle *device, unsigned char *data, size_t length)
+{
+ return usb_executor->await([=] {
+ int xfer = -1;
+ libusb_interrupt_transfer(device, 0x81, data, length, &xfer, 0);
+ return xfer;
+ });
+}
+
+}
+}