Compare commits

...

5 Commits

Author SHA1 Message Date
Frank A. Uepping bb490916a8 Date stamp added. 2005-01-29 15:53:54 +00:00
Frank A. Uepping e749b19cdd Docbook revised. 2005-01-25 18:13:37 +00:00
Frank A. Uepping abff2ffe45 Docbook revised. 2004-12-08 20:44:52 +00:00
Frank A. Uepping 5cb28f7a5f Documentation in docbook format added. 2004-12-06 21:13:23 +00:00
Frank A. Uepping 357ea34917 File removed in favor of the docbook. 2004-12-06 21:11:32 +00:00
11 changed files with 798 additions and 260 deletions

View File

@ -0,0 +1,281 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
<book id="NGC">
<bookinfo>
<title>Next Generation CAPI</title>
<copyright>
<year>2004</year>
<holder>Frank A. Uepping</holder>
</copyright>
<revhistory>
<revision>
<revnumber></revnumber>
<date>2005-01-27</date>
<revremark>Working Draft</revremark>
</revision>
</revhistory>
<legalnotice>
<para>
This documentation is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
</para>
<para>
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
</para>
<para>
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</para>
<para>
For more details see the file COPYING in the source distribution of
Linux.
</para>
</legalnotice>
</bookinfo>
<toc></toc>
<chapter id="intro">
<title>Introduction</title>
<para>
<acronym>CAPI</> (COMMON-ISDN-API) is a message oriented and event driven
programming interface, used by applications to access <acronym>ISDN</>
hardware equipment in a standardized and straightforward way. Publisher
of the <acronym>CAPI</> standard is the <ulink
url="http://www.capi.org">CAPI-Association</ulink>, a non-profit
international consortium of hardware and software manufactures and
telecommunications institutions; the <acronym>CAPI</> standard is freely
available for download on their website.
</para>
<para>
The <acronym>CAPI</> standard defines a set of messages, protocols, and
operations. While the messages and protocols are interoperable, the
interface to the operations is specific to each supported
operating system. For Linux, the standard defines <acronym>CAPI</>
interfaces for user and kernel space.
</para>
<para>
<ulink url="http://www.capi4linux.org/ngc"><emphasis>Next Generation
CAPI</emphasis></ulink> (<acronym>NGC</>) is an
<emphasis>experimental</emphasis> implementation of the <acronym>CAPI</>
2.0 standard and derived from <ulink
url="http://www.capi4linux.org">CAPI4Linux</ulink>.
</para>
<para>
The heart of the <acronym>NGC</> subsystem is the capicore and, as such,
it is crucial to the performance and the stability of the whole
subsystem. Basically, the capicore provides an infrastructure for the
communication between applications and device drivers. Applications are
interfaced with the capicore via <acronym>CAPI</>, and device drivers via
a custom made interface proprietary to Linux. This white paper is
concerned with these interfaces, and describes them from the viewpoint of
a device driver and an application developer, respectively. Further, it
is assumed that the reader is familiar with the basic concepts and terms
of the <acronym>CAPI</> standard and with Linux kernel programming in
general.
</para>
</chapter>
<chapter>
<title>Structures and Data Types</title>
<para>
The capicore provides a common set of structures and data types forming
the basis of communication between the various layers of the
<acronym>NGC</> subsystem.
</para>
!Iinclude/linux/isdn/capinfo.h
!Finclude/linux/capi.h capi_register_params capi_version capi_profile
!Finclude/linux/isdn/capiappl.h capi_stats capi_appl
!Finclude/linux/isdn/capidevice.h capi_driver capi_device
</chapter>
<chapter>
<title>Device Driver Interface</title>
<para>
Device drivers and applications communicate together, via the capicore,
in an asynchronous way by exchanging messages according to the
<acronym>CAPI</> standard. While the implementation of a device driver
might be rather complex internally, the interface with the capicore is
pretty simple. The declarations to this interface can be found in
<filename class="headerfile">linux/isdn/capidevice.h</filename>.
</para>
<sect1>
<title>Overview</title>
<para>
Devices are represented to the capicore by objects of the generic
<structname>capi_device</structname> structure. This structure forms
the basis of communication between the capicore and device drivers.
Devices are reference counted objects and need to be dynamically
allocated by the device driver via the function
<function>capi_device_alloc</function>. Destroying a device is
done by releasing all references to it via the function
<function>capi_device_put</function>.
</para>
<para>
Once a generic <structname>capi_device</structname> object is
initialized, the device driver can register it with the capicore via
the function <function>capi_device_register</function>. Removing the
device from the capicore is done via the function
<function>capi_device_unregister</function>; subsequently, the
device driver can release the device via the function
<function>capi_device_put</function>.
</para>
<para>
The device driver has to provide three functions for calling by the
capicore via the <structname>capi_driver</structname> structure,
enabling the registration and removal of applications with the device
driver's devices and the transfer of messages to them.
</para>
<para>
Each application owns a message queue by which devices are transferring
messages to the application. Adding messages to the application queue
is done via the function
<function>capi_appl_enqueue_message</function>. Upon that, the device
driver should <emphasis>wakeup</emphasis> the application via the
function <function>capi_appl_signal</function>. If the device driver
encounters an error related to a message (i.e., in the context of an
application), it should inform the concerned application about that
condition via the function <function>capi_appl_signal_error</function>,
causing the application to release.
</para>
<para>
Besides that, since <acronym>CAPI</> devices are <emphasis>class
devices</emphasis>, they can easily export own attributes to the sysfs,
enabling the device driver to offer device specific features to the
user. See <filename class="headerfile">linux/device.h</filename> for
more information.
</para>
</sect1>
<sect1>
<title>Operations</title>
!Fdrivers/isdn/capi/core.c capi_device_alloc capi_device_register capi_device_unregister
!Finclude/linux/isdn/capidevice.h capi_device_get capi_device_put capi_device_set_devdata capi_device_get_devdata capi_device_set_dev capi_device_get_dev to_capi_device capi_appl_enqueue_message capi_appl_signal capi_appl_signal_error
</sect1>
</chapter>
<chapter>
<title>Application Interface</title>
<para>
Applications and device drivers communicate together, via the capicore,
in an asynchronous way by exchanging messages according to the
<acronym>CAPI</> standard. While the implementation of an application
might be rather complex internally, the interface with the capicore is
pretty simple.
</para>
<para>
For Linux, the <acronym>CAPI</> standard defines <acronym>CAPI</>
interfaces for user and kernel space applications. Unfortunately, the
specification to the kernel space <acronym>CAPI</> is too unspecific. To
give developers the required backing in writing safe kernel space
applications, the capicore introduces an alternative interface which
we're going to describe here in detail. The declarations to this
interface can be found in <filename
class="headerfile">linux/isdn/capiappl.h</filename>.
</para>
<sect1>
<title>Overview</title>
<para>
Applications are represented to the capicore by objects of the generic
<structname>capi_appl</structname> structure. This structure forms the
basis of communication between the capicore and applications.
</para>
<para>
Once a generic <structname>capi_appl</structname> object is
initialized, the application can register it with the capicore via the
function <function>capi_register</function>. Removing an application
from the capicore is done via the function
<function>capi_release</function>.
</para>
<para>
Applications need to install a signal handler via the function
<function>capi_set_signal</function>. The signal handler serves as a
notification mechanism for asynchronous events, such as:
<itemizedlist mark=opencircle>
<listitem>
<para>the arrival of new messages</para>
</listitem>
<listitem>
<para>the clearance of queue-full/busy conditions</para>
</listitem>
<listitem>
<para>errors</para>
</listitem>
</itemizedlist>
Note that a signal handler is not meant to be a
<emphasis>workhorse</emphasis>, but just a mechanism for waking up and
scheduling applications.
</para>
<para>
Applications transfer messages via the function
<function>capi_put_message</function>, and fetch them via the function
<function>capi_get_message</function>. They can put back messages via
the function <function>capi_unget_message</function>, and check for
pending messages via the function
<function>capi_peek_message</function>.
</para>
<para>
Applications can retrieve informations from <acronym>CAPI</> devices
via the functions: <function>capi_get_manufacturer</function>,
<function>capi_get_serial_number</function>,
<function>capi_get_version</function>,
<function>capi_get_profile</function>, and
<function>capi_get_product</function>.
</para>
<para>
Since <acronym>CAPI</> devices are <emphasis>class devices</emphasis>,
applications can install a <emphasis>class interface</emphasis> with
the Linux device driver core to get informed when <acronym>CAPI</>
devices are being registered and removed with the capicore. See
<filename class="headerfile">linux/device.h</filename> for more
information.
</para>
</sect1>
<sect1>
<title>Operations</title>
!Finclude/linux/isdn/capiappl.h capi_set_signal
!Fdrivers/isdn/capi/core.c capi_register capi_release capi_put_message
!Finclude/linux/isdn/capiappl.h capi_get_message capi_unget_message capi_peek_message
!Fdrivers/isdn/capi/core.c capi_isinstalled capi_get_manufacturer capi_get_serial_number capi_get_version capi_get_profile capi_get_product
</sect1>
</chapter>
</book>

View File

@ -1,164 +0,0 @@
CAPI Device Interface
~~~~~~~~~~~~~~~~~~~~~
Frank A. Uepping
2004-10-29
The capicore provides an infrastructure for the communication between CAPI
drivers and CAPI applications. This document describes the interface at the
driver layer. See capidevice.h and capiappl.h in include/linux/isdn/ for the
declarations of the various functions and types used.
The service that drivers provide to the capicore is the sending and receiving
of CAPI messages. Consequently, the driver interface is quite straightforward,
comprising the following components:
* A generic device structure.
* Allocating and reference counting of devices.
* Registration and release of devices.
* Registration and release of applications.
* Message exchange.
Generic CAPI Device Structure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Devices are represented to the capicore via objects of the generic capi_device
structure. This structure forms the basis of communication between the capicore
and drivers.
Drivers own the following fields in the generic capi_device structure:
* product -- the product name of the device.
* manufacturer, serial, version and profile -- the CAPI specific fields.
See the CAPI standard for more information about these fields.
* drv -- pointer to the capi_driver operations structure.
All devices of a driver share this structure.
* class_dev.dev -- pointer to the associated generic device object.
This field may be NULL, if there is no such object (e.g. virtual CAPI device).
The driver should use capi_device_set_dev() and capi_device_get_dev() in order
to access this field.
* class_dev.class_data -- pointer free to use by the driver.
Usually, this field points to the driver specific device structure. The
driver should use capi_device_set_devdata() and capi_device_get_devdata() in
order to access this field.
* stats -- structure containing fields for statistics purposes.
The driver is responsible for updating the statistics and may freely use the
stats.lock field; the capicore will never touch that lock.
The capicore will pre-initialize stats for the driver.
The capi_device object must be created by the driver via capi_device_alloc(),
and must exists from the time that capi_device_register() is called until after
the call to capi_device_unregister() returns.
Allocating and Reference Counting of CAPI Devices
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
An object of the capi_device structure is reference counted. As such it has
to be dynamically allocated by the driver, and will be freed when the last
reference has been released.
The capicore provides these functions to drivers:
* capi_device_alloc() -- allocate a generic capi_device structure.
The reference counter is initialized to one.
* capi_device_get() -- acquire a reference to the capi_device structure.
The reference counter is incremented by one.
* capi_device_put() -- release a reference to the capi_device structure.
The reference counter is decremented by one, and the object will be freed
if the reference counter drops to zero.
While capi_device_alloc() blocks, capi_device_get() and capi_device_put()
do not.
Registration and Release of CAPI Devices
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order for the capicore to become aware of CAPI devices, the generic
capi_device objects need to be registered with the capicore. At the time when
a CAPI device wants to leave, it needs to be released from the capicore.
The capicore provides these functions to drivers for that purpose:
* capi_device_register() -- register a device with the capicore.
After this call returns all existing applications have been registered with
the device.
* capi_device_unregister() -- unregister a device from the capicore.
After this call returns, the capicore guarantees that no thread will be
executing in a call from the capicore to that driver's functions
capi_register(), capi_release() or capi_put_message(), and the capicore
will not call either of those functions subsequently. Afterwards the
driver should release the device structure via capi_device_put().
Both functions are blocking, and so they have to be called from process
context.
Registration and Release of CAPI Applications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order for devices to become aware of an application, the application needs
to be registered with the devices. At the time when the application leaves
the system, it will be released from the devices registered with.
The driver has to provide two functions via the capi_driver operations
structure for that purpose:
* capi_register() -- register an application with the device.
The driver may refuse to register the application by returning an
appropriate value.
* capi_release() -- release an application from the device.
After return from this call, the driver must ensure that no thread will be
executing in capi_appl_enqueue_message(), capi_appl_signal() or
capi_appl_signal_error() for that application, and the driver must not
call either of those functions subsequently.
Both functions must be thread safe and get called from process context (so they
are allowed to block).
CAPI Message Exchange
~~~~~~~~~~~~~~~~~~~~~
The service that drivers provide to the capicore is the sending and receiving
of messages. Messages issued by drivers must be valid as described by the CAPI
standard, and must be in conformance with the CAPI state machines.
The capicore provides these functions to drivers:
* capi_appl_enqueue_message() -- add a message to the tail of the application's
message queue. The queue has unbounded capacity, and the driver has to adhere
to the CAPI window protocol in order to prevent the queue from growing
immensely.
* capi_appl_signal() -- signal to the application the arrival of messages or
the clearance of a busy or queue-full condition.
* capi_appl_signal_error() -- signal a fatal message exchange error to the
application. The signaled error is permanent and will force the application
to release. The only errors which make sense here are:
CAPINFO_0X11_QUEUEOVERFLOW and CAPINFO_0X11_OSRESERR.
These functions will never block, and it is allowed to call them from hardware
interrupt context.
In order for a driver to receive messages from the capicore it has to provide
a function via the capi_driver operations structure.
* capi_put_message() -- receive a message from the capicore.
The message is at least 12 bytes long, no other guarantees are made.
The driver may reject the message for flow-control reasons (via returning
CAPINFO_0X11_QUEUEFULL or CAPINFO_0X11_BUSY), but then, it must later call
capi_appl_signal() when the condition has been cleared.
This function must be thread safe and may not to block.

View File

@ -154,9 +154,9 @@ static LIST_HEAD(capiminor_list);
/* ------------------------------------------------------------------ */
static capinfo_0x11 get_capi_message(struct capi_appl *a, struct sk_buff **msg)
static capinfo_0x11_t get_capi_message(struct capi_appl *a, struct sk_buff **msg)
{
capinfo_0x11 info = capi_get_message(a, msg);
capinfo_0x11_t info = capi_get_message(a, msg);
if (!info) {
int n = CAPIMSG_LEN((*msg)->data);
if (CAPIMSG_CMD((*msg)->data) == CAPI_DATA_B3_IND)
@ -171,9 +171,9 @@ static capinfo_0x11 get_capi_message(struct capi_appl *a, struct sk_buff **msg)
return info;
}
static capinfo_0x11 put_capi_message(struct capi_appl *a, struct sk_buff *msg)
static capinfo_0x11_t put_capi_message(struct capi_appl *a, struct sk_buff *msg)
{
capinfo_0x11 info;
capinfo_0x11_t info;
int n;
n = CAPIMSG_LEN(msg->data);
@ -543,7 +543,7 @@ static int handle_minor_send(struct capiminor *mp)
struct sk_buff *skb;
u16 len;
int count = 0;
capinfo_0x11 errcode;
capinfo_0x11_t errcode;
u16 datahandle;
if (mp->tty && mp->ttyoutstop) {

View File

@ -299,9 +299,9 @@ static inline u8 cip2si2(u16 cipval)
/* ------------------------------------------------------------------ */
static capinfo_0x11 get_capi_message(struct capi_appl *a, struct sk_buff **msg)
static capinfo_0x11_t get_capi_message(struct capi_appl *a, struct sk_buff **msg)
{
capinfo_0x11 info = capi_get_message(a, msg);
capinfo_0x11_t info = capi_get_message(a, msg);
if (!info) {
int n = CAPIMSG_LEN((*msg)->data);
if (CAPIMSG_CMD((*msg)->data) == CAPI_DATA_B3_IND)
@ -316,9 +316,9 @@ static capinfo_0x11 get_capi_message(struct capi_appl *a, struct sk_buff **msg)
return info;
}
static capinfo_0x11 put_capi_message(struct capi_appl *a, struct sk_buff *msg)
static capinfo_0x11_t put_capi_message(struct capi_appl *a, struct sk_buff *msg)
{
capinfo_0x11 info;
capinfo_0x11_t info;
int n;
n = CAPIMSG_LEN(msg->data);
@ -1411,7 +1411,7 @@ static _cmsg s_cmsg;
static void capidrv_recv_message(unsigned long data)
{
struct sk_buff* skb;
capinfo_0x11 info;
capinfo_0x11_t info;
while ((info = get_capi_message(&global.ap, &skb)) == CAPINFO_0X11_NOERR) {
capi_message2cmsg(&s_cmsg, skb->data);
@ -1875,7 +1875,7 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
capidrv_ncci *nccip;
int len = skb->len;
int msglen;
capinfo_0x11 errcode;
capinfo_0x11_t errcode;
u16 datahandle;
if (!card) {

View File

@ -39,6 +39,22 @@ static DECLARE_RWSEM(capi_devs_list_sem);
atomic_t nr_capi_devs = ATOMIC_INIT(0);
/**
* capi_device_alloc - allocate a device control structure
*
* Context: !in_interrupt()
*
* Allocate a new device control structure and initialize its reference
* counter to one.
*
* Upon successful allocation, a pointer to the new device control
* structure is returned. Otherwise, NULL is returned.
*
* Note: The device control structure must not be freed by simply calling
* kfree(), but by a call to capi_device_put(), which will cause the
* device control structure to be freed when the reference counter reaches
* zero.
*/
struct capi_device*
capi_device_alloc(void)
{
@ -60,6 +76,7 @@ free_capi_device(struct class_device* cd)
{
struct capi_device* dev = to_capi_device(cd);
/* Registered with the capicore? */
if (likely(dev->id)) {
spin_lock_bh(&capi_devs_table_lock);
capi_devs_table[dev->id - 1] = NULL;
@ -89,7 +106,7 @@ add_capi_device(struct capi_device* dev)
static void
register_capi_appl(struct capi_appl* appl, struct capi_device* dev)
{
capinfo_0x11 info = dev->drv->capi_register(dev, appl);
capinfo_0x11_t info = dev->drv->capi_register(dev, appl);
if (unlikely(info)) {
printk(KERN_NOTICE "capicore: appl %d couldn't be registered with device %d (info: %#x).\n", appl->id, dev->id, info);
return;
@ -133,6 +150,22 @@ unregister_capi_device(struct capi_device* dev)
}
/**
* capi_device_register - register a device with the capicore
* @dev: device
*
* Context: !in_interrupt()
*
* @dev is assigned a unique device number, and all applications are
* registered with @dev in turn. If the device driver fails to register
* an application with @dev, @dev is marked as erroneous on that
* application. Finally, @dev is registered with the sysfs, which in
* turn could result in applications issuing messages, from installed
* class interfaces, to @dev.
*
* Upon successful registration, 0 is returned. Otherwise, a negative
* error code is returned.
*/
int
capi_device_register(struct capi_device* dev)
{
@ -161,6 +194,27 @@ capi_device_register(struct capi_device* dev)
}
/**
* capi_device_unregister - remove a device from the capicore
* @dev: device
*
* Context: !in_interrupt()
*
* The device driver must ensure that by the time it is calling this
* function for @dev, no thread is and will be executing, in the context
* of @dev, in a call to any of these functions capi_appl_signal_error(),
* capi_appl_enqueue_message(), or capi_appl_signal().
*
* Furthermore, the capicore ensures that by the time the call to this
* function returns for @dev, no thread is and will be executing in a call
* from the capicore to any of @dev's device driver operations for @dev.
*
* By the time the device driver calls this function, applications could
* be in a passive state (e.g., listen state L-1) waiting for events from
* CAPI. The device driver should leave those applications as-is, even if
* they would wait forever; it is the responsibility of the user to deal
* with such situations.
*/
void
capi_device_unregister(struct capi_device* dev)
{
@ -211,7 +265,20 @@ bind_capi_appl(struct capi_appl* appl)
}
capinfo_0x10
/**
* capi_register - register an application with the capicore
* @appl: application
*
* Context: !in_interrupt()
*
* @appl is assigned a unique application number, and is registered with
* each device in turn. If a device fails to register @appl, that device
* is marked as erroneous on @appl.
*
* Upon successful registration, %CAPINFO_0X10_NOERR is returned.
* Otherwise, a value indicting an error is returned.
*/
capinfo_0x10_t
capi_register(struct capi_appl* appl)
{
if (unlikely(!appl))
@ -242,7 +309,25 @@ capi_device_listed(struct capi_device* dev)
}
capinfo_0x11
/**
* capi_release - remove an application from the capicore
* @appl: application
*
* Context: !in_interrupt()
*
* The application must ensure that by the time it is calling this
* function for @appl, no thread is and will be executing in a call to
* any of these functions capi_put_message(), capi_get_message(),
* capi_unget_message(), or capi_peek_message() for @appl.
*
* Furthermore, the capicore ensures that by the time a call to this
* function returns for @appl, no thread is and will be executing in a
* call from the capicore to the signal handler installed with @appl.
*
* Upon successful removal, %CAPINFO_0X11_NOERR is returned. Otherwise,
* a value indicating an error is returned.
*/
capinfo_0x11_t
capi_release(struct capi_appl* appl)
{
struct capi_device* dev;
@ -270,13 +355,37 @@ capi_release(struct capi_appl* appl)
}
capinfo_0x11
/**
* capi_put_message - transfer a message
* @appl: application
* @msg: message
*
* Context: !in_irq()
*
* %CAPINFO_0X11_QUEUEFULL or %CAPINFO_0X11_BUSY is returned if @msg
* could not be accepted, but this does not imply that messages cannot be
* accepted directed to another application, device, PLCI, or NCCI. This
* is a temporary condition and the application of @appl should retry
* sometime later after being signaled by the signal handler installed
* with @appl.
*
* If the message was accepted, %CAPINFO_0X11_NOERR is returned.
* Otherwise, a value indicating an error is returned.
*
* In the case of a data transfer message (DATA_B3_REQ), the data must be
* appended to the message (this is contrary to the CAPI standard which
* intends a shared buffer scheme), and the Data field will be ignored.
*
* The application should adhere to the CAPI data window protocol.
*
*/
capinfo_0x11_t
capi_put_message(struct capi_appl* appl, struct sk_buff* msg)
{
struct capi_device* dev;
int id;
capinfo_0x11 info = appl->info;
capinfo_0x11_t info = appl->info;
if (unlikely(info))
return info;
@ -299,31 +408,15 @@ capi_put_message(struct capi_appl* appl, struct sk_buff* msg)
}
capinfo_0x11
capi_get_message(struct capi_appl* appl, struct sk_buff** msg)
{
if (unlikely(appl->info))
return appl->info;
return (*msg = skb_dequeue(&appl->msg_queue)) ?
CAPINFO_0X11_NOERR :
CAPINFO_0X11_QUEUEEMPTY;
}
capinfo_0x11
capi_peek_message(struct capi_appl* appl)
{
if (unlikely(appl->info))
return appl->info;
return skb_queue_empty(&appl->msg_queue) ?
CAPINFO_0X11_QUEUEEMPTY :
CAPINFO_0X11_NOERR;
}
capinfo_0x11
/**
* capi_isinstalled - check whether any device is installed
*
* Context: in_irq()
*
* If any device is installed, %CAPINFO_0X11_NOERR is returned.
* Otherwise, %CAPINFO_0X11_NOTINSTALLED is returned.
*/
capinfo_0x11_t
capi_isinstalled(void)
{
return atomic_read(&nr_capi_devs) ?
@ -350,6 +443,20 @@ try_get_capi_device_by_id(int id)
}
/**
* capi_get_manufacturer - retrieve manufacturer information
* @id: device number
* @manufacturer: target buffer
*
* Context: !in_irq()
*
* Copy the manufacturer string of the device, denoted by @id, to the
* target buffer. If @id is 0, copy the manufacturer string of the
* capicore.
*
* NULL is returned if there is no such device with @id. Otherwise,
* @manufacturer is returned.
*/
u8*
capi_get_manufacturer(int id, u8 manufacturer[CAPI_MANUFACTURER_LEN])
{
@ -367,6 +474,20 @@ capi_get_manufacturer(int id, u8 manufacturer[CAPI_MANUFACTURER_LEN])
}
/**
* capi_get_serial_number - retrieve serial number information
* @id: device number
* @serial: target buffer
*
* Context: !in_irq()
*
* Copy the serial number string of the device, denoted by @id, to the
* target buffer. If @id is 0, copy the serial number string of the
* capicore.
*
* NULL is returned if there is no such device with @id. Otherwise,
* @serial is returned.
*/
u8*
capi_get_serial_number(int id, u8 serial[CAPI_SERIAL_LEN])
{
@ -384,6 +505,20 @@ capi_get_serial_number(int id, u8 serial[CAPI_SERIAL_LEN])
}
/**
* capi_get_version - retrieve version information
* @id: device number
* @version: target buffer
*
* Context: !in_irq()
*
* Copy the version structure of the device, denoted by @id, to the
* target buffer. If @id is 0, copy the version structure of the
* capicore.
*
* NULL is returned if there is no such device with @id. Otherwise,
* @version is returned.
*/
struct capi_version*
capi_get_version(int id, struct capi_version* version)
{
@ -403,7 +538,20 @@ capi_get_version(int id, struct capi_version* version)
}
capinfo_0x11
/**
* capi_get_profile - retrieve capabilities information
* @id: device number
* @profile: target buffer
*
* Context: !in_irq()
*
* Copy the capabilities of the device, denoted by @id, to the target
* buffer. If @id is 0, copy just the number of installed devices.
*
* CAPINFO_0X11_OSRESERR is returned if there is no such device with @id.
* Otherwise, CAPINFO_0X11_NOERR is returned.
*/
capinfo_0x11_t
capi_get_profile(int id, struct capi_profile* profile)
{
if (id) {
@ -421,6 +569,18 @@ capi_get_profile(int id, struct capi_profile* profile)
}
/**
* capi_get_product - retrieve device name
* @id: device number
* @product: target buffer
*
* Context: !in_irq()
*
* Copy the name of the device, denoted by @id, to the target buffer.
*
* NULL is returned if there is no such device with @id. Otherwise,
* @product is returned.
*/
u8*
capi_get_product(int id, u8 product[CAPI_PRODUCT_LEN])
{
@ -481,8 +641,6 @@ EXPORT_SYMBOL(capi_device_unregister);
EXPORT_SYMBOL(capi_register);
EXPORT_SYMBOL(capi_release);
EXPORT_SYMBOL(capi_put_message);
EXPORT_SYMBOL(capi_get_message);
EXPORT_SYMBOL(capi_peek_message);
EXPORT_SYMBOL(capi_isinstalled);
EXPORT_SYMBOL(capi_get_manufacturer);
EXPORT_SYMBOL(capi_get_serial_number);

View File

@ -53,7 +53,7 @@ kernelcapi_isinstalled(void)
static u16
kernelcapi_register(capi_register_params* param, u16* applid)
{
capinfo_0x10 info;
capinfo_0x10_t info;
struct kernelcapi_appl* a = kmalloc(sizeof *a, GFP_KERNEL);
if (unlikely(!a))
@ -86,7 +86,7 @@ static u16
kernelcapi_release(u16 applid)
{
struct kernelcapi_appl* a;
capinfo_0x11 info;
capinfo_0x11_t info;
if (unlikely(applid - 1 >= CAPI_MAX_APPLS))
return CAPINFO_0X11_ILLAPPNR;
@ -106,7 +106,7 @@ static u16
kernelcapi_put_message(u16 applid, struct sk_buff* msg)
{
struct kernelcapi_appl* a;
capinfo_0x11 info;
capinfo_0x11_t info;
int n;
if (unlikely(applid - 1 >= CAPI_MAX_APPLS))
@ -134,7 +134,7 @@ static u16
kernelcapi_get_message(u16 applid, struct sk_buff** msg)
{
struct kernelcapi_appl* a;
capinfo_0x11 info;
capinfo_0x11_t info;
if (unlikely(applid - 1 >= CAPI_MAX_APPLS))
return CAPINFO_0X11_ILLAPPNR;

View File

@ -20,10 +20,20 @@
* CAPI_REGISTER
*/
typedef struct capi_register_params { /* CAPI_REGISTER */
__u32 level3cnt; /* No. of simulatneous user data connections */
__u32 datablkcnt; /* No. of buffered data messages */
__u32 datablklen; /* Size of buffered data messages */
/**
* struct capi_register_params - application parameters structure
* @level3cnt: maximum number of logical connections the application
* can concurrently maintain
* @datablkcnt: maximum number of received data blocks (i.e., the
* receive data window) that can be reported to the
* application simultaneously for each logical connection
* @datablklen: maximum size of the application data block to be
* transmitted and received
*/
typedef struct capi_register_params {
__u32 level3cnt;
__u32 datablkcnt;
__u32 datablklen;
} capi_register_params;
#define CAPI_REGISTER _IOW('C',0x01,struct capi_register_params)
@ -40,6 +50,13 @@ typedef struct capi_register_params { /* CAPI_REGISTER */
* CAPI_GET_VERSION
*/
/**
* struct capi_version - version structure
* @majorversion: major CAPI version
* @minorversion: minor CAPI version
* @majormanuversion: major manufacturer specific version
* @minormanuversion: minor manufacturer specific version
*/
typedef struct capi_version {
__u32 majorversion;
__u32 minorversion;
@ -60,15 +77,26 @@ typedef struct capi_version {
* CAPI_GET_PROFILE
*/
/**
* struct capi_profile - device capabilities structure
* @ncontroller: number of installed devices
* @nbchannel: number of B-Channels
* @goptions: global options
* @support1: B1 protocols
* @support2: B2 protocols
* @support3: B3 protocols
* @reserved: reserved
* @manu: manufacturer specific information
*/
typedef struct capi_profile {
__u16 ncontroller; /* number of installed controller */
__u16 nbchannel; /* number of B-Channels */
__u32 goptions; /* global options */
__u32 support1; /* B1 protocols support */
__u32 support2; /* B2 protocols support */
__u32 support3; /* B3 protocols support */
__u32 reserved[6]; /* reserved */
__u32 manu[5]; /* manufacturer specific information */
__u16 ncontroller;
__u16 nbchannel;
__u32 goptions;
__u32 support1;
__u32 support2;
__u32 support3;
__u32 reserved[6];
__u32 manu[5];
} capi_profile;
#define CAPI_GET_PROFILE _IOWR('C',0x09,struct capi_profile)

View File

@ -36,6 +36,14 @@
struct capi_appl;
/**
* struct capi_stats - I/O statistics structure
* @lock: spinlock
* @rx_bytes: received bytes
* @tx_bytes: transmitted bytes
* @rx_packets: received messages
* @tx_packets: transmitted messages
*/
struct capi_stats {
spinlock_t lock;
@ -47,31 +55,65 @@ struct capi_stats {
};
typedef void (*capi_signal_handler) (struct capi_appl* appl, unsigned long param);
typedef void (*capi_signal_handler_t) (struct capi_appl* appl, unsigned long param);
/**
* struct capi_appl - application control structure
* @id: application number
* @stats: I/O statistics
* @params: parameters
* @data: private data
*
* The application is responsible for updating the application's
* I/O statistics, and may freely use the @stats.lock.
*
* More fields are present, but not documented, since they are
* not part of the public interface.
*/
struct capi_appl {
u16 id;
u16 id;
capi_signal_handler sig;
unsigned long sig_param;
capi_signal_handler_t sig;
unsigned long sig_param;
struct sk_buff_head msg_queue;
capinfo_0x11 info;
struct sk_buff_head msg_queue;
capinfo_0x11_t info;
unsigned long devs[BITS_TO_LONGS(CAPI_MAX_DEVS)];
unsigned long devs[BITS_TO_LONGS(CAPI_MAX_DEVS)];
struct capi_stats stats;
struct capi_stats stats;
capi_register_params params;
void* data;
struct capi_register_params params;
void* data;
struct list_head entry;
struct list_head entry;
};
/**
* capi_set_signal - install a signal handler
* @appl: application
* @signal: signal handler (in_irq() context)
* @param: parameter to signal handler
*
* The capicore ensures that by the time a call to the function
* capi_release() returns for @appl, no thread is and will be executing
* in a call from the capicore to @signal for @appl.
*
* The signal handler informs the application of @appl about new messages,
* errors, or cleared queue-full/busy conditions. The signal handler is
* not meant to be a workhorse, but just a mechanism for waking up and
* scheduling applications.
*
* The signal handler must be reentrant and will be called from in_irq()
* context; consequently, it should be as simple and fast as possible.
*
* The application must install a signal handler for @appl, and must not
* reset it once registered.
*/
static inline void
capi_set_signal(struct capi_appl* appl, capi_signal_handler signal, unsigned long param)
capi_set_signal(struct capi_appl* appl, capi_signal_handler_t signal, unsigned long param)
{
if (!appl)
return;
@ -81,6 +123,45 @@ capi_set_signal(struct capi_appl* appl, capi_signal_handler signal, unsigned lon
}
/**
* capi_get_message - fetch a message from an application queue
* @appl: application
* @msg: message
*
* Context: !in_irq()
*
* Fetch a message from the message queue of @appl. Upon successfully
* fetching a message, %CAPINFO_0X11_NOERR is returned and a pointer to
* the message is passed via @msg. If there wasn't a message pending,
* return immediately passing %CAPINFO_0X11_QUEUEEMPTY as return value.
* Otherwise, a value indicating an error is returned.
*
* In the case of a data transfer message (DATA_B3_IND), the data is
* appended to the message (this is contrary to the CAPI standard which
* intends a shared buffer scheme), and the Data field is undefined.
*/
static inline capinfo_0x11_t
capi_get_message(struct capi_appl* appl, struct sk_buff** msg)
{
if (unlikely(appl->info))
return appl->info;
return (*msg = skb_dequeue(&appl->msg_queue)) ?
CAPINFO_0X11_NOERR :
CAPINFO_0X11_QUEUEEMPTY;
}
/**
* capi_unget_message - reinsert a message to an application queue
* @appl: application
* @msg: message
*
* Context: !in_irq()
*
* @msg is placed at the head of the message queue of @appl, so that
* it will be fetched next.
*/
static inline void
capi_unget_message(struct capi_appl* appl, struct sk_buff* msg)
{
@ -88,17 +169,37 @@ capi_unget_message(struct capi_appl* appl, struct sk_buff* msg)
}
capinfo_0x10 capi_register (struct capi_appl* appl);
capinfo_0x11 capi_release (struct capi_appl* appl);
capinfo_0x11 capi_put_message (struct capi_appl* appl, struct sk_buff* msg);
capinfo_0x11 capi_get_message (struct capi_appl* appl, struct sk_buff** msg);
capinfo_0x11 capi_peek_message (struct capi_appl* appl);
capinfo_0x11 capi_isinstalled (void);
/**
* capi_peek_message - check whether a message is pending
* @appl: application
*
* Context: !in_irq()
*
* If a message is pending on the message queue of @appl,
* %CAPINFO_0X11_NOERR is returned. If not, %CAPINFO_0X11_QUEUEEMPTY
* is returned. Otherwise, a value indicating an error is returned.
*/
static inline capinfo_0x11_t
capi_peek_message(struct capi_appl* appl)
{
if (unlikely(appl->info))
return appl->info;
return skb_queue_empty(&appl->msg_queue) ?
CAPINFO_0X11_QUEUEEMPTY :
CAPINFO_0X11_NOERR;
}
capinfo_0x10_t capi_register (struct capi_appl* appl);
capinfo_0x11_t capi_release (struct capi_appl* appl);
capinfo_0x11_t capi_put_message (struct capi_appl* appl, struct sk_buff* msg);
capinfo_0x11_t capi_isinstalled (void);
u8* capi_get_manufacturer (int id, u8 manufacturer[CAPI_MANUFACTURER_LEN]);
u8* capi_get_serial_number (int id, u8 serial[CAPI_SERIAL_LEN]);
struct capi_version* capi_get_version (int id, struct capi_version* version);
capinfo_0x11 capi_get_profile (int id, struct capi_profile* profile);
capinfo_0x11_t capi_get_profile (int id, struct capi_profile* profile);
u8* capi_get_product (int id, u8 product[CAPI_PRODUCT_LEN]);
#endif /* __KERNEL__ */

View File

@ -39,13 +39,61 @@
struct capi_device;
/**
* struct capi_driver - device operations structure
* @capi_register: callback function registering an application
* @capi_release: callback function removing an application
* @capi_put_message: callback function transferring a message
*
* The device driver must provide three functions for calling by the
* capicore via this structure, enabling the registration and removal of
* applications with the device driver's devices and the transfer of
* messages to them.
*
* The device driver must ensure that by the time a call to the callback
* function @capi_release returns, no thread is and will be executing,
* in the context of @dev, in a call to any of these functions
* capi_appl_signal_error(), capi_appl_enqueue_message(), or
* capi_appl_signal() for @appl.
*
* The device driver has the option of rejecting @msg by either returning
* %CAPINFO_0X11_QUEUEFULL or %CAPINFO_0X11_BUSY from the callback function
* @capi_put_message. In this case, @appl could block waiting for the
* clearance of the pending condition, and the device driver must call the
* function capi_appl_signal() for @appl either when the device driver can
* accept messages again for @dev or when the device driver has enqueued
* any message for @appl, whichever happens first.
*
* While the callback functions @capi_register and @capi_release are called
* from process context and may block (but mustn't be slow, i.e., blocking
* indefinitely), @capi_put_message is called from bottom half context and
* must not block. All three callback functions must be reentrant.
*/
struct capi_driver {
capinfo_0x10 (*capi_register) (struct capi_device* dev, struct capi_appl* appl);
capinfo_0x10_t (*capi_register) (struct capi_device* dev, struct capi_appl* appl);
void (*capi_release) (struct capi_device* dev, struct capi_appl* appl);
capinfo_0x11 (*capi_put_message) (struct capi_device* dev, struct capi_appl* appl, struct sk_buff* msg);
capinfo_0x11_t (*capi_put_message) (struct capi_device* dev, struct capi_appl* appl, struct sk_buff* msg);
};
/**
* struct capi_device - device control structure
* @id: device number
* @product: device name
* @manufacturer: manufacturer
* @serial: serial number
* @version: version
* @profile: capabilities
* @drv: operations
* @stats: I/O statistics
* @class_dev: class device
*
* The device driver is responsible for updating the device's
* I/O statistics, and may freely use the @stats.lock.
*
* More fields are present, but not documented, since they are
* not part of the public interface.
*/
struct capi_device {
unsigned short id;
@ -56,7 +104,7 @@ struct capi_device {
struct capi_profile profile;
struct capi_driver* drv;
struct rw_semaphore sem;
struct rw_semaphore sem; /* If readable, the device is registered. */
struct capi_stats stats;
@ -71,6 +119,15 @@ int capi_device_register (struct capi_device* dev);
void capi_device_unregister (struct capi_device* dev);
/**
* capi_device_get - get another reference to a device
* @dev: device
*
* Context: !in_irq()
*
* Get another reference to @dev by incrementing its reference counter
* by one. Return @dev.
*/
static inline struct capi_device*
capi_device_get(struct capi_device* dev)
{
@ -83,6 +140,15 @@ capi_device_get(struct capi_device* dev)
}
/**
* capi_device_put - release a reference to a device
* @dev: device
*
* Context: !in_irq()
*
* Release a reference to @dev by decrementing its reference counter
* by one and, if zero, free @dev.
*/
static inline void
capi_device_put(struct capi_device* dev)
{
@ -90,6 +156,11 @@ capi_device_put(struct capi_device* dev)
}
/**
* capi_device_set_devdata - set private data pointer
* @dev: device
* @data: private data
*/
static inline void
capi_device_set_devdata(struct capi_device* dev, void* data)
{
@ -97,6 +168,10 @@ capi_device_set_devdata(struct capi_device* dev, void* data)
}
/**
* capi_device_get_devdata - return private data pointer
* @dev: device
*/
static inline void*
capi_device_get_devdata(struct capi_device* dev)
{
@ -104,6 +179,11 @@ capi_device_get_devdata(struct capi_device* dev)
}
/**
* capi_device_set_dev - set generic device pointer
* @capi_dev: device
* @dev: device
*/
static inline void
capi_device_set_dev(struct capi_device* capi_dev, struct device* dev)
{
@ -111,6 +191,10 @@ capi_device_set_dev(struct capi_device* capi_dev, struct device* dev)
}
/**
* capi_device_get_dev - return generic device pointer
* @capi_dev: device
*/
static inline struct device*
capi_device_get_dev(const struct capi_device* capi_dev)
{
@ -118,6 +202,10 @@ capi_device_get_dev(const struct capi_device* capi_dev)
}
/**
* to_capi_device - downcast to generic CAPI device control structure
* @cd: class device
*/
static inline struct capi_device*
to_capi_device(struct class_device* cd)
{
@ -126,13 +214,24 @@ to_capi_device(struct class_device* cd)
extern struct class capi_class;
static inline void
capi_appl_signal(struct capi_appl* appl)
{
appl->sig(appl, appl->sig_param);
}
/**
* capi_appl_enqueue_message - add a message to an application queue
* @appl: application
* @msg: message
*
* Context: in_irq()
*
* The message queue of @appl has unbounded capacity; hence the device
* driver must adhere to the CAPI data window protocol to prevent that
* queue from growing immensely. A full data window should cause the
* device driver to trigger flow control on the line, if supported by
* the line protocol; otherwise, the device driver should drop @msg and
* notify @appl about that condition.
*
* In the case of a data transfer message (DATA_B3_IND), the data must be
* appended to the message (this is contrary to the CAPI standard which
* intends a shared buffer scheme), and the Data field will be ignored.
*/
static inline void
capi_appl_enqueue_message(struct capi_appl* appl, struct sk_buff* msg)
{
@ -140,8 +239,33 @@ capi_appl_enqueue_message(struct capi_appl* appl, struct sk_buff* msg)
}
/**
* capi_appl_signal - wakeup an application
* @appl: application
*
* Context: in_irq()
*
* @appl should be woken up either after enqueuing messages or clearing a
* queue-full/busy condition on @appl, respectively.
*/
static inline void
capi_appl_signal_error(struct capi_appl* appl, capinfo_0x11 info)
capi_appl_signal(struct capi_appl* appl)
{
appl->sig(appl, appl->sig_param);
}
/**
* capi_appl_signal_error - signal an error to an application
* @appl: application
* @info: error
*
* Context: in_irq()
*
* The only recovery for @appl, from this condition, is to do a release.
*/
static inline void
capi_appl_signal_error(struct capi_appl* appl, capinfo_0x11_t info)
{
if (likely(!appl->info))
appl->info = info;

View File

@ -30,6 +30,11 @@
#define CAPI_MAX_APPLS CONFIG_ISDN_CAPI_MAX_APPLS
/**
* typedef capinfo_0x10_t - info class 0x10xx
*
* Enumeration representing application registration errors.
*/
typedef enum {
CAPINFO_0X10_NOERR = 0x0000,
CAPINFO_0X10_TOOMANYAPPLS = 0x1001,
@ -43,23 +48,28 @@ typedef enum {
CAPINFO_0X10_NOTINSTALLED = 0x1009,
CAPINFO_0X10_CTRLDOESNOTSUPPEXTEQUIP = 0x100a,
CAPINFO_0X10_CTRLDOESONLYSUPPEXTEQUIP = 0x100b
} capinfo_0x10;
} capinfo_0x10_t;
/**
* typedef capinfo_0x11_t - info class 0x11xx
*
* Enumeration representing message exchange errors.
*/
typedef enum {
CAPINFO_0X11_NOERR = 0x0000,
CAPINFO_0X11_ILLAPPNR = 0x1101,
CAPINFO_0X11_ILLCMDORMSGTOSMALL = 0x1102,
CAPINFO_0X11_QUEUEFULL = 0x1103,
CAPINFO_0X11_QUEUEEMPTY = 0x1104,
CAPINFO_0X11_QUEUEFULL = 0x1103, /* Temporary failure */
CAPINFO_0X11_QUEUEEMPTY = 0x1104, /* Temporary failure */
CAPINFO_0X11_QUEUEOVERFLOW = 0x1105,
CAPINFO_0X11_ILLNOTIFICATIONPARAM = 0x1106,
CAPINFO_0X11_BUSY = 0x1107,
CAPINFO_0X11_BUSY = 0x1107, /* Temporary failure */
CAPINFO_0X11_OSRESERR = 0x1108,
CAPINFO_0X11_NOTINSTALLED = 0x1109,
CAPINFO_0X11_CTRLDOESNOTSUPPEXTEQUIP = 0x110a,
CAPINFO_0X11_CTRLDOESONLYSUPPEXTEQUIP = 0x110b
} capinfo_0x11;
} capinfo_0x11_t;
#endif /* _CAPINFO_H */

View File

@ -37,7 +37,7 @@ struct capi_interface {
u16 (*capi_get_message) (u16 applid, struct sk_buff** msg);
u16 (*capi_set_signal) (u16 applid,
/* Called from hardware interrupt context. */
/* Called from in_irq() context. */
void (*signal)(u16 applid, u32 param),
u32 param);