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