KCAPI-DRV(9)

NAME
kcapi_ctlr_register, kcapi_ctlr_enable, kcapi_ctlr_disable, kcapi_ctlr_release, kcapi_ctlr_receive_capi_message, kcapi_ctlr_receive_notify_message, kcapi_get_mbuf, kcapi_free_mbuf kcapi_get_ctlr_notify_mbuf, CAPIDrv_RegisterFct_t, CAPIDrv_ReleaseFct_t, CAPIDrv_PutMessageFct_t, CAPIDrv_ResetCtlrFct_t, CAPIDrv_PutNotifyMsgFct_t - CAPI manager interface for ISDN controller drivers

SYNOPSIS
#include <capi20.h>
#include <capi_bsd.h>
#include <c4b/kcapimgr/capi_drv.h>

  Functions provided by the CAPI manager
unsigned
kcapi_ctlr_register(CAPICtlrRegisterParams_t *pCtlrRegParams, unsigned *puUniqueCtlrNum);
unsigned
kcapi_ctlr_enable(unsigned uUniqueCtlrNum, unsigned uDrvCtlrNum);
unsigned
kcapi_ctlr_disable(unsigned uUniqueCtlrNum);
unsigned
kcapi_ctlr_release(unsigned uUniqueCtlrNum);
void
kcapi_ctlr_receive_capi_message(unsigned uUniqueCtlrNum, unsigned uCtlrApplID, struct mbuf *pmbMsg);
void
kcapi_ctlr_receive_notify_message(unsigned uUniqueCtlrNum, struct mbuf *pmbMsg);
struct mbuf *
kcapi_get_mbuf(size_t nLen);
void
kcapi_free_mbuf(struct mbuf *pmbMsg);
struct mbuf *
kcapi_get_ctlr_notify_mbuf(size_t nLen);

  Functions provided by the controller driver
unsigned
(*CAPIDrv_RegisterFct_t)(unsigned uDrvCtlrNum, unsigned uMaxLogicalConnections, unsigned uMaxBDataBlocks, unsigned uMaxBDataLen, unsigned *puApplID);
unsigned
(*CAPIDrv_ReleaseFct_t)(unsigned uDrvCtlrNum, unsigned uCtlrApplID);
unsigned
(*CAPIDrv_PutMessageFct_t)(unsigned uDrvCtlrNum, unsigned uCtlrApplID, struct mbuf *pmbMsg);
unsigned
(*CAPIDrv_ResetCtlrFct_t)(unsigned uUniqueCtlrNum, size_t nNumDataBlocks, CAPICtlrDataBlock_t *paDataBlocks);
unsigned
(*CAPIDrv_PutNotifyMsgFct_t)(unsigned uDrvCtlrNum, struct mbuf *pmbMsg);

DESCRIPTION
The functions and function prototype declarations described in this manual page make up the controller driver interface of kcapimgr, the kernel CAPI manager. They are inspired by the driver interface of the Novell NetWare CAPI manager (see http://www.capi.org), but designed for the special environment and requirements of the BSD kernel.

  Controller number and application id mapping
The CAPI manager is able to perform mapping of controller numbers and application ids between the controller driver and CAPI applications. This may be needed if a controller imposes a limitation on the usable controller numbers and / or application ids.

In general it is not a good idea implementing a controller driver that requires such mapping. But there may be even good reasons to do so.

If a controller driver requires application id mapping, this is declared when registering the controller at the CAPI manager by calling kcapi_ctlr_register(). The structure argument to this function contains a field named ulFlags. The bit CAPI_CTLRFLAG_NEED_APPL_ID_MAPPING must be cleared (no application id mapping needed) or set (controller assigns its own application ids, mapping needed) according to the driver requirements.

Controller number mapping is declared in a different way. At the time a controller is registered, it may not be usable because it still needs to be downloaded with its firmware. After the firmware is loaded onto the board, the driver must enable the controller at the CAPI manager by calling kcapi_ctlr_enable(). This function requires two controller numbers as parameters. The first is the one assigned to the controller by the CAPI manager on registration. This is called the ‘unique controller number’. The second argument declares the driver specific controller number used for the controller. It is called the ‘driver controller number’. If both are equal no controller mapping is needed. If they are different, the CAPI manager will map between these two controller numbers in every CAPI message exchanged between the driver and the CAPI manager.

  Using mbufs as containers for CAPI messages and data blocks
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 an ISDN controller driver. 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.

The only exception from this rule is used when passing messages to the function kcapi_ctlr_receive_notify_message(). This function requires the mbuf passed to be allocated by the function kcapi_get_ctlr_notify_mbuf(). Releasing these mbufs is done as usual with kcapi_free_mbuf().

  General CAPI message exchange between CAPI manager and controller driver
As mentioned in the section before CAPI messages are exchanged through mbufs between the CAPI manager and the controller driver. When sending a message by calling the driver provided function (*CAPIDrv_PutMessage_t)() by the CAPI manager, an mbuf is passed to the driver. If the message can be accepted, the return value of the function call must be CAPI_OK. In this case the ownership of the mbuf has changed from the CAPI manager to the controller driver. The driver is then responsible to release the mbuf when it is not needed any more.

This is similar in the other direction. When the controller driver calls the CAPI manager functions kcapi_ctlr_receive_capi_message() or kcapi_ctlr_receive_notify_message(), the ownership of the mbuf (and all possibly attached mbufs) changes from the driver to the CAPI manager. As there is no return value for these two function calls, the mbufs will always leave the responsibility of the driver.

  Description of CAPI manager provided functions
At the time an ISDN controller device is attached, the device driver must register the controller at the CAPI manager by calling kcapi_ctlr_register(). If the direct function result is CAPI_OK, the controller will be assigned a unique controller number with a value between 1 and 127, inclusive. The first argument to this function is a structure that must be filled before calling this function. The memory for this structure must remain available until the driver calls kcapi_ctlr_release(). The address of this memory must not change during this time. The CAPI manager simply stores the address of the structure for the controller, it does not copy its content to another memory block.

The data type for this structure is declared in the header file c4b/kcapimgr/capi_drv.h, usually lying under the directory /usr/src/sys. The header file contains some comments about the structure fields. It is important to set each field to a valid value. Especially the function pointers must be set. The controller reset and PutNotify functions are optional. If resetting (i.e. downloading firmware or configuration) or receiving notify messages (sent by the driver itself) is not supported for a controller, these function pointers may be set to NULL.

The controller profile must be initialized at least with the valid number of B-channels. All other fields must be set to zero if the controller is currently not usable. Before enabling the controller the other fields shall be modified to reflect the actual capabilities of the controller.

Just after the registration a controller is marked to be in the disabled state internally in the CAPI manager. In this state the only valid operation is to call the driver provided function (*CAPIDrv_ResetCtlrFct_t)(). After a controller is ready for operation, probably because its firmware and / or configuration was just downloaded, the driver must call kcapi_ctlr_enable() for this controller. Before calling this function the driver may modify the controller profile data. The address of the surrounding data structure was formerly reported to the CAPI manager when registering the controller.

If the controller or the driver defines its own controller numbering scheme and thus needs controller number mapping, the second argument for kcapi_ctlr_enable() must be the internally used controller number. The CAPI manager will only send CAPI messages to the controller with the controller numbers in the message mapped to the internal number needed in the driver. If it is possible at all to not use controller number mapping, the driver shall not use this feature.

The function kcapi_ctlr_disable() is called by a driver if the controller shall not be used any more. The argument to the function must be the CAPI manager assigned unique controller number, not the driver controller number (may differ from the unique number). Calling this function is necessary e.g. just before executing the controller reset or download operation in the driver code. This function and kcapi_ctlr_enable() may even be called as a ‘callback’ operation, e.g. the CAPI manager calls the driver function (*CAPIDrv_ResetCtlrFct_t)() and the driver itself calls kcapi_ctlr_disable() with the first function call.

If the controller driver is unloaded (if compiled as a separate kernel module), it first must unregister every CAPI controller it drives. This is done by calling kcapi_ctlr_release() for each controller. The argument to the function must be the CAPI manager assigned unique controller number, not the driver controller number (may differ from the unique number). After this call the CAPI manager discards all information about this controller and sends Disconnect-Indications to every application that still handles an open connection over it. The unique controller number may be reused for another controller driver that is loaded after kcapi_ctlr_release() is called.

CAPI messages are transfered from a controller driver to the CAPI manager by calling kcapi_ctlr_receive_capi_message(). There is no return value, the CAPI manager just takes the message and from then on is responsible to deliver it to the application or to release the surrounding mbuf if it cannot be delivered.

A lost CAPI message or data block can be signalled to the CAPI manager (and thus to the CAPI application) by calling kcapi_ctlr_receive_capi_message() with an empty mbuf, i.e. an mbuf with the member m_len set to zero. The CAPI application will get the return value CME_GET_QUEUE_OVERFLOW the next time it calls kcapi_get_message().

The CAPI manager will not call directly into any CAPI application within this function call. Instead the CAPI message is simply put into an internal queue for later handling by the CAPI manager. For this purpose the CAPI manager runs a kernel thread of its own. The sense of this behaviour is to reduce CPU time consumption in interrupt context. If there are multiple controllers in the system and each one is under heavy load, board interrupts may get lost if the overall duration of interrupt routine calls is too high.

The function kcapi_ctlr_receive_notify_message() has a similar purpose. It is used for passive ISDN controllers or active ones that do not deal directly with CAPI messages. A controller driver may send itself a message out of an interrupt handler or in order to serialize other tasks. As an example an interrupt handler may collect incoming data from a controller i/o interface. As soon as this task is completed the handler may create a message to itself (i.e. to the driver) to further handle the data. This way the interrupt handler can be implemented rather short. Other time consuming tasks like e.g. DTMF detection for voice connections or other B-channel protocol handling will be done out of interrupt context.

Every controller notification message enqueued through kcapi_ctlr_receive_notify_message() will be sent back to the driver through the driver provided function (*CAPIDrv_PutNotifyMsgFct_t)(). For this to work the driver must specify a valid function pointer for the corresponding field in the controller registration structure. The mbuf for the notification message must be obtained by calling kcapi_get_ctlr_notify_mbuf() to be distinguishable from normal CAPI messages.

kcapi_get_mbuf() is used in controller drivers and in the CAPI manager itself to obtain new mbufs to store CAPI messages and Data-B3 blocks. If every driver 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-Indication a driver 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-Indication 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_ctlr_receive_capi_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().

The function kcapi_get_ctlr_notify_mbuf() must be called to obtain mbufs for sending through kcapi_ctlr_receive_notify_message(). If the driver wants to send some data with this mbuf that does not fit into a single mbuf, the data should be filled into a second mbuf and its address should be stored into the notification mbuf. E.g. in order to pass a data block of the maximum size of 2KB and some additional info data, a driver may allocate a notification mbuf for the informational data and attach the data mbuf by storing its address into the member m_next of the notification mbuf. This way both mbufs are correctly released when releasing the notification mbuf (the data mbuf is then released automatically), even if the release operation is not performed in the driver but instead in the CAPI manager.

  Description of controller driver provided functions
When registering a controller at the CAPI manager the driver has to fill the registration data strcture. Five fields of this structure are function pointers that may be called by the CAPI manager. The first three pointers of the prototypes (*CAPIDrv_RegisterFct_t)(), (*CAPIDrv_ReleaseFct_t)() and (*CAPIDrv_PutMessageFct_t)() are mandatory and must be filled with addresses of existing functions. The remaining two of the prototypes (*CAPIDrv_ResetCtlrFct_t)() and (*CAPIDrv_PutNotifyMsgFct_t)() are optional. If the driver does not support the corresponding functionality their values must be set to NULL.

The function of type (*CAPIDrv_RegisterFct_t)() will be called by the CAPI manager whenever a CAPI application is to be registered at the controller. Application registration within the CAPI manager is done on demand. When a CAPI application calls kcapi_register(), the CAPI manager only stores the registration parameters for later use. Only when the application sends the first CAPI message to a controller, the registration function for the controller is called. This way resources in controller drivers are saved if there are multiple controllers in the machine and applications use only one.

When registering an application the CAPI manager provides the driver with an already assigned application id. If the controller needs application id mapping this application id may be modified on return to the CAPI manager. This is the way the CAPI manager learns the controller specific application id to map the unique application id assigned by the CAPI manager to.

Application release in contrast is sent directly to every controller the application is registered to by calling (*CAPIDrv_ReleaseFct_t)().

The function of type (*CAPIDrv_PutMessageFct_t)() is called when there is a CAPI message to be sent to the controller. If the result value is CAPI_OK, the driver is responsible for releasing the mbuf and the possibly attached second mbuf for a Data-B3 block by calling kcapi_free_mbuf().

The CAPI manager does not maintain a send queue for each controller. Usually active controllers have an internal message queue of their own. So if the driver cannot handle the message at once, it either has to queue the message in a private queue or it may reject the message with a return value of CME_PUT_QUEUE_FULL. In the later case this return value will directly be returned to the CAPI application. If the driver maintains a message queue, it should implement a length restriction. Otherwise the queue could be filled up with all available mbufs and thus blocking vital kernel resources.

The function of type (*CAPIDrv_ResetCtlrFct_t)() is called (indirectly) by tool programs for downloading firmware and / or configuration to ISDN boards. For active ISDN controllers this is absolutely necessary as they cannot work without their firmware. Even for passive controllers this function is useful for providing the driver with the configuration of the line the controller is attached to.

For downloading firmware and / or configuration data the function (*CAPIDrv_ResetCtlrFct_t)() can be called with an array of data blocks, each array entry consisting of a length value and a pointer to the data as a byte array. Every driver defines the content and the number of supported data blocks it supports. In general for each driver supporting the reset operation there must be a corresponding tool program to do the download. If the number of data blocks specified in the function call is zero, the controller is to be reset only, no firmware shall be downloaded. This may be used to physically disable active boards, but it is not limited to these board types.

If the driver does not support or need the reset functionality, it must set the corresponding pointer in the controller registration data structure to NULL.

The function of type (*CAPIDrv_PutNotifyMsgFct_t)() is called by the CAPI manager whenever the driver has called kcapi_ctlr_receive_notify_message() before. The message mbuf given to the later CAPI manager function will be passed unchanged to the driver. If the driver does not support or need this functionality, it must set the corresponding pointer in the controller registration data structure to NULL.

IMPLEMENTATION NOTES
The mechanism of the notification messages is currently not used in the one and only existing controller driver avmaic. The concept seems to be useful even for passive controllers. But as such drivers still have to be implemented, this mechanism and so the function prototypes may change in the future if the need arises.

RETURN VALUES
All functions returning an integer value of unsigned return either CAPI_OK on success or a value not equal to zero if an error occurs. The allowed values for these error values are defined in the CAPI specification (see http://www.capi.org) and as well in the header files capi_result.h and capi_bsd.h.

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

STANDARDS
The messages exchanged between the CAPI manager and controller drivers comply with the CAPI 2.0 standard (not counting the notification messages). The same is true for the semantics of the CAPI messages.

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>.