GitHub issues can also be used to report HCL updates
[networkupstools/kirr.git] / drivers / usb-common.c
blob4fc88b68850211db60886c842bffe67ffff81e9c
1 /* usb-common.c - common useful USB functions
3 Copyright (C) 2008 Arnaud Quette <arnaud.quette@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "common.h"
21 #include "usb-common.h"
23 int is_usb_device_supported(usb_device_id_t *usb_device_id_list, USBDevice_t *device)
25 int retval = NOT_SUPPORTED;
26 usb_device_id_t *usbdev;
28 for (usbdev = usb_device_id_list; usbdev->vendorID != -1; usbdev++) {
30 if (usbdev->vendorID != device->VendorID) {
31 continue;
34 /* flag as possibly supported if we see a known vendor */
35 retval = POSSIBLY_SUPPORTED;
37 if (usbdev->productID != device->ProductID) {
38 continue;
41 /* call the specific handler, if it exists */
42 if (usbdev->fun != NULL) {
43 (*usbdev->fun)(device);
46 return SUPPORTED;
49 return retval;
52 /* ---------------------------------------------------------------------- */
53 /* matchers */
55 /* helper function: version of strcmp that tolerates NULL
56 * pointers. NULL is considered to come before all other strings
57 * alphabetically.
59 static int strcmp_null(char *s1, char *s2)
61 if (s1 == NULL && s2 == NULL) {
62 return 0;
65 if (s1 == NULL) {
66 return -1;
69 if (s2 == NULL) {
70 return 1;
73 return strcmp(s1, s2);
76 /* private callback function for exact matches
78 static int match_function_exact(USBDevice_t *hd, void *privdata)
80 USBDevice_t *data = (USBDevice_t *)privdata;
82 if (hd->VendorID != data->VendorID) {
83 return 0;
86 if (hd->ProductID != data->ProductID) {
87 return 0;
90 if (strcmp_null(hd->Vendor, data->Vendor) != 0) {
91 return 0;
94 if (strcmp_null(hd->Product, data->Product) != 0) {
95 return 0;
98 if (strcmp_null(hd->Serial, data->Serial) != 0) {
99 return 0;
101 #ifdef DEBUG_EXACT_MATCH_BUS
102 if (strcmp_null(hd->Bus, data->Bus) != 0) {
103 return 0;
105 #endif
106 return 1;
109 /* constructor: create an exact matcher that matches the device.
110 * On success, return 0 and store the matcher in *matcher. On
111 * error, return -1 with errno set
113 int USBNewExactMatcher(USBDeviceMatcher_t **matcher, USBDevice_t *hd)
115 USBDeviceMatcher_t *m;
116 USBDevice_t *data;
118 m = malloc(sizeof(*m));
119 if (!m) {
120 return -1;
123 data = calloc(1, sizeof(*data));
124 if (!data) {
125 free(m);
126 return -1;
129 m->match_function = &match_function_exact;
130 m->privdata = (void *)data;
131 m->next = NULL;
133 data->VendorID = hd->VendorID;
134 data->ProductID = hd->ProductID;
135 data->Vendor = hd->Vendor ? strdup(hd->Vendor) : NULL;
136 data->Product = hd->Product ? strdup(hd->Product) : NULL;
137 data->Serial = hd->Serial ? strdup(hd->Serial) : NULL;
138 #ifdef DEBUG_EXACT_MATCH_BUS
139 data->Bus = hd->Bus ? strdup(hd->Bus) : NULL;
140 #endif
141 *matcher = m;
143 return 0;
146 /* destructor: free matcher previously created with USBNewExactMatcher */
147 void USBFreeExactMatcher(USBDeviceMatcher_t *matcher)
149 USBDevice_t *data;
151 if (!matcher) {
152 return;
155 data = (USBDevice_t *)matcher->privdata;
157 free(data->Vendor);
158 free(data->Product);
159 free(data->Serial);
160 #ifdef DEBUG_EXACT_MATCH_BUS
161 free(data->Bus);
162 #endif
163 free(data);
164 free(matcher);
167 /* Private function for compiling a regular expression. On success,
168 * store the compiled regular expression (or NULL) in *compiled, and
169 * return 0. On error with errno set, return -1. If the supplied
170 * regular expression is unparseable, return -2 (an error message can
171 * then be retrieved with regerror(3)). Note that *compiled will be an
172 * allocated value, and must be freed with regfree(), then free(), see
173 * regex(3). As a special case, if regex==NULL, then set
174 * *compiled=NULL (regular expression NULL is intended to match
175 * anything).
177 static int compile_regex(regex_t **compiled, char *regex, int cflags)
179 int r;
180 regex_t *preg;
182 if (regex == NULL) {
183 *compiled = NULL;
184 return 0;
187 preg = malloc(sizeof(*preg));
188 if (!preg) {
189 return -1;
192 r = regcomp(preg, regex, cflags);
193 if (r) {
194 free(preg);
195 return -2;
198 *compiled = preg;
200 return 0;
203 /* Private function for regular expression matching. Check if the
204 * entire string str (minus any initial and trailing whitespace)
205 * matches the compiled regular expression preg. Return 1 if it
206 * matches, 0 if not. Return -1 on error with errno set. Special
207 * cases: if preg==NULL, it matches everything (no contraint). If
208 * str==NULL, then it is treated as "".
210 static int match_regex(regex_t *preg, char *str)
212 int r;
213 size_t len = 0;
214 char *string;
215 regmatch_t match;
217 if (!preg) {
218 return 1;
221 if (!str) {
222 string = xstrdup("");
223 } else {
224 /* skip leading whitespace */
225 for (len = 0; len < strlen(str); len++) {
227 if (!strchr(" \t\n", str[len])) {
228 break;
232 string = xstrdup(str+len);
234 /* skip trailing whitespace */
235 for (len = strlen(string); len > 0; len--) {
237 if (!strchr(" \t\n", string[len-1])) {
238 break;
242 string[len] = '\0';
245 /* test the regular expression */
246 r = regexec(preg, string, 1, &match, 0);
247 free(string);
248 if (r) {
249 return 0;
252 /* check that the match is the entire string */
253 if ((match.rm_so != 0) || (match.rm_eo != (int)len)) {
254 return 0;
257 return 1;
260 /* Private function, similar to match_regex, but the argument being
261 * matched is a (hexadecimal) number, rather than a string. It is
262 * converted to a 4-digit hexadecimal string. */
263 static int match_regex_hex(regex_t *preg, int n)
265 char buf[10];
267 snprintf(buf, sizeof(buf), "%04x", n);
269 return match_regex(preg, buf);
272 /* private data type: hold a set of compiled regular expressions. */
273 typedef struct regex_matcher_data_s {
274 regex_t *regex[6];
275 } regex_matcher_data_t;
277 /* private callback function for regex matches */
278 static int match_function_regex(USBDevice_t *hd, void *privdata)
280 regex_matcher_data_t *data = (regex_matcher_data_t *)privdata;
281 int r;
283 r = match_regex_hex(data->regex[0], hd->VendorID);
284 if (r != 1) {
285 return r;
288 r = match_regex_hex(data->regex[1], hd->ProductID);
289 if (r != 1) {
290 return r;
293 r = match_regex(data->regex[2], hd->Vendor);
294 if (r != 1) {
295 return r;
298 r = match_regex(data->regex[3], hd->Product);
299 if (r != 1) {
300 return r;
303 r = match_regex(data->regex[4], hd->Serial);
304 if (r != 1) {
305 return r;
308 r = match_regex(data->regex[5], hd->Bus);
309 if (r != 1) {
310 return r;
312 return 1;
315 /* constructor: create a regular expression matcher. This matcher is
316 * based on six regular expression strings in regex_array[0..5],
317 * corresponding to: vendorid, productid, vendor, product, serial,
318 * bus. Any of these strings can be NULL, which matches
319 * everything. Cflags are as in regcomp(3). Typical values for cflags
320 * are REG_ICASE (case insensitive matching) and REG_EXTENDED (use
321 * extended regular expressions). On success, return 0 and store the
322 * matcher in *matcher. On error, return -1 with errno set, or return
323 * i=1--6 to indicate that the regular expression regex_array[i-1] was
324 * ill-formed (an error message can then be retrieved with
325 * regerror(3)).
327 int USBNewRegexMatcher(USBDeviceMatcher_t **matcher, char **regex, int cflags)
329 int r, i;
330 USBDeviceMatcher_t *m;
331 regex_matcher_data_t *data;
333 m = malloc(sizeof(*m));
334 if (!m) {
335 return -1;
338 data = calloc(1, sizeof(*data));
339 if (!data) {
340 free(m);
341 return -1;
344 m->match_function = &match_function_regex;
345 m->privdata = (void *)data;
346 m->next = NULL;
348 for (i=0; i<6; i++) {
349 r = compile_regex(&data->regex[i], regex[i], cflags);
350 if (r == -2) {
351 r = i+1;
353 if (r) {
354 USBFreeRegexMatcher(m);
355 return r;
359 *matcher = m;
361 return 0;
364 void USBFreeRegexMatcher(USBDeviceMatcher_t *matcher)
366 int i;
367 regex_matcher_data_t *data;
369 if (!matcher) {
370 return;
373 data = (regex_matcher_data_t *)matcher->privdata;
375 for (i = 0; i < 6; i++) {
376 if (!data->regex[i]) {
377 continue;
380 regfree(data->regex[i]);
381 free(data->regex[i]);
384 free(data);
385 free(matcher);