Compare commits
5 Commits
a65839fdb5
...
bb490916a8
Author | SHA1 | Date |
---|---|---|
Frank A. Uepping | bb490916a8 | |
Frank A. Uepping | e749b19cdd | |
Frank A. Uepping | abff2ffe45 | |
Frank A. Uepping | 5cb28f7a5f | |
Frank A. Uepping | 357ea34917 |
|
@ -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>
|
|
@ -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.
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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__ */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue