2008-03-13 11:02:41 +00:00
|
|
|
/*
|
|
|
|
* CAPI 2.0 library
|
|
|
|
*
|
|
|
|
* 2002-03-27 - Added remote capi features.
|
|
|
|
* Armin Schindler <armin@melware.de>
|
|
|
|
*
|
|
|
|
* This program is free software and may be modified and
|
|
|
|
* distributed under the terms of the GNU Public License.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#define _LINUX_LIST_H
|
|
|
|
#include <linux/capi.h>
|
|
|
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
|
|
|
|
#include "capi20.h"
|
|
|
|
|
|
|
|
#ifndef CAPI_GET_FLAGS
|
|
|
|
#define CAPI_GET_FLAGS _IOR('C',0x23, unsigned)
|
|
|
|
#endif
|
|
|
|
#ifndef CAPI_SET_FLAGS
|
|
|
|
#define CAPI_SET_FLAGS _IOR('C',0x24, unsigned)
|
|
|
|
#endif
|
|
|
|
#ifndef CAPI_CLR_FLAGS
|
|
|
|
#define CAPI_CLR_FLAGS _IOR('C',0x25, unsigned)
|
|
|
|
#endif
|
|
|
|
#ifndef CAPI_NCCI_OPENCOUNT
|
|
|
|
#define CAPI_NCCI_OPENCOUNT _IOR('C',0x26, unsigned)
|
|
|
|
#endif
|
|
|
|
#ifndef CAPI_NCCI_GETUNIT
|
|
|
|
#define CAPI_NCCI_GETUNIT _IOR('C',0x27, unsigned)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define SEND_BUFSIZ (128+2048)
|
|
|
|
|
|
|
|
static char capidevname[] = "/dev/capi20";
|
|
|
|
static char capidevnamenew[] = "/dev/isdn/capi20";
|
|
|
|
|
|
|
|
static int capi_fd = -1;
|
|
|
|
static capi_ioctl_struct ioctl_data;
|
|
|
|
|
|
|
|
static int remote_capi;
|
|
|
|
static char *globalconfigfilename = "/etc/capi20.conf";
|
|
|
|
static char *userconfigfilename = ".capi20rc";
|
|
|
|
static unsigned short int port;
|
|
|
|
static char hostname[1024];
|
|
|
|
static int tracelevel;
|
|
|
|
static char *tracefile;
|
|
|
|
|
|
|
|
/* REMOTE-CAPI commands */
|
|
|
|
|
|
|
|
#define RCAPI_REGISTER_REQ CAPICMD(0xf2, 0xff)
|
|
|
|
#define RCAPI_REGISTER_CONF CAPICMD(0xf3, 0xff)
|
|
|
|
#define RCAPI_GET_MANUFACTURER_REQ CAPICMD(0xfa, 0xff)
|
|
|
|
#define RCAPI_GET_MANUFACTURER_CONF CAPICMD(0xfb, 0xff)
|
|
|
|
#define RCAPI_GET_SERIAL_NUMBER_REQ CAPICMD(0xfe, 0xff)
|
|
|
|
#define RCAPI_GET_SERIAL_NUMBER_CONF CAPICMD(0xff, 0xff)
|
|
|
|
#define RCAPI_GET_VERSION_REQ CAPICMD(0xfc, 0xff)
|
|
|
|
#define RCAPI_GET_VERSION_CONF CAPICMD(0xfd, 0xff)
|
|
|
|
#define RCAPI_GET_PROFILE_REQ CAPICMD(0xe0, 0xff)
|
|
|
|
#define RCAPI_GET_PROFILE_CONF CAPICMD(0xe1, 0xff)
|
|
|
|
#define RCAPI_AUTH_USER_REQ CAPICMD(0xff, 0x00)
|
|
|
|
#define RCAPI_AUTH_USER_CONF CAPICMD(0xff, 0x01)
|
|
|
|
|
|
|
|
static char *skip_whitespace(char *s)
|
|
|
|
{
|
|
|
|
while (*s && isspace(*s)) s++;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *skip_nonwhitespace(char *s)
|
|
|
|
{
|
|
|
|
while (*s && !isspace(*s)) s++;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned char get_byte(unsigned char **p)
|
|
|
|
{
|
|
|
|
*p += 1;
|
|
|
|
return((unsigned char)*(*p - 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned short get_word(unsigned char **p)
|
|
|
|
{
|
|
|
|
return(get_byte(p) | (get_byte(p) << 8));
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned short get_netword(unsigned char **p)
|
|
|
|
{
|
|
|
|
return((get_byte(p) << 8) | get_byte(p));
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static unsigned int get_dword(unsigned char **p)
|
|
|
|
{
|
|
|
|
return(get_word(p) | (get_word(p) << 16));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static unsigned char *put_byte(unsigned char **p, _cbyte val)
|
|
|
|
{
|
|
|
|
**p = val;
|
|
|
|
*p += 1;
|
|
|
|
return(*p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned char *put_word(unsigned char **p, _cword val)
|
|
|
|
{
|
|
|
|
put_byte(p, val & 0xff);
|
|
|
|
put_byte(p, (val & 0xff00) >> 8);
|
|
|
|
return(*p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned char *put_netword(unsigned char **p, _cword val)
|
|
|
|
{
|
|
|
|
put_byte(p, (val & 0xff00) >> 8);
|
|
|
|
put_byte(p, val & 0xff);
|
|
|
|
return(*p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned char *put_dword(unsigned char **p, _cdword val)
|
|
|
|
{
|
|
|
|
put_word(p, val & 0xffff);
|
|
|
|
put_word(p, (val & 0xffff0000) >> 16);
|
|
|
|
return(*p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* read config file
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int read_config(void)
|
|
|
|
{
|
|
|
|
FILE *fp = NULL;
|
|
|
|
char *s, *t;
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
if ((s = getenv("HOME")) != NULL) {
|
|
|
|
strcpy(buf, s);
|
|
|
|
strcat(buf, "/");
|
|
|
|
strcat(buf, userconfigfilename);
|
|
|
|
fp = fopen(buf, "r");
|
|
|
|
}
|
|
|
|
if ((!fp) && ((fp = fopen(globalconfigfilename, "r")) == NULL))
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
while(fgets(buf, sizeof(buf), fp)) {
|
|
|
|
buf[strlen(buf)-1] = 0;
|
|
|
|
s = skip_whitespace(buf);
|
|
|
|
if (*s == 0 || *s == '#')
|
|
|
|
continue;
|
|
|
|
if (!(strncmp(s, "REMOTE", 6))) {
|
|
|
|
remote_capi = 1;
|
|
|
|
s = skip_nonwhitespace(s);
|
|
|
|
|
|
|
|
t = skip_whitespace(s);
|
|
|
|
s = skip_nonwhitespace(t);
|
|
|
|
if (*s) *s++ = 0;
|
|
|
|
strncpy(hostname, t, (sizeof(hostname) - 1));
|
|
|
|
|
|
|
|
t = skip_whitespace(s);
|
|
|
|
s = skip_nonwhitespace(t);
|
|
|
|
if (*s) *s++ = 0;
|
|
|
|
port = strtol(t, NULL, 10);
|
|
|
|
if (!port)
|
|
|
|
port = 2662;
|
|
|
|
continue;
|
|
|
|
} else if (!(strncmp(s, "TRACELEVEL", 10))) {
|
|
|
|
t = skip_nonwhitespace(s);
|
|
|
|
s = skip_whitespace(t);
|
|
|
|
tracelevel = (int)strtol(s, NULL, 10);
|
|
|
|
continue;
|
|
|
|
} else if (!(strncmp(s, "TRACEFILE", 9))) {
|
|
|
|
t = skip_nonwhitespace(s);
|
|
|
|
s = skip_whitespace(t);
|
|
|
|
t = skip_nonwhitespace(s);
|
|
|
|
if (*t) *t++ = 0;
|
|
|
|
tracefile = strdup(s);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* socket function
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int open_socket(void)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
struct hostent *hostinfo;
|
|
|
|
struct sockaddr_in sadd;
|
|
|
|
|
|
|
|
/* connect to remote capi */
|
|
|
|
|
|
|
|
fd = socket(PF_INET, SOCK_STREAM, 0);
|
|
|
|
|
|
|
|
sadd.sin_family = AF_INET;
|
|
|
|
sadd.sin_port = htons(port);
|
|
|
|
hostinfo = gethostbyname(hostname);
|
|
|
|
if (hostinfo) {
|
|
|
|
sadd.sin_addr = *(struct in_addr *) hostinfo->h_addr;
|
|
|
|
if (!connect(fd, (struct sockaddr *) &sadd, sizeof(sadd))) {
|
|
|
|
return(fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int socket_read(int fd, unsigned char *buf, int l)
|
|
|
|
{
|
|
|
|
unsigned char tbuf[4096], *p;
|
|
|
|
int tlen, rlen, alen, olen;
|
|
|
|
time_t t;
|
|
|
|
|
|
|
|
if(read(fd, tbuf, 2) == 2) {
|
|
|
|
p = tbuf;
|
|
|
|
tlen = olen = (int)get_netword(&p) - 2;
|
|
|
|
t = time(NULL);
|
|
|
|
rlen = 0;
|
|
|
|
|
|
|
|
while(((alen = read(fd, &tbuf[rlen], tlen)) < tlen) && (time(NULL) < (t + 5))) {
|
|
|
|
if (alen > 0) {
|
|
|
|
tlen -= alen;
|
|
|
|
rlen += alen;
|
|
|
|
}
|
|
|
|
alen = 0;
|
|
|
|
}
|
|
|
|
if (alen > 0)
|
|
|
|
rlen += alen;
|
|
|
|
|
|
|
|
if (rlen != olen) {
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
if (!l)
|
|
|
|
l = olen;
|
|
|
|
olen = (l < rlen) ? l : rlen;
|
|
|
|
memcpy(buf, tbuf, olen);
|
|
|
|
return(olen);
|
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int remote_command(int fd, unsigned char *buf, int len, int conf)
|
|
|
|
{
|
|
|
|
unsigned char *p;
|
|
|
|
int l;
|
|
|
|
|
|
|
|
if(write(fd, buf, len) < len)
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
if ((l = socket_read(fd, buf, 0)) < 1)
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
p = buf + 4;
|
|
|
|
if(get_netword(&p) == conf) {
|
|
|
|
memmove(buf, buf + 8, l - 8);
|
|
|
|
return(l - 8);
|
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_rcapicmd_header(unsigned char **p, int len, _cword cmd, _cdword ctrl)
|
|
|
|
{
|
|
|
|
put_netword(p, len);
|
|
|
|
put_word(p, 0);
|
|
|
|
put_word(p, 0);
|
|
|
|
put_netword(p, cmd);
|
|
|
|
put_word(p, 0);
|
|
|
|
put_dword(p, ctrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_capi_trace(int send, unsigned char *buf, int length, int datamsg)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
_cdword ltime;
|
|
|
|
unsigned char header[7];
|
|
|
|
|
|
|
|
if (!tracefile)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (tracelevel < (datamsg + 1))
|
|
|
|
return;
|
|
|
|
|
|
|
|
fd = open(tracefile, O_WRONLY | O_CREAT | O_APPEND, 0644);
|
|
|
|
if (fd >= 0) {
|
|
|
|
ltime = (_cdword)time(NULL);
|
|
|
|
capimsg_setu16(header, 0, length + sizeof(header));
|
|
|
|
capimsg_setu32(header, 2, ltime);
|
|
|
|
header[6] = (send) ? 0x80:0x81;
|
|
|
|
write(fd, header, sizeof(header));
|
|
|
|
write(fd, buf, length);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned capi20_isinstalled (void)
|
|
|
|
{
|
|
|
|
if (capi_fd >= 0)
|
|
|
|
return CapiNoError;
|
|
|
|
|
|
|
|
/*----- open managment link -----*/
|
|
|
|
if (read_config() && (remote_capi)) {
|
|
|
|
capi_fd = open_socket();
|
|
|
|
if (capi_fd >= 0) {
|
|
|
|
/* TODO: we could do some AUTH here with rcapid */
|
|
|
|
return CapiNoError;
|
|
|
|
}
|
|
|
|
return CapiRegNotInstalled;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((capi_fd = open(capidevname, O_RDWR, 0666)) < 0 && (errno == ENOENT))
|
|
|
|
capi_fd = open(capidevnamenew, O_RDWR, 0666);
|
|
|
|
|
|
|
|
if (capi_fd < 0)
|
|
|
|
return CapiRegNotInstalled;
|
|
|
|
|
|
|
|
if (ioctl(capi_fd, CAPI_INSTALLED, 0) == 0)
|
|
|
|
return CapiNoError;
|
|
|
|
|
|
|
|
return CapiRegNotInstalled;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* managment of application ids
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define MAX_APPL 1024
|
|
|
|
|
|
|
|
static int applidmap[MAX_APPL];
|
|
|
|
|
|
|
|
static inline int remember_applid(unsigned applid, int fd)
|
|
|
|
{
|
|
|
|
if (applid >= MAX_APPL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
applidmap[applid] = fd;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned alloc_applid(int fd)
|
|
|
|
{
|
|
|
|
unsigned applid;
|
|
|
|
|
|
|
|
for (applid = 1; applid < MAX_APPL; applid++) {
|
|
|
|
if (applidmap[applid] < 0) {
|
|
|
|
applidmap[applid] = fd;
|
|
|
|
return applid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void freeapplid(unsigned applid)
|
|
|
|
{
|
|
|
|
if (applid < MAX_APPL)
|
|
|
|
applidmap[applid] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int validapplid(unsigned applid)
|
|
|
|
{
|
|
|
|
return ((applid > 0) && (applid < MAX_APPL) && (applidmap[applid] >= 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int applid2fd(unsigned applid)
|
|
|
|
{
|
|
|
|
if (applid < MAX_APPL)
|
|
|
|
return applidmap[applid];
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* buffer management
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct recvbuffer {
|
|
|
|
struct recvbuffer *next;
|
|
|
|
unsigned int datahandle;
|
|
|
|
unsigned int used;
|
|
|
|
unsigned int ncci;
|
|
|
|
unsigned char *buf; /* 128 + MaxSizeB3 */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct applinfo {
|
|
|
|
unsigned maxbufs;
|
|
|
|
unsigned nbufs;
|
|
|
|
size_t recvbuffersize;
|
|
|
|
struct recvbuffer *buffers;
|
|
|
|
struct recvbuffer *firstfree;
|
|
|
|
struct recvbuffer *lastfree;
|
|
|
|
unsigned char *bufferstart;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct applinfo *alloc_buffers(
|
|
|
|
unsigned MaxB3Connection,
|
|
|
|
unsigned MaxB3Blks,
|
|
|
|
unsigned MaxSizeB3)
|
|
|
|
{
|
|
|
|
struct applinfo *ap;
|
|
|
|
unsigned nbufs = 2 + MaxB3Connection * (MaxB3Blks + 1);
|
|
|
|
size_t recvbuffersize = 128 + MaxSizeB3;
|
|
|
|
unsigned i;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
if (recvbuffersize < 2048)
|
|
|
|
recvbuffersize = 2048;
|
|
|
|
|
|
|
|
size = sizeof(struct applinfo);
|
|
|
|
size += sizeof(struct recvbuffer) * nbufs;
|
|
|
|
size += recvbuffersize * nbufs;
|
|
|
|
|
|
|
|
ap = (struct applinfo *)malloc(size);
|
|
|
|
if (ap == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
memset(ap, 0, size);
|
|
|
|
ap->maxbufs = nbufs;
|
|
|
|
ap->recvbuffersize = recvbuffersize;
|
|
|
|
ap->buffers = (struct recvbuffer *)(ap+1);
|
|
|
|
ap->firstfree = ap->buffers;
|
|
|
|
ap->bufferstart = (unsigned char *)(ap->buffers+nbufs);
|
|
|
|
for (i = 0; i < ap->maxbufs; i++) {
|
|
|
|
ap->buffers[i].next = &ap->buffers[i+1];
|
|
|
|
ap->buffers[i].used = 0;
|
|
|
|
ap->buffers[i].ncci = 0;
|
|
|
|
ap->buffers[i].buf = ap->bufferstart+(recvbuffersize*i);
|
|
|
|
}
|
|
|
|
ap->lastfree = &ap->buffers[ap->maxbufs-1];
|
|
|
|
ap->lastfree->next = 0;
|
|
|
|
return ap;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_buffers(struct applinfo *ap)
|
|
|
|
{
|
|
|
|
free(ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct applinfo *applinfo[MAX_APPL];
|
|
|
|
|
|
|
|
static unsigned char *get_buffer(unsigned applid, size_t *sizep, unsigned *handle)
|
|
|
|
{
|
|
|
|
struct applinfo *ap;
|
|
|
|
struct recvbuffer *buf;
|
|
|
|
|
|
|
|
assert(validapplid(applid));
|
|
|
|
ap = applinfo[applid];
|
|
|
|
if ((buf = ap->firstfree) == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ap->firstfree = buf->next;
|
|
|
|
buf->next = 0;
|
|
|
|
buf->used = 1;
|
|
|
|
ap->nbufs++;
|
|
|
|
*sizep = ap->recvbuffersize;
|
|
|
|
*handle = (buf->buf-ap->bufferstart)/ap->recvbuffersize;
|
|
|
|
|
2009-02-09 17:55:29 +00:00
|
|
|
memset(buf->buf, 0, ap->recvbuffersize);
|
|
|
|
|
2008-03-13 11:02:41 +00:00
|
|
|
return buf->buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void save_datahandle(
|
|
|
|
unsigned char applid,
|
|
|
|
unsigned offset,
|
|
|
|
unsigned datahandle,
|
|
|
|
unsigned ncci)
|
|
|
|
{
|
|
|
|
struct applinfo *ap;
|
|
|
|
struct recvbuffer *buf;
|
|
|
|
|
|
|
|
assert(validapplid(applid));
|
|
|
|
ap = applinfo[applid];
|
|
|
|
assert(offset < ap->maxbufs);
|
|
|
|
buf = ap->buffers+offset;
|
|
|
|
buf->datahandle = datahandle;
|
|
|
|
buf->ncci = ncci;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned return_buffer(unsigned char applid, unsigned offset)
|
|
|
|
{
|
|
|
|
struct applinfo *ap;
|
|
|
|
struct recvbuffer *buf;
|
|
|
|
|
|
|
|
assert(validapplid(applid));
|
|
|
|
ap = applinfo[applid];
|
|
|
|
assert(offset < ap->maxbufs);
|
|
|
|
buf = ap->buffers+offset;
|
|
|
|
assert(buf->used == 1);
|
|
|
|
assert(buf->next == 0);
|
|
|
|
|
|
|
|
if (ap->lastfree) {
|
|
|
|
ap->lastfree->next = buf;
|
|
|
|
ap->lastfree = buf;
|
|
|
|
} else {
|
|
|
|
ap->firstfree = ap->lastfree = buf;
|
|
|
|
}
|
|
|
|
buf->used = 0;
|
|
|
|
buf->ncci = 0;
|
|
|
|
assert(ap->nbufs-- > 0);
|
|
|
|
|
|
|
|
return buf->datahandle;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cleanup_buffers_for_ncci(unsigned char applid, unsigned ncci)
|
|
|
|
{
|
|
|
|
struct applinfo *ap;
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
assert(validapplid(applid));
|
|
|
|
ap = applinfo[applid];
|
|
|
|
|
|
|
|
for (i = 0; i < ap->maxbufs; i++) {
|
|
|
|
if (ap->buffers[i].used) {
|
|
|
|
assert(ap->buffers[i].ncci != 0);
|
|
|
|
if (ap->buffers[i].ncci == ncci) {
|
|
|
|
return_buffer(applid, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cleanup_buffers_for_plci(unsigned char applid, unsigned plci)
|
|
|
|
{
|
|
|
|
struct applinfo *ap;
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
assert(validapplid(applid));
|
|
|
|
ap = applinfo[applid];
|
|
|
|
|
|
|
|
for (i = 0; i < ap->maxbufs; i++) {
|
|
|
|
if (ap->buffers[i].used) {
|
|
|
|
assert(ap->buffers[i].ncci != 0);
|
|
|
|
if ((ap->buffers[i].ncci & 0xffff) == plci) {
|
|
|
|
return_buffer(applid, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CAPI2.0 functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
capi20_register(
|
|
|
|
unsigned MaxB3Connection,
|
|
|
|
unsigned MaxB3Blks,
|
|
|
|
unsigned MaxSizeB3,
|
|
|
|
unsigned *ApplID)
|
|
|
|
{
|
|
|
|
int applid = 0;
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
int i, fd = -1;
|
|
|
|
|
|
|
|
*ApplID = 0;
|
|
|
|
|
|
|
|
if (capi20_isinstalled() != CapiNoError)
|
|
|
|
return CapiRegNotInstalled;
|
|
|
|
if ((!remote_capi) || ((remote_capi) && ((fd = open_socket()) < 0))) {
|
|
|
|
if ((fd = open(capidevname, O_RDWR|O_NONBLOCK, 0666)) < 0 &&
|
|
|
|
(errno == ENOENT)) {
|
|
|
|
fd = open(capidevnamenew, O_RDWR|O_NONBLOCK, 0666);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
return CapiRegOSResourceErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
ioctl_data.rparams.level3cnt = MaxB3Connection;
|
|
|
|
ioctl_data.rparams.datablkcnt = MaxB3Blks;
|
|
|
|
ioctl_data.rparams.datablklen = MaxSizeB3;
|
|
|
|
|
|
|
|
if (remote_capi) {
|
|
|
|
unsigned char buf[100];
|
|
|
|
unsigned char *p = buf;
|
|
|
|
int errcode;
|
|
|
|
set_rcapicmd_header(&p, 23, RCAPI_REGISTER_REQ, 0);
|
|
|
|
put_word(&p, 2048); /* fake size */
|
|
|
|
put_word(&p, MaxB3Connection);
|
|
|
|
put_word(&p, MaxB3Blks);
|
|
|
|
put_word(&p, MaxSizeB3);
|
|
|
|
put_byte(&p, 2); /* capi version */
|
|
|
|
if(!(remote_command(fd, buf, 23, RCAPI_REGISTER_CONF))) {
|
|
|
|
close(fd);
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
}
|
|
|
|
p = buf;
|
|
|
|
errcode = get_word(&p);
|
|
|
|
if(errcode == CapiNoError) {
|
|
|
|
applid = alloc_applid(fd);
|
|
|
|
} else {
|
|
|
|
close(fd);
|
|
|
|
return(errcode);
|
|
|
|
}
|
|
|
|
} else if ((applid = ioctl(fd, CAPI_REGISTER, &ioctl_data)) < 0) {
|
|
|
|
if (errno == EIO) {
|
|
|
|
if (ioctl(fd, CAPI_GET_ERRCODE, &ioctl_data) < 0) {
|
|
|
|
close (fd);
|
|
|
|
return CapiRegOSResourceErr;
|
|
|
|
}
|
|
|
|
close (fd);
|
|
|
|
return (unsigned)ioctl_data.errcode;
|
|
|
|
} else if (errno == EINVAL) { // old kernel driver
|
|
|
|
close (fd);
|
|
|
|
fd = -1;
|
|
|
|
for (i = 0; fd < 0; i++) {
|
|
|
|
/*----- open pseudo-clone device -----*/
|
|
|
|
sprintf(buf, "/dev/capi20.%02d", i);
|
|
|
|
if ((fd = open(buf, O_RDWR|O_NONBLOCK, 0666)) < 0) {
|
|
|
|
switch (errno) {
|
|
|
|
case EEXIST:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return CapiRegOSResourceErr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (fd < 0)
|
|
|
|
return CapiRegOSResourceErr;
|
|
|
|
|
|
|
|
ioctl_data.rparams.level3cnt = MaxB3Connection;
|
|
|
|
ioctl_data.rparams.datablkcnt = MaxB3Blks;
|
|
|
|
ioctl_data.rparams.datablklen = MaxSizeB3;
|
|
|
|
|
|
|
|
if ((applid = ioctl(fd, CAPI_REGISTER, &ioctl_data)) < 0) {
|
|
|
|
if (errno == EIO) {
|
|
|
|
if (ioctl(fd, CAPI_GET_ERRCODE, &ioctl_data) < 0) {
|
|
|
|
close(fd);
|
|
|
|
return CapiRegOSResourceErr;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
return (unsigned)ioctl_data.errcode;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
return CapiRegOSResourceErr;
|
|
|
|
}
|
|
|
|
applid = alloc_applid(fd);
|
|
|
|
} // end old driver compatibility
|
|
|
|
}
|
|
|
|
if (remember_applid(applid, fd) < 0) {
|
|
|
|
close(fd);
|
|
|
|
return CapiRegOSResourceErr;
|
|
|
|
}
|
|
|
|
applinfo[applid] = alloc_buffers(MaxB3Connection, MaxB3Blks, MaxSizeB3);
|
|
|
|
if (applinfo[applid] == 0) {
|
|
|
|
close(fd);
|
|
|
|
return CapiRegOSResourceErr;
|
|
|
|
}
|
|
|
|
*ApplID = applid;
|
|
|
|
return CapiNoError;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
capi20_release (unsigned ApplID)
|
|
|
|
{
|
|
|
|
if (capi20_isinstalled() != CapiNoError)
|
|
|
|
return CapiRegNotInstalled;
|
|
|
|
|
|
|
|
if (!validapplid(ApplID))
|
|
|
|
return CapiIllAppNr;
|
|
|
|
|
|
|
|
(void)close(applid2fd(ApplID));
|
|
|
|
freeapplid(ApplID);
|
|
|
|
free_buffers(applinfo[ApplID]);
|
|
|
|
applinfo[ApplID] = 0;
|
|
|
|
|
|
|
|
return CapiNoError;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
capi20_put_message (unsigned ApplID, unsigned char *Msg)
|
|
|
|
{
|
|
|
|
unsigned char sndbuf[SEND_BUFSIZ], *sbuf;
|
|
|
|
unsigned ret;
|
|
|
|
int len = (Msg[0] | (Msg[1] << 8));
|
|
|
|
int cmd = Msg[4];
|
|
|
|
int subcmd = Msg[5];
|
|
|
|
int rc;
|
|
|
|
int fd;
|
|
|
|
int datareq = 0;
|
|
|
|
|
|
|
|
if (capi20_isinstalled() != CapiNoError)
|
|
|
|
return CapiRegNotInstalled;
|
|
|
|
|
|
|
|
if (!validapplid(ApplID))
|
|
|
|
return CapiIllAppNr;
|
|
|
|
|
|
|
|
fd = applid2fd(ApplID);
|
|
|
|
|
|
|
|
sbuf = sndbuf;
|
|
|
|
if (remote_capi) {
|
|
|
|
sbuf = sndbuf + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(sbuf, Msg, len);
|
|
|
|
|
|
|
|
if (cmd == CAPI_DATA_B3) {
|
|
|
|
datareq = 1;
|
|
|
|
if (subcmd == CAPI_REQ) {
|
|
|
|
int datalen = (Msg[16] | (Msg[17] << 8));
|
|
|
|
void *dataptr;
|
|
|
|
if (sizeof(void *) != 4) {
|
|
|
|
if (len >= 30) { /* 64Bit CAPI-extention */
|
|
|
|
u_int64_t data64;
|
|
|
|
memcpy(&data64,Msg+22, sizeof(u_int64_t));
|
|
|
|
if (data64 != 0) {
|
|
|
|
dataptr = (void *)(unsigned long)data64;
|
|
|
|
} else {
|
|
|
|
dataptr = Msg + len; /* Assume data after message */
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dataptr = Msg + len; /* Assume data after message */
|
|
|
|
}
|
|
|
|
} else {
|
2008-10-29 22:35:19 +00:00
|
|
|
u_int32_t data = (Msg[12] | (Msg[13] << 8) | (Msg[14] << 16) | (Msg[15] << 24));
|
2008-03-13 11:02:41 +00:00
|
|
|
if (data != 0) {
|
|
|
|
dataptr = (void *)(unsigned long)data;
|
|
|
|
} else {
|
|
|
|
dataptr = Msg + len; /* Assume data after message */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (len + datalen > SEND_BUFSIZ)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
memcpy(sbuf+len, dataptr, datalen);
|
|
|
|
len += datalen;
|
|
|
|
} else if (subcmd == CAPI_RESP) {
|
|
|
|
capimsg_setu16(sbuf, 12,
|
|
|
|
return_buffer(ApplID, CAPIMSG_U16(sbuf, 12)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd == CAPI_DISCONNECT_B3 && subcmd == CAPI_RESP)
|
|
|
|
cleanup_buffers_for_ncci(ApplID, CAPIMSG_U32(sbuf, 8));
|
|
|
|
|
|
|
|
ret = CapiNoError;
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
write_capi_trace(1, sbuf, len, datareq);
|
|
|
|
|
|
|
|
if (remote_capi) {
|
|
|
|
len += 2;
|
|
|
|
sbuf = sndbuf;
|
|
|
|
put_netword(&sbuf, len);
|
|
|
|
}
|
|
|
|
if ((rc = write(fd, sndbuf, len)) != len) {
|
|
|
|
if (remote_capi) {
|
|
|
|
ret = CapiMsgOSResourceErr;
|
|
|
|
} else {
|
|
|
|
switch (errno) {
|
|
|
|
case EFAULT:
|
|
|
|
case EINVAL:
|
|
|
|
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
|
|
|
|
break;
|
|
|
|
case EBADF:
|
|
|
|
ret = CapiIllAppNr;
|
|
|
|
break;
|
|
|
|
case EIO:
|
|
|
|
if (ioctl(fd, CAPI_GET_ERRCODE, &ioctl_data) < 0) {
|
|
|
|
ret = CapiMsgOSResourceErr;
|
|
|
|
} else {
|
|
|
|
ret = (unsigned)ioctl_data.errcode;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ret = CapiMsgOSResourceErr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
capi20_get_message (unsigned ApplID, unsigned char **Buf)
|
|
|
|
{
|
|
|
|
unsigned char *rcvbuf;
|
|
|
|
unsigned offset;
|
|
|
|
unsigned ret;
|
|
|
|
size_t bufsiz;
|
|
|
|
int rc, fd;
|
|
|
|
|
|
|
|
if (capi20_isinstalled() != CapiNoError)
|
|
|
|
return CapiRegNotInstalled;
|
|
|
|
|
|
|
|
if (!validapplid(ApplID))
|
|
|
|
return CapiIllAppNr;
|
|
|
|
|
|
|
|
fd = applid2fd(ApplID);
|
|
|
|
|
|
|
|
if ((*Buf = rcvbuf = get_buffer(ApplID, &bufsiz, &offset)) == 0)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
|
|
|
|
if (remote_capi) {
|
|
|
|
rc = socket_read(fd, rcvbuf, bufsiz);
|
|
|
|
} else {
|
|
|
|
rc = read(fd, rcvbuf, bufsiz);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc > 0) {
|
|
|
|
write_capi_trace(0, rcvbuf, rc, (CAPIMSG_COMMAND(rcvbuf) == CAPI_DATA_B3)? 1:0);
|
|
|
|
CAPIMSG_SETAPPID(rcvbuf, ApplID); // workaround for old driver
|
|
|
|
if ((CAPIMSG_COMMAND(rcvbuf) == CAPI_DATA_B3) &&
|
|
|
|
(CAPIMSG_SUBCOMMAND(rcvbuf) == CAPI_IND)) {
|
|
|
|
save_datahandle(ApplID, offset, CAPIMSG_U16(rcvbuf, 18),
|
|
|
|
CAPIMSG_U32(rcvbuf, 8));
|
|
|
|
capimsg_setu16(rcvbuf, 18, offset); /* patch datahandle */
|
|
|
|
if (sizeof(void *) == 4) {
|
|
|
|
u_int32_t data = (u_int32_t)rcvbuf + CAPIMSG_LEN(rcvbuf);
|
|
|
|
rcvbuf[12] = data & 0xff;
|
|
|
|
rcvbuf[13] = (data >> 8) & 0xff;
|
|
|
|
rcvbuf[14] = (data >> 16) & 0xff;
|
|
|
|
rcvbuf[15] = (data >> 24) & 0xff;
|
|
|
|
} else {
|
|
|
|
u_int64_t data;
|
|
|
|
ulong radr = (ulong)rcvbuf;
|
|
|
|
if (CAPIMSG_LEN(rcvbuf) < 30) {
|
|
|
|
/*
|
|
|
|
* grr, 64bit arch, but no data64 included,
|
|
|
|
* seems to be old driver
|
|
|
|
*/
|
|
|
|
memmove(rcvbuf+30, rcvbuf+CAPIMSG_LEN(rcvbuf),
|
|
|
|
CAPIMSG_DATALEN(rcvbuf));
|
|
|
|
rcvbuf[0] = 30;
|
|
|
|
rcvbuf[1] = 0;
|
|
|
|
}
|
|
|
|
data = radr + CAPIMSG_LEN(rcvbuf);
|
|
|
|
rcvbuf[12] = rcvbuf[13] = rcvbuf[14] = rcvbuf[15] = 0;
|
|
|
|
rcvbuf[22] = data & 0xff;
|
|
|
|
rcvbuf[23] = (data >> 8) & 0xff;
|
|
|
|
rcvbuf[24] = (data >> 16) & 0xff;
|
|
|
|
rcvbuf[25] = (data >> 24) & 0xff;
|
|
|
|
rcvbuf[26] = (data >> 32) & 0xff;
|
|
|
|
rcvbuf[27] = (data >> 40) & 0xff;
|
|
|
|
rcvbuf[28] = (data >> 48) & 0xff;
|
|
|
|
rcvbuf[29] = (data >> 56) & 0xff;
|
|
|
|
}
|
|
|
|
/* keep buffer */
|
|
|
|
return CapiNoError;
|
|
|
|
}
|
|
|
|
return_buffer(ApplID, offset);
|
|
|
|
if ((CAPIMSG_COMMAND(rcvbuf) == CAPI_DISCONNECT) &&
|
|
|
|
(CAPIMSG_SUBCOMMAND(rcvbuf) == CAPI_IND)) {
|
|
|
|
cleanup_buffers_for_plci(ApplID, CAPIMSG_U32(rcvbuf, 8));
|
|
|
|
}
|
|
|
|
return CapiNoError;
|
|
|
|
}
|
|
|
|
|
|
|
|
return_buffer(ApplID, offset);
|
|
|
|
|
|
|
|
if (rc == 0)
|
|
|
|
return CapiReceiveQueueEmpty;
|
|
|
|
|
|
|
|
switch (errno) {
|
|
|
|
case EMSGSIZE:
|
|
|
|
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
|
|
|
|
break;
|
|
|
|
case EAGAIN:
|
|
|
|
return CapiReceiveQueueEmpty;
|
|
|
|
default:
|
|
|
|
ret = CapiMsgOSResourceErr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char *
|
|
|
|
capi20_get_manufacturer(unsigned Ctrl, unsigned char *Buf)
|
|
|
|
{
|
|
|
|
if (capi20_isinstalled() != CapiNoError)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (remote_capi) {
|
|
|
|
unsigned char buf[100];
|
|
|
|
unsigned char *p = buf;
|
|
|
|
set_rcapicmd_header(&p, 14, RCAPI_GET_MANUFACTURER_REQ, Ctrl);
|
|
|
|
if (!(remote_command(capi_fd, buf, 14, RCAPI_GET_MANUFACTURER_CONF)))
|
|
|
|
return 0;
|
|
|
|
memcpy(Buf, buf + 1, CAPI_MANUFACTURER_LEN);
|
|
|
|
Buf[CAPI_MANUFACTURER_LEN-1] = 0;
|
|
|
|
return Buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
ioctl_data.contr = Ctrl;
|
|
|
|
|
|
|
|
if (ioctl(capi_fd, CAPI_GET_MANUFACTURER, &ioctl_data) < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
memcpy(Buf, ioctl_data.manufacturer, CAPI_MANUFACTURER_LEN);
|
|
|
|
Buf[CAPI_MANUFACTURER_LEN-1] = 0;
|
|
|
|
|
|
|
|
return Buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char *
|
|
|
|
capi20_get_version(unsigned Ctrl, unsigned char *Buf)
|
|
|
|
{
|
|
|
|
if (capi20_isinstalled() != CapiNoError)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (remote_capi) {
|
|
|
|
unsigned char buf[100];
|
|
|
|
unsigned char *p = buf;
|
|
|
|
set_rcapicmd_header(&p, 14, RCAPI_GET_VERSION_REQ, Ctrl);
|
|
|
|
if(!(remote_command(capi_fd, buf, 14, RCAPI_GET_VERSION_CONF)))
|
|
|
|
return 0;
|
|
|
|
memcpy(Buf, buf + 1, sizeof(capi_version));
|
|
|
|
return Buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
ioctl_data.contr = Ctrl;
|
|
|
|
if (ioctl(capi_fd, CAPI_GET_VERSION, &ioctl_data) < 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(Buf, &ioctl_data.version, sizeof(capi_version));
|
|
|
|
return Buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char *
|
|
|
|
capi20_get_serial_number(unsigned Ctrl, unsigned char *Buf)
|
|
|
|
{
|
|
|
|
if (capi20_isinstalled() != CapiNoError)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (remote_capi) {
|
|
|
|
unsigned char buf[100];
|
|
|
|
unsigned char *p = buf;
|
|
|
|
set_rcapicmd_header(&p, 14, RCAPI_GET_SERIAL_NUMBER_REQ, Ctrl);
|
|
|
|
if(!(remote_command(capi_fd, buf, 14, RCAPI_GET_SERIAL_NUMBER_CONF)))
|
|
|
|
return 0;
|
|
|
|
memcpy(Buf, buf + 1, CAPI_SERIAL_LEN);
|
|
|
|
Buf[CAPI_SERIAL_LEN-1] = 0;
|
|
|
|
return Buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
ioctl_data.contr = Ctrl;
|
|
|
|
|
|
|
|
if (ioctl(capi_fd, CAPI_GET_SERIAL, &ioctl_data) < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
memcpy(Buf, &ioctl_data.serial, CAPI_SERIAL_LEN);
|
|
|
|
Buf[CAPI_SERIAL_LEN-1] = 0;
|
|
|
|
|
|
|
|
return Buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
capi20_get_profile(unsigned Ctrl, unsigned char *Buf)
|
|
|
|
{
|
|
|
|
if (capi20_isinstalled() != CapiNoError)
|
|
|
|
return CapiMsgNotInstalled;
|
|
|
|
|
|
|
|
if (remote_capi) {
|
|
|
|
unsigned char buf[100];
|
|
|
|
unsigned char *p = buf;
|
|
|
|
set_rcapicmd_header(&p, 14, RCAPI_GET_PROFILE_REQ, Ctrl);
|
|
|
|
if(!(remote_command(capi_fd, buf, 14, RCAPI_GET_PROFILE_CONF)))
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
if(*(unsigned short *)buf == CapiNoError) {
|
|
|
|
memcpy(Buf, buf + 2, (Ctrl) ? sizeof(struct capi_profile) : 2);
|
|
|
|
}
|
|
|
|
return (*(unsigned short *)buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
ioctl_data.contr = Ctrl;
|
|
|
|
|
|
|
|
if (ioctl(capi_fd, CAPI_GET_PROFILE, &ioctl_data) < 0) {
|
|
|
|
if (errno != EIO)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
if (ioctl(capi_fd, CAPI_GET_ERRCODE, &ioctl_data) < 0)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
return (unsigned)ioctl_data.errcode;
|
|
|
|
}
|
|
|
|
if (Ctrl) {
|
|
|
|
memcpy(Buf, &ioctl_data.profile, sizeof(struct capi_profile));
|
|
|
|
} else {
|
|
|
|
memcpy(Buf, &ioctl_data.profile.ncontroller,
|
|
|
|
sizeof(ioctl_data.profile.ncontroller));
|
|
|
|
}
|
|
|
|
return CapiNoError;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* functions added to the CAPI2.0 spec
|
|
|
|
*/
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
capi20_waitformessage(unsigned ApplID, struct timeval *TimeOut)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
fd_set rfds;
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
|
|
|
|
if (capi20_isinstalled() != CapiNoError)
|
|
|
|
return CapiRegNotInstalled;
|
|
|
|
|
|
|
|
if (!validapplid(ApplID))
|
|
|
|
return CapiIllAppNr;
|
|
|
|
|
|
|
|
fd = applid2fd(ApplID);
|
|
|
|
|
|
|
|
FD_SET(fd, &rfds);
|
|
|
|
|
|
|
|
if (select(fd + 1, &rfds, NULL, NULL, TimeOut) < 1)
|
|
|
|
return CapiReceiveQueueEmpty;
|
|
|
|
|
|
|
|
return CapiNoError;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
capi20_fileno(unsigned ApplID)
|
|
|
|
{
|
|
|
|
return applid2fd(ApplID);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extensions for middleware
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
capi20ext_get_flags(unsigned ApplID, unsigned *flagsptr)
|
|
|
|
{
|
|
|
|
if (remote_capi)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
|
|
|
|
if (ioctl(applid2fd(ApplID), CAPI_GET_FLAGS, flagsptr) < 0)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
|
|
|
|
return CapiNoError;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
capi20ext_set_flags(unsigned ApplID, unsigned flags)
|
|
|
|
{
|
|
|
|
if (remote_capi)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
|
|
|
|
if (ioctl(applid2fd(ApplID), CAPI_SET_FLAGS, &flags) < 0)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
|
|
|
|
return CapiNoError;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
capi20ext_clr_flags(unsigned ApplID, unsigned flags)
|
|
|
|
{
|
|
|
|
if (remote_capi)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
|
|
|
|
if (ioctl(applid2fd(ApplID), CAPI_CLR_FLAGS, &flags) < 0)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
|
|
|
|
return CapiNoError;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
capi20ext_get_tty_devname(unsigned applid, unsigned ncci, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
int unit;
|
|
|
|
|
|
|
|
if (remote_capi)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
unit = ioctl(applid2fd(applid), CAPI_NCCI_GETUNIT, &ncci);
|
|
|
|
if (unit < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
snprintf(buf, size, "/dev/capi/%d", unit);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
capi20ext_get_raw_devname(unsigned applid, unsigned ncci, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
int unit;
|
|
|
|
|
|
|
|
if (remote_capi)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
unit = ioctl(applid2fd(applid), CAPI_NCCI_GETUNIT, &ncci);
|
|
|
|
if (unit < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
snprintf(buf, size, "/dev/capi/r%d", unit);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
int capi20ext_ncci_opencount(unsigned applid, unsigned ncci)
|
|
|
|
{
|
|
|
|
if (remote_capi)
|
|
|
|
return CapiMsgOSResourceErr;
|
|
|
|
|
|
|
|
return ioctl(applid2fd(applid), CAPI_NCCI_OPENCOUNT, &ncci);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void initlib(void) __attribute__((constructor));
|
|
|
|
static void exitlib(void) __attribute__((destructor));
|
|
|
|
|
|
|
|
static void initlib(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_APPL; i++) {
|
|
|
|
applidmap[i] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void exitlib(void)
|
|
|
|
{
|
|
|
|
remote_capi = 0;
|
|
|
|
|
|
|
|
if (capi_fd >= 0) {
|
|
|
|
close(capi_fd);
|
|
|
|
capi_fd = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|