1 #include <nm_core.h>
2 #include <nm_utils.h>
3 #include <nm_usb_devices.h>
4
5 /* Disable USB on FreeBSD while libudev-devd
6 * will not supports calls udev_hwdb_* */
7
8 enum {NM_USB_SERIAL_LEN = 127};
9
10 static inline void nm_usb_dev_free(nm_usb_dev_t *dev);
11
12 #if defined (NM_OS_LINUX)
13 #include <libudev.h>
14 #include <libusb.h>
15
16 static const char *nm_usb_hwdb_get(const char *modalias, const char *key);
17 static const char *nm_usb_get_vendor(uint16_t vid);
18 static const char *nm_usb_get_product(uint16_t vid, uint16_t pid);
19 static int nm_usb_get_vendor_str(char *buf, size_t size, uint16_t vid);
20 static int nm_usb_get_product_str(char *buf, size_t size, uint16_t vid, uint16_t pid);
21
22 static struct udev_hwdb *hwdb = NULL;
23 #endif /* NM_OS_LINUX */
24
nm_usb_get_devs(nm_vect_t * v)25 void nm_usb_get_devs(nm_vect_t *v)
26 {
27 #if defined (NM_OS_LINUX)
28 libusb_context *ctx = NULL;
29 libusb_device **list = NULL;
30 struct udev *udev = NULL;
31 int rc;
32 ssize_t dev_count, n;
33 char vendor[128], product[128];
34
35 if ((udev = udev_new()) == NULL)
36 nm_bug(_("%s: udev_new failed"), __func__);
37
38 if ((hwdb = udev_hwdb_new(udev)) == NULL)
39 nm_bug(_("%s: udev_hwdb_new failed"), __func__);
40
41 if ((rc = libusb_init(&ctx)) != 0)
42 nm_bug("%s: %s", __func__, libusb_strerror(rc));
43
44 if ((dev_count = libusb_get_device_list(ctx, &list)) < 1)
45 nm_bug(_("%s: libusb_get_device_list failed"), __func__);
46
47 //@TODO Some of variables may be moved outside, and freed only once
48 for (n = 0; n < dev_count; n++) {
49 nm_usb_dev_t dev = NM_INIT_USB;
50 libusb_device *device = list[n];
51 struct libusb_device_descriptor desc;
52
53 memset(&desc, 0, sizeof(desc));
54
55 if (libusb_get_device_descriptor(device, &desc) != 0)
56 continue;
57
58 if (nm_usb_get_vendor_str(vendor, sizeof(vendor), desc.idVendor) == 0)
59 nm_str_alloc_text(&dev.name, "vendor-unknown");
60 else
61 nm_str_alloc_text(&dev.name, vendor);
62
63 if (nm_usb_get_product_str(product, sizeof(product), desc.idVendor, desc.idProduct) == 0)
64 nm_str_add_text(&dev.name, " product-unknown");
65 else
66 nm_str_add_text(&dev.name, product);
67
68 dev.bus_num = libusb_get_bus_number(device);
69 dev.dev_addr = libusb_get_device_address(device);
70
71 nm_str_format(&dev.vendor_id, "%04x", desc.idVendor);
72 nm_str_format(&dev.product_id, "%04x", desc.idProduct);
73
74 nm_vect_insert(v, &dev, sizeof(dev), nm_usb_vect_ins_cb);
75 nm_usb_dev_free(&dev);
76 }
77
78 /* cleanup */
79 libusb_free_device_list(list, 1);
80 udev_hwdb_unref(hwdb);
81 udev_unref(udev);
82 libusb_exit(ctx);
83 #else
84 (void) v;
85 #endif /* NM_OS_LINUX */
86 }
87
nm_usb_get_serial(const nm_usb_dev_t * dev,nm_str_t * serial)88 int nm_usb_get_serial(const nm_usb_dev_t *dev, nm_str_t *serial)
89 {
90 int rc = NM_ERR;
91 #if defined (NM_OS_LINUX)
92 libusb_context *ctx = NULL;
93 libusb_device **list = NULL;
94 int usb_rc;
95 ssize_t dev_count;
96
97 if (dev == NULL)
98 nm_bug(_("%s: null nm_usb_dev_t pointer"), __func__);
99
100 if ((usb_rc = libusb_init(&ctx)) != 0)
101 nm_bug("%s: %s", __func__, libusb_strerror(usb_rc));
102
103 if ((dev_count = libusb_get_device_list(ctx, &list)) < 1)
104 nm_bug(_("%s: libusb_get_device_list failed"), __func__);
105
106 for (ssize_t n = 0; n < dev_count; n++) {
107 uint8_t bus_num, dev_addr;
108 libusb_device *device = list[n];
109
110 bus_num = libusb_get_bus_number(device);
111 dev_addr = libusb_get_device_address(device);
112
113 if ((bus_num == dev->bus_num) &&
114 (dev_addr == dev->dev_addr)) {
115 libusb_device_handle *handle;
116 char serial_buf[NM_USB_SERIAL_LEN] = {0};
117 struct libusb_device_descriptor desc;
118
119 memset(&desc, 0, sizeof(desc));
120
121 if (libusb_get_device_descriptor(device, &desc) != 0)
122 break;
123
124 if ((usb_rc = libusb_open(device, &handle)) != 0)
125 nm_bug("%s: %s", __func__, libusb_strerror(usb_rc));
126
127 if (libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber,
128 (uint8_t *) serial_buf, NM_USB_SERIAL_LEN) > 0) {
129 nm_str_alloc_text(serial, serial_buf);
130 rc = NM_OK;
131 }
132
133 libusb_close(handle);
134
135 break;
136 }
137 }
138
139 /* cleanup */
140 libusb_free_device_list(list, 1);
141 libusb_exit(ctx);
142 #else
143 (void) dev;
144 (void) serial;
145 #endif /* NM_OS_LINUX */
146
147 return rc;
148 }
149
nm_usb_vect_ins_cb(void * unit_p,const void * ctx)150 void nm_usb_vect_ins_cb(void *unit_p, const void *ctx)
151 {
152 nm_str_copy(nm_usb_name(unit_p), nm_usb_name(ctx));
153 nm_str_copy(nm_usb_vendor_id(unit_p), nm_usb_vendor_id(ctx));
154 nm_str_copy(nm_usb_product_id(unit_p), nm_usb_product_id(ctx));
155 *nm_usb_bus_num(unit_p) = *nm_usb_bus_num(ctx);
156 *nm_usb_dev_addr(unit_p) = *nm_usb_dev_addr(ctx);
157 }
158
nm_usb_vect_free_cb(void * unit_p)159 void nm_usb_vect_free_cb(void *unit_p)
160 {
161 nm_str_free(nm_usb_name(unit_p));
162 nm_str_free(nm_usb_vendor_id(unit_p));
163 nm_str_free(nm_usb_product_id(unit_p));
164 }
165
nm_usb_data_vect_ins_cb(void * unit_p,const void * ctx)166 void nm_usb_data_vect_ins_cb(void *unit_p, const void *ctx)
167 {
168 nm_str_copy(nm_usb_data_serial(unit_p), nm_usb_data_serial(ctx));
169 *nm_usb_data_dev(unit_p) = *nm_usb_data_dev(ctx);
170 }
171
nm_usb_data_vect_free_cb(void * unit_p)172 void nm_usb_data_vect_free_cb(void *unit_p)
173 {
174 nm_str_free(nm_usb_data_serial(unit_p));
175 }
176
nm_usb_data_free(nm_usb_data_t * usb)177 void nm_usb_data_free(nm_usb_data_t *usb)
178 {
179 nm_str_free(&usb->serial);
180 nm_usb_dev_free(usb->dev);
181 }
182
nm_usb_dev_free(nm_usb_dev_t * dev)183 static inline void nm_usb_dev_free(nm_usb_dev_t *dev)
184 {
185 nm_str_free(&dev->name);
186 nm_str_free(&dev->vendor_id);
187 nm_str_free(&dev->product_id);
188 }
189
190 #if defined (NM_OS_LINUX)
nm_usb_hwdb_get(const char * modalias,const char * key)191 static const char *nm_usb_hwdb_get(const char *modalias, const char *key)
192 {
193 struct udev_list_entry *entry = NULL;
194
195 udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) {
196 if (strcmp(udev_list_entry_get_name(entry), key) == 0)
197 return udev_list_entry_get_value(entry);
198 }
199
200 return NULL;
201 }
202
nm_usb_get_vendor(uint16_t vid)203 static const char *nm_usb_get_vendor(uint16_t vid)
204 {
205 char modalias[64];
206
207 sprintf(modalias, "usb:v%04X*", vid);
208 return nm_usb_hwdb_get(modalias, "ID_VENDOR_FROM_DATABASE");
209 }
210
nm_usb_get_product(uint16_t vid,uint16_t pid)211 static const char *nm_usb_get_product(uint16_t vid, uint16_t pid)
212 {
213 char modalias[64];
214
215 sprintf(modalias, "usb:v%04Xp%04X*", vid, pid);
216 return nm_usb_hwdb_get(modalias, "ID_MODEL_FROM_DATABASE");
217 }
218
nm_usb_get_vendor_str(char * buf,size_t size,uint16_t vid)219 static int nm_usb_get_vendor_str(char *buf, size_t size, uint16_t vid)
220 {
221 const char *cp;
222
223 if (size < 1)
224 return 0;
225
226 *buf = 0;
227
228 if (!(cp = nm_usb_get_vendor(vid)))
229 return 0;
230
231 return snprintf(buf, size, "%s ", cp);
232 }
233
nm_usb_get_product_str(char * buf,size_t size,uint16_t vid,uint16_t pid)234 static int nm_usb_get_product_str(char *buf, size_t size, uint16_t vid, uint16_t pid)
235 {
236 const char *cp;
237
238 if (size < 1)
239 return 0;
240
241 *buf = 0;
242
243 if (!(cp = nm_usb_get_product(vid, pid)))
244 return 0;
245
246 return snprintf(buf, size, "%s", cp);
247 }
248 #endif /* NM_OS_LINUX */
249
250 /* vim:set ts=4 sw=4: */
251