Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
This commit is contained in:
141
drivers/isdn/i4l/Kconfig
Normal file
141
drivers/isdn/i4l/Kconfig
Normal file
@@ -0,0 +1,141 @@
|
||||
#
|
||||
# Old ISDN4Linux config
|
||||
#
|
||||
|
||||
config ISDN_PPP
|
||||
bool "Support synchronous PPP"
|
||||
depends on INET
|
||||
help
|
||||
Over digital connections such as ISDN, there is no need to
|
||||
synchronize sender and recipient's clocks with start and stop bits
|
||||
as is done over analog telephone lines. Instead, one can use
|
||||
"synchronous PPP". Saying Y here will include this protocol. This
|
||||
protocol is used by Cisco and Sun for example. So you want to say Y
|
||||
here if the other end of your ISDN connection supports it. You will
|
||||
need a special version of pppd (called ipppd) for using this
|
||||
feature. See <file:Documentation/isdn/README.syncppp> and
|
||||
<file:Documentation/isdn/syncPPP.FAQ> for more information.
|
||||
|
||||
config ISDN_PPP_VJ
|
||||
bool "Use VJ-compression with synchronous PPP"
|
||||
depends on ISDN_PPP
|
||||
help
|
||||
This enables Van Jacobson header compression for synchronous PPP.
|
||||
Say Y if the other end of the connection supports it.
|
||||
|
||||
config ISDN_MPP
|
||||
bool "Support generic MP (RFC 1717)"
|
||||
depends on ISDN_PPP
|
||||
help
|
||||
With synchronous PPP enabled, it is possible to increase throughput
|
||||
by bundling several ISDN-connections, using this protocol. See
|
||||
<file:Documentation/isdn/README.syncppp> for more information.
|
||||
|
||||
config IPPP_FILTER
|
||||
bool "Filtering for synchronous PPP"
|
||||
depends on ISDN_PPP
|
||||
help
|
||||
Say Y here if you want to be able to filter the packets passing over
|
||||
IPPP interfaces. This allows you to control which packets count as
|
||||
activity (i.e. which packets will reset the idle timer or bring up
|
||||
a demand-dialled link) and which packets are to be dropped entirely.
|
||||
You need to say Y here if you wish to use the pass-filter and
|
||||
active-filter options to ipppd.
|
||||
|
||||
config ISDN_PPP_BSDCOMP
|
||||
tristate "Support BSD compression"
|
||||
depends on ISDN_PPP
|
||||
help
|
||||
Support for the BSD-Compress compression method for PPP, which uses
|
||||
the LZW compression method to compress each PPP packet before it is
|
||||
sent over the wire. The machine at the other end of the PPP link
|
||||
(usually your ISP) has to support the BSD-Compress compression
|
||||
method as well for this to be useful. Even if they don't support it,
|
||||
it is safe to say Y here.
|
||||
|
||||
config ISDN_AUDIO
|
||||
bool "Support audio via ISDN"
|
||||
help
|
||||
If you say Y here, the modem-emulator will support a subset of the
|
||||
EIA Class 8 Voice commands. Using a getty with voice-support
|
||||
(mgetty+sendfax by <gert@greenie.muc.de> with an extension, available
|
||||
with the ISDN utility package for example), you will be able to use
|
||||
your Linux box as an ISDN-answering machine. Of course, this must be
|
||||
supported by the lowlevel driver also. Currently, the HiSax driver
|
||||
is the only voice-supporting driver. See
|
||||
<file:Documentation/isdn/README.audio> for more information.
|
||||
|
||||
config ISDN_TTY_FAX
|
||||
bool "Support AT-Fax Class 1 and 2 commands"
|
||||
depends on ISDN_AUDIO
|
||||
help
|
||||
If you say Y here, the modem-emulator will support a subset of the
|
||||
Fax Class 1 and 2 commands. Using a getty with fax-support
|
||||
(mgetty+sendfax, hylafax), you will be able to use your Linux box as
|
||||
an ISDN-fax-machine. This must be supported by the lowlevel driver
|
||||
also. See <file:Documentation/isdn/README.fax> for more information.
|
||||
|
||||
config ISDN_X25
|
||||
bool "X.25 PLP on top of ISDN"
|
||||
depends on X25
|
||||
help
|
||||
This feature provides the X.25 protocol over ISDN connections.
|
||||
See <file:Documentation/isdn/README.x25> for more information
|
||||
if you are thinking about using this.
|
||||
|
||||
|
||||
menu "ISDN feature submodules"
|
||||
depends on ISDN
|
||||
|
||||
config ISDN_DRV_LOOP
|
||||
tristate "isdnloop support"
|
||||
depends on BROKEN_ON_SMP
|
||||
help
|
||||
This driver provides a virtual ISDN card. Its primary purpose is
|
||||
testing of linklevel features or configuration without getting
|
||||
charged by your service-provider for lots of phone calls.
|
||||
You need will need the loopctrl utility from the latest isdn4k-utils
|
||||
package to set up this driver.
|
||||
|
||||
config ISDN_DIVERSION
|
||||
tristate "Support isdn diversion services"
|
||||
depends on ISDN && ISDN_I4L
|
||||
help
|
||||
This option allows you to use some supplementary diversion
|
||||
services in conjunction with the HiSax driver on an EURO/DSS1
|
||||
line.
|
||||
|
||||
Supported options are CD (call deflection), CFU (Call forward
|
||||
unconditional), CFB (Call forward when busy) and CFNR (call forward
|
||||
not reachable). Additionally the actual CFU, CFB and CFNR state may
|
||||
be interrogated.
|
||||
|
||||
The use of CFU, CFB, CFNR and interrogation may be limited to some
|
||||
countries. The keypad protocol is still not implemented. CD should
|
||||
work in all countries if the service has been subscribed to.
|
||||
|
||||
Please read the file <file:Documentation/isdn/README.diversion>.
|
||||
|
||||
endmenu
|
||||
|
||||
comment "ISDN4Linux hardware drivers"
|
||||
depends on NET && ISDN && ISDN_I4L
|
||||
|
||||
source "drivers/isdn/hisax/Kconfig"
|
||||
|
||||
|
||||
menu "Active cards"
|
||||
depends on NET && ISDN && ISDN_I4L!=n
|
||||
|
||||
source "drivers/isdn/icn/Kconfig"
|
||||
|
||||
source "drivers/isdn/pcbit/Kconfig"
|
||||
|
||||
source "drivers/isdn/sc/Kconfig"
|
||||
|
||||
source "drivers/isdn/act2000/Kconfig"
|
||||
|
||||
source "drivers/isdn/hysdn/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
18
drivers/isdn/i4l/Makefile
Normal file
18
drivers/isdn/i4l/Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
# Makefile for the kernel ISDN subsystem and device drivers.
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_ISDN_I4L) += isdn.o
|
||||
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
|
||||
|
||||
# Multipart objects.
|
||||
|
||||
isdn-y := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
|
||||
|
||||
# Optional parts of multipart objects.
|
||||
|
||||
isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o
|
||||
isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
|
||||
isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
|
||||
isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
|
||||
|
720
drivers/isdn/i4l/isdn_audio.c
Normal file
720
drivers/isdn/i4l/isdn_audio.c
Normal file
@@ -0,0 +1,720 @@
|
||||
/* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, audio conversion and compression (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
* DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
|
||||
* Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/isdn.h>
|
||||
#include "isdn_audio.h"
|
||||
#include "isdn_common.h"
|
||||
|
||||
char *isdn_audio_revision = "$Revision: 1.1.2.2 $";
|
||||
|
||||
/*
|
||||
* Misc. lookup-tables.
|
||||
*/
|
||||
|
||||
/* ulaw -> signed 16-bit */
|
||||
static short isdn_audio_ulaw_to_s16[] =
|
||||
{
|
||||
0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
|
||||
0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
|
||||
0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
|
||||
0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
|
||||
0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
|
||||
0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
|
||||
0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
|
||||
0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
|
||||
0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
|
||||
0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
|
||||
0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
|
||||
0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
|
||||
0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
|
||||
0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
|
||||
0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
|
||||
0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
|
||||
0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
|
||||
0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
|
||||
0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
|
||||
0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
|
||||
0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
|
||||
0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
|
||||
0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
|
||||
0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
|
||||
0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
|
||||
0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
|
||||
0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
|
||||
0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
|
||||
0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
|
||||
0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
|
||||
0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
|
||||
0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
|
||||
};
|
||||
|
||||
/* alaw -> signed 16-bit */
|
||||
static short isdn_audio_alaw_to_s16[] =
|
||||
{
|
||||
0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
|
||||
0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
|
||||
0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
|
||||
0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
|
||||
0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
|
||||
0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
|
||||
0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
|
||||
0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
|
||||
0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
|
||||
0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
|
||||
0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
|
||||
0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
|
||||
0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
|
||||
0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
|
||||
0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
|
||||
0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
|
||||
0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
|
||||
0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
|
||||
0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
|
||||
0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
|
||||
0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
|
||||
0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
|
||||
0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
|
||||
0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
|
||||
0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
|
||||
0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
|
||||
0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
|
||||
0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
|
||||
0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
|
||||
0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
|
||||
0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
|
||||
0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
|
||||
};
|
||||
|
||||
/* alaw -> ulaw */
|
||||
static char isdn_audio_alaw_to_ulaw[] =
|
||||
{
|
||||
0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
|
||||
0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
|
||||
0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
|
||||
0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
|
||||
0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
|
||||
0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
|
||||
0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
|
||||
0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
|
||||
0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
|
||||
0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
|
||||
0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
|
||||
0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
|
||||
0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
|
||||
0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
|
||||
0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
|
||||
0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
|
||||
0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
|
||||
0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
|
||||
0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
|
||||
0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
|
||||
0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
|
||||
0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
|
||||
0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
|
||||
0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
|
||||
0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
|
||||
0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
|
||||
0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
|
||||
0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
|
||||
0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
|
||||
0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
|
||||
0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
|
||||
0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
|
||||
};
|
||||
|
||||
/* ulaw -> alaw */
|
||||
static char isdn_audio_ulaw_to_alaw[] =
|
||||
{
|
||||
0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
|
||||
0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
|
||||
0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
|
||||
0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
|
||||
0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
|
||||
0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
|
||||
0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
|
||||
0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
|
||||
0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
|
||||
0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
|
||||
0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
|
||||
0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
|
||||
0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
|
||||
0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
|
||||
0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
|
||||
0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
|
||||
0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
|
||||
0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
|
||||
0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
|
||||
0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
|
||||
0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
|
||||
0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
|
||||
0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
|
||||
0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
|
||||
0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
|
||||
0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
|
||||
0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
|
||||
0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
|
||||
0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
|
||||
0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
|
||||
0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
|
||||
0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
|
||||
};
|
||||
|
||||
#define NCOEFF 8 /* number of frequencies to be analyzed */
|
||||
#define DTMF_TRESH 4000 /* above this is dtmf */
|
||||
#define SILENCE_TRESH 200 /* below this is silence */
|
||||
#define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */
|
||||
#define LOGRP 0
|
||||
#define HIGRP 1
|
||||
|
||||
/* For DTMF recognition:
|
||||
* 2 * cos(2 * PI * k / N) precalculated for all k
|
||||
*/
|
||||
static int cos2pik[NCOEFF] =
|
||||
{
|
||||
55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
|
||||
};
|
||||
|
||||
static char dtmf_matrix[4][4] =
|
||||
{
|
||||
{'1', '2', '3', 'A'},
|
||||
{'4', '5', '6', 'B'},
|
||||
{'7', '8', '9', 'C'},
|
||||
{'*', '0', '#', 'D'}
|
||||
};
|
||||
|
||||
static inline void
|
||||
isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n)
|
||||
{
|
||||
#ifdef __i386__
|
||||
unsigned long d0, d1, d2, d3;
|
||||
__asm__ __volatile__(
|
||||
"cld\n"
|
||||
"1:\tlodsb\n\t"
|
||||
"xlatb\n\t"
|
||||
"stosb\n\t"
|
||||
"loop 1b\n\t"
|
||||
: "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
|
||||
: "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
|
||||
: "memory", "ax");
|
||||
#else
|
||||
while (n--)
|
||||
*buff = table[*(unsigned char *)buff], buff++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
|
||||
{
|
||||
isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
|
||||
{
|
||||
isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* linear <-> adpcm conversion stuff
|
||||
* Most parts from the mgetty-package.
|
||||
* (C) by Gert Doering and Klaus Weidner
|
||||
* Used by permission of Gert Doering
|
||||
*/
|
||||
|
||||
|
||||
#define ZEROTRAP /* turn on the trap as per the MIL-STD */
|
||||
#undef ZEROTRAP
|
||||
#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
|
||||
#define CLIP 32635
|
||||
|
||||
static unsigned char
|
||||
isdn_audio_linear2ulaw(int sample)
|
||||
{
|
||||
static int exp_lut[256] =
|
||||
{
|
||||
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
|
||||
};
|
||||
int sign,
|
||||
exponent,
|
||||
mantissa;
|
||||
unsigned char ulawbyte;
|
||||
|
||||
/* Get the sample into sign-magnitude. */
|
||||
sign = (sample >> 8) & 0x80; /* set aside the sign */
|
||||
if (sign != 0)
|
||||
sample = -sample; /* get magnitude */
|
||||
if (sample > CLIP)
|
||||
sample = CLIP; /* clip the magnitude */
|
||||
|
||||
/* Convert from 16 bit linear to ulaw. */
|
||||
sample = sample + BIAS;
|
||||
exponent = exp_lut[(sample >> 7) & 0xFF];
|
||||
mantissa = (sample >> (exponent + 3)) & 0x0F;
|
||||
ulawbyte = ~(sign | (exponent << 4) | mantissa);
|
||||
#ifdef ZEROTRAP
|
||||
/* optional CCITT trap */
|
||||
if (ulawbyte == 0)
|
||||
ulawbyte = 0x02;
|
||||
#endif
|
||||
return (ulawbyte);
|
||||
}
|
||||
|
||||
|
||||
static int Mx[3][8] =
|
||||
{
|
||||
{0x3800, 0x5600, 0, 0, 0, 0, 0, 0},
|
||||
{0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0},
|
||||
{0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607},
|
||||
};
|
||||
|
||||
static int bitmask[9] =
|
||||
{
|
||||
0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
|
||||
};
|
||||
|
||||
static int
|
||||
isdn_audio_get_bits(adpcm_state * s, unsigned char **in, int *len)
|
||||
{
|
||||
while (s->nleft < s->nbits) {
|
||||
int d = *((*in)++);
|
||||
(*len)--;
|
||||
s->word = (s->word << 8) | d;
|
||||
s->nleft += 8;
|
||||
}
|
||||
s->nleft -= s->nbits;
|
||||
return (s->word >> s->nleft) & bitmask[s->nbits];
|
||||
}
|
||||
|
||||
static void
|
||||
isdn_audio_put_bits(int data, int nbits, adpcm_state * s,
|
||||
unsigned char **out, int *len)
|
||||
{
|
||||
s->word = (s->word << nbits) | (data & bitmask[nbits]);
|
||||
s->nleft += nbits;
|
||||
while (s->nleft >= 8) {
|
||||
int d = (s->word >> (s->nleft - 8));
|
||||
*(out[0]++) = d & 255;
|
||||
(*len)++;
|
||||
s->nleft -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
adpcm_state *
|
||||
isdn_audio_adpcm_init(adpcm_state * s, int nbits)
|
||||
{
|
||||
if (!s)
|
||||
s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
|
||||
if (s) {
|
||||
s->a = 0;
|
||||
s->d = 5;
|
||||
s->word = 0;
|
||||
s->nleft = 0;
|
||||
s->nbits = nbits;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
dtmf_state *
|
||||
isdn_audio_dtmf_init(dtmf_state * s)
|
||||
{
|
||||
if (!s)
|
||||
s = (dtmf_state *) kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
|
||||
if (s) {
|
||||
s->idx = 0;
|
||||
s->last = ' ';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompression of adpcm data to a/u-law
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
isdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in,
|
||||
unsigned char *out, int len)
|
||||
{
|
||||
int a = s->a;
|
||||
int d = s->d;
|
||||
int nbits = s->nbits;
|
||||
int olen = 0;
|
||||
|
||||
while (len) {
|
||||
int e = isdn_audio_get_bits(s, &in, &len);
|
||||
int sign;
|
||||
|
||||
if (nbits == 4 && e == 0)
|
||||
d = 4;
|
||||
sign = (e >> (nbits - 1)) ? -1 : 1;
|
||||
e &= bitmask[nbits - 1];
|
||||
a += sign * ((e << 1) + 1) * d >> 1;
|
||||
if (d & 1)
|
||||
a++;
|
||||
if (fmt)
|
||||
*out++ = isdn_audio_ulaw_to_alaw[
|
||||
isdn_audio_linear2ulaw(a << 2)];
|
||||
else
|
||||
*out++ = isdn_audio_linear2ulaw(a << 2);
|
||||
olen++;
|
||||
d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
|
||||
if (d < 5)
|
||||
d = 5;
|
||||
}
|
||||
s->a = a;
|
||||
s->d = d;
|
||||
return olen;
|
||||
}
|
||||
|
||||
int
|
||||
isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out)
|
||||
{
|
||||
int olen = 0;
|
||||
|
||||
if (s->nleft)
|
||||
isdn_audio_put_bits(0, 8 - s->nleft, s, &out, &olen);
|
||||
return olen;
|
||||
}
|
||||
|
||||
int
|
||||
isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in,
|
||||
unsigned char *out, int len)
|
||||
{
|
||||
int a = s->a;
|
||||
int d = s->d;
|
||||
int nbits = s->nbits;
|
||||
int olen = 0;
|
||||
|
||||
while (len--) {
|
||||
int e = 0,
|
||||
nmax = 1 << (nbits - 1);
|
||||
int sign,
|
||||
delta;
|
||||
|
||||
if (fmt)
|
||||
delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
|
||||
else
|
||||
delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
|
||||
if (delta < 0) {
|
||||
e = nmax;
|
||||
delta = -delta;
|
||||
}
|
||||
while (--nmax && delta > d) {
|
||||
delta -= d;
|
||||
e++;
|
||||
}
|
||||
if (nbits == 4 && ((e & 0x0f) == 0))
|
||||
e = 8;
|
||||
isdn_audio_put_bits(e, nbits, s, &out, &olen);
|
||||
sign = (e >> (nbits - 1)) ? -1 : 1;
|
||||
e &= bitmask[nbits - 1];
|
||||
|
||||
a += sign * ((e << 1) + 1) * d >> 1;
|
||||
if (d & 1)
|
||||
a++;
|
||||
d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
|
||||
if (d < 5)
|
||||
d = 5;
|
||||
}
|
||||
s->a = a;
|
||||
s->d = d;
|
||||
return olen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Goertzel algorithm.
|
||||
* See http://ptolemy.eecs.berkeley.edu/~pino/Ptolemy/papers/96/dtmf_ict/
|
||||
* for more info.
|
||||
* Result is stored into an sk_buff and queued up for later
|
||||
* evaluation.
|
||||
*/
|
||||
static void
|
||||
isdn_audio_goertzel(int *sample, modem_info * info)
|
||||
{
|
||||
int sk,
|
||||
sk1,
|
||||
sk2;
|
||||
int k,
|
||||
n;
|
||||
struct sk_buff *skb;
|
||||
int *result;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(int) * NCOEFF);
|
||||
if (!skb) {
|
||||
printk(KERN_WARNING
|
||||
"isdn_audio: Could not alloc DTMF result for ttyI%d\n",
|
||||
info->line);
|
||||
return;
|
||||
}
|
||||
result = (int *) skb_put(skb, sizeof(int) * NCOEFF);
|
||||
for (k = 0; k < NCOEFF; k++) {
|
||||
sk = sk1 = sk2 = 0;
|
||||
for (n = 0; n < DTMF_NPOINTS; n++) {
|
||||
sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;
|
||||
sk2 = sk1;
|
||||
sk1 = sk;
|
||||
}
|
||||
/* Avoid overflows */
|
||||
sk >>= 1;
|
||||
sk2 >>= 1;
|
||||
/* compute |X(k)|**2 */
|
||||
/* report overflows. This should not happen. */
|
||||
/* Comment this out if desired */
|
||||
if (sk < -32768 || sk > 32767)
|
||||
printk(KERN_DEBUG
|
||||
"isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
|
||||
if (sk2 < -32768 || sk2 > 32767)
|
||||
printk(KERN_DEBUG
|
||||
"isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
|
||||
result[k] =
|
||||
((sk * sk) >> AMP_BITS) -
|
||||
((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
|
||||
((sk2 * sk2) >> AMP_BITS);
|
||||
}
|
||||
skb_queue_tail(&info->dtmf_queue, skb);
|
||||
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_eval_dtmf(modem_info * info)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int *result;
|
||||
dtmf_state *s;
|
||||
int silence;
|
||||
int i;
|
||||
int di;
|
||||
int ch;
|
||||
int grp[2];
|
||||
char what;
|
||||
char *p;
|
||||
int thresh;
|
||||
|
||||
while ((skb = skb_dequeue(&info->dtmf_queue))) {
|
||||
result = (int *) skb->data;
|
||||
s = info->dtmf_state;
|
||||
grp[LOGRP] = grp[HIGRP] = -1;
|
||||
silence = 0;
|
||||
thresh = 0;
|
||||
for (i = 0; i < NCOEFF; i++) {
|
||||
if (result[i] > DTMF_TRESH) {
|
||||
if (result[i] > thresh)
|
||||
thresh = result[i];
|
||||
}
|
||||
else if (result[i] < SILENCE_TRESH)
|
||||
silence++;
|
||||
}
|
||||
if (silence == NCOEFF)
|
||||
what = ' ';
|
||||
else {
|
||||
if (thresh > 0) {
|
||||
thresh = thresh >> 4; /* touchtones must match within 12 dB */
|
||||
for (i = 0; i < NCOEFF; i++) {
|
||||
if (result[i] < thresh)
|
||||
continue; /* ignore */
|
||||
/* good level found. This is allowed only one time per group */
|
||||
if (i < NCOEFF / 2) {
|
||||
/* lowgroup*/
|
||||
if (grp[LOGRP] >= 0) {
|
||||
// Bad. Another tone found. */
|
||||
grp[LOGRP] = -1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
grp[LOGRP] = i;
|
||||
}
|
||||
else { /* higroup */
|
||||
if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
|
||||
grp[HIGRP] = -1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
grp[HIGRP] = i - NCOEFF/2;
|
||||
}
|
||||
}
|
||||
if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
|
||||
what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
|
||||
if (s->last != ' ' && s->last != '.')
|
||||
s->last = what; /* min. 1 non-DTMF between DTMF */
|
||||
} else
|
||||
what = '.';
|
||||
}
|
||||
else
|
||||
what = '.';
|
||||
}
|
||||
if ((what != s->last) && (what != ' ') && (what != '.')) {
|
||||
printk(KERN_DEBUG "dtmf: tt='%c'\n", what);
|
||||
p = skb->data;
|
||||
*p++ = 0x10;
|
||||
*p = what;
|
||||
skb_trim(skb, 2);
|
||||
ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
|
||||
ISDN_AUDIO_SKB_LOCK(skb) = 0;
|
||||
di = info->isdn_driver;
|
||||
ch = info->isdn_channel;
|
||||
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
|
||||
dev->drv[di]->rcvcount[ch] += 2;
|
||||
/* Schedule dequeuing */
|
||||
if ((dev->modempoll) && (info->rcvsched))
|
||||
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
|
||||
wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
|
||||
} else
|
||||
kfree_skb(skb);
|
||||
s->last = what;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode DTMF tones, queue result in separate sk_buf for
|
||||
* later examination.
|
||||
* Parameters:
|
||||
* s = pointer to state-struct.
|
||||
* buf = input audio data
|
||||
* len = size of audio data.
|
||||
* fmt = audio data format (0 = ulaw, 1 = alaw)
|
||||
*/
|
||||
void
|
||||
isdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt)
|
||||
{
|
||||
dtmf_state *s = info->dtmf_state;
|
||||
int i;
|
||||
int c;
|
||||
|
||||
while (len) {
|
||||
c = DTMF_NPOINTS - s->idx;
|
||||
if (c > len)
|
||||
c = len;
|
||||
if (c <= 0)
|
||||
break;
|
||||
for (i = 0; i < c; i++) {
|
||||
if (fmt)
|
||||
s->buf[s->idx++] =
|
||||
isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
|
||||
else
|
||||
s->buf[s->idx++] =
|
||||
isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
|
||||
}
|
||||
if (s->idx == DTMF_NPOINTS) {
|
||||
isdn_audio_goertzel(s->buf, info);
|
||||
s->idx = 0;
|
||||
}
|
||||
len -= c;
|
||||
}
|
||||
}
|
||||
|
||||
silence_state *
|
||||
isdn_audio_silence_init(silence_state * s)
|
||||
{
|
||||
if (!s)
|
||||
s = (silence_state *) kmalloc(sizeof(silence_state), GFP_ATOMIC);
|
||||
if (s) {
|
||||
s->idx = 0;
|
||||
s->state = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt)
|
||||
{
|
||||
silence_state *s = info->silence_state;
|
||||
int i;
|
||||
signed char c;
|
||||
|
||||
if (!info->emu.vpar[1]) return;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (fmt)
|
||||
c = isdn_audio_alaw_to_ulaw[*buf++];
|
||||
else
|
||||
c = *buf++;
|
||||
|
||||
if (c > 0) c -= 128;
|
||||
c = abs(c);
|
||||
|
||||
if (c > (info->emu.vpar[1] * 4)) {
|
||||
s->idx = 0;
|
||||
s->state = 1;
|
||||
} else {
|
||||
if (s->idx < 210000) s->idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_put_dle_code(modem_info * info, u_char code)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int di;
|
||||
int ch;
|
||||
char *p;
|
||||
|
||||
skb = dev_alloc_skb(2);
|
||||
if (!skb) {
|
||||
printk(KERN_WARNING
|
||||
"isdn_audio: Could not alloc skb for ttyI%d\n",
|
||||
info->line);
|
||||
return;
|
||||
}
|
||||
p = (char *) skb_put(skb, 2);
|
||||
p[0] = 0x10;
|
||||
p[1] = code;
|
||||
ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
|
||||
ISDN_AUDIO_SKB_LOCK(skb) = 0;
|
||||
di = info->isdn_driver;
|
||||
ch = info->isdn_channel;
|
||||
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
|
||||
dev->drv[di]->rcvcount[ch] += 2;
|
||||
/* Schedule dequeuing */
|
||||
if ((dev->modempoll) && (info->rcvsched))
|
||||
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
|
||||
wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_eval_silence(modem_info * info)
|
||||
{
|
||||
silence_state *s = info->silence_state;
|
||||
char what;
|
||||
|
||||
what = ' ';
|
||||
|
||||
if (s->idx > (info->emu.vpar[2] * 800)) {
|
||||
s->idx = 0;
|
||||
if (!s->state) { /* silence from beginning of rec */
|
||||
what = 's';
|
||||
} else {
|
||||
what = 'q';
|
||||
}
|
||||
}
|
||||
if ((what == 's') || (what == 'q')) {
|
||||
printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
|
||||
(what=='s') ? "silence":"quiet");
|
||||
isdn_audio_put_dle_code(info, what);
|
||||
}
|
||||
}
|
45
drivers/isdn/i4l/isdn_audio.h
Normal file
45
drivers/isdn/i4l/isdn_audio.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* $Id: isdn_audio.h,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, audio conversion and compression (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
|
||||
typedef struct adpcm_state {
|
||||
int a;
|
||||
int d;
|
||||
int word;
|
||||
int nleft;
|
||||
int nbits;
|
||||
} adpcm_state;
|
||||
|
||||
typedef struct dtmf_state {
|
||||
char last;
|
||||
char llast;
|
||||
int idx;
|
||||
int buf[DTMF_NPOINTS];
|
||||
} dtmf_state;
|
||||
|
||||
typedef struct silence_state {
|
||||
int state;
|
||||
unsigned int idx;
|
||||
} silence_state;
|
||||
|
||||
extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long);
|
||||
extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
|
||||
extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
|
||||
extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
|
||||
extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
|
||||
extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out);
|
||||
extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
|
||||
extern void isdn_audio_eval_dtmf(modem_info *);
|
||||
dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
|
||||
extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int);
|
||||
extern void isdn_audio_eval_silence(modem_info *);
|
||||
silence_state *isdn_audio_silence_init(silence_state *);
|
||||
extern void isdn_audio_put_dle_code(modem_info *, u_char);
|
937
drivers/isdn/i4l/isdn_bsdcomp.c
Normal file
937
drivers/isdn/i4l/isdn_bsdcomp.c
Normal file
@@ -0,0 +1,937 @@
|
||||
/*
|
||||
* BSD compression module
|
||||
*
|
||||
* Patched version for ISDN syncPPP written 1997/1998 by Michael Hipp
|
||||
* The whole module is now SKB based.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Update: The Berkeley copyright was changed, and the change
|
||||
* is retroactive to all "true" BSD software (ie everything
|
||||
* from UCB as opposed to other peoples code that just carried
|
||||
* the same license). The new copyright doesn't clash with the
|
||||
* GPL, so the module-only restriction has been removed..
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original copyright notice:
|
||||
*
|
||||
* Copyright (c) 1985, 1986 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* James A. Woods, derived from original work by Spencer Thomas
|
||||
* and Joseph Orost.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h> /* used in new tty drivers */
|
||||
#include <linux/signal.h> /* used in new tty drivers */
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#include <linux/if.h>
|
||||
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <linux/ppp_defs.h>
|
||||
|
||||
#include <linux/isdn.h>
|
||||
#include <linux/isdn_ppp.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/ppp-comp.h>
|
||||
|
||||
#include "isdn_ppp.h"
|
||||
|
||||
MODULE_DESCRIPTION("ISDN4Linux: BSD Compression for PPP over ISDN");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
#define BSD_VERSION(x) ((x) >> 5)
|
||||
#define BSD_NBITS(x) ((x) & 0x1F)
|
||||
|
||||
#define BSD_CURRENT_VERSION 1
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
/*
|
||||
* A dictionary for doing BSD compress.
|
||||
*/
|
||||
|
||||
struct bsd_dict {
|
||||
u32 fcode;
|
||||
u16 codem1; /* output of hash table -1 */
|
||||
u16 cptr; /* map code to hash table entry */
|
||||
};
|
||||
|
||||
struct bsd_db {
|
||||
int totlen; /* length of this structure */
|
||||
unsigned int hsize; /* size of the hash table */
|
||||
unsigned char hshift; /* used in hash function */
|
||||
unsigned char n_bits; /* current bits/code */
|
||||
unsigned char maxbits; /* maximum bits/code */
|
||||
unsigned char debug; /* non-zero if debug desired */
|
||||
unsigned char unit; /* ppp unit number */
|
||||
u16 seqno; /* sequence # of next packet */
|
||||
unsigned int mru; /* size of receive (decompress) bufr */
|
||||
unsigned int maxmaxcode; /* largest valid code */
|
||||
unsigned int max_ent; /* largest code in use */
|
||||
unsigned int in_count; /* uncompressed bytes, aged */
|
||||
unsigned int bytes_out; /* compressed bytes, aged */
|
||||
unsigned int ratio; /* recent compression ratio */
|
||||
unsigned int checkpoint; /* when to next check the ratio */
|
||||
unsigned int clear_count; /* times dictionary cleared */
|
||||
unsigned int incomp_count; /* incompressible packets */
|
||||
unsigned int incomp_bytes; /* incompressible bytes */
|
||||
unsigned int uncomp_count; /* uncompressed packets */
|
||||
unsigned int uncomp_bytes; /* uncompressed bytes */
|
||||
unsigned int comp_count; /* compressed packets */
|
||||
unsigned int comp_bytes; /* compressed bytes */
|
||||
unsigned short *lens; /* array of lengths of codes */
|
||||
struct bsd_dict *dict; /* dictionary */
|
||||
int xmit;
|
||||
};
|
||||
|
||||
#define BSD_OVHD 2 /* BSD compress overhead/packet */
|
||||
#define MIN_BSD_BITS 9
|
||||
#define BSD_INIT_BITS MIN_BSD_BITS
|
||||
#define MAX_BSD_BITS 15
|
||||
|
||||
/*
|
||||
* the next two codes should not be changed lightly, as they must not
|
||||
* lie within the contiguous general code space.
|
||||
*/
|
||||
#define CLEAR 256 /* table clear output code */
|
||||
#define FIRST 257 /* first free entry */
|
||||
#define LAST 255
|
||||
|
||||
#define MAXCODE(b) ((1 << (b)) - 1)
|
||||
#define BADCODEM1 MAXCODE(MAX_BSD_BITS);
|
||||
|
||||
#define BSD_HASH(prefix,suffix,hshift) ((((unsigned long)(suffix))<<(hshift)) \
|
||||
^ (unsigned long)(prefix))
|
||||
#define BSD_KEY(prefix,suffix) ((((unsigned long)(suffix)) << 16) \
|
||||
+ (unsigned long)(prefix))
|
||||
|
||||
#define CHECK_GAP 10000 /* Ratio check interval */
|
||||
|
||||
#define RATIO_SCALE_LOG 8
|
||||
#define RATIO_SCALE (1<<RATIO_SCALE_LOG)
|
||||
#define RATIO_MAX (0x7fffffff>>RATIO_SCALE_LOG)
|
||||
|
||||
/*
|
||||
* clear the dictionary
|
||||
*/
|
||||
|
||||
static void bsd_clear(struct bsd_db *db)
|
||||
{
|
||||
db->clear_count++;
|
||||
db->max_ent = FIRST-1;
|
||||
db->n_bits = BSD_INIT_BITS;
|
||||
db->bytes_out = 0;
|
||||
db->in_count = 0;
|
||||
db->incomp_count = 0;
|
||||
db->ratio = 0;
|
||||
db->checkpoint = CHECK_GAP;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the dictionary is full, then see if it is time to reset it.
|
||||
*
|
||||
* Compute the compression ratio using fixed-point arithmetic
|
||||
* with 8 fractional bits.
|
||||
*
|
||||
* Since we have an infinite stream instead of a single file,
|
||||
* watch only the local compression ratio.
|
||||
*
|
||||
* Since both peers must reset the dictionary at the same time even in
|
||||
* the absence of CLEAR codes (while packets are incompressible), they
|
||||
* must compute the same ratio.
|
||||
*/
|
||||
static int bsd_check (struct bsd_db *db) /* 1=output CLEAR */
|
||||
{
|
||||
unsigned int new_ratio;
|
||||
|
||||
if (db->in_count >= db->checkpoint)
|
||||
{
|
||||
/* age the ratio by limiting the size of the counts */
|
||||
if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX)
|
||||
{
|
||||
db->in_count -= (db->in_count >> 2);
|
||||
db->bytes_out -= (db->bytes_out >> 2);
|
||||
}
|
||||
|
||||
db->checkpoint = db->in_count + CHECK_GAP;
|
||||
|
||||
if (db->max_ent >= db->maxmaxcode)
|
||||
{
|
||||
/* Reset the dictionary only if the ratio is worse,
|
||||
* or if it looks as if it has been poisoned
|
||||
* by incompressible data.
|
||||
*
|
||||
* This does not overflow, because
|
||||
* db->in_count <= RATIO_MAX.
|
||||
*/
|
||||
|
||||
new_ratio = db->in_count << RATIO_SCALE_LOG;
|
||||
if (db->bytes_out != 0)
|
||||
{
|
||||
new_ratio /= db->bytes_out;
|
||||
}
|
||||
|
||||
if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
|
||||
{
|
||||
bsd_clear (db);
|
||||
return 1;
|
||||
}
|
||||
db->ratio = new_ratio;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return statistics.
|
||||
*/
|
||||
|
||||
static void bsd_stats (void *state, struct compstat *stats)
|
||||
{
|
||||
struct bsd_db *db = (struct bsd_db *) state;
|
||||
|
||||
stats->unc_bytes = db->uncomp_bytes;
|
||||
stats->unc_packets = db->uncomp_count;
|
||||
stats->comp_bytes = db->comp_bytes;
|
||||
stats->comp_packets = db->comp_count;
|
||||
stats->inc_bytes = db->incomp_bytes;
|
||||
stats->inc_packets = db->incomp_count;
|
||||
stats->in_count = db->in_count;
|
||||
stats->bytes_out = db->bytes_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset state, as on a CCP ResetReq.
|
||||
*/
|
||||
static void bsd_reset (void *state,unsigned char code, unsigned char id,
|
||||
unsigned char *data, unsigned len,
|
||||
struct isdn_ppp_resetparams *rsparm)
|
||||
{
|
||||
struct bsd_db *db = (struct bsd_db *) state;
|
||||
|
||||
bsd_clear(db);
|
||||
db->seqno = 0;
|
||||
db->clear_count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the compression structure
|
||||
*/
|
||||
static void bsd_free (void *state)
|
||||
{
|
||||
struct bsd_db *db = (struct bsd_db *) state;
|
||||
|
||||
if (db) {
|
||||
/*
|
||||
* Release the dictionary
|
||||
*/
|
||||
if (db->dict) {
|
||||
vfree (db->dict);
|
||||
db->dict = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the string buffer
|
||||
*/
|
||||
if (db->lens) {
|
||||
vfree (db->lens);
|
||||
db->lens = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally release the structure itself.
|
||||
*/
|
||||
kfree (db);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate space for a (de) compressor.
|
||||
*/
|
||||
static void *bsd_alloc (struct isdn_ppp_comp_data *data)
|
||||
{
|
||||
int bits;
|
||||
unsigned int hsize, hshift, maxmaxcode;
|
||||
struct bsd_db *db;
|
||||
int decomp;
|
||||
|
||||
static unsigned int htab[][2] = {
|
||||
{ 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } ,
|
||||
{ 9001 , 5 } , { 18013 , 6 } , { 35023 , 7 } , { 69001 , 8 }
|
||||
};
|
||||
|
||||
if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
|
||||
|| BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
|
||||
return NULL;
|
||||
|
||||
bits = BSD_NBITS(data->options[0]);
|
||||
|
||||
if(bits < 9 || bits > 15)
|
||||
return NULL;
|
||||
|
||||
hsize = htab[bits-9][0];
|
||||
hshift = htab[bits-9][1];
|
||||
|
||||
/*
|
||||
* Allocate the main control structure for this instance.
|
||||
*/
|
||||
maxmaxcode = MAXCODE(bits);
|
||||
db = (struct bsd_db *) kmalloc (sizeof (struct bsd_db),GFP_KERNEL);
|
||||
if (!db)
|
||||
return NULL;
|
||||
|
||||
memset (db, 0, sizeof(struct bsd_db));
|
||||
|
||||
db->xmit = data->flags & IPPP_COMP_FLAG_XMIT;
|
||||
decomp = db->xmit ? 0 : 1;
|
||||
|
||||
/*
|
||||
* Allocate space for the dictionary. This may be more than one page in
|
||||
* length.
|
||||
*/
|
||||
db->dict = (struct bsd_dict *) vmalloc (hsize * sizeof (struct bsd_dict));
|
||||
if (!db->dict) {
|
||||
bsd_free (db);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is the compression buffer then there is no length data.
|
||||
* For decompression, the length information is needed as well.
|
||||
*/
|
||||
if (!decomp)
|
||||
db->lens = NULL;
|
||||
else {
|
||||
db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
|
||||
sizeof (db->lens[0]));
|
||||
if (!db->lens) {
|
||||
bsd_free (db);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the data information for the compression code
|
||||
*/
|
||||
db->totlen = sizeof (struct bsd_db) + (sizeof (struct bsd_dict) * hsize);
|
||||
db->hsize = hsize;
|
||||
db->hshift = hshift;
|
||||
db->maxmaxcode = maxmaxcode;
|
||||
db->maxbits = bits;
|
||||
|
||||
return (void *) db;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the database.
|
||||
*/
|
||||
static int bsd_init (void *state, struct isdn_ppp_comp_data *data, int unit, int debug)
|
||||
{
|
||||
struct bsd_db *db = state;
|
||||
int indx;
|
||||
int decomp;
|
||||
|
||||
if(!state || !data) {
|
||||
printk(KERN_ERR "isdn_bsd_init: [%d] ERR, state %lx data %lx\n",unit,(long)state,(long)data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
decomp = db->xmit ? 0 : 1;
|
||||
|
||||
if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
|
||||
|| (BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
|
||||
|| (BSD_NBITS(data->options[0]) != db->maxbits)
|
||||
|| (decomp && db->lens == NULL)) {
|
||||
printk(KERN_ERR "isdn_bsd: %d %d %d %d %lx\n",data->optlen,data->num,data->options[0],decomp,(unsigned long)db->lens);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (decomp)
|
||||
for(indx=LAST;indx>=0;indx--)
|
||||
db->lens[indx] = 1;
|
||||
|
||||
indx = db->hsize;
|
||||
while (indx-- != 0) {
|
||||
db->dict[indx].codem1 = BADCODEM1;
|
||||
db->dict[indx].cptr = 0;
|
||||
}
|
||||
|
||||
db->unit = unit;
|
||||
db->mru = 0;
|
||||
|
||||
db->debug = 1;
|
||||
|
||||
bsd_reset(db,0,0,NULL,0,NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain pointers to the various structures in the compression tables
|
||||
*/
|
||||
|
||||
#define dict_ptrx(p,idx) &(p->dict[idx])
|
||||
#define lens_ptrx(p,idx) &(p->lens[idx])
|
||||
|
||||
#ifdef DEBUG
|
||||
static unsigned short *lens_ptr(struct bsd_db *db, int idx)
|
||||
{
|
||||
if ((unsigned int) idx > (unsigned int) db->maxmaxcode) {
|
||||
printk (KERN_DEBUG "<9>ppp: lens_ptr(%d) > max\n", idx);
|
||||
idx = 0;
|
||||
}
|
||||
return lens_ptrx (db, idx);
|
||||
}
|
||||
|
||||
static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx)
|
||||
{
|
||||
if ((unsigned int) idx >= (unsigned int) db->hsize) {
|
||||
printk (KERN_DEBUG "<9>ppp: dict_ptr(%d) > max\n", idx);
|
||||
idx = 0;
|
||||
}
|
||||
return dict_ptrx (db, idx);
|
||||
}
|
||||
|
||||
#else
|
||||
#define lens_ptr(db,idx) lens_ptrx(db,idx)
|
||||
#define dict_ptr(db,idx) dict_ptrx(db,idx)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* compress a packet
|
||||
*/
|
||||
static int bsd_compress (void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,int proto)
|
||||
{
|
||||
struct bsd_db *db;
|
||||
int hshift;
|
||||
unsigned int max_ent;
|
||||
unsigned int n_bits;
|
||||
unsigned int bitno;
|
||||
unsigned long accm;
|
||||
int ent;
|
||||
unsigned long fcode;
|
||||
struct bsd_dict *dictp;
|
||||
unsigned char c;
|
||||
int hval,disp,ilen,mxcode;
|
||||
unsigned char *rptr = skb_in->data;
|
||||
int isize = skb_in->len;
|
||||
|
||||
#define OUTPUT(ent) \
|
||||
{ \
|
||||
bitno -= n_bits; \
|
||||
accm |= ((ent) << bitno); \
|
||||
do { \
|
||||
if(skb_out && skb_tailroom(skb_out) > 0) \
|
||||
*(skb_put(skb_out,1)) = (unsigned char) (accm>>24); \
|
||||
accm <<= 8; \
|
||||
bitno += 8; \
|
||||
} while (bitno <= 24); \
|
||||
}
|
||||
|
||||
/*
|
||||
* If the protocol is not in the range we're interested in,
|
||||
* just return without compressing the packet. If it is,
|
||||
* the protocol becomes the first byte to compress.
|
||||
*/
|
||||
printk(KERN_DEBUG "bsd_compress called with %x\n",proto);
|
||||
|
||||
ent = proto;
|
||||
if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1) )
|
||||
return 0;
|
||||
|
||||
db = (struct bsd_db *) state;
|
||||
hshift = db->hshift;
|
||||
max_ent = db->max_ent;
|
||||
n_bits = db->n_bits;
|
||||
bitno = 32;
|
||||
accm = 0;
|
||||
mxcode = MAXCODE (n_bits);
|
||||
|
||||
/* This is the PPP header information */
|
||||
if(skb_out && skb_tailroom(skb_out) >= 2) {
|
||||
char *v = skb_put(skb_out,2);
|
||||
/* we only push our own data on the header,
|
||||
AC,PC and protos is pushed by caller */
|
||||
v[0] = db->seqno >> 8;
|
||||
v[1] = db->seqno;
|
||||
}
|
||||
|
||||
ilen = ++isize; /* This is off by one, but that is what is in draft! */
|
||||
|
||||
while (--ilen > 0) {
|
||||
c = *rptr++;
|
||||
fcode = BSD_KEY (ent, c);
|
||||
hval = BSD_HASH (ent, c, hshift);
|
||||
dictp = dict_ptr (db, hval);
|
||||
|
||||
/* Validate and then check the entry. */
|
||||
if (dictp->codem1 >= max_ent)
|
||||
goto nomatch;
|
||||
|
||||
if (dictp->fcode == fcode) {
|
||||
ent = dictp->codem1 + 1;
|
||||
continue; /* found (prefix,suffix) */
|
||||
}
|
||||
|
||||
/* continue probing until a match or invalid entry */
|
||||
disp = (hval == 0) ? 1 : hval;
|
||||
|
||||
do {
|
||||
hval += disp;
|
||||
if (hval >= db->hsize)
|
||||
hval -= db->hsize;
|
||||
dictp = dict_ptr (db, hval);
|
||||
if (dictp->codem1 >= max_ent)
|
||||
goto nomatch;
|
||||
} while (dictp->fcode != fcode);
|
||||
|
||||
ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
|
||||
continue;
|
||||
|
||||
nomatch:
|
||||
OUTPUT(ent); /* output the prefix */
|
||||
|
||||
/* code -> hashtable */
|
||||
if (max_ent < db->maxmaxcode) {
|
||||
struct bsd_dict *dictp2;
|
||||
struct bsd_dict *dictp3;
|
||||
int indx;
|
||||
|
||||
/* expand code size if needed */
|
||||
if (max_ent >= mxcode) {
|
||||
db->n_bits = ++n_bits;
|
||||
mxcode = MAXCODE (n_bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate old hash table entry using
|
||||
* this code, and then take it over.
|
||||
*/
|
||||
dictp2 = dict_ptr (db, max_ent + 1);
|
||||
indx = dictp2->cptr;
|
||||
dictp3 = dict_ptr (db, indx);
|
||||
|
||||
if (dictp3->codem1 == max_ent)
|
||||
dictp3->codem1 = BADCODEM1;
|
||||
|
||||
dictp2->cptr = hval;
|
||||
dictp->codem1 = max_ent;
|
||||
dictp->fcode = fcode;
|
||||
db->max_ent = ++max_ent;
|
||||
|
||||
if (db->lens) {
|
||||
unsigned short *len1 = lens_ptr (db, max_ent);
|
||||
unsigned short *len2 = lens_ptr (db, ent);
|
||||
*len1 = *len2 + 1;
|
||||
}
|
||||
}
|
||||
ent = c;
|
||||
}
|
||||
|
||||
OUTPUT(ent); /* output the last code */
|
||||
|
||||
if(skb_out)
|
||||
db->bytes_out += skb_out->len; /* Do not count bytes from here */
|
||||
db->uncomp_bytes += isize;
|
||||
db->in_count += isize;
|
||||
++db->uncomp_count;
|
||||
++db->seqno;
|
||||
|
||||
if (bitno < 32)
|
||||
++db->bytes_out; /* must be set before calling bsd_check */
|
||||
|
||||
/*
|
||||
* Generate the clear command if needed
|
||||
*/
|
||||
|
||||
if (bsd_check(db))
|
||||
OUTPUT (CLEAR);
|
||||
|
||||
/*
|
||||
* Pad dribble bits of last code with ones.
|
||||
* Do not emit a completely useless byte of ones.
|
||||
*/
|
||||
if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0)
|
||||
*(skb_put(skb_out,1)) = (unsigned char) ((accm | (0xff << (bitno-8))) >> 24);
|
||||
|
||||
/*
|
||||
* Increase code size if we would have without the packet
|
||||
* boundary because the decompressor will do so.
|
||||
*/
|
||||
if (max_ent >= mxcode && max_ent < db->maxmaxcode)
|
||||
db->n_bits++;
|
||||
|
||||
/* If output length is too large then this is an incompressible frame. */
|
||||
if (!skb_out || (skb_out && skb_out->len >= skb_in->len) ) {
|
||||
++db->incomp_count;
|
||||
db->incomp_bytes += isize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Count the number of compressed frames */
|
||||
++db->comp_count;
|
||||
db->comp_bytes += skb_out->len;
|
||||
return skb_out->len;
|
||||
|
||||
#undef OUTPUT
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the "BSD Compress" dictionary on the receiver for
|
||||
* incompressible data by pretending to compress the incoming data.
|
||||
*/
|
||||
static void bsd_incomp (void *state, struct sk_buff *skb_in,int proto)
|
||||
{
|
||||
bsd_compress (state, skb_in, NULL, proto);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompress "BSD Compress".
|
||||
*/
|
||||
static int bsd_decompress (void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,
|
||||
struct isdn_ppp_resetparams *rsparm)
|
||||
{
|
||||
struct bsd_db *db;
|
||||
unsigned int max_ent;
|
||||
unsigned long accm;
|
||||
unsigned int bitno; /* 1st valid bit in accm */
|
||||
unsigned int n_bits;
|
||||
unsigned int tgtbitno; /* bitno when we have a code */
|
||||
struct bsd_dict *dictp;
|
||||
int seq;
|
||||
unsigned int incode;
|
||||
unsigned int oldcode;
|
||||
unsigned int finchar;
|
||||
unsigned char *p,*ibuf;
|
||||
int ilen;
|
||||
int codelen;
|
||||
int extra;
|
||||
|
||||
db = (struct bsd_db *) state;
|
||||
max_ent = db->max_ent;
|
||||
accm = 0;
|
||||
bitno = 32; /* 1st valid bit in accm */
|
||||
n_bits = db->n_bits;
|
||||
tgtbitno = 32 - n_bits; /* bitno when we have a code */
|
||||
|
||||
printk(KERN_DEBUG "bsd_decompress called\n");
|
||||
|
||||
if(!skb_in || !skb_out) {
|
||||
printk(KERN_ERR "bsd_decompress called with NULL parameter\n");
|
||||
return DECOMP_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the sequence number.
|
||||
*/
|
||||
if( (p = skb_pull(skb_in,2)) == NULL) {
|
||||
return DECOMP_ERROR;
|
||||
}
|
||||
p-=2;
|
||||
seq = (p[0] << 8) + p[1];
|
||||
ilen = skb_in->len;
|
||||
ibuf = skb_in->data;
|
||||
|
||||
/*
|
||||
* Check the sequence number and give up if it differs from
|
||||
* the value we're expecting.
|
||||
*/
|
||||
if (seq != db->seqno) {
|
||||
if (db->debug) {
|
||||
printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n",
|
||||
db->unit, seq, db->seqno - 1);
|
||||
}
|
||||
return DECOMP_ERROR;
|
||||
}
|
||||
|
||||
++db->seqno;
|
||||
db->bytes_out += ilen;
|
||||
|
||||
if(skb_tailroom(skb_out) > 0)
|
||||
*(skb_put(skb_out,1)) = 0;
|
||||
else
|
||||
return DECOMP_ERR_NOMEM;
|
||||
|
||||
oldcode = CLEAR;
|
||||
|
||||
/*
|
||||
* Keep the checkpoint correctly so that incompressible packets
|
||||
* clear the dictionary at the proper times.
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
if (ilen-- <= 0) {
|
||||
db->in_count += (skb_out->len - 1); /* don't count the header */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accumulate bytes until we have a complete code.
|
||||
* Then get the next code, relying on the 32-bit,
|
||||
* unsigned accm to mask the result.
|
||||
*/
|
||||
|
||||
bitno -= 8;
|
||||
accm |= *ibuf++ << bitno;
|
||||
if (tgtbitno < bitno)
|
||||
continue;
|
||||
|
||||
incode = accm >> tgtbitno;
|
||||
accm <<= n_bits;
|
||||
bitno += n_bits;
|
||||
|
||||
/*
|
||||
* The dictionary must only be cleared at the end of a packet.
|
||||
*/
|
||||
|
||||
if (incode == CLEAR) {
|
||||
if (ilen > 0) {
|
||||
if (db->debug)
|
||||
printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit);
|
||||
return DECOMP_FATALERROR; /* probably a bug */
|
||||
}
|
||||
bsd_clear(db);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((incode > max_ent + 2) || (incode > db->maxmaxcode)
|
||||
|| (incode > max_ent && oldcode == CLEAR)) {
|
||||
if (db->debug) {
|
||||
printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
|
||||
db->unit, incode, oldcode);
|
||||
printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n",
|
||||
max_ent, skb_out->len, db->seqno);
|
||||
}
|
||||
return DECOMP_FATALERROR; /* probably a bug */
|
||||
}
|
||||
|
||||
/* Special case for KwKwK string. */
|
||||
if (incode > max_ent) {
|
||||
finchar = oldcode;
|
||||
extra = 1;
|
||||
} else {
|
||||
finchar = incode;
|
||||
extra = 0;
|
||||
}
|
||||
|
||||
codelen = *(lens_ptr (db, finchar));
|
||||
if( skb_tailroom(skb_out) < codelen + extra) {
|
||||
if (db->debug) {
|
||||
printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit);
|
||||
#ifdef DEBUG
|
||||
printk(KERN_DEBUG " len=%d, finchar=0x%x, codelen=%d,skblen=%d\n",
|
||||
ilen, finchar, codelen, skb_out->len);
|
||||
#endif
|
||||
}
|
||||
return DECOMP_FATALERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode this code and install it in the decompressed buffer.
|
||||
*/
|
||||
|
||||
p = skb_put(skb_out,codelen);
|
||||
p += codelen;
|
||||
while (finchar > LAST) {
|
||||
struct bsd_dict *dictp2 = dict_ptr (db, finchar);
|
||||
|
||||
dictp = dict_ptr (db, dictp2->cptr);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (--codelen <= 0 || dictp->codem1 != finchar-1) {
|
||||
if (codelen <= 0) {
|
||||
printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit);
|
||||
printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent);
|
||||
} else {
|
||||
if (dictp->codem1 != finchar-1) {
|
||||
printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",db->unit, incode, finchar);
|
||||
printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1);
|
||||
}
|
||||
}
|
||||
return DECOMP_FATALERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
u32 fcode = dictp->fcode;
|
||||
*--p = (fcode >> 16) & 0xff;
|
||||
finchar = fcode & 0xffff;
|
||||
}
|
||||
}
|
||||
*--p = finchar;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (--codelen != 0)
|
||||
printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent);
|
||||
#endif
|
||||
|
||||
if (extra) /* the KwKwK case again */
|
||||
*(skb_put(skb_out,1)) = finchar;
|
||||
|
||||
/*
|
||||
* If not first code in a packet, and
|
||||
* if not out of code space, then allocate a new code.
|
||||
*
|
||||
* Keep the hash table correct so it can be used
|
||||
* with uncompressed packets.
|
||||
*/
|
||||
if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
|
||||
struct bsd_dict *dictp2, *dictp3;
|
||||
u16 *lens1, *lens2;
|
||||
unsigned long fcode;
|
||||
int hval, disp, indx;
|
||||
|
||||
fcode = BSD_KEY(oldcode,finchar);
|
||||
hval = BSD_HASH(oldcode,finchar,db->hshift);
|
||||
dictp = dict_ptr (db, hval);
|
||||
|
||||
/* look for a free hash table entry */
|
||||
if (dictp->codem1 < max_ent) {
|
||||
disp = (hval == 0) ? 1 : hval;
|
||||
do {
|
||||
hval += disp;
|
||||
if (hval >= db->hsize)
|
||||
hval -= db->hsize;
|
||||
dictp = dict_ptr (db, hval);
|
||||
} while (dictp->codem1 < max_ent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate previous hash table entry
|
||||
* assigned this code, and then take it over
|
||||
*/
|
||||
|
||||
dictp2 = dict_ptr (db, max_ent + 1);
|
||||
indx = dictp2->cptr;
|
||||
dictp3 = dict_ptr (db, indx);
|
||||
|
||||
if (dictp3->codem1 == max_ent)
|
||||
dictp3->codem1 = BADCODEM1;
|
||||
|
||||
dictp2->cptr = hval;
|
||||
dictp->codem1 = max_ent;
|
||||
dictp->fcode = fcode;
|
||||
db->max_ent = ++max_ent;
|
||||
|
||||
/* Update the length of this string. */
|
||||
lens1 = lens_ptr (db, max_ent);
|
||||
lens2 = lens_ptr (db, oldcode);
|
||||
*lens1 = *lens2 + 1;
|
||||
|
||||
/* Expand code size if needed. */
|
||||
if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
|
||||
db->n_bits = ++n_bits;
|
||||
tgtbitno = 32-n_bits;
|
||||
}
|
||||
}
|
||||
oldcode = incode;
|
||||
}
|
||||
|
||||
++db->comp_count;
|
||||
++db->uncomp_count;
|
||||
db->comp_bytes += skb_in->len - BSD_OVHD;
|
||||
db->uncomp_bytes += skb_out->len;
|
||||
|
||||
if (bsd_check(db)) {
|
||||
if (db->debug)
|
||||
printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n",
|
||||
db->unit, db->seqno - 1);
|
||||
}
|
||||
return skb_out->len;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Table of addresses for the BSD compression module
|
||||
*************************************************************/
|
||||
|
||||
static struct isdn_ppp_compressor ippp_bsd_compress = {
|
||||
.owner = THIS_MODULE,
|
||||
.num = CI_BSD_COMPRESS,
|
||||
.alloc = bsd_alloc,
|
||||
.free = bsd_free,
|
||||
.init = bsd_init,
|
||||
.reset = bsd_reset,
|
||||
.compress = bsd_compress,
|
||||
.decompress = bsd_decompress,
|
||||
.incomp = bsd_incomp,
|
||||
.stat = bsd_stats,
|
||||
};
|
||||
|
||||
/*************************************************************
|
||||
* Module support routines
|
||||
*************************************************************/
|
||||
|
||||
static int __init isdn_bsdcomp_init(void)
|
||||
{
|
||||
int answer = isdn_ppp_register_compressor (&ippp_bsd_compress);
|
||||
if (answer == 0)
|
||||
printk (KERN_INFO "PPP BSD Compression module registered\n");
|
||||
return answer;
|
||||
}
|
||||
|
||||
static void __exit isdn_bsdcomp_exit(void)
|
||||
{
|
||||
isdn_ppp_unregister_compressor (&ippp_bsd_compress);
|
||||
}
|
||||
|
||||
module_init(isdn_bsdcomp_init);
|
||||
module_exit(isdn_bsdcomp_exit);
|
2253
drivers/isdn/i4l/isdn_common.c
Normal file
2253
drivers/isdn/i4l/isdn_common.c
Normal file
File diff suppressed because it is too large
Load Diff
47
drivers/isdn/i4l/isdn_common.h
Normal file
47
drivers/isdn/i4l/isdn_common.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* $Id: isdn_common.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem
|
||||
* common used functions and debugging-switches (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
|
||||
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#undef ISDN_DEBUG_MODEM_OPEN
|
||||
#undef ISDN_DEBUG_MODEM_IOCTL
|
||||
#undef ISDN_DEBUG_MODEM_WAITSENT
|
||||
#undef ISDN_DEBUG_MODEM_HUP
|
||||
#undef ISDN_DEBUG_MODEM_ICALL
|
||||
#undef ISDN_DEBUG_MODEM_DUMP
|
||||
#undef ISDN_DEBUG_MODEM_VOICE
|
||||
#undef ISDN_DEBUG_AT
|
||||
#undef ISDN_DEBUG_NET_DUMP
|
||||
#undef ISDN_DEBUG_NET_DIAL
|
||||
#undef ISDN_DEBUG_NET_ICALL
|
||||
|
||||
/* Prototypes */
|
||||
extern void isdn_lock_drivers(void);
|
||||
extern void isdn_unlock_drivers(void);
|
||||
extern void isdn_free_channel(int di, int ch, int usage);
|
||||
extern void isdn_all_eaz(int di, int ch);
|
||||
extern int isdn_command(isdn_ctrl *);
|
||||
extern int isdn_dc2minor(int di, int ch);
|
||||
extern void isdn_info_update(void);
|
||||
extern char *isdn_map_eaz2msn(char *msn, int di);
|
||||
extern void isdn_timer_ctrl(int tf, int onoff);
|
||||
extern void isdn_unexclusive_channel(int di, int ch);
|
||||
extern int isdn_getnum(char **);
|
||||
extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
|
||||
extern int isdn_get_free_channel(int, int, int, int, int, char *);
|
||||
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
|
||||
extern int register_isdn(isdn_if * i);
|
||||
extern int isdn_msncmp( const char *, const char *);
|
||||
extern int isdn_add_channels(isdn_driver_t *, int, int, int);
|
||||
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
|
||||
extern void isdn_dumppkt(char *, u_char *, int, int);
|
||||
#endif
|
108
drivers/isdn/i4l/isdn_concap.c
Normal file
108
drivers/isdn/i4l/isdn_concap.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/* $Id: isdn_concap.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, protocol encapsulation
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
|
||||
* stuff goes here. Stuff that depends only on the concap protocol goes to
|
||||
* another -- protocol specific -- source file.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/isdn.h>
|
||||
#include "isdn_x25iface.h"
|
||||
#include "isdn_net.h"
|
||||
#include <linux/concap.h>
|
||||
#include "isdn_concap.h"
|
||||
|
||||
|
||||
/* The following set of device service operations are for encapsulation
|
||||
protocols that require for reliable datalink semantics. That means:
|
||||
|
||||
- before any data is to be submitted the connection must explicitly
|
||||
be set up.
|
||||
- after the successful set up of the connection is signalled the
|
||||
connection is considered to be reliably up.
|
||||
|
||||
Auto-dialing ist not compatible with this requirements. Thus, auto-dialing
|
||||
is completely bypassed.
|
||||
|
||||
It might be possible to implement a (non standardized) datalink protocol
|
||||
that provides a reliable data link service while using some auto dialing
|
||||
mechanism. Such a protocol would need an auxiliary channel (i.e. user-user-
|
||||
signaling on the D-channel) while the B-channel is down.
|
||||
*/
|
||||
|
||||
|
||||
int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *ndev = concap -> net_dev;
|
||||
isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev;
|
||||
isdn_net_local *lp = isdn_net_get_locked_lp(nd);
|
||||
|
||||
IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
|
||||
if (!lp) {
|
||||
IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 1);
|
||||
return 1;
|
||||
}
|
||||
lp->huptimer = 0;
|
||||
isdn_net_writebuf_skb(lp, skb);
|
||||
spin_unlock_bh(&lp->xmit_lock);
|
||||
IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int isdn_concap_dl_connect_req(struct concap_proto *concap)
|
||||
{
|
||||
struct net_device *ndev = concap -> net_dev;
|
||||
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
|
||||
int ret;
|
||||
IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name);
|
||||
|
||||
/* dial ... */
|
||||
ret = isdn_net_dial_req( lp );
|
||||
if ( ret ) IX25DEBUG("dialing failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int isdn_concap_dl_disconn_req(struct concap_proto *concap)
|
||||
{
|
||||
IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name);
|
||||
|
||||
isdn_net_hangup( concap -> net_dev );
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct concap_device_ops isdn_concap_reliable_dl_dops = {
|
||||
&isdn_concap_dl_data_req,
|
||||
&isdn_concap_dl_connect_req,
|
||||
&isdn_concap_dl_disconn_req
|
||||
};
|
||||
|
||||
struct concap_device_ops isdn_concap_demand_dial_dops = {
|
||||
NULL, /* set this first entry to something like &isdn_net_start_xmit,
|
||||
but the entry part of the current isdn_net_start_xmit must be
|
||||
separated first. */
|
||||
/* no connection control for demand dial semantics */
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* The following should better go into a dedicated source file such that
|
||||
this sourcefile does not need to include any protocol specific header
|
||||
files. For now:
|
||||
*/
|
||||
struct concap_proto * isdn_concap_new( int encap )
|
||||
{
|
||||
switch ( encap ) {
|
||||
case ISDN_NET_ENCAP_X25IFACE:
|
||||
return isdn_x25iface_proto_new();
|
||||
}
|
||||
return NULL;
|
||||
}
|
14
drivers/isdn/i4l/isdn_concap.h
Normal file
14
drivers/isdn/i4l/isdn_concap.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/* $Id: isdn_concap.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, protocol encapsulation
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
extern struct concap_device_ops isdn_concap_reliable_dl_dops;
|
||||
extern struct concap_device_ops isdn_concap_demand_dial_dops;
|
||||
extern struct concap_proto * isdn_concap_new( int );
|
||||
|
||||
|
3222
drivers/isdn/i4l/isdn_net.c
Normal file
3222
drivers/isdn/i4l/isdn_net.c
Normal file
File diff suppressed because it is too large
Load Diff
190
drivers/isdn/i4l/isdn_net.h
Normal file
190
drivers/isdn/i4l/isdn_net.h
Normal file
@@ -0,0 +1,190 @@
|
||||
/* $Id: isdn_net.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem, network related functions (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
|
||||
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Definitions for hupflags: */
|
||||
#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */
|
||||
#define ISDN_HAVECHARGE 2 /* We know a charge info */
|
||||
#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */
|
||||
#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */
|
||||
#define ISDN_MANCHARGE 16 /* Charge Interval manually set */
|
||||
|
||||
/*
|
||||
* Definitions for Cisco-HDLC header.
|
||||
*/
|
||||
|
||||
#define CISCO_ADDR_UNICAST 0x0f
|
||||
#define CISCO_ADDR_BROADCAST 0x8f
|
||||
#define CISCO_CTRL 0x00
|
||||
#define CISCO_TYPE_CDP 0x2000
|
||||
#define CISCO_TYPE_SLARP 0x8035
|
||||
#define CISCO_SLARP_REQUEST 0
|
||||
#define CISCO_SLARP_REPLY 1
|
||||
#define CISCO_SLARP_KEEPALIVE 2
|
||||
|
||||
extern char *isdn_net_new(char *, struct net_device *);
|
||||
extern char *isdn_net_newslave(char *);
|
||||
extern int isdn_net_rm(char *);
|
||||
extern int isdn_net_rmall(void);
|
||||
extern int isdn_net_stat_callback(int, isdn_ctrl *);
|
||||
extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
|
||||
extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
|
||||
extern int isdn_net_addphone(isdn_net_ioctl_phone *);
|
||||
extern int isdn_net_getphones(isdn_net_ioctl_phone *, char __user *);
|
||||
extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone __user *);
|
||||
extern int isdn_net_delphone(isdn_net_ioctl_phone *);
|
||||
extern int isdn_net_find_icall(int, int, int, setup_parm *);
|
||||
extern void isdn_net_hangup(struct net_device *);
|
||||
extern void isdn_net_dial(void);
|
||||
extern void isdn_net_autohup(void);
|
||||
extern int isdn_net_force_hangup(char *);
|
||||
extern int isdn_net_force_dial(char *);
|
||||
extern isdn_net_dev *isdn_net_findif(char *);
|
||||
extern int isdn_net_rcv_skb(int, struct sk_buff *);
|
||||
extern int isdn_net_dial_req(isdn_net_local *);
|
||||
extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
|
||||
extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
|
||||
|
||||
#define ISDN_NET_MAX_QUEUE_LENGTH 2
|
||||
|
||||
/*
|
||||
* is this particular channel busy?
|
||||
*/
|
||||
static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
|
||||
{
|
||||
if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the given net device, this will get a non-busy channel out of the
|
||||
* corresponding bundle. The returned channel is locked.
|
||||
*/
|
||||
static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd)
|
||||
{
|
||||
unsigned long flags;
|
||||
isdn_net_local *lp;
|
||||
|
||||
spin_lock_irqsave(&nd->queue_lock, flags);
|
||||
lp = nd->queue; /* get lp on top of queue */
|
||||
spin_lock(&nd->queue->xmit_lock);
|
||||
while (isdn_net_lp_busy(nd->queue)) {
|
||||
spin_unlock(&nd->queue->xmit_lock);
|
||||
nd->queue = nd->queue->next;
|
||||
if (nd->queue == lp) { /* not found -- should never happen */
|
||||
lp = NULL;
|
||||
goto errout;
|
||||
}
|
||||
spin_lock(&nd->queue->xmit_lock);
|
||||
}
|
||||
lp = nd->queue;
|
||||
nd->queue = nd->queue->next;
|
||||
local_bh_disable();
|
||||
errout:
|
||||
spin_unlock_irqrestore(&nd->queue_lock, flags);
|
||||
return lp;
|
||||
}
|
||||
|
||||
/*
|
||||
* add a channel to a bundle
|
||||
*/
|
||||
static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
|
||||
{
|
||||
isdn_net_local *lp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&nd->queue_lock, flags);
|
||||
|
||||
lp = nd->queue;
|
||||
// printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n",
|
||||
// __FUNCTION__, lp->name, lp, nlp->name, nlp, lp->last);
|
||||
nlp->last = lp->last;
|
||||
lp->last->next = nlp;
|
||||
lp->last = nlp;
|
||||
nlp->next = lp;
|
||||
nd->queue = nlp;
|
||||
|
||||
spin_unlock_irqrestore(&nd->queue_lock, flags);
|
||||
}
|
||||
/*
|
||||
* remove a channel from the bundle it belongs to
|
||||
*/
|
||||
static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
|
||||
{
|
||||
isdn_net_local *master_lp = lp;
|
||||
unsigned long flags;
|
||||
|
||||
if (lp->master)
|
||||
master_lp = (isdn_net_local *) lp->master->priv;
|
||||
|
||||
// printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
|
||||
// __FUNCTION__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue);
|
||||
spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
|
||||
lp->last->next = lp->next;
|
||||
lp->next->last = lp->last;
|
||||
if (master_lp->netdev->queue == lp) {
|
||||
master_lp->netdev->queue = lp->next;
|
||||
if (lp->next == lp) { /* last in queue */
|
||||
master_lp->netdev->queue = master_lp->netdev->local;
|
||||
}
|
||||
}
|
||||
lp->next = lp->last = lp; /* (re)set own pointers */
|
||||
// printk(KERN_DEBUG "%s: mndq(%p)\n",
|
||||
// __FUNCTION__, master_lp->netdev->queue);
|
||||
spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
|
||||
}
|
||||
|
||||
static inline int
|
||||
put_u8(unsigned char *p, u8 x)
|
||||
{
|
||||
*p = x;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
put_u16(unsigned char *p, u16 x)
|
||||
{
|
||||
*((u16 *)p) = htons(x);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static inline int
|
||||
put_u32(unsigned char *p, u32 x)
|
||||
{
|
||||
*((u32 *)p) = htonl(x);
|
||||
return 4;
|
||||
}
|
||||
|
||||
static inline int
|
||||
get_u8(unsigned char *p, u8 *x)
|
||||
{
|
||||
*x = *p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
get_u16(unsigned char *p, u16 *x)
|
||||
{
|
||||
*x = ntohs(*((u16 *)p));
|
||||
return 2;
|
||||
}
|
||||
|
||||
static inline int
|
||||
get_u32(unsigned char *p, u32 *x)
|
||||
{
|
||||
*x = ntohl(*((u32 *)p));
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
3020
drivers/isdn/i4l/isdn_ppp.c
Normal file
3020
drivers/isdn/i4l/isdn_ppp.c
Normal file
File diff suppressed because it is too large
Load Diff
43
drivers/isdn/i4l/isdn_ppp.h
Normal file
43
drivers/isdn/i4l/isdn_ppp.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* $Id: isdn_ppp.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
|
||||
*
|
||||
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
|
||||
#include <linux/isdn_ppp.h> /* for isdn_ppp info */
|
||||
|
||||
extern int isdn_ppp_read(int, struct file *, char __user *, int);
|
||||
extern int isdn_ppp_write(int, struct file *, const char __user *, int);
|
||||
extern int isdn_ppp_open(int, struct file *);
|
||||
extern int isdn_ppp_init(void);
|
||||
extern void isdn_ppp_cleanup(void);
|
||||
extern int isdn_ppp_free(isdn_net_local *);
|
||||
extern int isdn_ppp_bind(isdn_net_local *);
|
||||
extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *);
|
||||
extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
|
||||
extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
|
||||
extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
|
||||
extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
|
||||
extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
|
||||
extern void isdn_ppp_release(int, struct file *);
|
||||
extern int isdn_ppp_dial_slave(char *);
|
||||
extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
|
||||
|
||||
extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc);
|
||||
extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc);
|
||||
|
||||
#define IPPP_OPEN 0x01
|
||||
#define IPPP_CONNECT 0x02
|
||||
#define IPPP_CLOSEWAIT 0x04
|
||||
#define IPPP_NOBLOCK 0x08
|
||||
#define IPPP_ASSIGNED 0x10
|
||||
|
||||
#define IPPP_MAX_HEADER 10
|
||||
|
||||
|
3911
drivers/isdn/i4l/isdn_tty.c
Normal file
3911
drivers/isdn/i4l/isdn_tty.c
Normal file
File diff suppressed because it is too large
Load Diff
122
drivers/isdn/i4l/isdn_tty.h
Normal file
122
drivers/isdn/i4l/isdn_tty.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/* $Id: isdn_tty.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem, tty related functions (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
|
||||
#define DLE 0x10
|
||||
#define ETX 0x03
|
||||
#define DC4 0x14
|
||||
|
||||
|
||||
/*
|
||||
* Definition of some special Registers of AT-Emulator
|
||||
*/
|
||||
#define REG_RINGATA 0
|
||||
#define REG_RINGCNT 1 /* ring counter register */
|
||||
#define REG_ESC 2
|
||||
#define REG_CR 3
|
||||
#define REG_LF 4
|
||||
#define REG_BS 5
|
||||
|
||||
#define REG_WAITC 7
|
||||
|
||||
#define REG_RESP 12 /* show response messages register */
|
||||
#define BIT_RESP 1 /* show response messages bit */
|
||||
#define REG_RESPNUM 12 /* show numeric responses register */
|
||||
#define BIT_RESPNUM 2 /* show numeric responses bit */
|
||||
#define REG_ECHO 12
|
||||
#define BIT_ECHO 4
|
||||
#define REG_DCD 12
|
||||
#define BIT_DCD 8
|
||||
#define REG_CTS 12
|
||||
#define BIT_CTS 16
|
||||
#define REG_DTRR 12
|
||||
#define BIT_DTRR 32
|
||||
#define REG_DSR 12
|
||||
#define BIT_DSR 64
|
||||
#define REG_CPPP 12
|
||||
#define BIT_CPPP 128
|
||||
|
||||
#define REG_DXMT 13
|
||||
#define BIT_DXMT 1
|
||||
#define REG_T70 13
|
||||
#define BIT_T70 2
|
||||
#define BIT_T70_EXT 32
|
||||
#define REG_DTRHUP 13
|
||||
#define BIT_DTRHUP 4
|
||||
#define REG_RESPXT 13
|
||||
#define BIT_RESPXT 8
|
||||
#define REG_CIDONCE 13
|
||||
#define BIT_CIDONCE 16
|
||||
#define REG_RUNG 13 /* show RUNG message register */
|
||||
#define BIT_RUNG 64 /* show RUNG message bit */
|
||||
#define REG_DISPLAY 13
|
||||
#define BIT_DISPLAY 128
|
||||
|
||||
#define REG_L2PROT 14
|
||||
#define REG_L3PROT 15
|
||||
#define REG_PSIZE 16
|
||||
#define REG_WSIZE 17
|
||||
#define REG_SI1 18
|
||||
#define REG_SI2 19
|
||||
#define REG_SI1I 20
|
||||
#define REG_PLAN 21
|
||||
#define REG_SCREEN 22
|
||||
|
||||
#define REG_CPN 23
|
||||
#define BIT_CPN 1
|
||||
#define REG_CPNFCON 23
|
||||
#define BIT_CPNFCON 2
|
||||
#define REG_CDN 23
|
||||
#define BIT_CDN 4
|
||||
|
||||
/* defines for result codes */
|
||||
#define RESULT_OK 0
|
||||
#define RESULT_CONNECT 1
|
||||
#define RESULT_RING 2
|
||||
#define RESULT_NO_CARRIER 3
|
||||
#define RESULT_ERROR 4
|
||||
#define RESULT_CONNECT64000 5
|
||||
#define RESULT_NO_DIALTONE 6
|
||||
#define RESULT_BUSY 7
|
||||
#define RESULT_NO_ANSWER 8
|
||||
#define RESULT_RINGING 9
|
||||
#define RESULT_NO_MSN_EAZ 10
|
||||
#define RESULT_VCON 11
|
||||
#define RESULT_RUNG 12
|
||||
|
||||
#define TTY_IS_FCLASS1(info) \
|
||||
((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
|
||||
(info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
|
||||
#define TTY_IS_FCLASS2(info) \
|
||||
((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
|
||||
(info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
|
||||
|
||||
extern void isdn_tty_modem_escape(void);
|
||||
extern void isdn_tty_modem_ring(void);
|
||||
extern void isdn_tty_carrier_timeout(void);
|
||||
extern void isdn_tty_modem_xmit(void);
|
||||
extern int isdn_tty_modem_init(void);
|
||||
extern void isdn_tty_exit(void);
|
||||
extern void isdn_tty_readmodem(void);
|
||||
extern int isdn_tty_find_icall(int, int, setup_parm *);
|
||||
extern void isdn_tty_cleanup_xmit(modem_info *);
|
||||
extern int isdn_tty_stat_callback(int, isdn_ctrl *);
|
||||
extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
|
||||
extern int isdn_tty_capi_facility(capi_msg *cm);
|
||||
extern void isdn_tty_at_cout(char *, modem_info *);
|
||||
extern void isdn_tty_modem_hup(modem_info *, int);
|
||||
#ifdef CONFIG_ISDN_TTY_FAX
|
||||
extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
|
||||
extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
|
||||
extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
|
||||
#endif
|
1122
drivers/isdn/i4l/isdn_ttyfax.c
Normal file
1122
drivers/isdn/i4l/isdn_ttyfax.c
Normal file
File diff suppressed because it is too large
Load Diff
18
drivers/isdn/i4l/isdn_ttyfax.h
Normal file
18
drivers/isdn/i4l/isdn_ttyfax.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* $Id: isdn_ttyfax.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem, tty_fax related functions (linklevel).
|
||||
*
|
||||
* Copyright 1999 by Armin Schindler (mac@melware.de)
|
||||
* Copyright 1999 by Ralf Spachmann (mel@melware.de)
|
||||
* Copyright 1999 by Cytronics & Melware
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define XON 0x11
|
||||
#define XOFF 0x13
|
||||
#define DC2 0x12
|
||||
|
617
drivers/isdn/i4l/isdn_v110.c
Normal file
617
drivers/isdn/i4l/isdn_v110.c
Normal file
@@ -0,0 +1,617 @@
|
||||
/* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, V.110 related functions (linklevel).
|
||||
*
|
||||
* Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/isdn.h>
|
||||
#include "isdn_v110.h"
|
||||
|
||||
#undef ISDN_V110_DEBUG
|
||||
|
||||
char *isdn_v110_revision = "$Revision: 1.1.2.2 $";
|
||||
|
||||
#define V110_38400 255
|
||||
#define V110_19200 15
|
||||
#define V110_9600 3
|
||||
|
||||
/*
|
||||
* The following data are precoded matrices, online and offline matrix
|
||||
* for 9600, 19200 und 38400, respectively
|
||||
*/
|
||||
static unsigned char V110_OnMatrix_9600[] =
|
||||
{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
|
||||
0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
|
||||
0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
|
||||
0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
|
||||
|
||||
static unsigned char V110_OffMatrix_9600[] =
|
||||
{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
static unsigned char V110_OnMatrix_19200[] =
|
||||
{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
|
||||
0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
|
||||
|
||||
static unsigned char V110_OffMatrix_19200[] =
|
||||
{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
static unsigned char V110_OnMatrix_38400[] =
|
||||
{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
|
||||
|
||||
static unsigned char V110_OffMatrix_38400[] =
|
||||
{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
/*
|
||||
* FlipBits reorders sequences of keylen bits in one byte.
|
||||
* E.g. source order 7654321 will be converted to 45670123 when keylen = 4,
|
||||
* and to 67452301 when keylen = 2. This is necessary because ordering on
|
||||
* the isdn line is the other way.
|
||||
*/
|
||||
static __inline unsigned char
|
||||
FlipBits(unsigned char c, int keylen)
|
||||
{
|
||||
unsigned char b = c;
|
||||
unsigned char bit = 128;
|
||||
int i;
|
||||
int j;
|
||||
int hunks = (8 / keylen);
|
||||
|
||||
c = 0;
|
||||
for (i = 0; i < hunks; i++) {
|
||||
for (j = 0; j < keylen; j++) {
|
||||
if (b & (bit >> j))
|
||||
c |= bit >> (keylen - j - 1);
|
||||
}
|
||||
bit >>= keylen;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/* isdn_v110_open allocates and initializes private V.110 data
|
||||
* structures and returns a pointer to these.
|
||||
*/
|
||||
static isdn_v110_stream *
|
||||
isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
|
||||
{
|
||||
int i;
|
||||
isdn_v110_stream *v;
|
||||
|
||||
if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
|
||||
return NULL;
|
||||
memset(v, 0, sizeof(isdn_v110_stream));
|
||||
v->key = key;
|
||||
v->nbits = 0;
|
||||
for (i = 0; key & (1 << i); i++)
|
||||
v->nbits++;
|
||||
|
||||
v->nbytes = 8 / v->nbits;
|
||||
v->decodelen = 0;
|
||||
|
||||
switch (key) {
|
||||
case V110_38400:
|
||||
v->OnlineFrame = V110_OnMatrix_38400;
|
||||
v->OfflineFrame = V110_OffMatrix_38400;
|
||||
break;
|
||||
case V110_19200:
|
||||
v->OnlineFrame = V110_OnMatrix_19200;
|
||||
v->OfflineFrame = V110_OffMatrix_19200;
|
||||
break;
|
||||
default:
|
||||
v->OnlineFrame = V110_OnMatrix_9600;
|
||||
v->OfflineFrame = V110_OffMatrix_9600;
|
||||
break;
|
||||
}
|
||||
v->framelen = v->nbytes * 10;
|
||||
v->SyncInit = 5;
|
||||
v->introducer = 0;
|
||||
v->dbit = 1;
|
||||
v->b = 0;
|
||||
v->skbres = hdrlen;
|
||||
v->maxsize = maxsize - hdrlen;
|
||||
if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) {
|
||||
kfree(v);
|
||||
return NULL;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/* isdn_v110_close frees private V.110 data structures */
|
||||
void
|
||||
isdn_v110_close(isdn_v110_stream * v)
|
||||
{
|
||||
if (v == NULL)
|
||||
return;
|
||||
#ifdef ISDN_V110_DEBUG
|
||||
printk(KERN_DEBUG "v110 close\n");
|
||||
#endif
|
||||
kfree(v->encodebuf);
|
||||
kfree(v);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ValidHeaderBytes return the number of valid bytes in v->decodebuf
|
||||
*/
|
||||
static int
|
||||
ValidHeaderBytes(isdn_v110_stream * v)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; (i < v->decodelen) && (i < v->nbytes); i++)
|
||||
if ((v->decodebuf[i] & v->key) != 0)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* SyncHeader moves the decodebuf ptr to the next valid header
|
||||
*/
|
||||
static void
|
||||
SyncHeader(isdn_v110_stream * v)
|
||||
{
|
||||
unsigned char *rbuf = v->decodebuf;
|
||||
int len = v->decodelen;
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
for (rbuf++, len--; len > 0; len--, rbuf++) /* such den SyncHeader in buf ! */
|
||||
if ((*rbuf & v->key) == 0) /* erstes byte gefunden ? */
|
||||
break; /* jupp! */
|
||||
if (len)
|
||||
memcpy(v->decodebuf, rbuf, len);
|
||||
|
||||
v->decodelen = len;
|
||||
#ifdef ISDN_V110_DEBUG
|
||||
printk(KERN_DEBUG "isdn_v110: Header resync\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
|
||||
len is the number of matrix-lines. len must be a multiple of 10, i.e.
|
||||
only complete matices must be given.
|
||||
From these, netto data is extracted and returned in buf. The return-value
|
||||
is the bytecount of the decoded data.
|
||||
*/
|
||||
static int
|
||||
DecodeMatrix(isdn_v110_stream * v, unsigned char *m, int len, unsigned char *buf)
|
||||
{
|
||||
int line = 0;
|
||||
int buflen = 0;
|
||||
int mbit = 64;
|
||||
int introducer = v->introducer;
|
||||
int dbit = v->dbit;
|
||||
unsigned char b = v->b;
|
||||
|
||||
while (line < len) { /* Are we done with all lines of the matrix? */
|
||||
if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */
|
||||
if (m[line] != 0x00) { /* not 0 ? -> error! */
|
||||
#ifdef ISDN_V110_DEBUG
|
||||
printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
|
||||
/* returning now is not the right thing, though :-( */
|
||||
#endif
|
||||
}
|
||||
line++; /* next line of matrix */
|
||||
continue;
|
||||
} else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */
|
||||
if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */
|
||||
#ifdef ISDN_V110_DEBUG
|
||||
printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
|
||||
/* returning now is not the right thing, though :-( */
|
||||
#endif
|
||||
}
|
||||
line++; /* next line */
|
||||
continue;
|
||||
} else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */
|
||||
introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */
|
||||
next_byte:
|
||||
if (mbit > 2) { /* was it the last bit in this line ? */
|
||||
mbit >>= 1; /* no -> take next */
|
||||
continue;
|
||||
} /* otherwise start with leftmost bit in the next line */
|
||||
mbit = 64;
|
||||
line++;
|
||||
continue;
|
||||
} else { /* otherwise we need to set a data bit */
|
||||
if (m[line] & mbit) /* was that bit set in the matrix ? */
|
||||
b |= dbit; /* yes -> set it in the data byte */
|
||||
else
|
||||
b &= dbit - 1; /* no -> clear it in the data byte */
|
||||
if (dbit < 128) /* is that data byte done ? */
|
||||
dbit <<= 1; /* no, got the next bit */
|
||||
else { /* data byte is done */
|
||||
buf[buflen++] = b; /* copy byte into the output buffer */
|
||||
introducer = b = 0; /* init of the intro sequence and of the data byte */
|
||||
dbit = 1; /* next we look for the 0th bit */
|
||||
}
|
||||
goto next_byte; /* look for next bit in the matrix */
|
||||
}
|
||||
}
|
||||
v->introducer = introducer;
|
||||
v->dbit = dbit;
|
||||
v->b = b;
|
||||
return buflen; /* return number of bytes in the output buffer */
|
||||
}
|
||||
|
||||
/*
|
||||
* DecodeStream receives V.110 coded data from the input stream. It recovers the
|
||||
* original frames.
|
||||
* The input stream doesn't need to be framed
|
||||
*/
|
||||
struct sk_buff *
|
||||
isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int len;
|
||||
unsigned char *v110_buf;
|
||||
unsigned char *rbuf;
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_WARNING "isdn_v110_decode called with NULL skb!\n");
|
||||
return NULL;
|
||||
}
|
||||
rbuf = skb->data;
|
||||
len = skb->len;
|
||||
if (v == NULL) {
|
||||
/* invalid handle, no chance to proceed */
|
||||
printk(KERN_WARNING "isdn_v110_decode called with NULL stream!\n");
|
||||
dev_kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
if (v->decodelen == 0) /* cache empty? */
|
||||
for (; len > 0; len--, rbuf++) /* scan for SyncHeader in buf */
|
||||
if ((*rbuf & v->key) == 0)
|
||||
break; /* found first byte */
|
||||
if (len == 0) {
|
||||
dev_kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
/* copy new data to decode-buffer */
|
||||
memcpy(&(v->decodebuf[v->decodelen]), rbuf, len);
|
||||
v->decodelen += len;
|
||||
ReSync:
|
||||
if (v->decodelen < v->nbytes) { /* got a new header ? */
|
||||
dev_kfree_skb(skb);
|
||||
return NULL; /* no, try later */
|
||||
}
|
||||
if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */
|
||||
SyncHeader(v); /* no -> look for header */
|
||||
goto ReSync;
|
||||
}
|
||||
len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
|
||||
if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) {
|
||||
printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n");
|
||||
dev_kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
v110_buf[i] = 0;
|
||||
for (j = 0; j < v->nbytes; j++)
|
||||
v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits));
|
||||
v110_buf[i] = FlipBits(v110_buf[i], v->nbits);
|
||||
}
|
||||
v->decodelen = (v->decodelen % (10 * v->nbytes));
|
||||
memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen);
|
||||
|
||||
skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data));
|
||||
kfree(v110_buf);
|
||||
if (skb->len)
|
||||
return skb;
|
||||
else {
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* EncodeMatrix takes input data in buf, len is the bytecount.
|
||||
Data is encoded into v110 frames in m. Return value is the number of
|
||||
matrix-lines generated.
|
||||
*/
|
||||
static int
|
||||
EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
|
||||
{
|
||||
int line = 0;
|
||||
int i = 0;
|
||||
int mbit = 128;
|
||||
int dbit = 1;
|
||||
int introducer = 3;
|
||||
int ibit[] = {0, 1, 1};
|
||||
|
||||
while ((i < len) && (line < mlen)) { /* while we still have input data */
|
||||
switch (line % 10) { /* in which line of the matrix are we? */
|
||||
case 0:
|
||||
m[line++] = 0x00; /* line 0 is always 0 */
|
||||
mbit = 128; /* go on with the 7th bit */
|
||||
break;
|
||||
case 5:
|
||||
m[line++] = 0xbf; /* line 5 is always 10111111 */
|
||||
mbit = 128; /* go on with the 7th bit */
|
||||
break;
|
||||
}
|
||||
if (line >= mlen) {
|
||||
printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
|
||||
return line;
|
||||
}
|
||||
next_bit:
|
||||
switch (mbit) { /* leftmost or rightmost bit ? */
|
||||
case 1:
|
||||
line++; /* rightmost -> go to next line */
|
||||
if (line >= mlen) {
|
||||
printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
|
||||
return line;
|
||||
}
|
||||
case 128:
|
||||
m[line] = 128; /* leftmost -> set byte to 1000000 */
|
||||
mbit = 64; /* current bit in the matrix line */
|
||||
continue;
|
||||
}
|
||||
if (introducer) { /* set 110 sequence ? */
|
||||
introducer--; /* set on digit less */
|
||||
m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */
|
||||
mbit >>= 1; /* bit of matrix line >> 1 */
|
||||
goto next_bit; /* and go on there */
|
||||
} /* else push data bits into the matrix! */
|
||||
m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */
|
||||
if (dbit == 128) { /* was it the last one? */
|
||||
dbit = 1; /* then go on with first bit of */
|
||||
i++; /* next byte in input buffer */
|
||||
if (i < len) /* input buffer done ? */
|
||||
introducer = 3; /* no, write introducer 110 */
|
||||
else { /* input buffer done ! */
|
||||
m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */
|
||||
break;
|
||||
}
|
||||
} else /* not the last data bit */
|
||||
dbit <<= 1; /* then go to next data bit */
|
||||
mbit >>= 1; /* go to next bit of matrix */
|
||||
goto next_bit;
|
||||
|
||||
}
|
||||
/* if necessary, generate remaining lines of the matrix... */
|
||||
if ((line) && ((line + 10) < mlen))
|
||||
switch (++line % 10) {
|
||||
case 1:
|
||||
m[line++] = 0xfe;
|
||||
case 2:
|
||||
m[line++] = 0xfe;
|
||||
case 3:
|
||||
m[line++] = 0xfe;
|
||||
case 4:
|
||||
m[line++] = 0xfe;
|
||||
case 5:
|
||||
m[line++] = 0xbf;
|
||||
case 6:
|
||||
m[line++] = 0xfe;
|
||||
case 7:
|
||||
m[line++] = 0xfe;
|
||||
case 8:
|
||||
m[line++] = 0xfe;
|
||||
case 9:
|
||||
m[line++] = 0xfe;
|
||||
}
|
||||
return line; /* that's how many lines we have */
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a sync frame.
|
||||
*/
|
||||
static struct sk_buff *
|
||||
isdn_v110_sync(isdn_v110_stream *v)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (v == NULL) {
|
||||
/* invalid handle, no chance to proceed */
|
||||
printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
|
||||
return NULL;
|
||||
}
|
||||
if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
|
||||
skb_reserve(skb, v->skbres);
|
||||
memcpy(skb_put(skb, v->framelen), v->OfflineFrame, v->framelen);
|
||||
}
|
||||
return skb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build an idle frame.
|
||||
*/
|
||||
static struct sk_buff *
|
||||
isdn_v110_idle(isdn_v110_stream *v)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (v == NULL) {
|
||||
/* invalid handle, no chance to proceed */
|
||||
printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
|
||||
return NULL;
|
||||
}
|
||||
if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
|
||||
skb_reserve(skb, v->skbres);
|
||||
memcpy(skb_put(skb, v->framelen), v->OnlineFrame, v->framelen);
|
||||
}
|
||||
return skb;
|
||||
}
|
||||
|
||||
struct sk_buff *
|
||||
isdn_v110_encode(isdn_v110_stream * v, struct sk_buff *skb)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int rlen;
|
||||
int mlen;
|
||||
int olen;
|
||||
int size;
|
||||
int sval1;
|
||||
int sval2;
|
||||
int nframes;
|
||||
unsigned char *v110buf;
|
||||
unsigned char *rbuf;
|
||||
struct sk_buff *nskb;
|
||||
|
||||
if (v == NULL) {
|
||||
/* invalid handle, no chance to proceed */
|
||||
printk(KERN_WARNING "isdn_v110_encode called with NULL stream!\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!skb) {
|
||||
/* invalid skb, no chance to proceed */
|
||||
printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n");
|
||||
return NULL;
|
||||
}
|
||||
rlen = skb->len;
|
||||
nframes = (rlen + 3) / 4;
|
||||
v110buf = v->encodebuf;
|
||||
if ((nframes * 40) > v->maxsize) {
|
||||
size = v->maxsize;
|
||||
rlen = v->maxsize / 40;
|
||||
} else
|
||||
size = nframes * 40;
|
||||
if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) {
|
||||
printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n");
|
||||
return NULL;
|
||||
}
|
||||
skb_reserve(nskb, v->skbres + sizeof(int));
|
||||
if (skb->len == 0) {
|
||||
memcpy(skb_put(nskb, v->framelen), v->OnlineFrame, v->framelen);
|
||||
*((int *)skb_push(nskb, sizeof(int))) = 0;
|
||||
return nskb;
|
||||
}
|
||||
mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
|
||||
/* now distribute 2 or 4 bits each to the output stream! */
|
||||
rbuf = skb_put(nskb, size);
|
||||
olen = 0;
|
||||
sval1 = 8 - v->nbits;
|
||||
sval2 = v->key << sval1;
|
||||
for (i = 0; i < mlen; i++) {
|
||||
v110buf[i] = FlipBits(v110buf[i], v->nbits);
|
||||
for (j = 0; j < v->nbytes; j++) {
|
||||
if (size--)
|
||||
*rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1);
|
||||
else {
|
||||
printk(KERN_WARNING "isdn_v110_encode: buffers full!\n");
|
||||
goto buffer_full;
|
||||
}
|
||||
olen++;
|
||||
}
|
||||
}
|
||||
buffer_full:
|
||||
skb_trim(nskb, olen);
|
||||
*((int *)skb_push(nskb, sizeof(int))) = rlen;
|
||||
return nskb;
|
||||
}
|
||||
|
||||
int
|
||||
isdn_v110_stat_callback(int idx, isdn_ctrl * c)
|
||||
{
|
||||
isdn_v110_stream *v = NULL;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (idx < 0)
|
||||
return 0;
|
||||
switch (c->command) {
|
||||
case ISDN_STAT_BSENT:
|
||||
/* Keep the send-queue of the driver filled
|
||||
* with frames:
|
||||
* If number of outstanding frames < 3,
|
||||
* send down an Idle-Frame (or an Sync-Frame, if
|
||||
* v->SyncInit != 0).
|
||||
*/
|
||||
if (!(v = dev->v110[idx]))
|
||||
return 0;
|
||||
atomic_inc(&dev->v110use[idx]);
|
||||
for (i=0; i * v->framelen < c->parm.length; i++) {
|
||||
if (v->skbidle > 0) {
|
||||
v->skbidle--;
|
||||
ret = 1;
|
||||
} else {
|
||||
if (v->skbuser > 0)
|
||||
v->skbuser--;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
for (i = v->skbuser + v->skbidle; i < 2; i++) {
|
||||
struct sk_buff *skb;
|
||||
if (v->SyncInit > 0)
|
||||
skb = isdn_v110_sync(v);
|
||||
else
|
||||
skb = isdn_v110_idle(v);
|
||||
if (skb) {
|
||||
if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
} else {
|
||||
if (v->SyncInit)
|
||||
v->SyncInit--;
|
||||
v->skbidle++;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
atomic_dec(&dev->v110use[idx]);
|
||||
return ret;
|
||||
case ISDN_STAT_DHUP:
|
||||
case ISDN_STAT_BHUP:
|
||||
while (1) {
|
||||
atomic_inc(&dev->v110use[idx]);
|
||||
if (atomic_dec_and_test(&dev->v110use[idx])) {
|
||||
isdn_v110_close(dev->v110[idx]);
|
||||
dev->v110[idx] = NULL;
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
break;
|
||||
case ISDN_STAT_BCONN:
|
||||
if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
|
||||
int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
|
||||
int maxsize = dev->drv[c->driver]->interface->maxbufsize;
|
||||
atomic_inc(&dev->v110use[idx]);
|
||||
switch (dev->v110emu[idx]) {
|
||||
case ISDN_PROTO_L2_V11096:
|
||||
dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
|
||||
break;
|
||||
case ISDN_PROTO_L2_V11019:
|
||||
dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
|
||||
break;
|
||||
case ISDN_PROTO_L2_V11038:
|
||||
dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
if ((v = dev->v110[idx])) {
|
||||
while (v->SyncInit) {
|
||||
struct sk_buff *skb = isdn_v110_sync(v);
|
||||
if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
|
||||
dev_kfree_skb(skb);
|
||||
/* Unable to send, try later */
|
||||
break;
|
||||
}
|
||||
v->SyncInit--;
|
||||
v->skbidle++;
|
||||
}
|
||||
} else
|
||||
printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
|
||||
atomic_dec(&dev->v110use[idx]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
29
drivers/isdn/i4l/isdn_v110.h
Normal file
29
drivers/isdn/i4l/isdn_v110.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* $Id: isdn_v110.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, V.110 related functions (linklevel).
|
||||
*
|
||||
* Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _isdn_v110_h_
|
||||
#define _isdn_v110_h_
|
||||
|
||||
/*
|
||||
* isdn_v110_encode will take raw data and encode it using V.110
|
||||
*/
|
||||
extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
|
||||
|
||||
/*
|
||||
* isdn_v110_decode receives V.110 coded data from the stream and rebuilds
|
||||
* frames from them. The source stream doesn't need to be framed.
|
||||
*/
|
||||
extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
|
||||
|
||||
extern int isdn_v110_stat_callback(int, isdn_ctrl *);
|
||||
extern void isdn_v110_close(isdn_v110_stream * v);
|
||||
|
||||
#endif
|
328
drivers/isdn/i4l/isdn_x25iface.c
Normal file
328
drivers/isdn/i4l/isdn_x25iface.c
Normal file
@@ -0,0 +1,328 @@
|
||||
/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, X.25 related functions
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
* stuff needed to support the Linux X.25 PLP code on top of devices that
|
||||
* can provide a lab_b service using the concap_proto mechanism.
|
||||
* This module supports a network interface wich provides lapb_sematics
|
||||
* -- as defined in Documentation/networking/x25-iface.txt -- to
|
||||
* the upper layer and assumes that the lower layer provides a reliable
|
||||
* data link service by means of the concap_device_ops callbacks.
|
||||
*
|
||||
* Only protocol specific stuff goes here. Device specific stuff
|
||||
* goes to another -- device related -- concap_proto support source file.
|
||||
*
|
||||
*/
|
||||
|
||||
/* #include <linux/isdn.h> */
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/concap.h>
|
||||
#include <linux/wanrouter.h>
|
||||
#include <net/x25device.h>
|
||||
#include "isdn_x25iface.h"
|
||||
|
||||
/* for debugging messages not to cause an oops when device pointer is NULL*/
|
||||
#define MY_DEVNAME(dev) ( (dev) ? (dev)->name : "DEVICE UNSPECIFIED" )
|
||||
|
||||
|
||||
typedef struct isdn_x25iface_proto_data {
|
||||
int magic;
|
||||
enum wan_states state;
|
||||
/* Private stuff, not to be accessed via proto_data. We provide the
|
||||
other storage for the concap_proto instance here as well,
|
||||
enabling us to allocate both with just one kmalloc(): */
|
||||
struct concap_proto priv;
|
||||
} ix25_pdata_t;
|
||||
|
||||
|
||||
|
||||
/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
|
||||
void isdn_x25iface_proto_del( struct concap_proto * );
|
||||
int isdn_x25iface_proto_close( struct concap_proto * );
|
||||
int isdn_x25iface_proto_restart( struct concap_proto *,
|
||||
struct net_device *,
|
||||
struct concap_device_ops *);
|
||||
int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * );
|
||||
int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * );
|
||||
int isdn_x25iface_connect_ind( struct concap_proto * );
|
||||
int isdn_x25iface_disconn_ind( struct concap_proto * );
|
||||
|
||||
|
||||
static struct concap_proto_ops ix25_pops = {
|
||||
&isdn_x25iface_proto_new,
|
||||
&isdn_x25iface_proto_del,
|
||||
&isdn_x25iface_proto_restart,
|
||||
&isdn_x25iface_proto_close,
|
||||
&isdn_x25iface_xmit,
|
||||
&isdn_x25iface_receive,
|
||||
&isdn_x25iface_connect_ind,
|
||||
&isdn_x25iface_disconn_ind
|
||||
};
|
||||
|
||||
/* error message helper function */
|
||||
static void illegal_state_warn( unsigned state, unsigned char firstbyte)
|
||||
{
|
||||
printk( KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
|
||||
"current state %d\n",firstbyte, state );
|
||||
}
|
||||
|
||||
/* check protocol data field for consistency */
|
||||
static int pdata_is_bad( ix25_pdata_t * pda ){
|
||||
|
||||
if( pda && pda -> magic == ISDN_X25IFACE_MAGIC ) return 0;
|
||||
printk( KERN_WARNING
|
||||
"isdn_x25iface_xxx: illegal pointer to proto data\n" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* create a new x25 interface protocol instance
|
||||
*/
|
||||
struct concap_proto * isdn_x25iface_proto_new(void)
|
||||
{
|
||||
ix25_pdata_t * tmp = kmalloc(sizeof(ix25_pdata_t),GFP_KERNEL);
|
||||
IX25DEBUG("isdn_x25iface_proto_new\n");
|
||||
if( tmp ){
|
||||
tmp -> magic = ISDN_X25IFACE_MAGIC;
|
||||
tmp -> state = WAN_UNCONFIGURED;
|
||||
/* private data space used to hold the concap_proto data.
|
||||
Only to be accessed via the returned pointer */
|
||||
spin_lock_init(&tmp->priv.lock);
|
||||
tmp -> priv.dops = NULL;
|
||||
tmp -> priv.net_dev = NULL;
|
||||
tmp -> priv.pops = &ix25_pops;
|
||||
tmp -> priv.flags = 0;
|
||||
tmp -> priv.proto_data = tmp;
|
||||
return( &(tmp -> priv) );
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
/* close the x25iface encapsulation protocol
|
||||
*/
|
||||
int isdn_x25iface_proto_close(struct concap_proto *cprot){
|
||||
|
||||
ix25_pdata_t *tmp;
|
||||
int ret = 0;
|
||||
ulong flags;
|
||||
|
||||
if( ! cprot ){
|
||||
printk( KERN_ERR "isdn_x25iface_proto_close: "
|
||||
"invalid concap_proto pointer\n" );
|
||||
return -1;
|
||||
}
|
||||
IX25DEBUG( "isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot -> net_dev) );
|
||||
spin_lock_irqsave(&cprot->lock, flags);
|
||||
cprot -> dops = NULL;
|
||||
cprot -> net_dev = NULL;
|
||||
tmp = cprot -> proto_data;
|
||||
if( pdata_is_bad( tmp ) ){
|
||||
ret = -1;
|
||||
} else {
|
||||
tmp -> state = WAN_UNCONFIGURED;
|
||||
}
|
||||
spin_unlock_irqrestore(&cprot->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Delete the x25iface encapsulation protocol instance
|
||||
*/
|
||||
void isdn_x25iface_proto_del(struct concap_proto *cprot){
|
||||
|
||||
ix25_pdata_t * tmp;
|
||||
|
||||
IX25DEBUG( "isdn_x25iface_proto_del \n" );
|
||||
if( ! cprot ){
|
||||
printk( KERN_ERR "isdn_x25iface_proto_del: "
|
||||
"concap_proto pointer is NULL\n" );
|
||||
return;
|
||||
}
|
||||
tmp = cprot -> proto_data;
|
||||
if( tmp == NULL ){
|
||||
printk( KERN_ERR "isdn_x25iface_proto_del: inconsistent "
|
||||
"proto_data pointer (maybe already deleted?)\n");
|
||||
return;
|
||||
}
|
||||
/* close if the protocol is still open */
|
||||
if( cprot -> dops ) isdn_x25iface_proto_close(cprot);
|
||||
/* freeing the storage should be sufficient now. But some additional
|
||||
settings might help to catch wild pointer bugs */
|
||||
tmp -> magic = 0;
|
||||
cprot -> proto_data = NULL;
|
||||
|
||||
kfree( tmp );
|
||||
return;
|
||||
}
|
||||
|
||||
/* (re-)initialize the data structures for x25iface encapsulation
|
||||
*/
|
||||
int isdn_x25iface_proto_restart(struct concap_proto *cprot,
|
||||
struct net_device *ndev,
|
||||
struct concap_device_ops *dops)
|
||||
{
|
||||
ix25_pdata_t * pda = cprot -> proto_data ;
|
||||
ulong flags;
|
||||
|
||||
IX25DEBUG( "isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev) );
|
||||
|
||||
if ( pdata_is_bad( pda ) ) return -1;
|
||||
|
||||
if( !( dops && dops -> data_req && dops -> connect_req
|
||||
&& dops -> disconn_req ) ){
|
||||
printk( KERN_WARNING "isdn_x25iface_restart: required dops"
|
||||
" missing\n" );
|
||||
isdn_x25iface_proto_close(cprot);
|
||||
return -1;
|
||||
}
|
||||
spin_lock_irqsave(&cprot->lock, flags);
|
||||
cprot -> net_dev = ndev;
|
||||
cprot -> pops = &ix25_pops;
|
||||
cprot -> dops = dops;
|
||||
pda -> state = WAN_DISCONNECTED;
|
||||
spin_unlock_irqrestore(&cprot->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* deliver a dl_data frame received from i4l HL driver to the network layer
|
||||
*/
|
||||
int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
|
||||
{
|
||||
IX25DEBUG( "isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev) );
|
||||
if ( ( (ix25_pdata_t*) (cprot->proto_data) )
|
||||
-> state == WAN_CONNECTED ){
|
||||
if( skb_push(skb, 1)){
|
||||
skb -> data[0]=0x00;
|
||||
skb->protocol = x25_type_trans(skb, cprot->net_dev);
|
||||
netif_rx(skb);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev) );
|
||||
dev_kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* a connection set up is indicated by lower layer
|
||||
*/
|
||||
int isdn_x25iface_connect_ind(struct concap_proto *cprot)
|
||||
{
|
||||
struct sk_buff * skb = dev_alloc_skb(1);
|
||||
enum wan_states *state_p
|
||||
= &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
|
||||
IX25DEBUG( "isdn_x25iface_connect_ind %s \n"
|
||||
, MY_DEVNAME(cprot->net_dev) );
|
||||
if( *state_p == WAN_UNCONFIGURED ){
|
||||
printk(KERN_WARNING
|
||||
"isdn_x25iface_connect_ind while unconfigured %s\n"
|
||||
, MY_DEVNAME(cprot->net_dev) );
|
||||
return -1;
|
||||
}
|
||||
*state_p = WAN_CONNECTED;
|
||||
if( skb ){
|
||||
*( skb_put(skb, 1) ) = 0x01;
|
||||
skb->protocol = x25_type_trans(skb, cprot->net_dev);
|
||||
netif_rx(skb);
|
||||
return 0;
|
||||
} else {
|
||||
printk(KERN_WARNING "isdn_x25iface_connect_ind: "
|
||||
" out of memory -- disconnecting\n");
|
||||
cprot -> dops -> disconn_req(cprot);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* a disconnect is indicated by lower layer
|
||||
*/
|
||||
int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
enum wan_states *state_p
|
||||
= &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
|
||||
IX25DEBUG( "isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot -> net_dev) );
|
||||
if( *state_p == WAN_UNCONFIGURED ){
|
||||
printk(KERN_WARNING
|
||||
"isdn_x25iface_disconn_ind while unconfigured\n");
|
||||
return -1;
|
||||
}
|
||||
if(! cprot -> net_dev) return -1;
|
||||
*state_p = WAN_DISCONNECTED;
|
||||
skb = dev_alloc_skb(1);
|
||||
if( skb ){
|
||||
*( skb_put(skb, 1) ) = 0x02;
|
||||
skb->protocol = x25_type_trans(skb, cprot->net_dev);
|
||||
netif_rx(skb);
|
||||
return 0;
|
||||
} else {
|
||||
printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
|
||||
" out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* process a frame handed over to us from linux network layer. First byte
|
||||
semantics as defined in Documentation/networking/x25-iface.txt
|
||||
*/
|
||||
int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
|
||||
{
|
||||
unsigned char firstbyte = skb->data[0];
|
||||
enum wan_states *state = &((ix25_pdata_t*)cprot->proto_data)->state;
|
||||
int ret = 0;
|
||||
IX25DEBUG( "isdn_x25iface_xmit: %s first=%x state=%d \n", MY_DEVNAME(cprot -> net_dev), firstbyte, *state );
|
||||
switch ( firstbyte ){
|
||||
case 0x00: /* dl_data request */
|
||||
if( *state == WAN_CONNECTED ){
|
||||
skb_pull(skb, 1);
|
||||
cprot -> net_dev -> trans_start = jiffies;
|
||||
ret = ( cprot -> dops -> data_req(cprot, skb) );
|
||||
/* prepare for future retransmissions */
|
||||
if( ret ) skb_push(skb,1);
|
||||
return ret;
|
||||
}
|
||||
illegal_state_warn( *state, firstbyte );
|
||||
break;
|
||||
case 0x01: /* dl_connect request */
|
||||
if( *state == WAN_DISCONNECTED ){
|
||||
*state = WAN_CONNECTING;
|
||||
ret = cprot -> dops -> connect_req(cprot);
|
||||
if(ret){
|
||||
/* reset state and notify upper layer about
|
||||
* immidiatly failed attempts */
|
||||
isdn_x25iface_disconn_ind(cprot);
|
||||
}
|
||||
} else {
|
||||
illegal_state_warn( *state, firstbyte );
|
||||
}
|
||||
break;
|
||||
case 0x02: /* dl_disconnect request */
|
||||
switch ( *state ){
|
||||
case WAN_DISCONNECTED:
|
||||
/* Should not happen. However, give upper layer a
|
||||
chance to recover from inconstistency but don't
|
||||
trust the lower layer sending the disconn_confirm
|
||||
when already disconnected */
|
||||
printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
|
||||
" requested while disconnected\n" );
|
||||
isdn_x25iface_disconn_ind(cprot);
|
||||
break; /* prevent infinite loops */
|
||||
case WAN_CONNECTING:
|
||||
case WAN_CONNECTED:
|
||||
*state = WAN_DISCONNECTED;
|
||||
cprot -> dops -> disconn_req(cprot);
|
||||
break;
|
||||
default:
|
||||
illegal_state_warn( *state, firstbyte );
|
||||
}
|
||||
break;
|
||||
case 0x03: /* changing lapb parameters requested */
|
||||
printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
|
||||
" options not yet supported\n");
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
|
||||
" first byte %x ignored:\n", firstbyte);
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
39
drivers/isdn/i4l/isdn_x25iface.h
Normal file
39
drivers/isdn/i4l/isdn_x25iface.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* $Id: isdn_x25iface.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem, x.25 related functions
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_ISDN_X25IFACE_H
|
||||
#define _LINUX_ISDN_X25IFACE_H
|
||||
|
||||
#define ISDN_X25IFACE_MAGIC 0x1e75a2b9
|
||||
/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */
|
||||
#ifdef DEBUG_ISDN_X25
|
||||
# define IX25DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args)
|
||||
#else
|
||||
# define IX25DEBUG(fmt,args...)
|
||||
#endif
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/wanrouter.h>
|
||||
#include <linux/isdn.h>
|
||||
#include <linux/concap.h>
|
||||
|
||||
extern struct concap_proto_ops * isdn_x25iface_concap_proto_ops_pt;
|
||||
extern struct concap_proto * isdn_x25iface_proto_new(void);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user