Typos. Mostly by Lintian
[dahdi/tools.git] / xpp / xtalk / xusb_common.c
1 #define _GNU_SOURCE     /* for memrchr() */
2 #include <assert.h>
3 #include <ctype.h>
4 #include <errno.h>
5 #include <stdarg.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <xtalk/debug.h>
9 #include <autoconfig.h>
10 #include "xusb_common.h"
11
12 #define DBG_MASK        0x01
13
14 const char *xusb_tt_name(enum xusb_transfer_type tt)
15 {
16         switch (tt) {
17         case XUSB_TT_BULK: return "BULK";
18         case XUSB_TT_INTERRUPT: return "INTERRUPT";
19         case XUSB_TT_ILLEGAL:
20                 break;
21         }
22         return "ILLEGAL";
23 }
24
25 /* GCC versions before 4.6 did not support neither push and pop on
26  * the diagnostic pragma nor applying it inside a function.
27  */
28 #ifndef HAVE_GCC_PRAGMA_DIAG_STACK
29 #pragma GCC diagnostic ignored "-Wformat-security"
30 #endif
31 int xusb_printf(const struct xusb_iface *iface, int level, int debug_mask,
32         const char *prefix, const char *fmt, ...)
33 {
34         int n;
35         va_list ap;
36         char fmtbuf[BUFSIZ];
37         char tmpbuf[BUFSIZ];
38
39         snprintf(fmtbuf, sizeof(fmtbuf), "%s%03d/%03d[%d] %s",
40                 prefix,
41                 xusb_bus_num(iface->xusb_device),
42                 xusb_device_num(iface->xusb_device),
43                 xusb_interface_num(iface),
44                 fmt);
45         va_start(ap, fmt);
46         n = vsnprintf(tmpbuf, sizeof(tmpbuf), fmtbuf, ap);
47         va_end(ap);
48 #ifdef HAVE_GCC_PRAGMA_DIAG_STACK
49 #pragma GCC diagnostic push
50 #pragma GCC diagnostic ignored "-Wformat-security"
51 #endif
52         log_function(level, debug_mask, tmpbuf);
53 #ifdef HAVE_GCC_PRAGMA_DIAG_STACK
54 #pragma GCC diagnostic pop
55 #endif
56         return n;
57 }
58 #ifndef HAVE_GCC_PRAGMA_DIAG_STACK
59 #pragma GCC diagnostic error "-Wformat-security"
60 #endif
61
62 int xusb_printf_details(const struct xusb_iface *iface, int level, int debug_mask,
63         const char *file, int line, const char *severity, const char *func,
64         const char *fmt, ...)
65 {
66         int n;
67         va_list ap;
68         char prefix[BUFSIZ];
69         char tmpbuf[BUFSIZ];
70
71         va_start(ap, fmt);
72         vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
73         va_end(ap);
74         snprintf(prefix, sizeof(prefix), "%s:%d: %s(%s): ",
75                 file, line, severity, func);
76         va_start(ap, fmt);
77         n = xusb_printf(iface, level, DBG_MASK, prefix, tmpbuf);
78         va_end(ap);
79         return n;
80 }
81
82 void xusb_init_spec(struct xusb_spec *spec, char *name,
83         uint16_t vendor_id, uint16_t product_id)
84 {
85         DBG("Initialize [%02X:%02X] - %s\n", vendor_id, product_id, name);
86         memset(spec, 0, sizeof(*spec));
87         spec->name = name;
88         spec->vendor_id = vendor_id;
89         spec->product_id = product_id;
90 }
91
92 const struct xusb_spec *xusb_device_spec(const struct xusb_device *xusb_device)
93 {
94         return xusb_device->spec;
95 }
96
97 /*
98  * Match the string "tail" as the tail of string "path"
99  * Returns 1 in case they match, 0 otherwise
100  */
101 int match_devpath(const char *path, const char *tail)
102 {
103         int len_path = strlen(path);
104         int len_tail = strlen(tail);
105         int path_offset = len_path - len_tail;
106
107         if (path_offset < 0)
108                 return 0;
109         return strstr(path + path_offset, tail) != NULL;
110 }
111
112 int match_device(const struct xusb_device *xusb_device,
113                 const struct xusb_spec *spec)
114 {
115         assert(xusb_device);
116         DBG("Checking: %04X:%04X: "
117                         "\"%s\"\n",
118                         spec->vendor_id,
119                         spec->product_id,
120                         spec->name);
121         if (xusb_device->idVendor != spec->vendor_id) {
122                 DBG("Wrong vendor id 0x%X\n", xusb_device->idVendor);
123                 return 0;
124         }
125         if (xusb_device->idProduct != spec->product_id) {
126                 DBG("Wrong product id 0x%X\n", xusb_device->idProduct);
127                 return 0;
128         }
129         return  1;
130 }
131
132 struct xusb_device *xusb_deviceof(struct xusb_iface *iface)
133 {
134         return iface->xusb_device;
135 }
136
137 int xusb_is_claimed(struct xusb_iface *iface)
138 {
139         return iface->is_claimed != 0;
140 }
141
142 struct xusb_iface *xusb_interface_of(const struct xusb_device *dev, int num)
143 {
144         return dev->interfaces[num];
145 }
146
147 #define XUSB_IFACE_DUMP(prefix, level, iface) \
148         XUSB_PRINT((iface), level, "%s%d\tep_out=0x%2X ep_in=0x%02X [%s]\n", \
149                         (prefix), \
150                         (iface)->interface_num, \
151                         (iface)->ep_out, \
152                         (iface)->ep_in, \
153                         (iface)->iInterface)
154
155 void xusb_list_dump(struct xlist_node *xusb_list)
156 {
157         struct xlist_node       *curr;
158         struct xusb_device      *xusb_device;
159
160         for (curr = xusb_list->next; curr != xusb_list; curr = curr->next) {
161                 struct xusb_iface **piface;
162
163                 xusb_device = curr->data;
164                 assert(xusb_device);
165                 DBG("%s: usb:ID=%04X:%04X [%s / %s / %s]\n",
166                         xusb_device->devpath_tail,
167                         xusb_device->idVendor,
168                         xusb_device->idProduct,
169                         xusb_device->iManufacturer,
170                         xusb_device->iProduct,
171                         xusb_device->iSerialNumber
172                         );
173                 for (piface = xusb_device->interfaces; *piface; piface++)
174                         XUSB_IFACE_DUMP("\t", DEBUG, *piface);
175         }
176 }
177
178 void xusb_destroy_interface(struct xusb_iface *iface)
179 {
180         if (iface) {
181                 xusb_release(iface);
182                 XUSB_DBG(iface, "MEM: FREE interface\n");
183                 memset(iface, 0, sizeof(*iface));
184                 free(iface);
185                 iface = NULL;
186         }
187 }
188
189 static const char *path_tail(const char *path)
190 {
191         const char      *p;
192
193         assert(path != NULL);
194         /* Find last '/' */
195         p = memrchr(path, '/', strlen(path));
196         if (!p) {
197                 ERR("Missing a '/' in %s\n", path);
198                 return NULL;
199         }
200         /* Search for a '/' before that */
201         p = memrchr(path, '/', p - path);
202         if (!p)
203                 p = path;               /* No more '/' */
204         else
205                 p++;                    /* skip '/' */
206         return p;
207 }
208
209 int xusb_filter_bypath(const struct xusb_device *xusb_device, void *data)
210 {
211         const char      *p;
212         const char      *path = data;
213
214         DBG("%s\n", path);
215         assert(path != NULL);
216         p = path_tail(path);
217         if (strcmp(xusb_device->devpath_tail, p) != 0) {
218                 DBG("%s: device path mismatch (!= '%s')\n",
219                         xusb_device->devpath_tail, p);
220                 return 0;
221         }
222         return 1;
223 }
224
225 struct xusb_iface *xusb_open_one(const struct xusb_spec *specs, int numspecs,
226                 int interface_num,
227                 xusb_filter_t filterfunc, void *data)
228 {
229         struct xlist_node       *xusb_list;
230         struct xlist_node       *curr;
231         int                     num;
232         struct xusb_device      *xusb_device = NULL;
233         struct xusb_iface       *iface = NULL;
234         int ret;
235
236         xusb_list = xusb_find_byproduct(specs, numspecs, filterfunc, data);
237         num = xlist_length(xusb_list);
238         DBG("total %d devices\n", num);
239         switch (num) {
240         case 0:
241                 ERR("No matching device.\n");
242                 break;
243         case 1:
244                 curr = xlist_shift(xusb_list);
245                 xusb_device = curr->data;
246                 xlist_destroy(curr, NULL);
247                 xlist_destroy(xusb_list, NULL);
248                 ret = xusb_claim(xusb_device, interface_num, &iface);
249                 if (ret < 0) {
250                         ERR("%s: Failed claiming interface %d (ret = %d)\n",
251                                 xusb_device->devpath_tail,
252                                 interface_num,
253                                 ret);
254                         xusb_destroy(xusb_device);
255                         return NULL;
256                 }
257                 break;
258         default:
259                 ERR("Too many devices (%d). Aborting.\n", num);
260                 break;
261         }
262         return iface;
263 }
264
265 int xusb_interface_num(const struct xusb_iface *iface)
266 {
267         return iface->interface_num;
268 }
269
270 uint16_t xusb_vendor_id(const struct xusb_device *xusb_device)
271 {
272         return xusb_device->idVendor;
273 }
274
275 uint16_t xusb_product_id(const struct xusb_device *xusb_device)
276 {
277         return  xusb_device->idProduct;
278 }
279
280 size_t xusb_packet_size(const struct xusb_device *xusb_device)
281 {
282         return xusb_device->packet_size;
283 }
284
285 const char *xusb_serial(const struct xusb_device *xusb_device)
286 {
287         return xusb_device->iSerialNumber;
288 }
289
290 const char *xusb_devpath(const struct xusb_device *xusb_device)
291 {
292         return xusb_device->devpath_tail;
293 }
294
295 uint16_t xusb_bus_num(const struct xusb_device *xusb_device)
296 {
297         return xusb_device->bus_num;
298 }
299
300 uint16_t xusb_device_num(const struct xusb_device *xusb_device)
301 {
302         return xusb_device->device_num;
303 }
304
305 const char *xusb_interface_name(const struct xusb_iface *iface)
306 {
307         return iface->iInterface;
308 }
309
310 const char *xusb_manufacturer(const struct xusb_device *xusb_device)
311 {
312         return xusb_device->iManufacturer;
313 }
314
315 const char *xusb_product(const struct xusb_device *xusb_device)
316 {
317         return xusb_device->iProduct;
318 }
319
320 const struct xusb_spec *xusb_spec(const struct xusb_device *xusb_device)
321 {
322         return xusb_device->spec;
323 }
324
325 int xusb_flushread(struct xusb_iface *iface)
326 {
327         char tmpbuf[BUFSIZ];
328         int ret;
329
330         XUSB_DBG(iface, "starting...\n");
331         memset(tmpbuf, 0, BUFSIZ);
332         ret = xusb_recv(iface, tmpbuf, BUFSIZ, 1);
333         if (ret < 0 && ret != -ETIMEDOUT) {
334                 XUSB_ERR(iface, "ret=%d\n", ret);
335                 return ret;
336         } else if (ret > 0) {
337                 XUSB_DBG(iface, "Got %d bytes:\n", ret);
338                 dump_packet(LOG_DEBUG, DBG_MASK, __func__, tmpbuf, ret);
339         }
340         return 0;
341 }
342
343 static int use_clear_halt = 0;
344
345 static int xtalk_one_option(const char *option_string)
346 {
347         if (strcmp(option_string, "use-clear-halt") == 0) {
348                 use_clear_halt = 1;
349                 return 0;
350         }
351         if (strcmp(option_string, "no-use-clear-halt") == 0) {
352                 use_clear_halt = 0;
353                 return 0;
354         }
355         ERR("Unknown XTALK_OPTIONS content: '%s'\n", option_string);
356         return -EINVAL;
357 }
358
359 int xtalk_option_use_clear_halt(void)
360 {
361         return use_clear_halt;
362 }
363
364 static void chomp(char *buf)
365 {
366         char *p;
367         int len;
368
369         if (!buf)
370                 return;
371         len = strlen(buf);
372         for (p = buf + len - 1; p >= buf && isspace(*p); p--)
373                 *p = '\0';
374 }
375
376 static const char *OPTION_VAR = "XTALK_OPTIONS";
377
378 /* Caller should free the returned string if it is not NULL */
379 static char *read_options(const char *fname)
380 {
381         FILE *fp;
382         char buf[BUFSIZ];
383         char *p;
384         char *ret_buf;
385
386         fp = fopen(fname, "r");
387         if (!fp) {
388                 DBG("Failed opening '$fname': %s\n", strerror(errno));
389                 return NULL;
390         }
391         while (fgets(buf, sizeof(buf), fp) != NULL) {
392                 chomp(buf);
393                 if (buf[0] == '\0' || buf[0] == '#')
394                         continue;
395                 if (strncmp(buf, OPTION_VAR, strlen(OPTION_VAR)) != 0)
396                         continue;
397                 /* fprintf(stderr, "INPUT> '%s'\n", p); */
398                 p = buf + strlen(OPTION_VAR);
399                 while (*p && (isspace(*p) || *p == '='))
400                         p++;
401                 ret_buf = malloc(sizeof(buf));
402                 strcpy(ret_buf, p); /* Cannot overflow */
403                 return ret_buf;
404         }
405         fclose(fp);
406         return NULL;
407 }
408
409 int xtalk_parse_options(void)
410 {
411         char *xtalk_options;
412         char *saveptr;
413         char *token;
414         int ret;
415         int free_options = 0;
416
417         xtalk_options = getenv("XTALK_OPTIONS");
418         if (!xtalk_options) {
419                 xtalk_options = read_options(XTALK_OPTIONS_FILE);
420                 if (!xtalk_options)
421                         return 0;
422                 free_options = 1;
423         }
424         token = strtok_r(xtalk_options, " \t", &saveptr);
425         while (token) {
426                 ret = xtalk_one_option(token);
427                 if (ret < 0)
428                         return ret;
429                 token = strtok_r(NULL, " \t", &saveptr);
430         }
431         if (free_options)
432                 free(xtalk_options);
433         return 0;
434 }