KCAPI(9)

NAME
kcapi_register, kcapi_release, kcapi_put_message, kcapi_get_message, kcapi_set_signal, kcapi_get_manufacturer, kcapi_get_version, kcapi_get_serial_number, kcapi_get_profile, kcapi_get_ctlr_driver_info, kcapi_reset_ctlr, kcapi_get_mbuf, kcapi_free_mbuf - CAPI manager interface for kernel space CAPI applications

SYNOPSIS
#include <capi20.h>
#include <capi_bsd.h>
unsigned
kcapi_register(unsigned uMaxLogicalConnections, unsigned uMaxBDataBlocks, unsigned uMaxBDataLen, unsigned *puApplID);
unsigned
kcapi_release(unsigned uApplID);
unsigned
kcapi_put_message(unsigned uApplID, struct mbuf *pmbMsg);
unsigned
kcapi_get_message(unsigned uApplID, struct mbuf **ppmbMsg);
unsigned
kcapi_set_signal(unsigned uApplID, void (*pfnCallback) (unsigned uApplID, u_int32_t dwParam), u_int32_t dwParam);
unsigned
kcapi_get_manufacturer(unsigned uCtlr, unsigned char *pszBuffer);
unsigned
kcapi_get_version(unsigned uCtlr, unsigned *puCAPIMajor, unsigned *puCAPIMinor, unsigned *puManufacturerMajor, unsigned *puManufacturerMinor, unsigned *puBSDMajor, unsigned *puBSDMinor);
unsigned
kcapi_get_serial_number(unsigned uCtlr, unsigned char *pszBuffer);
unsigned
kcapi_get_profile(unsigned uCtlr, CAPIProfileBuffer_t *pProfile);
unsigned
kcapi_get_ctlr_driver_info(unsigned uCtlr, CAPICtlrDriverInfo_t *pDrvInfo);
unsigned
kcapi_reset_ctlr(unsigned uCtlr, size_t nNumDataBlocks, CAPICtlrDataBlock_t *paDataBlocks);
struct mbuf *
kcapi_get_mbuf(size_t nLen);
void
kcapi_free_mbuf(struct mbuf *pmbMsg);

DESCRIPTION
The functions described in this manual page make up the application interface for kernel space CAPI applications of kcapimgr, the kernel CAPI manager. They are modelled after the CAPI specification for other operating systems (see http://www.capi.org), namely Novell NetWare and Linux. In addition to the standard CAPI operations there are functions for additional information about a controller and its driver, for downloading an active board with its firmware and configuration and finally two helper functions for allocating and releasing mbufs.

  Purpose and handling of mbufs
Mbufs are used in c4b to store CAPI messages and Data-B3 blocks. If You are not familiar with this term, You probably do not want to write a kernel space CAPI application. Every CAPI message is transfered through the interfaces of the CAPI manager with mbufs. The mbufs are allocated with a packet header to be compatible with i4b and other network interfaces of the kernel. The CAPI messages themselves are stored into the data part of the mbuf. The mbuf header is mainly used to put mbufs, and thus CAPI messages, into internal message queues.

If the message is a Data-B3-Request or -Indication there is an attached data block for the message. This data block is stored in an additional mbuf. The address of this second mbuf is stored in the member m_next (the same as m_hdr.mh_next) of the mbuf for the corresponding CAPI message. This way both mbufs are automatically released with one function call when releasing the mbuf for the CAPI message. As a convenience function (and to ensure compatibility with all components of c4b) the helper function kcapi_get_mbuf() shall be used for allocating mbufs to store CAPI messages and their data blocks. The counterpart named kcapi_free_mbuf() shall be used to release such mbufs.

  Signalling of incoming CAPI messages
Incoming CAPI messages are only signalled to the CAPI application through a callback function registered with kcapi_set_signal(). If an application does not register such a callback function, it must poll for new messages.

  Architecture independent declaration of CAPI structures and messages
The definitions for CAPI messages and related structures in the header file capi20.h use some macros to declare the structure members. E.g. a 16bit integer is declared as of type cWORD. This identifier is either defined as u_int16_t or as unsigned char [2] internally, according to the definition state of the symbol WANT_MACHINE_INDEPENDANT_CAPI_DEFS.

On machines with Intel (little endian) byte order it is usually sufficient to use the scalar types, because CAPI messages are defined to be in Intel byte order. But on other platforms all integer fields larger than 8bit need to be byte swapped in order to be handled in the normal way.

For these architectures the array notation is necessary. The CAPI messages are defined to use the Intel byte order. But other architectures can only handle integer values in big endian byte order. So when exchanging CAPI messages between an application and the CAPI manager the byte order must be switched.

Therefore additional macros are defined for extracting the scalar value out of such fields. For the above example the macro C_GET_WORD() can be used to extract the 16bit value into a regular integer variable suitable for the machine architecture.

The extraction macro can be used in every case, even if the type cWORD is defined to be u_int16_t. In this case the macro would simply return the field value unchanged. There are other macros for the other direction, i.e. to store a scalar integer value into a byte array of the necessary length.

So it is possible to write an application that works well on either of the two architecture families, little and big endian. One only has to use the macros to get the current value of a variable or store it into a CAPI message. If the application will only run on the Intel platform, one may leave the get and put macros aside and simply use the members of the CAPI structures as normal scalar integer types. The just mentioned macros for data types and macros to extract the variable values are defined in the header file capidef.h (automatically included within capi20.h).

Lets look at a simple example. Assume the following structure definition:

    struct
    {
       cBYTE  b;
       cWORD  w;
       cDWORD dw;
    } s;

An Intel-only application could leave the symbol WANT_MACHINE_INDEPENDANT_CAPI_DEFS undefined and simply use the structure members as normal scalar variables.

    u_int8_t  a = s.b;
    u_int16_t b = s.w;
    u_int32_t c = s.dw;

An architecture independent application should use code like the following and define the symbol WANT_MACHINE_INDEPENDANT_CAPI_DEFS at least on non-Intel machines:

    u_int8_t  a = C_GET_BYTE (s.b);
    u_int16_t b = C_GET_WORD (s.w);
    u_int32_t c = C_GET_DWORD (s.dw);

The method to store data into the structure members for Intel-only applications should be clear enough to leave the sample out. Architecture independent applications would store data as follows:

    C_PUT_BYTE (s.b, 42);
    C_PUT_WORD (s.w, 4711);
    C_PUT_DWORD (s.dw, 123456);

Currently c4b and its components are only supported under FreeBSD and on Intel machines. But this could change quickly if someone implements a device driver for an ISDN controller on the Alpha platform, for example. The CAPI manager itself and the other kernel modules (but unfortunately not the AVM active ISDN controller driver) are ready to be compiled under non-Intel platforms.

  Return values of the CAPI functions
Nearly all functions return an unsigned integer value as a direct function result. This result is one of the CAPI info, reason or reason-b3 values defined in the CAPI specification. Identifiers for them are defined in the header file capi_result.h (like most other CAPI header files automatically included within capi20.h). There are some additional result values specific to the BSD implementation defined in the header file capi_bsd.h. If a function call succeeds the value CAPI_OK (0) is returned. Other values in general signal some error value, see the CAPI specification.

  Description of the individual functions
Most of the functions mentioned in section SYNOPSIS are CAPI standard operations. These functions do not need extensive explanation, as they are already defined in the CAPI specification (see http://www.capi.org). In the following paragraphs only the BSD-specific differences are described in detail. The additional functions are extensions to the CAPI standard operations for the BSD operating systems. They are only described in this manual page.

The kcapi_register() function must be called before any CAPI message can be exchanged between the application and the CAPI manager (and effectively the ISDN controller). If the registration operation is successful the caller is assigned a new application id. This application id must be used in all later function calls regarding this registered CAPI application. The caller must call kcapi_release() when the obtained application id is not needed any more.

Beware that there is no mechanism in the kernel to automatically cleanup (CAPI) resources on process exit for kernel modules, because the calling process is the kernel itself. And this process will only die when the system is shut down.

The function kcapi_release() must be called when an application id earlier obtained through kcapi_register() is not needed any more. As there is no automatic cleanup mechanism for kernel space CAPI applications there will be resource leaks if the release call is missing in a kernel CAPI application.

kcapi_put_message() is used to send CAPI messages from an application to an ISDN controller (or just to the CAPI manager itself, e.g. to enable the CAPI tracing facility). Before calling this function, the application must call kcapi_register() to obtain a valid application id. The CAPI message to send must be stored into an mbuf. If the message is a Data-B3-Indication the data block must be stored in a second mbuf, its address must be stored in the member m_next of the mbuf for the CAPI message. The data block length must be set in the CAPI message itself and in the length field of the data mbuf.

Differing from the general CAPI specification the mbuf(s) specified as the parameter to this function call change their ownership from application to the CAPI manager if the result is CAPI_OK. In this case the mbuf with the CAPI message (and the possibly attached Data-B3 block) is inserted into internal queues of the CAPI manager or the controller driver. The application must not assume ownership of the mbuf(s) after a successful call to kcapi_put_message() or even that there is still valid data to read in it.

The counterpart kcapi_get_message() is called to receive an incoming CAPI message from an ISDN controller. The new message is returned in an mbuf. Again if the message is a Data-B3-Indication, the data block is stored in an additional mbuf and its address is stored in the member m_next of the mbuf for the CAPI message.

Differing from the general CAPI specification the mbuf(s) returned change their ownership from the CAPI manager to the application if the function call is successful. The CAPI manager will not assume ownership nor even try to read any data from the mbuf(s) after a successful kcapi_get_message(). The CAPI application is responsible to call kcapi_free_mbuf() for the obtained mbuf with the CAPI message, when it (and the possibly attached data block mbuf) is not needed any more. Beware again, there is no mechanism to cleanup allocated mbufs for kernel space CAPI applications when kcapi_release() is called. If the kernel runs out of mbufs, it will panic sooner or later.

A CAPI application might poll for incoming messages (not recommended) or register a callback function through kcapi_set_signal(). The callback function specified will be called for the application id whenever a new CAPI message arrives for it. The application shall not do much in a call to the callback function. If this call is held the whole CAPI manager is blocked. No other application can send or receive any CAPI message in this case. The application usually only sets a flag or the like and later fetches the new message in another thread. The callback function may be unregistered when calling kcapi_set_signal() with a NULL pointer as the callback function argument.

The function kcapi_get_manufacturer() is used to obtain a string representation for the vendor of the ISDN controller in question, zero terminated. If the controller number specified is zero, the manufacturer string of the CAPI manager itself is returned. The target buffer must be large enough to hold at least 64 bytes of data, including the terminating null byte.

The function kcapi_get_version() is called to get version information from an ISDN controller. Three pairs of version values may be obtained, each pair consisting of a major and a minor version number. Each parameter argument may be NULL if the corresponding version number part is not needed. The first pair will always be ‘2.0’ until the CAPI association is releasing a CAPI version higher than 2.0 and it is implemented in the CAPI manager for BSD. The second version pair will receive the version information of the controller firmware. The source of this information is delivered by the driver when registering the controller at the CAPI manager, if this information is available to the driver. The last version pair receives the version number of the device driver for the controller. Especially for active boards this might be different to the firmware, because on free operating systems the driver implementor is often different from the hardware manufacturer. If the controller number is specified as 0 the version numbers for the CAPI manager itself are returned. As in this case there is no distinction between firmware and driver version, both the manufacturer and the BSD version are the same.

kcapi_get_serial_number() is very similar to kcapi_get_manufacturer(). It is called to obtain the serial number of a specific controller. If the controller does not support serial numbers, the result buffer will receive an empty string, i.e. the first byte will be set to zero. If the controller number is specified as 0 the serial number of the CAPI manager will be returned. As it has no serial number the result is an empty string.

The kcapi_get_profile() function is used to get information about the number of installed controllers and about the capabilities of a specific controller. This function is fully compatible with other operating system variants of this function.

As an extension to kcapi_get_profile() the function kcapi_get_ctlr_driver_info() may be called to obtain additional information about the controller and its driver. Note that here the controller number 0 is not allowed. The data structure specified on the parameter list receives information about the unique controller name, the controller type name, the driver name, the driver unit number, the number of ISDN ports of this board and the port number of the current controller for the board. The later information is intended for boards with more than one ISDN port, e.g. the AVM-C4 owns four ISDN ports which are registered as four separate CAPI controllers. Very useful is this information for tools to download firmware and configuration data to active ISDN boards. A download will only be performed if the downloading tool recognizes a valid board type and driver string.

Active ISDN boards must be downloaded with firmware and configuration data. This task is performed by calling kcapi_reset_ctlr() with a memory block for the firmware and additional data blocks with configuration data if needed. The content and the number of data blocks needed for a specific board is defined by the respective driver. For every driver requiring a download of firmware and / or configuration data there must be a corresponding downloading tool exclusively for this driver. E.g. the avmaic device driver comes with the tool avmaicctl that performs the downloading operations and internally calls kcapi_reset_ctlr(). This operation may not be supported by all drivers. If the number of data blocks specified for this function is zero, the board will only be reset and disabled by the driver (if this operation is supported).

kcapi_get_mbuf() is used in CAPI applications, controller drivers and in the CAPI manager itself to obtain new mbufs to store CAPI messages and Data-B3 blocks. If every application calls this function to get mbufs, compatibility is retained within c4b. The argument to this function must be the maximum length of data (i.e. a CAPI message or a Data-B3 block) to store into the mbuf. The member m_len of the mbuf is already set to this size value if a new mbuf is returned. If there are no more mbufs available in the kernel tables, the result value of this function is NULL.

To code a Data-B3-Request an application first needs an mbuf for the CAPI message itself. So an mbuf with a maximum length of 22 bytes (normal length of a Data-B3-Request message) is requested. Then a second mbuf is needed for the data block. The address of this data block mbuf must be stored into the member m_next of the CAPI message mbuf. After filling the message and the data into their respective mbufs this message is ready to be sent through kcapi_put_message().

The counter part of kcapi_get_mbuf() is kcapi_free_mbuf(). Every mbuf obtained earlier through kcapi_get_mbuf() shall be released by calling kcapi_free_mbuf(). Note that an attached data block mbuf whose address is stored in the member m_next of the mbuf specified as a function parameter is automatically released, too. So if a data block attached to a CAPI message should still be available after the message itself is released, the member m_next of the CAPI message mbuf must be set to NULL before calling kcapi_free_mbuf().

RETURN VALUES
All functions but kcapi_get_mbuf() and kcapi_free_mbuf() return an unsigned integer value as a direct result. If this value is CAPI_OK (defined as 0) the function call was successful. Other values usually signal an error. The possible return values are defined in the CAPI specification (see http://www.capi.org) and in the header files capi_result.h and capi_bsd.h.

SEE ALSO
capi20(3), c4b(4), i4b(4), kcapimgr(4), capi-trc(7). CAPI Association e.V., Common ISDN API v2.0 4th Edition, June 2001, see http://www.capi.org.

STANDARDS
The functions kcapi_register(), kcapi_release(), kcapi_put_message(), kcapi_get_message(), kcapi_set_signal(), kcapi_get_manufacturer(), kcapi_get_version(), kcapi_get_serial_number(), kcapi_get_profile() largely comply with the currently existing CAPI specification. The differences originate in the specific environment of the BSD kernel (e.g. passing messages in mbufs).

The c4b implementation of CAPI for the BSD operating systems should be added to the official CAPI standard. But for this task an active member of the CAPI association must introduce a recommendation on one of the regular meetings and the author of c4b is no member.

HISTORY
This manual page and the kernel CAPI implementation first appeared as an add-on for FreeBSD 4.6.

AUTHORS
This manual page was written by Thomas Wintergerst <twinterg@gmx.de>.