/* * $Id: capi20.c,v 1.27 2005/05/09 08:21:57 calle Exp $ * * $Log: capi20.c,v $ * Revision 1.27 2005/05/09 08:21:57 calle * - get_buffer() now returns 0, if no buffer is available. * * Revision 1.26 2005/03/04 11:00:31 calle * New functions: cleanup_buffers_for_ncci() and cleanup_buffers_for_plci() * triggered by DISCONNECT_B3_RESP and DISCONNECT_IND to fix buffer leak. * * Revision 1.25 2005/02/21 17:37:06 keil * libcapi20 version 3.0.0 * - add SENDING COMPLETE in ALERT_REQ * - add Globalconfiguration to CONNECT_REQ/RESP and SELECT_B_PROTOCOL_REQ * * * NOTE: incompatible to 2.X.Y versions * * Revision 1.24 2004/12/15 14:27:54 calle * Bugfix: returncode of get_buffer() is now checked. * * Revision 1.23 2004/10/06 15:24:42 calle * - "SendingComplete"-Patch reverted => 2.0.8 was not binaer compartible * - Bugfix: capi20_register() with MaxB3Connection == 0 results in a * core dump. Now at least one buffer is allocated. * * Revision 1.22 2004/06/14 11:23:48 calle * Erweiterungen fuer ALERT_REQ. * * Revision 1.21 2004/03/31 18:12:40 calle * - add receive buffer managment according to CAPI2.0 spec. * - send buffer is now on stack. * - new library version 2.0.7 * * Revision 1.20 2004/01/16 15:27:11 calle * remove several warnings. * * Revision 1.19 2001/03/01 14:59:11 paul * Various patches to fix errors when using the newest glibc, * replaced use of insecure tempnam() function * and to remove warnings etc. * * Revision 1.18 2000/11/12 16:06:41 kai * fix backwards compatibility in capi20 library, small other changes * * Revision 1.17 2000/06/26 15:00:43 calle * - Will also compile with 2.0 Kernelheaders. * * Revision 1.16 2000/05/18 15:02:26 calle * Updated _cmsg handling added new functions need by "capiconn". * * Revision 1.15 2000/04/10 09:08:06 calle * capi20_wait_for_message will now return CapiReceiveQueueEmpty on * timeout and error. * * Revision 1.14 2000/04/07 16:06:09 calle * Bugfix: without devfs open where without NONBLOCK, ahhh. * * Revision 1.13 2000/04/03 14:27:15 calle * non CAPI2.0 standard functions now named capi20ext not capi20. * Extentionfunctions will work with actual driver version. * * Revision 1.12 2000/03/03 15:56:14 calle * - now uses cloning device /dev/capi20. * - middleware extentions prepared. * * Revision 1.11 1999/12/22 17:46:21 calle * - Last byte in serial number now always 0. * - Last byte of manufacturer now always 0. * - returncode in capi20_isinstalled corrected. * * Revision 1.10 1999/11/11 09:24:07 calle * add shared lib destructor, to close "capi_fd" on unload with dlclose .. * * Revision 1.9 1999/10/20 16:43:17 calle * - The CAPI20 library is now a shared library. * - Arguments of function capi20_put_message swapped, to match capi spec. * - All capi20 related subdirs converted to use automake. * - Removed dependency to CONFIG_KERNELDIR where not needed. * * Revision 1.8 1999/09/15 08:10:44 calle * Bugfix: error in 64Bit extention. * * Revision 1.7 1999/09/10 17:20:33 calle * Last changes for proposed standards (CAPI 2.0): * - AK1-148 "Linux Extention" * - AK1-155 "Support of 64-bit Applications" * * Revision 1.6 1999/09/06 17:40:07 calle * Changes for CAPI 2.0 Spec. * * Revision 1.5 1999/04/20 19:52:19 calle * Bugfix in capi20_get_profile: wrong size in memcpy from * Kai Germaschewski * * Revision 1.4 1998/11/18 17:05:44 paul * fixed a (harmless) warning * * Revision 1.3 1998/08/30 09:57:14 calle * I hope it is know readable for everybody. * * Revision 1.1 1998/08/25 16:33:16 calle * Added CAPI2.0 library. First Version. * */ #include #include #include #include #include #include #include #include #include #define _LINUX_LIST_H #include #include #include #include #include #include #include #include #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+1) static int capi_fd = -1; #define MAX_CONTROLLERS 16 static unsigned int number_of_controllers = 0; static struct _capi_controller_info { unsigned char manufacturer_name[64]; struct _capi_version { unsigned int capi_major; unsigned int capi_minor; unsigned int manu_major; unsigned int manu_minor; } __attribute__ ((packed)) version; unsigned char serial[8]; unsigned char profile[64]; } __attribute__ ((packed)) controller_info[MAX_CONTROLLERS]; #define MSG_TYPE_PROFILE 0 #define MSG_TYPE_CAPI 1 /*-------------------------------------------------------------------------------------*\ * msec, NEEDS CLOCK_MONOTONIC !! \*-------------------------------------------------------------------------------------*/ #define CLOCK_MONOTONIC 1 static unsigned long getclock(void) { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { return (ts.tv_sec * 1000) + (ts.tv_nsec/1000000); } return 0; } #if 0 /*-------------------------------------------------------------------------------------*\ * delay in msec \*-------------------------------------------------------------------------------------*/ static void delay_since(unsigned long when, unsigned long delay) { unsigned long now; struct timeval tv; now = getclock(); if (now >= (when + delay)) return; delay = when + delay - now; tv.tv_sec = (delay/1000); tv.tv_usec = (delay%1000)*1000; select(0,NULL,NULL,NULL,&tv); } #endif /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static int capi20_open_socket(void) { /*--- int sock; ---*/ int err; /*--- struct sockaddr_in addr; ---*/ char* env = NULL; /*--- long int port; ---*/ long timeout = 0; int fd; unsigned char hello[] = "\0Hallo"; /*--- sock = socket(PF_INET, SOCK_STREAM, 0); ---*/ /*--- if (sock < 0) return sock; ---*/ env = getenv("remote_capi_timeout"); if (env != NULL) { timeout = strtol(env, NULL, 10); if ((timeout == LONG_MIN) || (timeout == LONG_MAX) || (timeout == 0)) { timeout = 0; } else { timeout = timeout * 1000; } } #if 0 if (getenv("remote_capi_ip")) { char* ptr; env = strdup(getenv("remote_capi_ip")); ptr = env; while (*ptr) { if (*ptr == ':') { *ptr = '\0'; ptr++; break; } ptr++; } port = strtol(ptr, NULL, 10); if ((port == LONG_MIN) || (port == LONG_MAX) || (port == 0)) { port = 1234; } addr.sin_port = htons((unsigned short)port); addr.sin_addr.s_addr = inet_addr(env); if (env) free(env); } else { addr.sin_port = htons(1234); addr.sin_addr.s_addr = inet_addr("127.0.0.1"); } addr.sin_family = AF_INET; #endif fd = open("/dev/rcapi20", O_RDWR); if (fd < 0) { /*--- printf("couldn't open /dev/rcapi20: %s\n", strerror(errno)); ---*/ return -1; } do { unsigned long start, now; struct pollfd pollfd; start = getclock(); pollfd.fd = fd; pollfd.events = POLLIN; err = write(fd, (void*)hello, 6); err = poll(&pollfd, 1, 1000); if (err > 0) break; if (timeout > 0) { now = getclock(); if ((now - start) > (unsigned long)timeout) timeout = 0; else timeout -= (now - start); } } while ((err <= 0) && (timeout > 0)); if (err < 0) { /*--- printf("connect: %s\n", strerror(errno)); ---*/ close(fd); return err; } /*--- printf("got response from capi\n"); ---*/ /*-------------------------------------------------------------------------------------*\ * CAPI Infos lesen * 4 Bytes Num. Controllers * 64 Bytes Manufacturer * 4 Bytes CAPI Major * 4 Bytes CAPI Minor * 4 Bytes Manu Major * 4 Bytes Manu Minor * 8 Bytes Serial No. * 64 Bytes Profile \*-------------------------------------------------------------------------------------*/ { int err, i; unsigned char msg[1500]; unsigned char *ptr; err = read(fd, (void*)&msg[0], 1500); if (err <= 0) { /*--- printf("buffer too small to read profile info!\n"); ---*/ goto err_close_socket; } if (msg[0] == MSG_TYPE_PROFILE) { ptr = &msg[1]; number_of_controllers = *(unsigned int*)ptr; ptr += sizeof(unsigned int); printf("number of controllers: %d\n", number_of_controllers); for (i = 0; (unsigned)i < number_of_controllers; i++) { memcpy((void*)&controller_info[i], ptr, sizeof(struct _capi_controller_info)); ptr += sizeof(struct _capi_controller_info); } } else { /*--- printf("got unexpected type %d\n", msg[0]); ---*/ goto err_close_socket; } } return fd; err_close_socket: close(fd); return -1; } unsigned capi20_isinstalled (void) { if (capi_fd >= 0) return CapiNoError; /*----- open managment link -----*/ capi_fd = capi20_open_socket(); if (capi_fd < 0) { /*--- printf("CAPI not installed\n"); ---*/ return CapiRegNotInstalled; } return CapiNoError; } /* * 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 + 1; 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; 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; int fd = -1; unsigned char buffer[128]; int err; *ApplID = 0; if (capi20_isinstalled() != CapiNoError) return CapiRegNotInstalled; fd = capi20_open_socket(); if (fd < 0) return CapiRegOSResourceErr; /*-------------------------------------------------------------------------------------*\ * Register Message \*-------------------------------------------------------------------------------------*/ buffer[0] = MSG_TYPE_CAPI; memcpy((void*)&buffer[9], (void*)&MaxB3Connection, 4); memcpy((void*)&buffer[13], (void*)&MaxB3Blks, 4); memcpy((void*)&buffer[17], (void*)&MaxSizeB3, 4); *(unsigned short*)&buffer[1] = 20; *(unsigned short*)&buffer[3] = 0; buffer[5] = 0xfd; /* REGISTER */ buffer[6] = 0x80; *(unsigned short*)&buffer[7] = 0; err = write(fd, &buffer[0], 21); if (err < 21) { close(fd); return CapiRegOSResourceErr; } /*-------------------------------------------------------------------------------------*\ * Register Antwort \*-------------------------------------------------------------------------------------*/ err = read(fd, &buffer[0], 128); /*--- printf("reading register conf: %d %s\n", err, err < 0 ? strerror(errno) : "ok"); ---*/ if (err < 11) { /*--- printf("error reading register conf, %d bytes read\n", err); ---*/ close(fd); return CapiRegOSResourceErr; } if (buffer[0] != MSG_TYPE_CAPI) { /*--- printf("error reading register conf, unexpected type %d\n", buffer[0]); ---*/ close(fd); return CapiRegOSResourceErr; } if (*(unsigned short*)&buffer[9]) { /*--- printf("register conf has result %04x\n", *(unsigned short*)&buffer[9]); ---*/ close(fd); return *(unsigned short*)&buffer[9]; } /* ApplID steht im Message Header */ applid = *(unsigned short*)&buffer[3]; /*--- printf("got applid: %d\n", applid); ---*/ 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]; unsigned ret; int len = (Msg[0] | (Msg[1] << 8)); int cmd = Msg[4]; int subcmd = Msg[5]; int rc; int fd; if (capi20_isinstalled() != CapiNoError) return CapiRegNotInstalled; if (!validapplid(ApplID)) return CapiIllAppNr; fd = applid2fd(ApplID); /*--- printf("put to appl %d, fd %d\n", ApplID, fd); ---*/ sndbuf[0] = MSG_TYPE_CAPI; memcpy(&sndbuf[1], Msg, len); if (cmd == CAPI_DATA_B3) { 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 { u_int32_t data; memcpy(&data,Msg+12, sizeof(u_int32_t)); if (data != 0) dataptr = (void *)(unsigned long)data; else dataptr = Msg + len; /* Assume data after message */ } if (len + datalen > SEND_BUFSIZ) return CapiMsgOSResourceErr; memcpy(sndbuf+len+1, dataptr, datalen); len += datalen; } else if (subcmd == CAPI_RESP) { capimsg_setu16(sndbuf, 12+1, return_buffer(ApplID, CAPIMSG_U16(sndbuf, 12+1))); } } if (cmd == CAPI_DISCONNECT_B3 && subcmd == CAPI_RESP) cleanup_buffers_for_ncci(ApplID, CAPIMSG_U32(sndbuf, 8+1)); ret = CapiNoError; errno = 0; rc = write(fd, &sndbuf[0], len+1); if (rc <= 0) { /*--- printf("put message write error\n"); ---*/ ret = CapiMsgOSResourceErr; } else if (rc < len) { ret = CapiMsgOSResourceErr; } /*--- printf("put message ret %d\n", ret); ---*/ #ifdef OLD_LOCAL_CAPI if ((rc = write(fd, sndbuf, len)) != len) { 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; } } #endif return ret; } unsigned capi20_get_message (unsigned ApplID, unsigned char **Buf) { unsigned char *rcvbuf; unsigned offset; size_t bufsiz; int rc, fd; unsigned len; struct pollfd pfds; unsigned char* msg; if (capi20_isinstalled() != CapiNoError) return CapiRegNotInstalled; if (!validapplid(ApplID)) return CapiIllAppNr; fd = applid2fd(ApplID); /*--- printf("get from appl %d, fd %d\n", ApplID, fd); ---*/ pfds.fd = fd; pfds.events = POLLIN; if (poll(&pfds, 1, 0) <= 0) { /*--- printf("poll <= 0: message queue empty\n"); ---*/ return CapiReceiveQueueEmpty; } if ((rcvbuf = get_buffer(ApplID, &bufsiz, &offset)) == 0) { /*--- printf("get no buf\n"); ---*/ return CapiMsgOSResourceErr; } *Buf = &rcvbuf[1]; msg = *Buf; rc = read(fd, &rcvbuf[0], bufsiz); if (rc < 9) { /*--- printf("error reading message %s, len %d\n", strerror(errno), rc); ---*/ return_buffer(ApplID, offset); return CapiMsgOSResourceErr; } if (rcvbuf[0] != MSG_TYPE_CAPI) { /*--- printf("unexpected message type on get message: %d\n", rcvbuf[0]); ---*/ return_buffer(ApplID, offset); return CapiMsgOSResourceErr; } len = msg[0] | (msg[1] << 8); if ((unsigned)rc < (len + 1)) { /*--- printf("get_msg: message too short?! (1), rc %d, len %d\n", rc, len); ---*/ return_buffer(ApplID, offset); return CapiMsgOSResourceErr; } /*--- printf("got msg from appl %d, fd %d\n", ApplID, fd); ---*/ CAPIMSG_SETAPPID(msg, ApplID); // workaround for old driver if (CAPIMSG_COMMAND(msg) == CAPI_DATA_B3 && CAPIMSG_SUBCOMMAND(msg) == CAPI_IND) { unsigned int datalen = CAPIMSG_DATALEN(msg); if ((unsigned)rc < (len + datalen + 1)) { /*--- printf("get_msg: message too short?! (2), rc %d, len %d datalen %d\n", rc, len, datalen); ---*/ return_buffer(ApplID, offset); return CapiMsgOSResourceErr; } /*--- printf("got data\n"); ---*/ save_datahandle(ApplID, offset, CAPIMSG_U16(msg, 18), CAPIMSG_U32(msg, 8)); capimsg_setu16(msg, 18, offset); /* patch datahandle */ if (sizeof(void *) == 4) { u_int32_t data = (u_int32_t)msg + CAPIMSG_LEN(msg); msg[12] = data & 0xff; msg[13] = (data >> 8) & 0xff; msg[14] = (data >> 16) & 0xff; msg[15] = (data >> 24) & 0xff; } else { u_int64_t data; ulong radr = (ulong)msg; if (CAPIMSG_LEN(msg) < 30) { /* * grr, 64bit arch, but no data64 included, * seems to be old driver */ memmove(msg+30, msg+CAPIMSG_LEN(msg), CAPIMSG_DATALEN(msg)); msg[0] = 30; msg[1] = 0; } data = radr + CAPIMSG_LEN(msg); msg[12] = msg[13] = msg[14] = msg[15] = 0; msg[22] = data & 0xff; msg[23] = (data >> 8) & 0xff; msg[24] = (data >> 16) & 0xff; msg[25] = (data >> 24) & 0xff; msg[26] = (data >> 32) & 0xff; msg[27] = (data >> 40) & 0xff; msg[28] = (data >> 48) & 0xff; msg[29] = (data >> 56) & 0xff; } /* keep buffer */ return CapiNoError; } return_buffer(ApplID, offset); if (CAPIMSG_COMMAND(msg) == CAPI_DISCONNECT && CAPIMSG_SUBCOMMAND(msg) == CAPI_IND) cleanup_buffers_for_plci(ApplID, CAPIMSG_U32(msg, 8)); return CapiNoError; } unsigned char * capi20_get_manufacturer(unsigned Ctrl, unsigned char *Buf) { if ((capi20_isinstalled() != CapiNoError) || (Ctrl > number_of_controllers)) return 0; if (Ctrl == 0) { Ctrl = 1; } memcpy(Buf, controller_info[Ctrl-1].manufacturer_name, 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) || (Ctrl > number_of_controllers)) return 0; if (Ctrl == 0) { Ctrl = 1; } memcpy(Buf, &controller_info[Ctrl-1].version, sizeof(struct _capi_version)); return Buf; } unsigned char * capi20_get_serial_number(unsigned Ctrl, unsigned char *Buf) { if ((capi20_isinstalled() != CapiNoError) || (Ctrl > number_of_controllers)) return 0; if (Ctrl == 0) { Ctrl = 1; } memcpy(Buf, controller_info[Ctrl-1].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 (Ctrl) { memcpy(Buf, &controller_info[Ctrl-1].profile[0], sizeof(struct capi_profile)); } else { memcpy(Buf, &number_of_controllers, sizeof(number_of_controllers)); /*--- printf("number_of_controllers: %d\n", number_of_controllers); ---*/ } 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) { /*--- printf("capi20ext_get_flags\n"); ---*/ if (ioctl(applid2fd(ApplID), CAPI_GET_FLAGS, flagsptr) < 0) return CapiMsgOSResourceErr; return CapiNoError; } int capi20ext_set_flags(unsigned ApplID, unsigned flags) { /*--- printf("capi20ext_set_flags\n"); ---*/ if (ioctl(applid2fd(ApplID), CAPI_SET_FLAGS, &flags) < 0) return CapiMsgOSResourceErr; return CapiNoError; } int capi20ext_clr_flags(unsigned ApplID, unsigned flags) { /*--- printf("capi20ext_clr_flags\n"); ---*/ 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) { return 0; } char * capi20ext_get_raw_devname(unsigned applid, unsigned ncci, char *buf, size_t size) { return 0; } int capi20ext_ncci_opencount(unsigned applid, unsigned ncci) { /*--- printf("capi20ext_ncci_opencount\n"); ---*/ 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) { if (capi_fd >= 0) { close(capi_fd); capi_fd = -1; } }