blob: 846ed58be3b880cf56fca172ebd25cd25c596601 [file] [log] [blame]
Daniel Thompson1d507a02018-07-12 11:02:28 +01001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2016 secunet Security Networks AG
5 * Copyright (C) 2018 Linaro Limited
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
Edward O'Callaghanb8631272019-10-22 10:46:04 +110018#include <inttypes.h>
Daniel Thompsonaf499192018-07-12 12:03:51 +010019#include <stdbool.h>
Daniel Thompson1d507a02018-07-12 11:02:28 +010020#include <string.h>
21#include <libusb.h>
22#include "programmer.h"
23
Daniel Thompsonaf499192018-07-12 12:03:51 +010024/*
25 * Check whether we should filter the current device.
26 *
27 * The main code filters by VID/PID then calls out to the filter function for extra filtering.
28 * The filter function is called twice for each device. Once with handle == NULL to allow the
29 * filter to cull devices without opening them and, assuming the first filter does not trigger,
30 * also with a real handle to allow the filter to query the device further.
31 *
32 * Returns true if the device should be skipped.
33 */
34typedef bool (*filter_func)(struct libusb_device_descriptor *desc, struct libusb_device_handle *handle, void*ctx);
35
36static struct libusb_device_handle *get_by_vid_pid_filter(struct libusb_context *usb_ctx,
37 uint16_t vid, uint16_t pid, filter_func filter_fn, void *filter_ctx)
Daniel Thompson1d507a02018-07-12 11:02:28 +010038{
39 struct libusb_device **list;
40 ssize_t count = libusb_get_device_list(usb_ctx, &list);
41 if (count < 0) {
42 msg_perr("Getting the USB device list failed (%s)!\n", libusb_error_name(count));
43 return NULL;
44 }
45
46 ssize_t i = 0;
47 for (i = 0; i < count; i++) {
48 struct libusb_device *dev = list[i];
49 struct libusb_device_descriptor desc;
50 struct libusb_device_handle *handle;
51
52 int res = libusb_get_device_descriptor(dev, &desc);
53 if (res != 0) {
54 msg_perr("Reading the USB device descriptor failed (%s)!\n", libusb_error_name(res));
55 continue;
56 }
57
Patrick Rudolph4ca575d2019-05-20 11:31:44 +020058 if ((desc.idVendor != vid) || (desc.idProduct != pid))
Daniel Thompson1d507a02018-07-12 11:02:28 +010059 continue;
60
61 msg_pdbg("Found USB device %04"PRIx16":%04"PRIx16" at address %d-%d.\n",
62 desc.idVendor, desc.idProduct,
63 libusb_get_bus_number(dev), libusb_get_device_address(dev));
64
Daniel Thompsonaf499192018-07-12 12:03:51 +010065 /* allow filters to trigger before the device is opened */
66 if (filter_fn(&desc, NULL, filter_ctx))
67 continue;
68
Daniel Thompson1d507a02018-07-12 11:02:28 +010069 res = libusb_open(dev, &handle);
70 if (res != 0) {
Daniel Thompsonaf499192018-07-12 12:03:51 +010071 msg_perr("Opening the USB device at address %d-%d failed (%s)!\n",
72 libusb_get_bus_number(dev), libusb_get_device_address(dev),
73 libusb_error_name(res));
74 break;
Daniel Thompson1d507a02018-07-12 11:02:28 +010075 }
76
Daniel Thompsonaf499192018-07-12 12:03:51 +010077 /* filter can also trigger after a device is opened */
78 if (filter_fn(&desc, handle, filter_ctx)) {
79 libusb_close(handle);
80 continue;
Daniel Thompson1d507a02018-07-12 11:02:28 +010081 }
82
83 libusb_free_device_list(list, 1);
84 return handle;
85 }
86
87 libusb_free_device_list(list, 1);
88 return NULL;
Daniel Thompsonaf499192018-07-12 12:03:51 +010089
90}
91
92static bool filter_by_serial(struct libusb_device_descriptor *desc, struct libusb_device_handle *handle,
93 void *serialno)
94{
95 /* Never filter if device is not yet open or when user did not provide a serial number */
96 if (!handle || !serialno)
97 return false;
98
99 unsigned char myserial[64];
100 int res = libusb_get_string_descriptor_ascii(handle, desc->iSerialNumber, myserial, sizeof(myserial));
101 if (res < 0) {
102 msg_perr("Reading the USB serialno failed (%s)!\n", libusb_error_name(res));
103 return true;
104 }
105 msg_pdbg("Serial number is %s\n", myserial);
106
107 /* Filter out any serial number that does not commence with serialno */
108 return 0 != strncmp(serialno, (char *)myserial, strlen(serialno));
109}
110
111struct libusb_device_handle *usb_dev_get_by_vid_pid_serial(
112 struct libusb_context *usb_ctx, uint16_t vid, uint16_t pid, const char *serialno)
113{
114 return get_by_vid_pid_filter(usb_ctx, vid, pid, filter_by_serial, (void *)serialno);
115}
116
117static bool filter_by_number(struct libusb_device_descriptor *desc, struct libusb_device_handle *handle,
118 void *ctx)
119{
120 /* This filter never triggers once it has allowed the device to be opened */
121 if (handle != NULL)
122 return false;
123
124 unsigned int *nump = ctx;
125 if (*nump) {
126 (*nump)--;
127 return true;
128 }
129
130 return false;
Daniel Thompson1d507a02018-07-12 11:02:28 +0100131}
132
133/*
134 * This function allows different devices to be targeted based on enumeration order. Different
135 * hotplug sequencing (or simply a reboot) may change the enumeration order. This function should
136 * only be used if a programmers does not provide an alternative way to identify itself uniquely
137 * (such as a unique serial number).
138 */
139struct libusb_device_handle *usb_dev_get_by_vid_pid_number(
140 struct libusb_context *usb_ctx, uint16_t vid, uint16_t pid, unsigned int num)
141{
Daniel Thompsonaf499192018-07-12 12:03:51 +0100142 return get_by_vid_pid_filter(usb_ctx, vid, pid, filter_by_number, &num);
Daniel Thompson1d507a02018-07-12 11:02:28 +0100143}