2001-07-13 19:08:15 +00:00
|
|
|
/*
|
|
|
|
* Hamlib Interface - provides registering for dynamically loadable backends.
|
|
|
|
* Copyright (c) 2000,2001 by Stephane Fillod and Frank Singleton
|
|
|
|
*
|
2001-12-16 11:14:47 +00:00
|
|
|
* $Id: register.c,v 1.11 2001-12-16 11:14:46 fillods Exp $
|
2001-07-13 19:08:15 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Library General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*
|
2000-10-08 21:20:44 +00:00
|
|
|
*/
|
|
|
|
|
2001-02-11 23:15:38 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
2000-10-08 21:20:44 +00:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
2001-06-02 17:54:43 +00:00
|
|
|
/* This is libtool's dl wrapper */
|
|
|
|
#include <ltdl.h>
|
2000-10-08 21:20:44 +00:00
|
|
|
|
|
|
|
#include <hamlib/rig.h>
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef PATH_MAX
|
|
|
|
# define PATH_MAX 1024
|
|
|
|
#endif
|
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
#define RIG_BACKEND_MAX 32
|
2000-10-08 21:20:44 +00:00
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
/*
|
|
|
|
* RIG_BACKEND_LIST is defined in riglist.h, please keep it up to data,
|
|
|
|
* ie. each time you give birth to a new backend
|
|
|
|
* Also, it should be possible to register "external" backend,
|
|
|
|
* that is backend that were not known by Hamlib at compile time.
|
|
|
|
* Maybe, riglist.h should reserve some numbers for them? --SF
|
|
|
|
*/
|
|
|
|
static struct {
|
|
|
|
int be_num;
|
|
|
|
const char *be_name;
|
|
|
|
rig_model_t (*be_probe)(port_t *);
|
|
|
|
} rig_backend_list[RIG_BACKEND_MAX] = RIG_BACKEND_LIST;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This struct to keep track of known rig models.
|
|
|
|
* It is chained, and used in a hash table, see below.
|
|
|
|
*/
|
2000-10-08 21:20:44 +00:00
|
|
|
struct rig_list {
|
|
|
|
const struct rig_caps *caps;
|
2001-06-02 17:54:43 +00:00
|
|
|
lt_dlhandle handle; /* handle returned by lt_dlopen() */
|
2000-10-08 21:20:44 +00:00
|
|
|
struct rig_list *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define RIGLSTHASHSZ 16
|
|
|
|
#define HASH_FUNC(a) ((a)%RIGLSTHASHSZ)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The rig_hash_table is a hash table pointing to a list of next==NULL
|
|
|
|
* terminated caps.
|
|
|
|
*/
|
|
|
|
static struct rig_list *rig_hash_table[RIGLSTHASHSZ] = { NULL, };
|
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
|
|
|
|
static int rig_lookup_backend(rig_model_t rig_model);
|
|
|
|
|
2000-10-08 21:20:44 +00:00
|
|
|
/*
|
|
|
|
* Basically, this is a hash insert function that doesn't check for dup!
|
|
|
|
*/
|
|
|
|
int rig_register(const struct rig_caps *caps)
|
|
|
|
{
|
|
|
|
int hval;
|
|
|
|
struct rig_list *p;
|
|
|
|
|
|
|
|
if (!caps)
|
|
|
|
return -RIG_EINVAL;
|
|
|
|
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "rig_register (%d)\n",caps->rig_model);
|
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
#ifndef DONT_WANT_DUP_CHECK
|
2000-10-08 21:20:44 +00:00
|
|
|
if (rig_get_caps(caps->rig_model)!=NULL)
|
|
|
|
return -RIG_EINVAL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
p = (struct rig_list*)malloc(sizeof(struct rig_list));
|
|
|
|
if (!p)
|
|
|
|
return -RIG_ENOMEM;
|
|
|
|
|
|
|
|
hval = HASH_FUNC(caps->rig_model);
|
|
|
|
p->caps = caps;
|
|
|
|
p->handle = NULL;
|
|
|
|
p->next = rig_hash_table[hval];
|
|
|
|
rig_hash_table[hval] = p;
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get rig capabilities.
|
|
|
|
* ie. rig_hash_table lookup
|
|
|
|
*/
|
|
|
|
|
|
|
|
const struct rig_caps *rig_get_caps(rig_model_t rig_model)
|
|
|
|
{
|
|
|
|
struct rig_list *p;
|
|
|
|
|
|
|
|
for (p = rig_hash_table[HASH_FUNC(rig_model)]; p; p=p->next) {
|
|
|
|
if (p->caps->rig_model == rig_model)
|
|
|
|
return p->caps;
|
|
|
|
}
|
|
|
|
return NULL; /* sorry, caps not registered! */
|
|
|
|
}
|
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
/*
|
|
|
|
* lookup for backend index in rig_backend_list table,
|
|
|
|
* according to BACKEND_NUM
|
|
|
|
* return -1 if not found.
|
|
|
|
*/
|
|
|
|
static int rig_lookup_backend(rig_model_t rig_model)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i<RIG_BACKEND_MAX && rig_backend_list[i].be_name; i++) {
|
|
|
|
if (RIG_BACKEND_NUM(rig_model) ==
|
|
|
|
rig_backend_list[i].be_num)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* rig_check_backend
|
|
|
|
* check the backend declaring this model has been loaded
|
|
|
|
* and if not loaded already, load it!
|
|
|
|
* This permits seamless operation in rig_init.
|
|
|
|
*/
|
|
|
|
int rig_check_backend(rig_model_t rig_model)
|
|
|
|
{
|
|
|
|
const struct rig_caps *caps;
|
|
|
|
int be_idx;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
/* already loaded ? */
|
|
|
|
caps = rig_get_caps(rig_model);
|
|
|
|
if (caps)
|
|
|
|
return RIG_OK;
|
|
|
|
|
|
|
|
be_idx = rig_lookup_backend(rig_model);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Never heard about this backend family!
|
|
|
|
*/
|
|
|
|
if (be_idx == -1) {
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "rig_check_backend: unsupported "
|
|
|
|
"backend %d for model %d\n",
|
|
|
|
RIG_BACKEND_NUM(rig_model), rig_model
|
|
|
|
);
|
|
|
|
return -RIG_ENAVAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = rig_load_backend(rig_backend_list[be_idx].be_name);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-10-08 21:20:44 +00:00
|
|
|
|
|
|
|
int rig_unregister(rig_model_t rig_model)
|
|
|
|
{
|
|
|
|
int hval;
|
|
|
|
struct rig_list *p,*q;
|
|
|
|
|
|
|
|
hval = HASH_FUNC(rig_model);
|
|
|
|
q = NULL;
|
|
|
|
for (p = rig_hash_table[hval]; p; p=p->next) {
|
|
|
|
if (p->caps->rig_model == rig_model) {
|
|
|
|
if (q == NULL)
|
|
|
|
rig_hash_table[hval] = p->next;
|
|
|
|
else
|
|
|
|
q->next = p->next;
|
|
|
|
free(p);
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
q = p;
|
|
|
|
}
|
|
|
|
return -RIG_EINVAL; /* sorry, caps not registered! */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* rig_list_foreach
|
|
|
|
* executes cfunc on all the elements stored in the rig hash list
|
|
|
|
*/
|
2001-06-11 00:41:28 +00:00
|
|
|
int rig_list_foreach(int (*cfunc)(const struct rig_caps*, rig_ptr_t),rig_ptr_t data)
|
2000-10-08 21:20:44 +00:00
|
|
|
{
|
|
|
|
struct rig_list *p;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!cfunc)
|
|
|
|
return -RIG_EINVAL;
|
|
|
|
|
|
|
|
for (i=0; i<RIGLSTHASHSZ; i++) {
|
|
|
|
for (p=rig_hash_table[i]; p; p=p->next)
|
|
|
|
if ((*cfunc)(p->caps,data) == 0)
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
/*
|
|
|
|
* rig_probe_all
|
|
|
|
* called straight by rig_probe
|
|
|
|
*/
|
|
|
|
rig_model_t rig_probe_all(port_t *p)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
rig_model_t rig_model;
|
|
|
|
|
|
|
|
for (i=0; i<RIG_BACKEND_MAX && rig_backend_list[i].be_name; i++) {
|
|
|
|
if (rig_backend_list[i].be_probe) {
|
|
|
|
rig_model = (*rig_backend_list[i].be_probe)(p);
|
|
|
|
if (rig_model != RIG_MODEL_NONE)
|
|
|
|
return rig_model;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return RIG_MODEL_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int rig_load_all_backends()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i<RIG_BACKEND_MAX && rig_backend_list[i].be_name; i++) {
|
|
|
|
rig_load_backend(rig_backend_list[i].be_name);
|
|
|
|
}
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define MAXFUNCNAMELEN 64
|
2000-10-08 21:20:44 +00:00
|
|
|
/*
|
|
|
|
* rig_load_backend
|
|
|
|
* Dynamically load a rig backend through dlopen mechanism
|
|
|
|
*/
|
|
|
|
int rig_load_backend(const char *be_name)
|
|
|
|
{
|
2001-07-06 08:17:48 +00:00
|
|
|
/*
|
|
|
|
* determine PREFIX and POSTFIX values from configure script
|
|
|
|
*/
|
|
|
|
#ifdef __CYGWIN__
|
|
|
|
# define PREFIX "cyghamlib-"
|
|
|
|
# define POSTFIX ".dll"
|
|
|
|
#else
|
2000-10-08 21:20:44 +00:00
|
|
|
# define PREFIX "libhamlib-"
|
2001-09-19 21:58:33 +00:00
|
|
|
# define POSTFIX ".la"
|
2001-07-06 08:17:48 +00:00
|
|
|
#endif
|
2001-09-19 21:58:33 +00:00
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
lt_dlhandle be_handle;
|
2001-06-11 00:41:28 +00:00
|
|
|
int (*be_init)(rig_ptr_t);
|
2001-06-04 21:17:53 +00:00
|
|
|
int status;
|
|
|
|
char libname[PATH_MAX];
|
|
|
|
char initfname[MAXFUNCNAMELEN] = "init_";
|
|
|
|
char probefname[MAXFUNCNAMELEN] = "probe_";
|
|
|
|
int i;
|
2000-10-08 21:20:44 +00:00
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
/*
|
|
|
|
* lt_dlinit may be called several times
|
|
|
|
*/
|
2001-06-11 00:41:28 +00:00
|
|
|
LTDL_SET_PRELOADED_SYMBOLS();
|
2001-12-16 11:14:47 +00:00
|
|
|
|
2001-06-02 17:54:43 +00:00
|
|
|
status = lt_dlinit();
|
|
|
|
if (status) {
|
2001-06-04 21:17:53 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "rig_backend_load: lt_dlinit for %s "
|
2001-12-16 11:14:47 +00:00
|
|
|
"failed: %s\n", be_name, lt_dlerror());
|
2001-06-02 17:54:43 +00:00
|
|
|
return -RIG_EINTERNAL;
|
|
|
|
}
|
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "rig: loading backend %s\n",be_name);
|
2000-10-08 21:20:44 +00:00
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
/*
|
|
|
|
* add hamlib directory here
|
|
|
|
*/
|
2001-12-16 11:14:47 +00:00
|
|
|
#ifdef HAMLIB_DLL
|
2001-06-04 21:17:53 +00:00
|
|
|
snprintf (libname, sizeof (libname), PREFIX"%s"POSTFIX, be_name);
|
|
|
|
|
|
|
|
be_handle = lt_dlopen (libname);
|
2001-12-16 11:14:47 +00:00
|
|
|
#else
|
|
|
|
be_handle = lt_dlopen (NULL);
|
|
|
|
#endif
|
2001-06-04 21:17:53 +00:00
|
|
|
|
|
|
|
if (!be_handle) {
|
2001-12-16 11:14:47 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "rig: lt_dlopen(\"%s\") failed (%s)\n",
|
2001-06-04 21:17:53 +00:00
|
|
|
libname, lt_dlerror());
|
|
|
|
return -RIG_EINVAL;
|
|
|
|
}
|
2001-06-02 17:54:43 +00:00
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
strncat(initfname, be_name, MAXFUNCNAMELEN);
|
2001-06-11 00:41:28 +00:00
|
|
|
be_init = (int (*)(rig_ptr_t)) lt_dlsym (be_handle, initfname);
|
2001-06-04 21:17:53 +00:00
|
|
|
if (!be_init) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "rig: dlsym(%s) failed (%s)\n",
|
|
|
|
initfname, lt_dlerror());
|
|
|
|
lt_dlclose(be_handle);
|
2000-10-08 21:20:44 +00:00
|
|
|
return -RIG_EINVAL;
|
2001-06-04 21:17:53 +00:00
|
|
|
}
|
2000-10-08 21:20:44 +00:00
|
|
|
|
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
/*
|
|
|
|
* register probe function if present
|
|
|
|
* NOTE: rig_load_backend might have been called upon a backend
|
|
|
|
* not in riglist.h! In this case, do nothing.
|
|
|
|
*/
|
|
|
|
for (i=0; i<RIG_BACKEND_MAX && rig_backend_list[i].be_name; i++) {
|
|
|
|
if (!strncmp(be_name, rig_backend_list[i].be_name, 64)) {
|
|
|
|
strncat(probefname, be_name, MAXFUNCNAMELEN);
|
|
|
|
rig_backend_list[i].be_probe = (rig_model_t (*)(port_t *))
|
|
|
|
lt_dlsym (be_handle, probefname);
|
|
|
|
break;
|
2000-10-08 21:20:44 +00:00
|
|
|
}
|
2001-06-04 21:17:53 +00:00
|
|
|
}
|
2000-10-08 21:20:44 +00:00
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
status = (*be_init)(be_handle);
|
2000-10-08 21:20:44 +00:00
|
|
|
|
2001-06-04 21:17:53 +00:00
|
|
|
return status;
|
2000-10-08 21:20:44 +00:00
|
|
|
}
|
|
|
|
|