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
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
) {
34 /* flag as possibly supported if we see a known vendor */
35 retval
= POSSIBLY_SUPPORTED
;
37 if (usbdev
->productID
!= device
->ProductID
) {
41 /* call the specific handler, if it exists */
42 if (usbdev
->fun
!= NULL
) {
43 (*usbdev
->fun
)(device
);
52 /* ---------------------------------------------------------------------- */
55 /* helper function: version of strcmp that tolerates NULL
56 * pointers. NULL is considered to come before all other strings
59 static int strcmp_null(char *s1
, char *s2
)
61 if (s1
== NULL
&& s2
== NULL
) {
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
) {
86 if (hd
->ProductID
!= data
->ProductID
) {
90 if (strcmp_null(hd
->Vendor
, data
->Vendor
) != 0) {
94 if (strcmp_null(hd
->Product
, data
->Product
) != 0) {
98 if (strcmp_null(hd
->Serial
, data
->Serial
) != 0) {
101 #ifdef DEBUG_EXACT_MATCH_BUS
102 if (strcmp_null(hd
->Bus
, data
->Bus
) != 0) {
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
;
118 m
= malloc(sizeof(*m
));
123 data
= calloc(1, sizeof(*data
));
129 m
->match_function
= &match_function_exact
;
130 m
->privdata
= (void *)data
;
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
;
146 /* destructor: free matcher previously created with USBNewExactMatcher */
147 void USBFreeExactMatcher(USBDeviceMatcher_t
*matcher
)
155 data
= (USBDevice_t
*)matcher
->privdata
;
160 #ifdef DEBUG_EXACT_MATCH_BUS
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
177 static int compile_regex(regex_t
**compiled
, char *regex
, int cflags
)
187 preg
= malloc(sizeof(*preg
));
192 r
= regcomp(preg
, regex
, cflags
);
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
)
222 string
= xstrdup("");
224 /* skip leading whitespace */
225 for (len
= 0; len
< strlen(str
); len
++) {
227 if (!strchr(" \t\n", str
[len
])) {
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])) {
245 /* test the regular expression */
246 r
= regexec(preg
, string
, 1, &match
, 0);
252 /* check that the match is the entire string */
253 if ((match
.rm_so
!= 0) || (match
.rm_eo
!= (int)len
)) {
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
)
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
{
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
;
283 r
= match_regex_hex(data
->regex
[0], hd
->VendorID
);
288 r
= match_regex_hex(data
->regex
[1], hd
->ProductID
);
293 r
= match_regex(data
->regex
[2], hd
->Vendor
);
298 r
= match_regex(data
->regex
[3], hd
->Product
);
303 r
= match_regex(data
->regex
[4], hd
->Serial
);
308 r
= match_regex(data
->regex
[5], hd
->Bus
);
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
327 int USBNewRegexMatcher(USBDeviceMatcher_t
**matcher
, char **regex
, int cflags
)
330 USBDeviceMatcher_t
*m
;
331 regex_matcher_data_t
*data
;
333 m
= malloc(sizeof(*m
));
338 data
= calloc(1, sizeof(*data
));
344 m
->match_function
= &match_function_regex
;
345 m
->privdata
= (void *)data
;
348 for (i
=0; i
<6; i
++) {
349 r
= compile_regex(&data
->regex
[i
], regex
[i
], cflags
);
354 USBFreeRegexMatcher(m
);
364 void USBFreeRegexMatcher(USBDeviceMatcher_t
*matcher
)
367 regex_matcher_data_t
*data
;
373 data
= (regex_matcher_data_t
*)matcher
->privdata
;
375 for (i
= 0; i
< 6; i
++) {
376 if (!data
->regex
[i
]) {
380 regfree(data
->regex
[i
]);
381 free(data
->regex
[i
]);