Add jaylink_device_get_usb_bus_ports()
[libjaylink.git] / libjaylink / discovery_usb.c
blob48d5322929b284be570670ea37be75b09bacfc93
1 /*
2 * This file is part of the libjaylink project.
4 * Copyright (C) 2014-2016 Marc Schink <jaylink-dev@marcschink.de>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include <string.h>
24 #include <sys/types.h>
26 #include "libjaylink.h"
27 #include "libjaylink-internal.h"
30 * libusb.h includes windows.h and therefore must be included after anything
31 * that includes winsock2.h.
33 #include <libusb.h>
35 /**
36 * @file
38 * Device discovery (USB).
41 /** @cond PRIVATE */
42 /** USB Vendor ID (VID) of SEGGER products. */
43 #define USB_VENDOR_ID 0x1366
45 /* USB Product IDs (PID) and their corresponding USB addresses. */
46 static const uint16_t pids[][2] = {
47 {0x0101, 0},
48 {0x0102, 1},
49 {0x0103, 2},
50 {0x0104, 3},
51 {0x0105, 0},
52 {0x0107, 0},
53 {0x0108, 0},
54 {0x1010, 0},
55 {0x1011, 0},
56 {0x1012, 0},
57 {0x1013, 0},
58 {0x1014, 0},
59 {0x1015, 0},
60 {0x1016, 0},
61 {0x1017, 0},
62 {0x1018, 0}
65 /** Maximum length of the USB string descriptor for the serial number. */
66 #define USB_SERIAL_NUMBER_LENGTH 12
68 /**
69 * Maximum number of digits in a serial number
71 * The serial number of a device consists of at most 9 digits but user defined
72 * serial numbers are allowed with up to 10 digits.
74 #define MAX_SERIAL_NUMBER_DIGITS 10
75 /** @endcond */
77 static bool parse_serial_number(const char *str, uint32_t *serial_number)
79 size_t length;
81 length = strlen(str);
84 * Skip the first digits which are not part of a valid serial number.
85 * This is necessary because some devices erroneously use random digits
86 * instead of zeros for padding.
88 if (length > MAX_SERIAL_NUMBER_DIGITS)
89 str = str + (length - MAX_SERIAL_NUMBER_DIGITS);
91 if (jaylink_parse_serial_number(str, serial_number) != JAYLINK_OK)
92 return false;
94 return true;
97 static bool compare_devices(const void *a, const void *b)
99 const struct jaylink_device *dev;
100 const struct libusb_device *usb_dev;
102 dev = a;
103 usb_dev = b;
105 if (dev->iface != JAYLINK_HIF_USB)
106 return false;
108 if (dev->usb_dev == usb_dev)
109 return true;
111 return false;
114 static struct jaylink_device *find_device(const struct jaylink_context *ctx,
115 const struct libusb_device *usb_dev)
117 struct list *item;
119 item = list_find_custom(ctx->devs, &compare_devices, usb_dev);
121 if (item)
122 return item->data;
124 return NULL;
127 static struct jaylink_device *probe_device(struct jaylink_context *ctx,
128 struct libusb_device *usb_dev)
130 int ret;
131 struct libusb_device_descriptor desc;
132 struct libusb_device_handle *usb_devh;
133 struct jaylink_device *dev;
134 char buf[USB_SERIAL_NUMBER_LENGTH + 1];
135 uint8_t usb_address;
136 uint32_t serial_number;
137 bool valid_serial_number;
138 bool found_device;
139 size_t i;
141 ret = libusb_get_device_descriptor(usb_dev, &desc);
143 if (ret != LIBUSB_SUCCESS) {
144 log_warn(ctx, "Failed to get device descriptor: %s.",
145 libusb_error_name(ret));
146 return NULL;
149 if (desc.idVendor != USB_VENDOR_ID)
150 return NULL;
152 found_device = false;
154 for (i = 0; i < sizeof(pids) / sizeof(pids[0]); i++) {
155 if (pids[i][0] == desc.idProduct) {
156 found_device = true;
157 usb_address = pids[i][1];
158 break;
162 if (!found_device)
163 return NULL;
165 log_dbg(ctx, "Found device (VID:PID = %04x:%04x, bus:address = "
166 "%03u:%03u).", desc.idVendor, desc.idProduct,
167 libusb_get_bus_number(usb_dev),
168 libusb_get_device_address(usb_dev));
171 * Search for an already allocated device instance for this device and
172 * if found return a reference to it.
174 dev = find_device(ctx, usb_dev);
176 if (dev) {
177 log_dbg(ctx, "Device: USB address = %u.", dev->usb_address);
179 if (dev->valid_serial_number)
180 log_dbg(ctx, "Device: Serial number = %u.",
181 dev->serial_number);
182 else
183 log_dbg(ctx, "Device: Serial number = N/A.");
185 log_dbg(ctx, "Using existing device instance.");
186 return jaylink_ref_device(dev);
189 /* Open the device to be able to retrieve its serial number. */
190 ret = libusb_open(usb_dev, &usb_devh);
192 if (ret != LIBUSB_SUCCESS) {
193 log_warn(ctx, "Failed to open device: %s.",
194 libusb_error_name(ret));
195 return NULL;
198 serial_number = 0;
199 valid_serial_number = true;
201 ret = libusb_get_string_descriptor_ascii(usb_devh, desc.iSerialNumber,
202 (unsigned char *)buf, USB_SERIAL_NUMBER_LENGTH + 1);
204 libusb_close(usb_devh);
206 if (ret < 0) {
207 log_warn(ctx, "Failed to retrieve serial number: %s.",
208 libusb_error_name(ret));
209 valid_serial_number = false;
212 if (valid_serial_number) {
213 if (!parse_serial_number(buf, &serial_number)) {
214 log_warn(ctx, "Failed to parse serial number.");
215 return NULL;
219 log_dbg(ctx, "Device: USB address = %u.", usb_address);
221 if (valid_serial_number)
222 log_dbg(ctx, "Device: Serial number = %u.", serial_number);
223 else
224 log_dbg(ctx, "Device: Serial number = N/A.");
226 log_dbg(ctx, "Allocating new device instance.");
228 dev = device_allocate(ctx);
230 if (!dev) {
231 log_warn(ctx, "Device instance malloc failed.");
232 return NULL;
235 dev->iface = JAYLINK_HIF_USB;
236 dev->usb_dev = libusb_ref_device(usb_dev);
237 dev->usb_address = usb_address;
238 dev->serial_number = serial_number;
239 dev->valid_serial_number = valid_serial_number;
241 return dev;
244 JAYLINK_PRIV int discovery_usb_scan(struct jaylink_context *ctx)
246 ssize_t ret;
247 struct libusb_device **devs;
248 struct jaylink_device *dev;
249 size_t num;
250 size_t i;
252 ret = libusb_get_device_list(ctx->usb_ctx, &devs);
254 if (ret == LIBUSB_ERROR_IO) {
255 log_err(ctx, "Failed to retrieve device list: input/output "
256 "error.");
257 return JAYLINK_ERR_IO;
258 } else if (ret < 0) {
259 log_err(ctx, "Failed to retrieve device list: %s.",
260 libusb_error_name(ret));
261 return JAYLINK_ERR;
264 num = 0;
266 for (i = 0; devs[i]; i++) {
267 dev = probe_device(ctx, devs[i]);
269 if (!dev)
270 continue;
272 ctx->discovered_devs = list_prepend(ctx->discovered_devs, dev);
273 num++;
276 libusb_free_device_list(devs, true);
277 log_dbg(ctx, "Found %zu USB device(s).", num);
279 return JAYLINK_OK;