/* * $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 "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 int capi_fd = -1; #define MAX_CONTROLLERS 16 static unsigned int number_of_controllers; 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]; /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ int capi20_open_socket(void) { int sock; int err; struct sockaddr_in addr; char* env = NULL; long int port; sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) return sock; 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; err = connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)); if (err < 0) { /*--- printf("connect: %s\n", strerror(errno)); ---*/ close(sock); return err; } /*--- printf("capi open\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; int bytes_read; unsigned char buf[4]; bytes_read = 0; while (bytes_read < 4) { err = read(sock, (void*)&buf[bytes_read], 4 - bytes_read); if (err <= 0) break; bytes_read += err; } if (bytes_read < 4) goto err_close_socket; number_of_controllers = *(unsigned int*)buf; /*--- printf("number of controllers: %d\n", number_of_controllers); ---*/ for (i = 0; i < number_of_controllers; i++) { bytes_read = 0; while (bytes_read < sizeof(struct _capi_controller_info)) { err = read(sock, ((unsigned char*)&controller_info[i]) + bytes_read, sizeof(struct _capi_controller_info) - bytes_read); if (err <= 0) break; bytes_read += err; } if (bytes_read < sizeof(struct _capi_controller_info)) goto err_close_socket; /*--- printf("got controller %d, %d bytes read\n", i, bytes_read); ---*/ } /*--- printf("got capi info\n"); ---*/ } return sock; err_close_socket: close(sock); 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; 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[20]; unsigned written; *ApplID = 0; if (capi20_isinstalled() != CapiNoError) return CapiRegNotInstalled; fd = capi20_open_socket(); if (fd < 0) return CapiRegOSResourceErr; /*-------------------------------------------------------------------------------------*\ * Register Message \*-------------------------------------------------------------------------------------*/ memcpy((void*)&buffer[8], (void*)&MaxB3Connection, 4); memcpy((void*)&buffer[12], (void*)&MaxB3Blks, 4); memcpy((void*)&buffer[16], (void*)&MaxSizeB3, 4); *(unsigned short*)&buffer[0] = 20; *(unsigned short*)&buffer[2] = 0; buffer[4] = 0xfd; /* REGISTER */ buffer[5] = 0x80; *(unsigned short*)&buffer[6] = 0; written = 0; while (written < 20) { int err; err = write(fd, &buffer[written], 20 - written); if (err <= 0) break; written += err; } if (written < 20) { close(fd); return CapiRegOSResourceErr; } /*-------------------------------------------------------------------------------------*\ * Register Antwort \*-------------------------------------------------------------------------------------*/ written = 0; while (written < 10) { int err; err = read(fd, &buffer[written], 10 - written); if (err <= 0) break; written += err; } if (written < 10) { /*--- printf("error reading register conf, %d bytes read\n", written); ---*/ close(fd); return CapiRegOSResourceErr; } if (*(unsigned short*)&buffer[8]) { close(fd); /*--- printf("register conf has result %04x\n", *(unsigned short*)&buffer[8]); ---*/ return *(unsigned short*)&buffer[8]; } /* ApplID steht im Message Header */ applid = *(unsigned short*)&buffer[2]; /*--- 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; unsigned written; if (capi20_isinstalled() != CapiNoError) return CapiRegNotInstalled; if (!validapplid(ApplID)) return CapiIllAppNr; fd = applid2fd(ApplID); /*--- printf("put to appl %d, fd %d\n", ApplID, fd); ---*/ memcpy(sndbuf, 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, dataptr, datalen); len += datalen; } else if (subcmd == CAPI_RESP) { capimsg_setu16(sndbuf, 12, return_buffer(ApplID, CAPIMSG_U16(sndbuf, 12))); } } if (cmd == CAPI_DISCONNECT_B3 && subcmd == CAPI_RESP) cleanup_buffers_for_ncci(ApplID, CAPIMSG_U32(sndbuf, 8)); ret = CapiNoError; errno = 0; written = 0; while (written < len) { rc = write(fd, &sndbuf[written], len); if (rc <= 0) { /*--- printf("put message write error\n"); ---*/ ret = CapiMsgOSResourceErr; } written += rc; } if (written < 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 bytes_read; unsigned len; struct pollfd pfds; 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 ((*Buf = rcvbuf = get_buffer(ApplID, &bufsiz, &offset)) == 0) { /*--- printf("get no buf\n"); ---*/ return CapiMsgOSResourceErr; } bytes_read = 0; while (bytes_read < 2) { pfds.fd = fd; pfds.events = POLLIN; if (poll(&pfds, 1, -1) <= 0) { /*--- printf("poll <= 0: %s\n", strerror(errno)); ---*/ return CapiMsgOSResourceErr; } rc = read(fd, &rcvbuf[bytes_read], 2 - bytes_read); if (rc < 0) { return_buffer(ApplID, offset); /*--- printf("get message read error %s\n", strerror(errno)); ---*/ return CapiMsgOSResourceErr; } if ((rc == 0) && (bytes_read == 0)) { return_buffer(ApplID, offset); /*--- printf("get message queue empty\n"); ---*/ return CapiReceiveQueueEmpty; } bytes_read += rc; } len = rcvbuf[0] | (rcvbuf[1] << 8); while (bytes_read < len) { pfds.fd = fd; pfds.events = POLLIN; if (poll(&pfds, 1, -1) <= 0) { /*--- printf("poll <= 0: %s\n", strerror(errno)); ---*/ return CapiMsgOSResourceErr; } rc = read(fd, &rcvbuf[bytes_read], len - bytes_read); if (rc <= 0) { return_buffer(ApplID, offset); /*--- printf("get message read error (2) %s\n", strerror(errno)); ---*/ return CapiMsgOSResourceErr; } bytes_read += rc; } /*--- printf("got msg from appl %d, fd %d\n", ApplID, fd); ---*/ CAPIMSG_SETAPPID(rcvbuf, ApplID); // workaround for old driver if (CAPIMSG_COMMAND(rcvbuf) == CAPI_DATA_B3 && CAPIMSG_SUBCOMMAND(rcvbuf) == CAPI_IND) { unsigned int datalen = CAPIMSG_DATALEN(rcvbuf); while (bytes_read < (len + datalen)) { pfds.fd = fd; pfds.events = POLLIN; if (poll(&pfds, 1, -1) <= 0) { /*--- printf("poll <= 0: %s\n", strerror(errno)); ---*/ return CapiMsgOSResourceErr; } rc = read(fd, &rcvbuf[bytes_read], (len + datalen) - bytes_read); if (rc <= 0) { return_buffer(ApplID, offset); return CapiMsgOSResourceErr; } bytes_read += rc; } /*--- printf("got data\n"); ---*/ 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; } unsigned char * capi20_get_manufacturer(unsigned Ctrl, unsigned char *Buf) { if (capi20_isinstalled() != CapiNoError) return 0; memcpy(Buf, controller_info[Ctrl].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) return 0; memcpy(Buf, &controller_info[Ctrl].version, sizeof(struct _capi_version)); return Buf; } unsigned char * capi20_get_serial_number(unsigned Ctrl, unsigned char *Buf) { if (capi20_isinstalled() != CapiNoError) return 0; memcpy(Buf, controller_info[Ctrl].serial, CAPI_SERIAL_LEN); Buf[CAPI_SERIAL_LEN-1] = 0; return Buf; } unsigned capi20_get_profile(unsigned Ctrl, unsigned char *Buf) { /*--- printf("capi20_get_profile: %d %d\n", Ctrl, sizeof(struct capi_profile)); ---*/ 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; } }