1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id$ */
3
4 /* libticables2 - link cable library, a part of the TiLP project
5 * Copyright (C) 1999-2005 Romain Lievin
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 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #if defined(__WIN32__)
31 #include <windows.h>
32 #endif
33 #include <locale.h>
34 #ifdef __LINUX__
35 #include <sys/utsname.h>
36 #endif
37
38 #ifdef _MSC_VER
39 # include "./win32/usb.h"
40 #elif defined(HAVE_LIBUSB)
41 # include <usb.h>
42 #elif defined(HAVE_LIBUSB_1_0)
43 # include <libusb.h>
44 #endif
45
46 #include "gettext.h"
47 #include "ticables.h"
48 #include "internal.h"
49 #include "logging.h"
50 #include "error.h"
51 #include "link_xxx.h"
52 #include "data_log.h"
53
54 /*****************/
55 /* Internal data */
56 /*****************/
57
58 static CableFncts const *const cables[] =
59 {
60 &cable_nul,
61 #ifndef NO_CABLE_GRY
62 &cable_gry,
63 #endif
64 #if !defined(NO_CABLE_BLK) && !defined(__MACOSX__)
65 &cable_ser,
66 #endif
67 #if !defined(NO_CABLE_PAR) && (defined(HAVE_LINUX_PARPORT_H) || defined(__WIN32__))
68 &cable_par,
69 #endif
70 #if !defined(NO_CABLE_SLV) && (defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0) || defined(__WIN32__))
71 &cable_slv,
72 #endif
73 #if !defined(NO_CABLE_SLV) && (defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0) || defined(__WIN32__))
74 &cable_raw,
75 #endif
76 #ifndef NO_CABLE_VTI
77 &cable_vti,
78 #endif
79 #ifndef NO_CABLE_TIE
80 &cable_tie,
81 #endif
82 &cable_ilp,
83 &cable_nul, // Dead cable
84 #if !defined(NO_CABLE_TCPC) && !defined(__WIN32__)
85 &cable_tcpc,
86 #endif
87 #if !defined(NO_CABLE_TCPS) && !defined(__WIN32__)
88 &cable_tcps,
89 #endif
90 NULL
91 };
92
93 static const uint32_t supported_cables =
94 (1U << CABLE_NUL)
95 #ifndef NO_CABLE_GRY
96 | (1U << CABLE_GRY)
97 #endif
98 #if !defined(NO_CABLE_BLK) && !defined(__MACOSX__)
99 | (1U << CABLE_BLK)
100 #endif
101 #if !defined(NO_CABLE_PAR) && (defined(HAVE_LINUX_PARPORT_H) || defined(__WIN32__))
102 | (1U << CABLE_PAR)
103 #endif
104 #if !defined(NO_CABLE_SLV) && (defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0) || defined(__WIN32__))
105 | (1U << CABLE_SLV)
106 #endif
107 #if !defined(NO_CABLE_SLV) && (defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0) || defined(__WIN32__))
108 | (1U << CABLE_USB)
109 #endif
110 #ifndef NO_CABLE_VTI
111 | (1U << CABLE_VTI)
112 #endif
113 #ifndef NO_CABLE_TIE
114 | (1U << CABLE_TIE)
115 #endif
116 | (1U << CABLE_ILP)
117 // | (1U << CABLE_DEV) Dead cable
118 #if !defined(NO_CABLE_TCPC) && !defined(__WIN32__)
119 | (1U << CABLE_TCPC)
120 #endif
121 #if !defined(NO_CABLE_TCPS) && !defined(__WIN32__)
122 | (1U << CABLE_TCPS)
123 #endif
124 ;
125
126 /****************/
127 /* Entry points */
128 /****************/
129
130 // not static, must be shared between instances
131 int ticables_instance = 0; // counts # of instances
132 #ifdef HAVE_LIBUSB_1_0
133 int libusb_working = -1;
134 #endif
135
136 /**
137 * ticables_library_init:
138 *
139 * This function must be the first one to call. It inits library internals.
140 *
141 * Return value: the instance count.
142 **/
ticables_library_init(void)143 TIEXPORT1 int TICALL ticables_library_init(void)
144 {
145 char locale_dir[65536];
146
147 #ifdef __WIN32__
148 HANDLE hDll;
149 int i;
150
151 hDll = GetModuleHandle("libticables2-7.dll");
152 GetModuleFileName(hDll, locale_dir, 65515);
153
154 for (i = strlen(locale_dir); i >= 0; i--)
155 {
156 if (locale_dir[i] == '\\')
157 {
158 break;
159 }
160 }
161 locale_dir[i] = '\0';
162
163 #ifdef __MINGW32__
164 strcat(locale_dir, "\\..\\share\\locale");
165 #else
166 strcat(locale_dir, "\\locale");
167 #endif
168 #else
169 strncpy(locale_dir, LOCALEDIR, sizeof(locale_dir) - 21);
170 #endif
171
172 if (ticables_instance)
173 {
174 return (++ticables_instance);
175 }
176 ticables_info(_("ticables library version %s"), libticables2_VERSION);
177 errno = 0;
178
179 #if defined(ENABLE_NLS)
180 ticables_info("setlocale: %s", setlocale(LC_ALL, ""));
181 ticables_info("bindtextdomain: %s", bindtextdomain(PACKAGE, locale_dir));
182 bind_textdomain_codeset(PACKAGE, "UTF-8"/*"ISO-8859-15"*/);
183 ticables_info("textdomain: %s", textdomain(NULL));
184 #endif
185 #ifdef __LINUX__
186 {
187 struct utsname buf;
188
189 uname(&buf);
190 ticables_info("kernel: %s", buf.release);
191 }
192 #endif
193 #if defined(HAVE_LIBUSB)
194 // init libusb
195 usb_init();
196 #elif defined(HAVE_LIBUSB_1_0)
197 // init libusb, keeping track of success / failure status
198 libusb_working = libusb_init(NULL);
199 if (libusb_working == LIBUSB_SUCCESS) {
200 libusb_set_debug(NULL, 3);
201 }
202 #endif
203
204 return (++ticables_instance);
205 }
206
207
208 /**
209 * ticables_library_exit:
210 *
211 * This function must be the last one to call. Used to release internal resources.
212 *
213 * Return value: the instance count.
214 **/
ticables_library_exit(void)215 TIEXPORT1 int TICALL ticables_library_exit(void)
216 {
217 #if defined(HAVE_LIBUSB)
218 // No exit function for libusb 0.1.x.
219 #elif defined(HAVE_LIBUSB_1_0)
220 // Must not call libusb_exit() if libusb_init() failed, or call it multiple times.
221 if (ticables_instance == 1 && libusb_working == LIBUSB_SUCCESS) {
222 libusb_exit(NULL);
223 }
224 #endif
225 return (--ticables_instance);
226 }
227
228 /***********/
229 /* Methods */
230 /***********/
231
232 /**
233 * ticables_version_get:
234 *
235 * This function returns the library version like "X.Y.Z".
236 *
237 * Return value: a string.
238 **/
ticables_version_get(void)239 TIEXPORT1 const char *TICALL ticables_version_get(void)
240 {
241 return libticables2_VERSION;
242 }
243
244 /**
245 * ticables_supported_cables:
246 *
247 * This function returns the cables built into the current binary.
248 *
249 * Return value: an integer containing a binary OR of (1 << CABLE_*) values,
250 * where CABLE_* values are defined in enum CableModel.
251 **/
ticables_supported_cables(void)252 TIEXPORT1 uint32_t TICALL ticables_supported_cables (void)
253 {
254 return supported_cables;
255 }
256
default_pre_send_hook(CableHandle * handle,uint8_t * data,uint32_t len)257 static int default_pre_send_hook(CableHandle * handle, uint8_t * data, uint32_t len)
258 {
259 (void)handle, (void)data, (void)len;
260 return 0;
261 }
262
default_post_send_hook(CableHandle * handle,uint8_t * data,uint32_t len,int retval)263 static int default_post_send_hook(CableHandle * handle, uint8_t * data, uint32_t len, int retval)
264 {
265 LOG_N_DATA(handle, LOG_OUT, data, len);
266 return retval;
267 }
268
default_pre_recv_hook(CableHandle * handle,uint8_t * data,uint32_t len)269 static int default_pre_recv_hook(CableHandle * handle, uint8_t * data, uint32_t len)
270 {
271 (void)handle, (void)data, (void)len;
272 return 0;
273 }
274
default_post_recv_hook(CableHandle * handle,uint8_t * data,uint32_t len,int retval)275 static int default_post_recv_hook(CableHandle * handle, uint8_t * data, uint32_t len, int retval)
276 {
277 LOG_N_DATA(handle, LOG_IN, data, len);
278 return retval;
279 }
280
281 /**
282 * ticables_handle_new:
283 * @model: a cable model
284 * @port: the generic port on which cable is attached.
285 *
286 * Create a new handle associated with the given cable on the given port.
287 * Must be freed with ticables_handle_del when no longer needed.
288 * Note: the handle is a pointer on an opaque structure and should not be modified.
289 *
290 * Return value: NULL if error, an handle otherwise.
291 **/
ticables_handle_new(CableModel model,CablePort port)292 TIEXPORT1 CableHandle* TICALL ticables_handle_new(CableModel model, CablePort port)
293 {
294 CableHandle *handle = (CableHandle *)calloc(1, sizeof(CableHandle));
295 int i;
296
297 handle->model = model;
298 handle->port = port;
299
300 handle->delay = DFLT_DELAY;
301 handle->timeout = DFLT_TIMEOUT;
302
303 for (i = 0; cables[i] != NULL; i++)
304 {
305 if (cables[i]->model == (const int)model)
306 {
307 handle->cable = (CableFncts *)cables[i];
308 break;
309 }
310 }
311
312 if (handle->cable == NULL)
313 {
314 free(handle);
315 handle = NULL;
316 }
317
318 if (handle != NULL)
319 {
320 handle->pre_send_hook = default_pre_send_hook;
321 handle->post_send_hook = default_post_send_hook;
322 handle->pre_recv_hook = default_pre_recv_hook;
323 handle->post_recv_hook = default_post_recv_hook;
324 }
325
326 return handle;
327 }
328
329 /**
330 * ticables_handle_del:
331 * @handle: the handle
332 *
333 * Release the cable and free the associated resources.
334 *
335 * Return value: always 0.
336 **/
ticables_handle_del(CableHandle * handle)337 TIEXPORT1 int TICALL ticables_handle_del(CableHandle* handle)
338 {
339 VALIDATE_HANDLE(handle);
340
341 free(handle->priv2);
342 handle->priv2 = NULL;
343
344 free(handle->device);
345 handle->device = NULL;
346
347 memset((void *)handle, 0, sizeof(*handle));
348 free(handle);
349
350 return 0;
351 }
352
353 /**
354 * ticables_options_set_timeout:
355 * @handle: the handle
356 * @timeout: timeout value in tenth of seconds
357 *
358 * Set timeout for any cable.
359 *
360 * Return value: the previous timeout.
361 **/
ticables_options_set_timeout(CableHandle * handle,unsigned int timeout)362 TIEXPORT1 unsigned int TICALL ticables_options_set_timeout(CableHandle* handle, unsigned int timeout)
363 {
364 if (handle != NULL)
365 {
366 const CableFncts *cable;
367 unsigned int old_timeout = handle->timeout;
368
369 handle->timeout = timeout;
370 cable = handle->cable;
371
372 if(!handle->open)
373 {
374 return -1;
375 }
376 if(handle->busy)
377 {
378 return ERR_BUSY;
379 }
380
381 handle->busy = 1;
382 if(cable->timeout)
383 {
384 cable->timeout(handle);
385 }
386 handle->busy = 0;
387
388 return old_timeout;
389 }
390 else
391 {
392 ticables_critical("%s: handle is NULL", __FUNCTION__);
393 return 0;
394 }
395 }
396
397 /**
398 * ticables_options_set_delay:
399 * @handle: the handle
400 * @delay: delay in micro-seconds
401 *
402 * Set inter-bit delay for parallel or BlackLink cable.
403 *
404 * Return value: the previous delay.
405 **/
ticables_options_set_delay(CableHandle * handle,unsigned int delay)406 TIEXPORT1 unsigned int TICALL ticables_options_set_delay(CableHandle* handle, unsigned int delay)
407 {
408 if (handle != NULL)
409 {
410 unsigned int old_delay = handle->delay;
411 handle->delay = delay;
412 return old_delay;
413 }
414 else
415 {
416 ticables_critical("%s: handle is NULL", __FUNCTION__);
417 return 0;
418 }
419 }
420
421 /**
422 * ticables_get_model:
423 * @handle: the handle
424 *
425 * Retrieve link cable model.
426 *
427 * Return value: the previous #CableModel value.
428 **/
ticables_get_model(CableHandle * handle)429 TIEXPORT1 CableModel TICALL ticables_get_model(CableHandle* handle)
430 {
431 if (handle != NULL)
432 {
433 return handle->model;
434 }
435 else
436 {
437 ticables_critical("%s(NULL)", __FUNCTION__);
438 return 0;
439 }
440 }
441
442 /**
443 * ticables_get_port:
444 * @handle: the handle
445 *
446 * Retrieve link port.
447 *
448 * Return value: a #CablePort value.
449 **/
ticables_get_port(CableHandle * handle)450 TIEXPORT1 CablePort TICALL ticables_get_port(CableHandle* handle)
451 {
452 if (handle != NULL)
453 {
454 return handle->port;
455 }
456 else
457 {
458 ticables_critical("%s(NULL)", __FUNCTION__);
459 return 0;
460 }
461 }
462
463 /**
464 * ticables_get_device:
465 * @handle: the handle
466 *
467 * Retrieve device port.
468 *
469 * Return value: a char pointer.
470 **/
ticables_get_device(CableHandle * handle)471 TIEXPORT1 const char * TICALL ticables_get_device(CableHandle* handle)
472 {
473 if (handle != NULL)
474 {
475 return handle->device;
476 }
477 else
478 {
479 ticables_critical("%s(NULL)", __FUNCTION__);
480 return 0;
481 }
482 }
483
484 /**
485 * ticables_get_timeout:
486 * @handle: the handle
487 *
488 * Retrieve timeout.
489 *
490 * Return value: an unsigned integer;
491 **/
ticables_get_timeout(CableHandle * handle)492 TIEXPORT1 unsigned int TICALL ticables_get_timeout(CableHandle *handle)
493 {
494 if (handle != NULL)
495 {
496 return handle->timeout;
497 }
498 else
499 {
500 ticables_critical("%s(NULL)", __FUNCTION__);
501 return 0;
502 }
503 }
504
505 /**
506 * ticables_get_delay:
507 * @handle: the handle
508 *
509 * Retrieve timeout.
510 *
511 * Return value: an unsigned integer;
512 **/
ticables_get_delay(CableHandle * handle)513 TIEXPORT1 unsigned int TICALL ticables_get_delay(CableHandle *handle)
514 {
515 if (handle != NULL)
516 {
517 return handle->delay;
518 }
519 else
520 {
521 ticables_critical("%s(NULL)", __FUNCTION__);
522 return 0;
523 }
524 }
525
526 /**
527 * ticables_handle_show:
528 * @handle: the handle
529 *
530 * Show information stored in the handle.
531 *
532 * Return value: always 0.
533 **/
ticables_handle_show(CableHandle * handle)534 TIEXPORT1 int TICALL ticables_handle_show(CableHandle* handle)
535 {
536 if (handle != NULL)
537 {
538 ticables_info(_("Link cable handle details:"));
539 ticables_info(_(" model : %s"), ticables_model_to_string(handle->model));
540 ticables_info(_(" port : %s"), ticables_port_to_string(handle->port));
541 ticables_info(_(" timeout : %2.1fs"), (float)handle->timeout / 10);
542 ticables_info(_(" delay : %i us"), handle->delay);
543 if(handle->device)
544 {
545 ticables_info(_(" device : %s"), handle->device);
546 ticables_info(_(" address : 0x%03x"), handle->address);
547 }
548 }
549 else
550 {
551 ticables_critical("%s(NULL)", __FUNCTION__);
552 }
553
554 return 0;
555 }
556